xref: /petsc/src/dm/impls/plex/plex.c (revision cbc6b2250e380677eada4bbc58a36dc55ca92067)
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);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; /* Just vertices */
5247     else vertexchart = PETSC_FALSE;                                 /* Assume all interpolated points are in chart */
5248   }
5249   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
5250   for (PetscInt d=1; d<=dim; d++) {
5251     PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
5252     PetscInt *perm;
5253 
5254     for (f = 0; f < Nf; ++f) {
5255       ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
5256       size += PetscPowInt(k+1, d)*Nc;
5257     }
5258     ierr = PetscMalloc1(size, &perm);CHKERRQ(ierr);
5259     for (f = 0; f < Nf; ++f) {
5260       switch (d) {
5261       case 1:
5262         ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
5263         /*
5264          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
5265          We want              [ vtx0; edge of length k-1; vtx1 ]
5266          */
5267         for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset;
5268         for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset;
5269         for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset;
5270         foffset = offset;
5271         break;
5272       case 2:
5273         /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
5274         ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
5275         /* The SEM order is
5276 
5277          v_lb, {e_b}, v_rb,
5278          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
5279          v_lt, reverse {e_t}, v_rt
5280          */
5281         {
5282           const PetscInt of   = 0;
5283           const PetscInt oeb  = of   + PetscSqr(k-1);
5284           const PetscInt oer  = oeb  + (k-1);
5285           const PetscInt oet  = oer  + (k-1);
5286           const PetscInt oel  = oet  + (k-1);
5287           const PetscInt ovlb = oel  + (k-1);
5288           const PetscInt ovrb = ovlb + 1;
5289           const PetscInt ovrt = ovrb + 1;
5290           const PetscInt ovlt = ovrt + 1;
5291           PetscInt       o;
5292 
5293           /* bottom */
5294           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
5295           for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5296           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
5297           /* middle */
5298           for (i = 0; i < k-1; ++i) {
5299             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
5300             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;
5301             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
5302           }
5303           /* top */
5304           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
5305           for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5306           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
5307           foffset = offset;
5308         }
5309         break;
5310       case 3:
5311         /* The original hex closure is
5312 
5313          {c,
5314          f_b, f_t, f_f, f_b, f_r, f_l,
5315          e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
5316          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
5317          */
5318         ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
5319         /* The SEM order is
5320          Bottom Slice
5321          v_blf, {e^{(k-1)-n}_bf}, v_brf,
5322          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
5323          v_blb, {e_bb}, v_brb,
5324 
5325          Middle Slice (j)
5326          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
5327          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
5328          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
5329 
5330          Top Slice
5331          v_tlf, {e_tf}, v_trf,
5332          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
5333          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
5334          */
5335         {
5336           const PetscInt oc    = 0;
5337           const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
5338           const PetscInt oft   = ofb   + PetscSqr(k-1);
5339           const PetscInt off   = oft   + PetscSqr(k-1);
5340           const PetscInt ofk   = off   + PetscSqr(k-1);
5341           const PetscInt ofr   = ofk   + PetscSqr(k-1);
5342           const PetscInt ofl   = ofr   + PetscSqr(k-1);
5343           const PetscInt oebl  = ofl   + PetscSqr(k-1);
5344           const PetscInt oebb  = oebl  + (k-1);
5345           const PetscInt oebr  = oebb  + (k-1);
5346           const PetscInt oebf  = oebr  + (k-1);
5347           const PetscInt oetf  = oebf  + (k-1);
5348           const PetscInt oetr  = oetf  + (k-1);
5349           const PetscInt oetb  = oetr  + (k-1);
5350           const PetscInt oetl  = oetb  + (k-1);
5351           const PetscInt oerf  = oetl  + (k-1);
5352           const PetscInt oelf  = oerf  + (k-1);
5353           const PetscInt oelb  = oelf  + (k-1);
5354           const PetscInt oerb  = oelb  + (k-1);
5355           const PetscInt ovblf = oerb  + (k-1);
5356           const PetscInt ovblb = ovblf + 1;
5357           const PetscInt ovbrb = ovblb + 1;
5358           const PetscInt ovbrf = ovbrb + 1;
5359           const PetscInt ovtlf = ovbrf + 1;
5360           const PetscInt ovtrf = ovtlf + 1;
5361           const PetscInt ovtrb = ovtrf + 1;
5362           const PetscInt ovtlb = ovtrb + 1;
5363           PetscInt       o, n;
5364 
5365           /* Bottom Slice */
5366           /*   bottom */
5367           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
5368           for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5369           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
5370           /*   middle */
5371           for (i = 0; i < k-1; ++i) {
5372             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
5373             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;}
5374             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
5375           }
5376           /*   top */
5377           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
5378           for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5379           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
5380 
5381           /* Middle Slice */
5382           for (j = 0; j < k-1; ++j) {
5383             /*   bottom */
5384             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
5385             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;
5386             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
5387             /*   middle */
5388             for (i = 0; i < k-1; ++i) {
5389               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
5390               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;
5391               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
5392             }
5393             /*   top */
5394             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
5395             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;
5396             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
5397           }
5398 
5399           /* Top Slice */
5400           /*   bottom */
5401           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
5402           for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5403           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
5404           /*   middle */
5405           for (i = 0; i < k-1; ++i) {
5406             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
5407             for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
5408             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
5409           }
5410           /*   top */
5411           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
5412           for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5413           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
5414 
5415           foffset = offset;
5416         }
5417         break;
5418       default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", d);
5419       }
5420     }
5421     PetscCheckFalse(offset != size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
5422     /* Check permutation */
5423     {
5424       PetscInt *check;
5425 
5426       ierr = PetscMalloc1(size, &check);CHKERRQ(ierr);
5427       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]);}
5428       for (i = 0; i < size; ++i) check[perm[i]] = i;
5429       for (i = 0; i < size; ++i) {PetscCheckFalse(check[i] < 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
5430       ierr = PetscFree(check);CHKERRQ(ierr);
5431     }
5432     ierr = PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm);CHKERRQ(ierr);
5433   }
5434   PetscFunctionReturn(0);
5435 }
5436 
5437 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
5438 {
5439   PetscDS        prob;
5440   PetscInt       depth, Nf, h;
5441   DMLabel        label;
5442   PetscErrorCode ierr;
5443 
5444   PetscFunctionBeginHot;
5445   ierr = DMGetDS(dm, &prob);CHKERRQ(ierr);
5446   Nf      = prob->Nf;
5447   label   = dm->depthLabel;
5448   *dspace = NULL;
5449   if (field < Nf) {
5450     PetscObject disc = prob->disc[field];
5451 
5452     if (disc->classid == PETSCFE_CLASSID) {
5453       PetscDualSpace dsp;
5454 
5455       ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr);
5456       ierr = DMLabelGetNumValues(label,&depth);CHKERRQ(ierr);
5457       ierr = DMLabelGetValue(label,point,&h);CHKERRQ(ierr);
5458       h    = depth - 1 - h;
5459       if (h) {
5460         ierr = PetscDualSpaceGetHeightSubspace(dsp,h,dspace);CHKERRQ(ierr);
5461       } else {
5462         *dspace = dsp;
5463       }
5464     }
5465   }
5466   PetscFunctionReturn(0);
5467 }
5468 
5469 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5470 {
5471   PetscScalar    *array, *vArray;
5472   const PetscInt *cone, *coneO;
5473   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
5474   PetscErrorCode  ierr;
5475 
5476   PetscFunctionBeginHot;
5477   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5478   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
5479   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
5480   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
5481   if (!values || !*values) {
5482     if ((point >= pStart) && (point < pEnd)) {
5483       PetscInt dof;
5484 
5485       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5486       size += dof;
5487     }
5488     for (p = 0; p < numPoints; ++p) {
5489       const PetscInt cp = cone[p];
5490       PetscInt       dof;
5491 
5492       if ((cp < pStart) || (cp >= pEnd)) continue;
5493       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
5494       size += dof;
5495     }
5496     if (!values) {
5497       if (csize) *csize = size;
5498       PetscFunctionReturn(0);
5499     }
5500     ierr = DMGetWorkArray(dm, size, MPIU_SCALAR, &array);CHKERRQ(ierr);
5501   } else {
5502     array = *values;
5503   }
5504   size = 0;
5505   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
5506   if ((point >= pStart) && (point < pEnd)) {
5507     PetscInt     dof, off, d;
5508     PetscScalar *varr;
5509 
5510     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5511     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5512     varr = &vArray[off];
5513     for (d = 0; d < dof; ++d, ++offset) {
5514       array[offset] = varr[d];
5515     }
5516     size += dof;
5517   }
5518   for (p = 0; p < numPoints; ++p) {
5519     const PetscInt cp = cone[p];
5520     PetscInt       o  = coneO[p];
5521     PetscInt       dof, off, d;
5522     PetscScalar   *varr;
5523 
5524     if ((cp < pStart) || (cp >= pEnd)) continue;
5525     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
5526     ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
5527     varr = &vArray[off];
5528     if (o >= 0) {
5529       for (d = 0; d < dof; ++d, ++offset) {
5530         array[offset] = varr[d];
5531       }
5532     } else {
5533       for (d = dof-1; d >= 0; --d, ++offset) {
5534         array[offset] = varr[d];
5535       }
5536     }
5537     size += dof;
5538   }
5539   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
5540   if (!*values) {
5541     if (csize) *csize = size;
5542     *values = array;
5543   } else {
5544     PetscCheckFalse(size > *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
5545     *csize = size;
5546   }
5547   PetscFunctionReturn(0);
5548 }
5549 
5550 /* Compress out points not in the section */
5551 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
5552 {
5553   const PetscInt np = *numPoints;
5554   PetscInt       pStart, pEnd, p, q;
5555   PetscErrorCode ierr;
5556 
5557   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5558   for (p = 0, q = 0; p < np; ++p) {
5559     const PetscInt r = points[p*2];
5560     if ((r >= pStart) && (r < pEnd)) {
5561       points[q*2]   = r;
5562       points[q*2+1] = points[p*2+1];
5563       ++q;
5564     }
5565   }
5566   *numPoints = q;
5567   return 0;
5568 }
5569 
5570 /* Compressed closure does not apply closure permutation */
5571 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5572 {
5573   const PetscInt *cla = NULL;
5574   PetscInt       np, *pts = NULL;
5575   PetscErrorCode ierr;
5576 
5577   PetscFunctionBeginHot;
5578   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);CHKERRQ(ierr);
5579   if (*clPoints) {
5580     PetscInt dof, off;
5581 
5582     ierr = PetscSectionGetDof(*clSec, point, &dof);CHKERRQ(ierr);
5583     ierr = PetscSectionGetOffset(*clSec, point, &off);CHKERRQ(ierr);
5584     ierr = ISGetIndices(*clPoints, &cla);CHKERRQ(ierr);
5585     np   = dof/2;
5586     pts  = (PetscInt *) &cla[off];
5587   } else {
5588     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);CHKERRQ(ierr);
5589     ierr = CompressPoints_Private(section, &np, pts);CHKERRQ(ierr);
5590   }
5591   *numPoints = np;
5592   *points    = pts;
5593   *clp       = cla;
5594   PetscFunctionReturn(0);
5595 }
5596 
5597 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5598 {
5599   PetscErrorCode ierr;
5600 
5601   PetscFunctionBeginHot;
5602   if (!*clPoints) {
5603     ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);CHKERRQ(ierr);
5604   } else {
5605     ierr = ISRestoreIndices(*clPoints, clp);CHKERRQ(ierr);
5606   }
5607   *numPoints = 0;
5608   *points    = NULL;
5609   *clSec     = NULL;
5610   *clPoints  = NULL;
5611   *clp       = NULL;
5612   PetscFunctionReturn(0);
5613 }
5614 
5615 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
5616 {
5617   PetscInt          offset = 0, p;
5618   const PetscInt    **perms = NULL;
5619   const PetscScalar **flips = NULL;
5620   PetscErrorCode    ierr;
5621 
5622   PetscFunctionBeginHot;
5623   *size = 0;
5624   ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5625   for (p = 0; p < numPoints; p++) {
5626     const PetscInt    point = points[2*p];
5627     const PetscInt    *perm = perms ? perms[p] : NULL;
5628     const PetscScalar *flip = flips ? flips[p] : NULL;
5629     PetscInt          dof, off, d;
5630     const PetscScalar *varr;
5631 
5632     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5633     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5634     varr = &vArray[off];
5635     if (clperm) {
5636       if (perm) {
5637         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
5638       } else {
5639         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
5640       }
5641       if (flip) {
5642         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
5643       }
5644     } else {
5645       if (perm) {
5646         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
5647       } else {
5648         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
5649       }
5650       if (flip) {
5651         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
5652       }
5653     }
5654     offset += dof;
5655   }
5656   ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5657   *size = offset;
5658   PetscFunctionReturn(0);
5659 }
5660 
5661 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[])
5662 {
5663   PetscInt          offset = 0, f;
5664   PetscErrorCode    ierr;
5665 
5666   PetscFunctionBeginHot;
5667   *size = 0;
5668   for (f = 0; f < numFields; ++f) {
5669     PetscInt          p;
5670     const PetscInt    **perms = NULL;
5671     const PetscScalar **flips = NULL;
5672 
5673     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5674     for (p = 0; p < numPoints; p++) {
5675       const PetscInt    point = points[2*p];
5676       PetscInt          fdof, foff, b;
5677       const PetscScalar *varr;
5678       const PetscInt    *perm = perms ? perms[p] : NULL;
5679       const PetscScalar *flip = flips ? flips[p] : NULL;
5680 
5681       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5682       ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
5683       varr = &vArray[foff];
5684       if (clperm) {
5685         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
5686         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
5687         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
5688       } else {
5689         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
5690         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
5691         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
5692       }
5693       offset += fdof;
5694     }
5695     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5696   }
5697   *size = offset;
5698   PetscFunctionReturn(0);
5699 }
5700 
5701 /*@C
5702   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
5703 
5704   Not collective
5705 
5706   Input Parameters:
5707 + dm - The DM
5708 . section - The section describing the layout in v, or NULL to use the default section
5709 . v - The local vector
5710 - point - The point in the DM
5711 
5712   Input/Output Parameters:
5713 + csize  - The size of the input values array, or NULL; on output the number of values in the closure
5714 - values - An array to use for the values, or NULL to have it allocated automatically;
5715            if the user provided NULL, it is a borrowed array and should not be freed
5716 
5717 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
5718 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
5719 $ assembly function, and a user may already have allocated storage for this operation.
5720 $
5721 $ A typical use could be
5722 $
5723 $  values = NULL;
5724 $  ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
5725 $  for (cl = 0; cl < clSize; ++cl) {
5726 $    <Compute on closure>
5727 $  }
5728 $  ierr = DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
5729 $
5730 $ or
5731 $
5732 $  PetscMalloc1(clMaxSize, &values);
5733 $  for (p = pStart; p < pEnd; ++p) {
5734 $    clSize = clMaxSize;
5735 $    ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
5736 $    for (cl = 0; cl < clSize; ++cl) {
5737 $      <Compute on closure>
5738 $    }
5739 $  }
5740 $  PetscFree(values);
5741 
5742   Fortran Notes:
5743   Since it returns an array, this routine is only available in Fortran 90, and you must
5744   include petsc.h90 in your code.
5745 
5746   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5747 
5748   Level: intermediate
5749 
5750 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5751 @*/
5752 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5753 {
5754   PetscSection       clSection;
5755   IS                 clPoints;
5756   PetscInt          *points = NULL;
5757   const PetscInt    *clp, *perm;
5758   PetscInt           depth, numFields, numPoints, asize;
5759   PetscErrorCode     ierr;
5760 
5761   PetscFunctionBeginHot;
5762   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5763   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5764   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5765   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5766   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5767   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5768   if (depth == 1 && numFields < 2) {
5769     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
5770     PetscFunctionReturn(0);
5771   }
5772   /* Get points */
5773   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5774   /* Get sizes */
5775   asize = 0;
5776   for (PetscInt p = 0; p < numPoints*2; p += 2) {
5777     PetscInt dof;
5778     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5779     asize += dof;
5780   }
5781   if (values) {
5782     const PetscScalar *vArray;
5783     PetscInt          size;
5784 
5785     if (*values) {
5786       PetscCheckFalse(*csize < asize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided array size %D not sufficient to hold closure size %D", *csize, asize);
5787     } else {ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, values);CHKERRQ(ierr);}
5788     ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm);CHKERRQ(ierr);
5789     ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr);
5790     /* Get values */
5791     if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values);CHKERRQ(ierr);}
5792     else               {ierr = DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values);CHKERRQ(ierr);}
5793     PetscCheckFalse(asize != size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %D does not match Vec closure size %D", asize, size);
5794     /* Cleanup array */
5795     ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr);
5796   }
5797   if (csize) *csize = asize;
5798   /* Cleanup points */
5799   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5800   PetscFunctionReturn(0);
5801 }
5802 
5803 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
5804 {
5805   DMLabel            depthLabel;
5806   PetscSection       clSection;
5807   IS                 clPoints;
5808   PetscScalar       *array;
5809   const PetscScalar *vArray;
5810   PetscInt          *points = NULL;
5811   const PetscInt    *clp, *perm = NULL;
5812   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;
5813   PetscErrorCode     ierr;
5814 
5815   PetscFunctionBeginHot;
5816   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5817   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5818   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5819   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5820   ierr = DMPlexGetDepth(dm, &mdepth);CHKERRQ(ierr);
5821   ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr);
5822   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5823   if (mdepth == 1 && numFields < 2) {
5824     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
5825     PetscFunctionReturn(0);
5826   }
5827   /* Get points */
5828   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5829   for (clsize=0,p=0; p<Np; p++) {
5830     PetscInt dof;
5831     ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr);
5832     clsize += dof;
5833   }
5834   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm);CHKERRQ(ierr);
5835   /* Filter points */
5836   for (p = 0; p < numPoints*2; p += 2) {
5837     PetscInt dep;
5838 
5839     ierr = DMLabelGetValue(depthLabel, points[p], &dep);CHKERRQ(ierr);
5840     if (dep != depth) continue;
5841     points[Np*2+0] = points[p];
5842     points[Np*2+1] = points[p+1];
5843     ++Np;
5844   }
5845   /* Get array */
5846   if (!values || !*values) {
5847     PetscInt asize = 0, dof;
5848 
5849     for (p = 0; p < Np*2; p += 2) {
5850       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5851       asize += dof;
5852     }
5853     if (!values) {
5854       ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5855       if (csize) *csize = asize;
5856       PetscFunctionReturn(0);
5857     }
5858     ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);CHKERRQ(ierr);
5859   } else {
5860     array = *values;
5861   }
5862   ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr);
5863   /* Get values */
5864   if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array);CHKERRQ(ierr);}
5865   else               {ierr = DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array);CHKERRQ(ierr);}
5866   /* Cleanup points */
5867   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5868   /* Cleanup array */
5869   ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr);
5870   if (!*values) {
5871     if (csize) *csize = size;
5872     *values = array;
5873   } else {
5874     PetscCheckFalse(size > *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
5875     *csize = size;
5876   }
5877   PetscFunctionReturn(0);
5878 }
5879 
5880 /*@C
5881   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
5882 
5883   Not collective
5884 
5885   Input Parameters:
5886 + dm - The DM
5887 . section - The section describing the layout in v, or NULL to use the default section
5888 . v - The local vector
5889 . point - The point in the DM
5890 . csize - The number of values in the closure, or NULL
5891 - values - The array of values, which is a borrowed array and should not be freed
5892 
5893   Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()
5894 
5895   Fortran Notes:
5896   Since it returns an array, this routine is only available in Fortran 90, and you must
5897   include petsc.h90 in your code.
5898 
5899   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5900 
5901   Level: intermediate
5902 
5903 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5904 @*/
5905 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5906 {
5907   PetscInt       size = 0;
5908   PetscErrorCode ierr;
5909 
5910   PetscFunctionBegin;
5911   /* Should work without recalculating size */
5912   ierr = DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);CHKERRQ(ierr);
5913   *values = NULL;
5914   PetscFunctionReturn(0);
5915 }
5916 
5917 static inline void add   (PetscScalar *x, PetscScalar y) {*x += y;}
5918 static inline void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
5919 
5920 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[])
5921 {
5922   PetscInt        cdof;   /* The number of constraints on this point */
5923   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5924   PetscScalar    *a;
5925   PetscInt        off, cind = 0, k;
5926   PetscErrorCode  ierr;
5927 
5928   PetscFunctionBegin;
5929   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5930   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5931   a    = &array[off];
5932   if (!cdof || setBC) {
5933     if (clperm) {
5934       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
5935       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
5936     } else {
5937       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
5938       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
5939     }
5940   } else {
5941     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5942     if (clperm) {
5943       if (perm) {for (k = 0; k < dof; ++k) {
5944           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5945           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
5946         }
5947       } else {
5948         for (k = 0; k < dof; ++k) {
5949           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5950           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
5951         }
5952       }
5953     } else {
5954       if (perm) {
5955         for (k = 0; k < dof; ++k) {
5956           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5957           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
5958         }
5959       } else {
5960         for (k = 0; k < dof; ++k) {
5961           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5962           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
5963         }
5964       }
5965     }
5966   }
5967   PetscFunctionReturn(0);
5968 }
5969 
5970 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[])
5971 {
5972   PetscInt        cdof;   /* The number of constraints on this point */
5973   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5974   PetscScalar    *a;
5975   PetscInt        off, cind = 0, k;
5976   PetscErrorCode  ierr;
5977 
5978   PetscFunctionBegin;
5979   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5980   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5981   a    = &array[off];
5982   if (cdof) {
5983     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5984     if (clperm) {
5985       if (perm) {
5986         for (k = 0; k < dof; ++k) {
5987           if ((cind < cdof) && (k == cdofs[cind])) {
5988             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
5989             cind++;
5990           }
5991         }
5992       } else {
5993         for (k = 0; k < dof; ++k) {
5994           if ((cind < cdof) && (k == cdofs[cind])) {
5995             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
5996             cind++;
5997           }
5998         }
5999       }
6000     } else {
6001       if (perm) {
6002         for (k = 0; k < dof; ++k) {
6003           if ((cind < cdof) && (k == cdofs[cind])) {
6004             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
6005             cind++;
6006           }
6007         }
6008       } else {
6009         for (k = 0; k < dof; ++k) {
6010           if ((cind < cdof) && (k == cdofs[cind])) {
6011             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
6012             cind++;
6013           }
6014         }
6015       }
6016     }
6017   }
6018   PetscFunctionReturn(0);
6019 }
6020 
6021 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[])
6022 {
6023   PetscScalar    *a;
6024   PetscInt        fdof, foff, fcdof, foffset = *offset;
6025   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6026   PetscInt        cind = 0, b;
6027   PetscErrorCode  ierr;
6028 
6029   PetscFunctionBegin;
6030   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6031   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
6032   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
6033   a    = &array[foff];
6034   if (!fcdof || setBC) {
6035     if (clperm) {
6036       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
6037       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
6038     } else {
6039       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
6040       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
6041     }
6042   } else {
6043     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6044     if (clperm) {
6045       if (perm) {
6046         for (b = 0; b < fdof; b++) {
6047           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6048           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
6049         }
6050       } else {
6051         for (b = 0; b < fdof; b++) {
6052           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6053           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
6054         }
6055       }
6056     } else {
6057       if (perm) {
6058         for (b = 0; b < fdof; b++) {
6059           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6060           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
6061         }
6062       } else {
6063         for (b = 0; b < fdof; b++) {
6064           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6065           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
6066         }
6067       }
6068     }
6069   }
6070   *offset += fdof;
6071   PetscFunctionReturn(0);
6072 }
6073 
6074 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[])
6075 {
6076   PetscScalar    *a;
6077   PetscInt        fdof, foff, fcdof, foffset = *offset;
6078   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6079   PetscInt        Nc, cind = 0, ncind = 0, b;
6080   PetscBool       ncSet, fcSet;
6081   PetscErrorCode  ierr;
6082 
6083   PetscFunctionBegin;
6084   ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
6085   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6086   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
6087   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
6088   a    = &array[foff];
6089   if (fcdof) {
6090     /* We just override fcdof and fcdofs with Ncc and comps */
6091     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6092     if (clperm) {
6093       if (perm) {
6094         if (comps) {
6095           for (b = 0; b < fdof; b++) {
6096             ncSet = fcSet = PETSC_FALSE;
6097             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6098             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6099             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
6100           }
6101         } else {
6102           for (b = 0; b < fdof; b++) {
6103             if ((cind < fcdof) && (b == fcdofs[cind])) {
6104               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
6105               ++cind;
6106             }
6107           }
6108         }
6109       } else {
6110         if (comps) {
6111           for (b = 0; b < fdof; b++) {
6112             ncSet = fcSet = PETSC_FALSE;
6113             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6114             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6115             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
6116           }
6117         } else {
6118           for (b = 0; b < fdof; b++) {
6119             if ((cind < fcdof) && (b == fcdofs[cind])) {
6120               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
6121               ++cind;
6122             }
6123           }
6124         }
6125       }
6126     } else {
6127       if (perm) {
6128         if (comps) {
6129           for (b = 0; b < fdof; b++) {
6130             ncSet = fcSet = PETSC_FALSE;
6131             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6132             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6133             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
6134           }
6135         } else {
6136           for (b = 0; b < fdof; b++) {
6137             if ((cind < fcdof) && (b == fcdofs[cind])) {
6138               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
6139               ++cind;
6140             }
6141           }
6142         }
6143       } else {
6144         if (comps) {
6145           for (b = 0; b < fdof; b++) {
6146             ncSet = fcSet = PETSC_FALSE;
6147             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6148             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6149             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
6150           }
6151         } else {
6152           for (b = 0; b < fdof; b++) {
6153             if ((cind < fcdof) && (b == fcdofs[cind])) {
6154               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
6155               ++cind;
6156             }
6157           }
6158         }
6159       }
6160     }
6161   }
6162   *offset += fdof;
6163   PetscFunctionReturn(0);
6164 }
6165 
6166 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6167 {
6168   PetscScalar    *array;
6169   const PetscInt *cone, *coneO;
6170   PetscInt        pStart, pEnd, p, numPoints, off, dof;
6171   PetscErrorCode  ierr;
6172 
6173   PetscFunctionBeginHot;
6174   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6175   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
6176   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
6177   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
6178   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6179   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
6180     const PetscInt cp = !p ? point : cone[p-1];
6181     const PetscInt o  = !p ? 0     : coneO[p-1];
6182 
6183     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
6184     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
6185     /* ADD_VALUES */
6186     {
6187       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6188       PetscScalar    *a;
6189       PetscInt        cdof, coff, cind = 0, k;
6190 
6191       ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
6192       ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
6193       a    = &array[coff];
6194       if (!cdof) {
6195         if (o >= 0) {
6196           for (k = 0; k < dof; ++k) {
6197             a[k] += values[off+k];
6198           }
6199         } else {
6200           for (k = 0; k < dof; ++k) {
6201             a[k] += values[off+dof-k-1];
6202           }
6203         }
6204       } else {
6205         ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
6206         if (o >= 0) {
6207           for (k = 0; k < dof; ++k) {
6208             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6209             a[k] += values[off+k];
6210           }
6211         } else {
6212           for (k = 0; k < dof; ++k) {
6213             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6214             a[k] += values[off+dof-k-1];
6215           }
6216         }
6217       }
6218     }
6219   }
6220   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6221   PetscFunctionReturn(0);
6222 }
6223 
6224 /*@C
6225   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
6226 
6227   Not collective
6228 
6229   Input Parameters:
6230 + dm - The DM
6231 . section - The section describing the layout in v, or NULL to use the default section
6232 . v - The local vector
6233 . point - The point in the DM
6234 . values - The array of values
6235 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
6236          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
6237 
6238   Fortran Notes:
6239   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
6240 
6241   Level: intermediate
6242 
6243 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
6244 @*/
6245 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6246 {
6247   PetscSection    clSection;
6248   IS              clPoints;
6249   PetscScalar    *array;
6250   PetscInt       *points = NULL;
6251   const PetscInt *clp, *clperm = NULL;
6252   PetscInt        depth, numFields, numPoints, p, clsize;
6253   PetscErrorCode  ierr;
6254 
6255   PetscFunctionBeginHot;
6256   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6257   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
6258   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6259   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6260   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6261   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6262   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
6263     ierr = DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);CHKERRQ(ierr);
6264     PetscFunctionReturn(0);
6265   }
6266   /* Get points */
6267   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6268   for (clsize=0,p=0; p<numPoints; p++) {
6269     PetscInt dof;
6270     ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr);
6271     clsize += dof;
6272   }
6273   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm);CHKERRQ(ierr);
6274   /* Get array */
6275   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6276   /* Get values */
6277   if (numFields > 0) {
6278     PetscInt offset = 0, f;
6279     for (f = 0; f < numFields; ++f) {
6280       const PetscInt    **perms = NULL;
6281       const PetscScalar **flips = NULL;
6282 
6283       ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6284       switch (mode) {
6285       case INSERT_VALUES:
6286         for (p = 0; p < numPoints; p++) {
6287           const PetscInt    point = points[2*p];
6288           const PetscInt    *perm = perms ? perms[p] : NULL;
6289           const PetscScalar *flip = flips ? flips[p] : NULL;
6290           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
6291         } break;
6292       case INSERT_ALL_VALUES:
6293         for (p = 0; p < numPoints; p++) {
6294           const PetscInt    point = points[2*p];
6295           const PetscInt    *perm = perms ? perms[p] : NULL;
6296           const PetscScalar *flip = flips ? flips[p] : NULL;
6297           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
6298         } break;
6299       case INSERT_BC_VALUES:
6300         for (p = 0; p < numPoints; p++) {
6301           const PetscInt    point = points[2*p];
6302           const PetscInt    *perm = perms ? perms[p] : NULL;
6303           const PetscScalar *flip = flips ? flips[p] : NULL;
6304           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
6305         } break;
6306       case ADD_VALUES:
6307         for (p = 0; p < numPoints; p++) {
6308           const PetscInt    point = points[2*p];
6309           const PetscInt    *perm = perms ? perms[p] : NULL;
6310           const PetscScalar *flip = flips ? flips[p] : NULL;
6311           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
6312         } break;
6313       case ADD_ALL_VALUES:
6314         for (p = 0; p < numPoints; p++) {
6315           const PetscInt    point = points[2*p];
6316           const PetscInt    *perm = perms ? perms[p] : NULL;
6317           const PetscScalar *flip = flips ? flips[p] : NULL;
6318           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
6319         } break;
6320       case ADD_BC_VALUES:
6321         for (p = 0; p < numPoints; p++) {
6322           const PetscInt    point = points[2*p];
6323           const PetscInt    *perm = perms ? perms[p] : NULL;
6324           const PetscScalar *flip = flips ? flips[p] : NULL;
6325           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
6326         } break;
6327       default:
6328         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6329       }
6330       ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6331     }
6332   } else {
6333     PetscInt dof, off;
6334     const PetscInt    **perms = NULL;
6335     const PetscScalar **flips = NULL;
6336 
6337     ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6338     switch (mode) {
6339     case INSERT_VALUES:
6340       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6341         const PetscInt    point = points[2*p];
6342         const PetscInt    *perm = perms ? perms[p] : NULL;
6343         const PetscScalar *flip = flips ? flips[p] : NULL;
6344         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6345         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
6346       } break;
6347     case INSERT_ALL_VALUES:
6348       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6349         const PetscInt    point = points[2*p];
6350         const PetscInt    *perm = perms ? perms[p] : NULL;
6351         const PetscScalar *flip = flips ? flips[p] : NULL;
6352         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6353         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
6354       } break;
6355     case INSERT_BC_VALUES:
6356       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6357         const PetscInt    point = points[2*p];
6358         const PetscInt    *perm = perms ? perms[p] : NULL;
6359         const PetscScalar *flip = flips ? flips[p] : NULL;
6360         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6361         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
6362       } break;
6363     case ADD_VALUES:
6364       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6365         const PetscInt    point = points[2*p];
6366         const PetscInt    *perm = perms ? perms[p] : NULL;
6367         const PetscScalar *flip = flips ? flips[p] : NULL;
6368         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6369         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
6370       } break;
6371     case ADD_ALL_VALUES:
6372       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6373         const PetscInt    point = points[2*p];
6374         const PetscInt    *perm = perms ? perms[p] : NULL;
6375         const PetscScalar *flip = flips ? flips[p] : NULL;
6376         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6377         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
6378       } break;
6379     case ADD_BC_VALUES:
6380       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6381         const PetscInt    point = points[2*p];
6382         const PetscInt    *perm = perms ? perms[p] : NULL;
6383         const PetscScalar *flip = flips ? flips[p] : NULL;
6384         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6385         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
6386       } break;
6387     default:
6388       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6389     }
6390     ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6391   }
6392   /* Cleanup points */
6393   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6394   /* Cleanup array */
6395   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6396   PetscFunctionReturn(0);
6397 }
6398 
6399 /* Check whether the given point is in the label. If not, update the offset to skip this point */
6400 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset)
6401 {
6402   PetscFunctionBegin;
6403   if (label) {
6404     PetscInt       val, fdof;
6405     PetscErrorCode ierr;
6406 
6407     /* There is a problem with this:
6408          Suppose we have two label values, defining surfaces, interecting along a line in 3D. When we add cells to the label, the cells that
6409        touch both surfaces must pick a label value. Thus we miss setting values for the surface with that other value intersecting that cell.
6410        Thus I am only going to check val != -1, not val != labelId
6411     */
6412     ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
6413     if (val < 0) {
6414       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6415       *offset += fdof;
6416       PetscFunctionReturn(1);
6417     }
6418   }
6419   PetscFunctionReturn(0);
6420 }
6421 
6422 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
6423 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)
6424 {
6425   PetscSection      clSection;
6426   IS                clPoints;
6427   PetscScalar       *array;
6428   PetscInt          *points = NULL;
6429   const PetscInt    *clp;
6430   PetscInt          numFields, numPoints, p;
6431   PetscInt          offset = 0, f;
6432   PetscErrorCode    ierr;
6433 
6434   PetscFunctionBeginHot;
6435   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6436   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
6437   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6438   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6439   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6440   /* Get points */
6441   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6442   /* Get array */
6443   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6444   /* Get values */
6445   for (f = 0; f < numFields; ++f) {
6446     const PetscInt    **perms = NULL;
6447     const PetscScalar **flips = NULL;
6448 
6449     if (!fieldActive[f]) {
6450       for (p = 0; p < numPoints*2; p += 2) {
6451         PetscInt fdof;
6452         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6453         offset += fdof;
6454       }
6455       continue;
6456     }
6457     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6458     switch (mode) {
6459     case INSERT_VALUES:
6460       for (p = 0; p < numPoints; p++) {
6461         const PetscInt    point = points[2*p];
6462         const PetscInt    *perm = perms ? perms[p] : NULL;
6463         const PetscScalar *flip = flips ? flips[p] : NULL;
6464         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6465         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array);
6466       } break;
6467     case INSERT_ALL_VALUES:
6468       for (p = 0; p < numPoints; p++) {
6469         const PetscInt    point = points[2*p];
6470         const PetscInt    *perm = perms ? perms[p] : NULL;
6471         const PetscScalar *flip = flips ? flips[p] : NULL;
6472         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6473         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array);
6474       } break;
6475     case INSERT_BC_VALUES:
6476       for (p = 0; p < numPoints; p++) {
6477         const PetscInt    point = points[2*p];
6478         const PetscInt    *perm = perms ? perms[p] : NULL;
6479         const PetscScalar *flip = flips ? flips[p] : NULL;
6480         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6481         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array);
6482       } break;
6483     case ADD_VALUES:
6484       for (p = 0; p < numPoints; p++) {
6485         const PetscInt    point = points[2*p];
6486         const PetscInt    *perm = perms ? perms[p] : NULL;
6487         const PetscScalar *flip = flips ? flips[p] : NULL;
6488         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6489         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array);
6490       } break;
6491     case ADD_ALL_VALUES:
6492       for (p = 0; p < numPoints; p++) {
6493         const PetscInt    point = points[2*p];
6494         const PetscInt    *perm = perms ? perms[p] : NULL;
6495         const PetscScalar *flip = flips ? flips[p] : NULL;
6496         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6497         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array);
6498       } break;
6499     default:
6500       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6501     }
6502     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6503   }
6504   /* Cleanup points */
6505   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6506   /* Cleanup array */
6507   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6508   PetscFunctionReturn(0);
6509 }
6510 
6511 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
6512 {
6513   PetscMPIInt    rank;
6514   PetscInt       i, j;
6515   PetscErrorCode ierr;
6516 
6517   PetscFunctionBegin;
6518   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr);
6519   ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);CHKERRQ(ierr);
6520   for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);}
6521   for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);}
6522   numCIndices = numCIndices ? numCIndices : numRIndices;
6523   if (!values) PetscFunctionReturn(0);
6524   for (i = 0; i < numRIndices; i++) {
6525     ierr = PetscViewerASCIIPrintf(viewer, "[%d]", rank);CHKERRQ(ierr);
6526     for (j = 0; j < numCIndices; j++) {
6527 #if defined(PETSC_USE_COMPLEX)
6528       ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr);
6529 #else
6530       ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr);
6531 #endif
6532     }
6533     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
6534   }
6535   PetscFunctionReturn(0);
6536 }
6537 
6538 /*
6539   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
6540 
6541   Input Parameters:
6542 + section - The section for this data layout
6543 . islocal - Is the section (and thus indices being requested) local or global?
6544 . point   - The point contributing dofs with these indices
6545 . off     - The global offset of this point
6546 . loff    - The local offset of each field
6547 . setBC   - The flag determining whether to include indices of boundary values
6548 . perm    - A permutation of the dofs on this point, or NULL
6549 - indperm - A permutation of the entire indices array, or NULL
6550 
6551   Output Parameter:
6552 . indices - Indices for dofs on this point
6553 
6554   Level: developer
6555 
6556   Note: The indices could be local or global, depending on the value of 'off'.
6557 */
6558 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
6559 {
6560   PetscInt        dof;   /* The number of unknowns on this point */
6561   PetscInt        cdof;  /* The number of constraints on this point */
6562   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6563   PetscInt        cind = 0, k;
6564   PetscErrorCode  ierr;
6565 
6566   PetscFunctionBegin;
6567   PetscCheckFalse(!islocal && setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC");
6568   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6569   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6570   if (!cdof || setBC) {
6571     for (k = 0; k < dof; ++k) {
6572       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
6573       const PetscInt ind    = indperm ? indperm[preind] : preind;
6574 
6575       indices[ind] = off + k;
6576     }
6577   } else {
6578     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6579     for (k = 0; k < dof; ++k) {
6580       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
6581       const PetscInt ind    = indperm ? indperm[preind] : preind;
6582 
6583       if ((cind < cdof) && (k == cdofs[cind])) {
6584         /* Insert check for returning constrained indices */
6585         indices[ind] = -(off+k+1);
6586         ++cind;
6587       } else {
6588         indices[ind] = off + k - (islocal ? 0 : cind);
6589       }
6590     }
6591   }
6592   *loff += dof;
6593   PetscFunctionReturn(0);
6594 }
6595 
6596 /*
6597  DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.
6598 
6599  Input Parameters:
6600 + section - a section (global or local)
6601 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global
6602 . point - point within section
6603 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
6604 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
6605 . setBC - identify constrained (boundary condition) points via involution.
6606 . perms - perms[f][permsoff][:] is a permutation of dofs within each field
6607 . permsoff - offset
6608 - indperm - index permutation
6609 
6610  Output Parameter:
6611 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
6612 . indices - array to hold indices (as defined by section) of each dof associated with point
6613 
6614  Notes:
6615  If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
6616  If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
6617  in the local vector.
6618 
6619  If section is global and setBC=false, the indices for constrained points are negative (and their value is not
6620  significant).  It is invalid to call with a global section and setBC=true.
6621 
6622  Developer Note:
6623  The section is only used for field layout, so islocal is technically a statement about the offset (off).  At some point
6624  in the future, global sections may have fields set, in which case we could pass the global section and obtain the
6625  offset could be obtained from the section instead of passing it explicitly as we do now.
6626 
6627  Example:
6628  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
6629  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
6630  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
6631  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.
6632 
6633  Level: developer
6634 */
6635 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[])
6636 {
6637   PetscInt       numFields, foff, f;
6638   PetscErrorCode ierr;
6639 
6640   PetscFunctionBegin;
6641   PetscCheckFalse(!islocal && setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC");
6642   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6643   for (f = 0, foff = 0; f < numFields; ++f) {
6644     PetscInt        fdof, cfdof;
6645     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6646     PetscInt        cind = 0, b;
6647     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
6648 
6649     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6650     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
6651     if (!cfdof || setBC) {
6652       for (b = 0; b < fdof; ++b) {
6653         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6654         const PetscInt ind    = indperm ? indperm[preind] : preind;
6655 
6656         indices[ind] = off+foff+b;
6657       }
6658     } else {
6659       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6660       for (b = 0; b < fdof; ++b) {
6661         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6662         const PetscInt ind    = indperm ? indperm[preind] : preind;
6663 
6664         if ((cind < cfdof) && (b == fcdofs[cind])) {
6665           indices[ind] = -(off+foff+b+1);
6666           ++cind;
6667         } else {
6668           indices[ind] = off + foff + b - (islocal ? 0 : cind);
6669         }
6670       }
6671     }
6672     foff     += (setBC || islocal ? fdof : (fdof - cfdof));
6673     foffs[f] += fdof;
6674   }
6675   PetscFunctionReturn(0);
6676 }
6677 
6678 /*
6679   This version believes the globalSection offsets for each field, rather than just the point offset
6680 
6681  . foffs - The offset into 'indices' for each field, since it is segregated by field
6682 
6683  Notes:
6684  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
6685  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
6686 */
6687 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
6688 {
6689   PetscInt       numFields, foff, f;
6690   PetscErrorCode ierr;
6691 
6692   PetscFunctionBegin;
6693   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6694   for (f = 0; f < numFields; ++f) {
6695     PetscInt        fdof, cfdof;
6696     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6697     PetscInt        cind = 0, b;
6698     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
6699 
6700     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6701     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
6702     ierr = PetscSectionGetFieldOffset(globalSection, point, f, &foff);CHKERRQ(ierr);
6703     if (!cfdof) {
6704       for (b = 0; b < fdof; ++b) {
6705         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6706         const PetscInt ind    = indperm ? indperm[preind] : preind;
6707 
6708         indices[ind] = foff+b;
6709       }
6710     } else {
6711       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6712       for (b = 0; b < fdof; ++b) {
6713         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6714         const PetscInt ind    = indperm ? indperm[preind] : preind;
6715 
6716         if ((cind < cfdof) && (b == fcdofs[cind])) {
6717           indices[ind] = -(foff+b+1);
6718           ++cind;
6719         } else {
6720           indices[ind] = foff+b-cind;
6721         }
6722       }
6723     }
6724     foffs[f] += fdof;
6725   }
6726   PetscFunctionReturn(0);
6727 }
6728 
6729 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)
6730 {
6731   Mat             cMat;
6732   PetscSection    aSec, cSec;
6733   IS              aIS;
6734   PetscInt        aStart = -1, aEnd = -1;
6735   const PetscInt  *anchors;
6736   PetscInt        numFields, f, p, q, newP = 0;
6737   PetscInt        newNumPoints = 0, newNumIndices = 0;
6738   PetscInt        *newPoints, *indices, *newIndices;
6739   PetscInt        maxAnchor, maxDof;
6740   PetscInt        newOffsets[32];
6741   PetscInt        *pointMatOffsets[32];
6742   PetscInt        *newPointOffsets[32];
6743   PetscScalar     *pointMat[32];
6744   PetscScalar     *newValues=NULL,*tmpValues;
6745   PetscBool       anyConstrained = PETSC_FALSE;
6746   PetscErrorCode  ierr;
6747 
6748   PetscFunctionBegin;
6749   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6750   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6751   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6752 
6753   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
6754   /* if there are point-to-point constraints */
6755   if (aSec) {
6756     ierr = PetscArrayzero(newOffsets, 32);CHKERRQ(ierr);
6757     ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
6758     ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
6759     /* figure out how many points are going to be in the new element matrix
6760      * (we allow double counting, because it's all just going to be summed
6761      * into the global matrix anyway) */
6762     for (p = 0; p < 2*numPoints; p+=2) {
6763       PetscInt b    = points[p];
6764       PetscInt bDof = 0, bSecDof;
6765 
6766       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
6767       if (!bSecDof) {
6768         continue;
6769       }
6770       if (b >= aStart && b < aEnd) {
6771         ierr = PetscSectionGetDof(aSec,b,&bDof);CHKERRQ(ierr);
6772       }
6773       if (bDof) {
6774         /* this point is constrained */
6775         /* it is going to be replaced by its anchors */
6776         PetscInt bOff, q;
6777 
6778         anyConstrained = PETSC_TRUE;
6779         newNumPoints  += bDof;
6780         ierr = PetscSectionGetOffset(aSec,b,&bOff);CHKERRQ(ierr);
6781         for (q = 0; q < bDof; q++) {
6782           PetscInt a = anchors[bOff + q];
6783           PetscInt aDof;
6784 
6785           ierr           = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
6786           newNumIndices += aDof;
6787           for (f = 0; f < numFields; ++f) {
6788             PetscInt fDof;
6789 
6790             ierr             = PetscSectionGetFieldDof(section, a, f, &fDof);CHKERRQ(ierr);
6791             newOffsets[f+1] += fDof;
6792           }
6793         }
6794       }
6795       else {
6796         /* this point is not constrained */
6797         newNumPoints++;
6798         newNumIndices += bSecDof;
6799         for (f = 0; f < numFields; ++f) {
6800           PetscInt fDof;
6801 
6802           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
6803           newOffsets[f+1] += fDof;
6804         }
6805       }
6806     }
6807   }
6808   if (!anyConstrained) {
6809     if (outNumPoints)  *outNumPoints  = 0;
6810     if (outNumIndices) *outNumIndices = 0;
6811     if (outPoints)     *outPoints     = NULL;
6812     if (outValues)     *outValues     = NULL;
6813     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
6814     PetscFunctionReturn(0);
6815   }
6816 
6817   if (outNumPoints)  *outNumPoints  = newNumPoints;
6818   if (outNumIndices) *outNumIndices = newNumIndices;
6819 
6820   for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
6821 
6822   if (!outPoints && !outValues) {
6823     if (offsets) {
6824       for (f = 0; f <= numFields; f++) {
6825         offsets[f] = newOffsets[f];
6826       }
6827     }
6828     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
6829     PetscFunctionReturn(0);
6830   }
6831 
6832   PetscCheckFalse(numFields && newOffsets[numFields] != newNumIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
6833 
6834   ierr = DMGetDefaultConstraints(dm, &cSec, &cMat);CHKERRQ(ierr);
6835 
6836   /* workspaces */
6837   if (numFields) {
6838     for (f = 0; f < numFields; f++) {
6839       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
6840       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
6841     }
6842   }
6843   else {
6844     ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
6845     ierr = DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
6846   }
6847 
6848   /* get workspaces for the point-to-point matrices */
6849   if (numFields) {
6850     PetscInt totalOffset, totalMatOffset;
6851 
6852     for (p = 0; p < numPoints; p++) {
6853       PetscInt b    = points[2*p];
6854       PetscInt bDof = 0, bSecDof;
6855 
6856       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
6857       if (!bSecDof) {
6858         for (f = 0; f < numFields; f++) {
6859           newPointOffsets[f][p + 1] = 0;
6860           pointMatOffsets[f][p + 1] = 0;
6861         }
6862         continue;
6863       }
6864       if (b >= aStart && b < aEnd) {
6865         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6866       }
6867       if (bDof) {
6868         for (f = 0; f < numFields; f++) {
6869           PetscInt fDof, q, bOff, allFDof = 0;
6870 
6871           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
6872           ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
6873           for (q = 0; q < bDof; q++) {
6874             PetscInt a = anchors[bOff + q];
6875             PetscInt aFDof;
6876 
6877             ierr     = PetscSectionGetFieldDof(section, a, f, &aFDof);CHKERRQ(ierr);
6878             allFDof += aFDof;
6879           }
6880           newPointOffsets[f][p+1] = allFDof;
6881           pointMatOffsets[f][p+1] = fDof * allFDof;
6882         }
6883       }
6884       else {
6885         for (f = 0; f < numFields; f++) {
6886           PetscInt fDof;
6887 
6888           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
6889           newPointOffsets[f][p+1] = fDof;
6890           pointMatOffsets[f][p+1] = 0;
6891         }
6892       }
6893     }
6894     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
6895       newPointOffsets[f][0] = totalOffset;
6896       pointMatOffsets[f][0] = totalMatOffset;
6897       for (p = 0; p < numPoints; p++) {
6898         newPointOffsets[f][p+1] += newPointOffsets[f][p];
6899         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
6900       }
6901       totalOffset    = newPointOffsets[f][numPoints];
6902       totalMatOffset = pointMatOffsets[f][numPoints];
6903       ierr = DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
6904     }
6905   }
6906   else {
6907     for (p = 0; p < numPoints; p++) {
6908       PetscInt b    = points[2*p];
6909       PetscInt bDof = 0, bSecDof;
6910 
6911       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
6912       if (!bSecDof) {
6913         newPointOffsets[0][p + 1] = 0;
6914         pointMatOffsets[0][p + 1] = 0;
6915         continue;
6916       }
6917       if (b >= aStart && b < aEnd) {
6918         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6919       }
6920       if (bDof) {
6921         PetscInt bOff, q, allDof = 0;
6922 
6923         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
6924         for (q = 0; q < bDof; q++) {
6925           PetscInt a = anchors[bOff + q], aDof;
6926 
6927           ierr    = PetscSectionGetDof(section, a, &aDof);CHKERRQ(ierr);
6928           allDof += aDof;
6929         }
6930         newPointOffsets[0][p+1] = allDof;
6931         pointMatOffsets[0][p+1] = bSecDof * allDof;
6932       }
6933       else {
6934         newPointOffsets[0][p+1] = bSecDof;
6935         pointMatOffsets[0][p+1] = 0;
6936       }
6937     }
6938     newPointOffsets[0][0] = 0;
6939     pointMatOffsets[0][0] = 0;
6940     for (p = 0; p < numPoints; p++) {
6941       newPointOffsets[0][p+1] += newPointOffsets[0][p];
6942       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
6943     }
6944     ierr = DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
6945   }
6946 
6947   /* output arrays */
6948   ierr = DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
6949 
6950   /* get the point-to-point matrices; construct newPoints */
6951   ierr = PetscSectionGetMaxDof(aSec, &maxAnchor);CHKERRQ(ierr);
6952   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6953   ierr = DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
6954   ierr = DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
6955   if (numFields) {
6956     for (p = 0, newP = 0; p < numPoints; p++) {
6957       PetscInt b    = points[2*p];
6958       PetscInt o    = points[2*p+1];
6959       PetscInt bDof = 0, bSecDof;
6960 
6961       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
6962       if (!bSecDof) {
6963         continue;
6964       }
6965       if (b >= aStart && b < aEnd) {
6966         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6967       }
6968       if (bDof) {
6969         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
6970 
6971         fStart[0] = 0;
6972         fEnd[0]   = 0;
6973         for (f = 0; f < numFields; f++) {
6974           PetscInt fDof;
6975 
6976           ierr        = PetscSectionGetFieldDof(cSec, b, f, &fDof);CHKERRQ(ierr);
6977           fStart[f+1] = fStart[f] + fDof;
6978           fEnd[f+1]   = fStart[f+1];
6979         }
6980         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
6981         ierr = DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices);CHKERRQ(ierr);
6982 
6983         fAnchorStart[0] = 0;
6984         fAnchorEnd[0]   = 0;
6985         for (f = 0; f < numFields; f++) {
6986           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
6987 
6988           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
6989           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
6990         }
6991         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
6992         for (q = 0; q < bDof; q++) {
6993           PetscInt a = anchors[bOff + q], aOff;
6994 
6995           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
6996           newPoints[2*(newP + q)]     = a;
6997           newPoints[2*(newP + q) + 1] = 0;
6998           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
6999           ierr = DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices);CHKERRQ(ierr);
7000         }
7001         newP += bDof;
7002 
7003         if (outValues) {
7004           /* get the point-to-point submatrix */
7005           for (f = 0; f < numFields; f++) {
7006             ierr = MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);CHKERRQ(ierr);
7007           }
7008         }
7009       }
7010       else {
7011         newPoints[2 * newP]     = b;
7012         newPoints[2 * newP + 1] = o;
7013         newP++;
7014       }
7015     }
7016   } else {
7017     for (p = 0; p < numPoints; p++) {
7018       PetscInt b    = points[2*p];
7019       PetscInt o    = points[2*p+1];
7020       PetscInt bDof = 0, bSecDof;
7021 
7022       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
7023       if (!bSecDof) {
7024         continue;
7025       }
7026       if (b >= aStart && b < aEnd) {
7027         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
7028       }
7029       if (bDof) {
7030         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
7031 
7032         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
7033         ierr = DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices);CHKERRQ(ierr);
7034 
7035         ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr);
7036         for (q = 0; q < bDof; q++) {
7037           PetscInt a = anchors[bOff + q], aOff;
7038 
7039           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
7040 
7041           newPoints[2*(newP + q)]     = a;
7042           newPoints[2*(newP + q) + 1] = 0;
7043           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
7044           ierr = DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices);CHKERRQ(ierr);
7045         }
7046         newP += bDof;
7047 
7048         /* get the point-to-point submatrix */
7049         if (outValues) {
7050           ierr = MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);CHKERRQ(ierr);
7051         }
7052       }
7053       else {
7054         newPoints[2 * newP]     = b;
7055         newPoints[2 * newP + 1] = o;
7056         newP++;
7057       }
7058     }
7059   }
7060 
7061   if (outValues) {
7062     ierr = DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
7063     ierr = PetscArrayzero(tmpValues,newNumIndices*numIndices);CHKERRQ(ierr);
7064     /* multiply constraints on the right */
7065     if (numFields) {
7066       for (f = 0; f < numFields; f++) {
7067         PetscInt oldOff = offsets[f];
7068 
7069         for (p = 0; p < numPoints; p++) {
7070           PetscInt cStart = newPointOffsets[f][p];
7071           PetscInt b      = points[2 * p];
7072           PetscInt c, r, k;
7073           PetscInt dof;
7074 
7075           ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
7076           if (!dof) {
7077             continue;
7078           }
7079           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7080             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
7081             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
7082 
7083             for (r = 0; r < numIndices; r++) {
7084               for (c = 0; c < nCols; c++) {
7085                 for (k = 0; k < dof; k++) {
7086                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
7087                 }
7088               }
7089             }
7090           }
7091           else {
7092             /* copy this column as is */
7093             for (r = 0; r < numIndices; r++) {
7094               for (c = 0; c < dof; c++) {
7095                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7096               }
7097             }
7098           }
7099           oldOff += dof;
7100         }
7101       }
7102     }
7103     else {
7104       PetscInt oldOff = 0;
7105       for (p = 0; p < numPoints; p++) {
7106         PetscInt cStart = newPointOffsets[0][p];
7107         PetscInt b      = points[2 * p];
7108         PetscInt c, r, k;
7109         PetscInt dof;
7110 
7111         ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
7112         if (!dof) {
7113           continue;
7114         }
7115         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7116           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
7117           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
7118 
7119           for (r = 0; r < numIndices; r++) {
7120             for (c = 0; c < nCols; c++) {
7121               for (k = 0; k < dof; k++) {
7122                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
7123               }
7124             }
7125           }
7126         }
7127         else {
7128           /* copy this column as is */
7129           for (r = 0; r < numIndices; r++) {
7130             for (c = 0; c < dof; c++) {
7131               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7132             }
7133           }
7134         }
7135         oldOff += dof;
7136       }
7137     }
7138 
7139     if (multiplyLeft) {
7140       ierr = DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr);
7141       ierr = PetscArrayzero(newValues,newNumIndices*newNumIndices);CHKERRQ(ierr);
7142       /* multiply constraints transpose on the left */
7143       if (numFields) {
7144         for (f = 0; f < numFields; f++) {
7145           PetscInt oldOff = offsets[f];
7146 
7147           for (p = 0; p < numPoints; p++) {
7148             PetscInt rStart = newPointOffsets[f][p];
7149             PetscInt b      = points[2 * p];
7150             PetscInt c, r, k;
7151             PetscInt dof;
7152 
7153             ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
7154             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7155               PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
7156               const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
7157 
7158               for (r = 0; r < nRows; r++) {
7159                 for (c = 0; c < newNumIndices; c++) {
7160                   for (k = 0; k < dof; k++) {
7161                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7162                   }
7163                 }
7164               }
7165             }
7166             else {
7167               /* copy this row as is */
7168               for (r = 0; r < dof; r++) {
7169                 for (c = 0; c < newNumIndices; c++) {
7170                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7171                 }
7172               }
7173             }
7174             oldOff += dof;
7175           }
7176         }
7177       }
7178       else {
7179         PetscInt oldOff = 0;
7180 
7181         for (p = 0; p < numPoints; p++) {
7182           PetscInt rStart = newPointOffsets[0][p];
7183           PetscInt b      = points[2 * p];
7184           PetscInt c, r, k;
7185           PetscInt dof;
7186 
7187           ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
7188           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7189             PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
7190             const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
7191 
7192             for (r = 0; r < nRows; r++) {
7193               for (c = 0; c < newNumIndices; c++) {
7194                 for (k = 0; k < dof; k++) {
7195                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7196                 }
7197               }
7198             }
7199           }
7200           else {
7201             /* copy this row as is */
7202             for (r = 0; r < dof; r++) {
7203               for (c = 0; c < newNumIndices; c++) {
7204                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7205               }
7206             }
7207           }
7208           oldOff += dof;
7209         }
7210       }
7211 
7212       ierr = DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
7213     }
7214     else {
7215       newValues = tmpValues;
7216     }
7217   }
7218 
7219   /* clean up */
7220   ierr = DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
7221   ierr = DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
7222 
7223   if (numFields) {
7224     for (f = 0; f < numFields; f++) {
7225       ierr = DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
7226       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
7227       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
7228     }
7229   }
7230   else {
7231     ierr = DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
7232     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
7233     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
7234   }
7235   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
7236 
7237   /* output */
7238   if (outPoints) {
7239     *outPoints = newPoints;
7240   }
7241   else {
7242     ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
7243   }
7244   if (outValues) {
7245     *outValues = newValues;
7246   }
7247   for (f = 0; f <= numFields; f++) {
7248     offsets[f] = newOffsets[f];
7249   }
7250   PetscFunctionReturn(0);
7251 }
7252 
7253 /*@C
7254   DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.
7255 
7256   Not collective
7257 
7258   Input Parameters:
7259 + dm         - The DM
7260 . section    - The PetscSection describing the points (a local section)
7261 . idxSection - The PetscSection from which to obtain indices (may be local or global)
7262 . point      - The point defining the closure
7263 - useClPerm  - Use the closure point permutation if available
7264 
7265   Output Parameters:
7266 + numIndices - The number of dof indices in the closure of point with the input sections
7267 . indices    - The dof indices
7268 . outOffsets - Array to write the field offsets into, or NULL
7269 - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
7270 
7271   Notes:
7272   Must call DMPlexRestoreClosureIndices() to free allocated memory
7273 
7274   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
7275   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
7276   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
7277   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
7278   indices (with the above semantics) are implied.
7279 
7280   Level: advanced
7281 
7282 .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection()
7283 @*/
7284 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm,
7285                                        PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7286 {
7287   /* Closure ordering */
7288   PetscSection        clSection;
7289   IS                  clPoints;
7290   const PetscInt     *clp;
7291   PetscInt           *points;
7292   const PetscInt     *clperm = NULL;
7293   /* Dof permutation and sign flips */
7294   const PetscInt    **perms[32] = {NULL};
7295   const PetscScalar **flips[32] = {NULL};
7296   PetscScalar        *valCopy   = NULL;
7297   /* Hanging node constraints */
7298   PetscInt           *pointsC = NULL;
7299   PetscScalar        *valuesC = NULL;
7300   PetscInt            NclC, NiC;
7301 
7302   PetscInt           *idx;
7303   PetscInt            Nf, Ncl, Ni = 0, offsets[32], p, f;
7304   PetscBool           isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
7305   PetscErrorCode      ierr;
7306 
7307   PetscFunctionBeginHot;
7308   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7309   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7310   PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3);
7311   if (numIndices) PetscValidPointer(numIndices, 6);
7312   if (indices)    PetscValidPointer(indices, 7);
7313   if (outOffsets) PetscValidPointer(outOffsets, 8);
7314   if (values)     PetscValidPointer(values, 9);
7315   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
7316   PetscCheckFalse(Nf > 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
7317   ierr = PetscArrayzero(offsets, 32);CHKERRQ(ierr);
7318   /* 1) Get points in closure */
7319   ierr = DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr);
7320   if (useClPerm) {
7321     PetscInt depth, clsize;
7322     ierr = DMPlexGetPointDepth(dm, point, &depth);CHKERRQ(ierr);
7323     for (clsize=0,p=0; p<Ncl; p++) {
7324       PetscInt dof;
7325       ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr);
7326       clsize += dof;
7327     }
7328     ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm);CHKERRQ(ierr);
7329   }
7330   /* 2) Get number of indices on these points and field offsets from section */
7331   for (p = 0; p < Ncl*2; p += 2) {
7332     PetscInt dof, fdof;
7333 
7334     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7335     for (f = 0; f < Nf; ++f) {
7336       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7337       offsets[f+1] += fdof;
7338     }
7339     Ni += dof;
7340   }
7341   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
7342   PetscCheckFalse(Nf && offsets[Nf] != Ni,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Ni);
7343   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
7344   for (f = 0; f < PetscMax(1, Nf); ++f) {
7345     if (Nf) {ierr = PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7346     else    {ierr = PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7347     /* may need to apply sign changes to the element matrix */
7348     if (values && flips[f]) {
7349       PetscInt foffset = offsets[f];
7350 
7351       for (p = 0; p < Ncl; ++p) {
7352         PetscInt           pnt  = points[2*p], fdof;
7353         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
7354 
7355         if (!Nf) {ierr = PetscSectionGetDof(section, pnt, &fdof);CHKERRQ(ierr);}
7356         else     {ierr = PetscSectionGetFieldDof(section, pnt, f, &fdof);CHKERRQ(ierr);}
7357         if (flip) {
7358           PetscInt i, j, k;
7359 
7360           if (!valCopy) {
7361             ierr = DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy);CHKERRQ(ierr);
7362             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
7363             *values = valCopy;
7364           }
7365           for (i = 0; i < fdof; ++i) {
7366             PetscScalar fval = flip[i];
7367 
7368             for (k = 0; k < Ni; ++k) {
7369               valCopy[Ni * (foffset + i) + k] *= fval;
7370               valCopy[Ni * k + (foffset + i)] *= fval;
7371             }
7372           }
7373         }
7374         foffset += fdof;
7375       }
7376     }
7377   }
7378   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
7379   ierr = DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE);CHKERRQ(ierr);
7380   if (NclC) {
7381     if (valCopy) {ierr = DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy);CHKERRQ(ierr);}
7382     for (f = 0; f < PetscMax(1, Nf); ++f) {
7383       if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7384       else    {ierr = PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7385     }
7386     for (f = 0; f < PetscMax(1, Nf); ++f) {
7387       if (Nf) {ierr = PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]);CHKERRQ(ierr);}
7388       else    {ierr = PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]);CHKERRQ(ierr);}
7389     }
7390     ierr = DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr);
7391     Ncl     = NclC;
7392     Ni      = NiC;
7393     points  = pointsC;
7394     if (values) *values = valuesC;
7395   }
7396   /* 5) Calculate indices */
7397   ierr = DMGetWorkArray(dm, Ni, MPIU_INT, &idx);CHKERRQ(ierr);
7398   if (Nf) {
7399     PetscInt  idxOff;
7400     PetscBool useFieldOffsets;
7401 
7402     if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];}
7403     ierr = PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets);CHKERRQ(ierr);
7404     if (useFieldOffsets) {
7405       for (p = 0; p < Ncl; ++p) {
7406         const PetscInt pnt = points[p*2];
7407 
7408         ierr = DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx);CHKERRQ(ierr);
7409       }
7410     } else {
7411       for (p = 0; p < Ncl; ++p) {
7412         const PetscInt pnt = points[p*2];
7413 
7414         ierr = PetscSectionGetOffset(idxSection, pnt, &idxOff);CHKERRQ(ierr);
7415         /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
7416          * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
7417          * global section. */
7418         ierr = DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx);CHKERRQ(ierr);
7419       }
7420     }
7421   } else {
7422     PetscInt off = 0, idxOff;
7423 
7424     for (p = 0; p < Ncl; ++p) {
7425       const PetscInt  pnt  = points[p*2];
7426       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
7427 
7428       ierr = PetscSectionGetOffset(idxSection, pnt, &idxOff);CHKERRQ(ierr);
7429       /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
7430        * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
7431       ierr = DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx);CHKERRQ(ierr);
7432     }
7433   }
7434   /* 6) Cleanup */
7435   for (f = 0; f < PetscMax(1, Nf); ++f) {
7436     if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7437     else    {ierr = PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7438   }
7439   if (NclC) {
7440     ierr = DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC);CHKERRQ(ierr);
7441   } else {
7442     ierr = DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr);
7443   }
7444 
7445   if (numIndices) *numIndices = Ni;
7446   if (indices)    *indices    = idx;
7447   PetscFunctionReturn(0);
7448 }
7449 
7450 /*@C
7451   DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.
7452 
7453   Not collective
7454 
7455   Input Parameters:
7456 + dm         - The DM
7457 . section    - The PetscSection describing the points (a local section)
7458 . idxSection - The PetscSection from which to obtain indices (may be local or global)
7459 . point      - The point defining the closure
7460 - useClPerm  - Use the closure point permutation if available
7461 
7462   Output Parameters:
7463 + numIndices - The number of dof indices in the closure of point with the input sections
7464 . indices    - The dof indices
7465 . outOffsets - Array to write the field offsets into, or NULL
7466 - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
7467 
7468   Notes:
7469   If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values).
7470 
7471   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
7472   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
7473   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
7474   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
7475   indices (with the above semantics) are implied.
7476 
7477   Level: advanced
7478 
7479 .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection()
7480 @*/
7481 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm,
7482                                            PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7483 {
7484   PetscErrorCode ierr;
7485 
7486   PetscFunctionBegin;
7487   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7488   PetscValidPointer(indices, 7);
7489   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, indices);CHKERRQ(ierr);
7490   PetscFunctionReturn(0);
7491 }
7492 
7493 /*@C
7494   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
7495 
7496   Not collective
7497 
7498   Input Parameters:
7499 + dm - The DM
7500 . section - The section describing the layout in v, or NULL to use the default section
7501 . globalSection - The section describing the layout in v, or NULL to use the default global section
7502 . A - The matrix
7503 . point - The point in the DM
7504 . values - The array of values
7505 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7506 
7507   Fortran Notes:
7508   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
7509 
7510   Level: intermediate
7511 
7512 .seealso DMPlexMatSetClosureGeneral(), DMPlexVecGetClosure(), DMPlexVecSetClosure()
7513 @*/
7514 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7515 {
7516   DM_Plex           *mesh = (DM_Plex*) dm->data;
7517   PetscInt          *indices;
7518   PetscInt           numIndices;
7519   const PetscScalar *valuesOrig = values;
7520   PetscErrorCode     ierr;
7521 
7522   PetscFunctionBegin;
7523   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7524   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
7525   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7526   if (!globalSection) {ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
7527   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
7528   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
7529 
7530   ierr = DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7531 
7532   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);}
7533   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7534   if (ierr) {
7535     PetscMPIInt    rank;
7536     PetscErrorCode ierr2;
7537 
7538     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2);
7539     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7540     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
7541     ierr2 = DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr2);
7542     if (values != valuesOrig) {ierr2 = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values);CHKERRQ(ierr2);}
7543     SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values");
7544   }
7545   if (mesh->printFEM > 1) {
7546     PetscInt i;
7547     ierr = PetscPrintf(PETSC_COMM_SELF, "  Indices:");CHKERRQ(ierr);
7548     for (i = 0; i < numIndices; ++i) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);CHKERRQ(ierr);}
7549     ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
7550   }
7551 
7552   ierr = DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7553   if (values != valuesOrig) {ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values);CHKERRQ(ierr);}
7554   PetscFunctionReturn(0);
7555 }
7556 
7557 /*@C
7558   DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section
7559 
7560   Not collective
7561 
7562   Input Parameters:
7563 + dmRow - The DM for the row fields
7564 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow
7565 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow
7566 . dmCol - The DM for the column fields
7567 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol
7568 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol
7569 . A - The matrix
7570 . point - The point in the DMs
7571 . values - The array of values
7572 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7573 
7574   Level: intermediate
7575 
7576 .seealso DMPlexMatSetClosure(), DMPlexVecGetClosure(), DMPlexVecSetClosure()
7577 @*/
7578 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7579 {
7580   DM_Plex           *mesh = (DM_Plex*) dmRow->data;
7581   PetscInt          *indicesRow, *indicesCol;
7582   PetscInt           numIndicesRow, numIndicesCol;
7583   const PetscScalar *valuesOrig = values;
7584   PetscErrorCode     ierr;
7585 
7586   PetscFunctionBegin;
7587   PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1);
7588   if (!sectionRow) {ierr = DMGetLocalSection(dmRow, &sectionRow);CHKERRQ(ierr);}
7589   PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2);
7590   if (!globalSectionRow) {ierr = DMGetGlobalSection(dmRow, &globalSectionRow);CHKERRQ(ierr);}
7591   PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3);
7592   PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4);
7593   if (!sectionCol) {ierr = DMGetLocalSection(dmCol, &sectionCol);CHKERRQ(ierr);}
7594   PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5);
7595   if (!globalSectionCol) {ierr = DMGetGlobalSection(dmCol, &globalSectionCol);CHKERRQ(ierr);}
7596   PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6);
7597   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
7598 
7599   ierr = DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7600   ierr = DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7601 
7602   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values);CHKERRQ(ierr);}
7603   ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode);
7604   if (ierr) {
7605     PetscMPIInt    rank;
7606     PetscErrorCode ierr2;
7607 
7608     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2);
7609     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7610     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values);CHKERRQ(ierr2);
7611     ierr2 = DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr2);
7612     ierr2 = DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr2);
7613     if (values != valuesOrig) {ierr2 = DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values);CHKERRQ(ierr2);}
7614     CHKERRQ(ierr);
7615   }
7616 
7617   ierr = DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7618   ierr = DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7619   if (values != valuesOrig) {ierr = DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values);CHKERRQ(ierr);}
7620   PetscFunctionReturn(0);
7621 }
7622 
7623 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7624 {
7625   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
7626   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
7627   PetscInt       *cpoints = NULL;
7628   PetscInt       *findices, *cindices;
7629   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7630   PetscInt        foffsets[32], coffsets[32];
7631   DMPolytopeType  ct;
7632   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
7633   PetscErrorCode  ierr;
7634 
7635   PetscFunctionBegin;
7636   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
7637   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
7638   if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);}
7639   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
7640   if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);}
7641   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
7642   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
7643   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
7644   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
7645   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
7646   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
7647   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
7648   PetscCheckFalse(numFields > 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7649   ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr);
7650   ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr);
7651   /* Column indices */
7652   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7653   maxFPoints = numCPoints;
7654   /* Compress out points not in the section */
7655   /*   TODO: Squeeze out points with 0 dof as well */
7656   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
7657   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
7658     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
7659       cpoints[q*2]   = cpoints[p];
7660       cpoints[q*2+1] = cpoints[p+1];
7661       ++q;
7662     }
7663   }
7664   numCPoints = q;
7665   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
7666     PetscInt fdof;
7667 
7668     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
7669     if (!dof) continue;
7670     for (f = 0; f < numFields; ++f) {
7671       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
7672       coffsets[f+1] += fdof;
7673     }
7674     numCIndices += dof;
7675   }
7676   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
7677   /* Row indices */
7678   ierr = DMPlexGetCellType(dmc, point, &ct);CHKERRQ(ierr);
7679   {
7680     DMPlexTransform tr;
7681     DMPolytopeType *rct;
7682     PetscInt       *rsize, *rcone, *rornt, Nt;
7683 
7684     ierr = DMPlexTransformCreate(PETSC_COMM_SELF, &tr);CHKERRQ(ierr);
7685     ierr = DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR);CHKERRQ(ierr);
7686     ierr = DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt);CHKERRQ(ierr);
7687     numSubcells = rsize[Nt-1];
7688     ierr = DMPlexTransformDestroy(&tr);CHKERRQ(ierr);
7689   }
7690   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7691   for (r = 0, q = 0; r < numSubcells; ++r) {
7692     /* TODO Map from coarse to fine cells */
7693     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7694     /* Compress out points not in the section */
7695     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
7696     for (p = 0; p < numFPoints*2; p += 2) {
7697       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
7698         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
7699         if (!dof) continue;
7700         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
7701         if (s < q) continue;
7702         ftotpoints[q*2]   = fpoints[p];
7703         ftotpoints[q*2+1] = fpoints[p+1];
7704         ++q;
7705       }
7706     }
7707     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7708   }
7709   numFPoints = q;
7710   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
7711     PetscInt fdof;
7712 
7713     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
7714     if (!dof) continue;
7715     for (f = 0; f < numFields; ++f) {
7716       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
7717       foffsets[f+1] += fdof;
7718     }
7719     numFIndices += dof;
7720   }
7721   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
7722 
7723   PetscCheckFalse(numFields && foffsets[numFields] != numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
7724   PetscCheckFalse(numFields && coffsets[numFields] != numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
7725   ierr = DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
7726   ierr = DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
7727   if (numFields) {
7728     const PetscInt **permsF[32] = {NULL};
7729     const PetscInt **permsC[32] = {NULL};
7730 
7731     for (f = 0; f < numFields; f++) {
7732       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7733       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7734     }
7735     for (p = 0; p < numFPoints; p++) {
7736       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7737       ierr = DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr);
7738     }
7739     for (p = 0; p < numCPoints; p++) {
7740       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7741       ierr = DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr);
7742     }
7743     for (f = 0; f < numFields; f++) {
7744       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7745       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7746     }
7747   } else {
7748     const PetscInt **permsF = NULL;
7749     const PetscInt **permsC = NULL;
7750 
7751     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7752     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7753     for (p = 0, off = 0; p < numFPoints; p++) {
7754       const PetscInt *perm = permsF ? permsF[p] : NULL;
7755 
7756       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7757       ierr = DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr);
7758     }
7759     for (p = 0, off = 0; p < numCPoints; p++) {
7760       const PetscInt *perm = permsC ? permsC[p] : NULL;
7761 
7762       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7763       ierr = DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr);
7764     }
7765     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7766     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7767   }
7768   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);}
7769   /* TODO: flips */
7770   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
7771   if (ierr) {
7772     PetscMPIInt    rank;
7773     PetscErrorCode ierr2;
7774 
7775     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2);
7776     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7777     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
7778     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
7779     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
7780     CHKERRQ(ierr);
7781   }
7782   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7783   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7784   ierr = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
7785   ierr = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
7786   PetscFunctionReturn(0);
7787 }
7788 
7789 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
7790 {
7791   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
7792   PetscInt      *cpoints = NULL;
7793   PetscInt       foffsets[32], coffsets[32];
7794   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7795   DMPolytopeType ct;
7796   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
7797   PetscErrorCode ierr;
7798 
7799   PetscFunctionBegin;
7800   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
7801   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
7802   if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);}
7803   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
7804   if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);}
7805   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
7806   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
7807   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
7808   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
7809   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
7810   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
7811   PetscCheckFalse(numFields > 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7812   ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr);
7813   ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr);
7814   /* Column indices */
7815   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7816   maxFPoints = numCPoints;
7817   /* Compress out points not in the section */
7818   /*   TODO: Squeeze out points with 0 dof as well */
7819   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
7820   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
7821     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
7822       cpoints[q*2]   = cpoints[p];
7823       cpoints[q*2+1] = cpoints[p+1];
7824       ++q;
7825     }
7826   }
7827   numCPoints = q;
7828   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
7829     PetscInt fdof;
7830 
7831     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
7832     if (!dof) continue;
7833     for (f = 0; f < numFields; ++f) {
7834       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
7835       coffsets[f+1] += fdof;
7836     }
7837     numCIndices += dof;
7838   }
7839   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
7840   /* Row indices */
7841   ierr = DMPlexGetCellType(dmc, point, &ct);CHKERRQ(ierr);
7842   {
7843     DMPlexTransform tr;
7844     DMPolytopeType *rct;
7845     PetscInt       *rsize, *rcone, *rornt, Nt;
7846 
7847     ierr = DMPlexTransformCreate(PETSC_COMM_SELF, &tr);CHKERRQ(ierr);
7848     ierr = DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR);CHKERRQ(ierr);
7849     ierr = DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt);CHKERRQ(ierr);
7850     numSubcells = rsize[Nt-1];
7851     ierr = DMPlexTransformDestroy(&tr);CHKERRQ(ierr);
7852   }
7853   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7854   for (r = 0, q = 0; r < numSubcells; ++r) {
7855     /* TODO Map from coarse to fine cells */
7856     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7857     /* Compress out points not in the section */
7858     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
7859     for (p = 0; p < numFPoints*2; p += 2) {
7860       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
7861         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
7862         if (!dof) continue;
7863         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
7864         if (s < q) continue;
7865         ftotpoints[q*2]   = fpoints[p];
7866         ftotpoints[q*2+1] = fpoints[p+1];
7867         ++q;
7868       }
7869     }
7870     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7871   }
7872   numFPoints = q;
7873   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
7874     PetscInt fdof;
7875 
7876     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
7877     if (!dof) continue;
7878     for (f = 0; f < numFields; ++f) {
7879       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
7880       foffsets[f+1] += fdof;
7881     }
7882     numFIndices += dof;
7883   }
7884   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
7885 
7886   PetscCheckFalse(numFields && foffsets[numFields] != numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
7887   PetscCheckFalse(numFields && coffsets[numFields] != numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
7888   if (numFields) {
7889     const PetscInt **permsF[32] = {NULL};
7890     const PetscInt **permsC[32] = {NULL};
7891 
7892     for (f = 0; f < numFields; f++) {
7893       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7894       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7895     }
7896     for (p = 0; p < numFPoints; p++) {
7897       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7898       ierr = DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr);
7899     }
7900     for (p = 0; p < numCPoints; p++) {
7901       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7902       ierr = DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr);
7903     }
7904     for (f = 0; f < numFields; f++) {
7905       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7906       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7907     }
7908   } else {
7909     const PetscInt **permsF = NULL;
7910     const PetscInt **permsC = NULL;
7911 
7912     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7913     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7914     for (p = 0, off = 0; p < numFPoints; p++) {
7915       const PetscInt *perm = permsF ? permsF[p] : NULL;
7916 
7917       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7918       ierr = DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr);
7919     }
7920     for (p = 0, off = 0; p < numCPoints; p++) {
7921       const PetscInt *perm = permsC ? permsC[p] : NULL;
7922 
7923       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7924       ierr = DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr);
7925     }
7926     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7927     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7928   }
7929   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7930   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7931   PetscFunctionReturn(0);
7932 }
7933 
7934 /*@C
7935   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
7936 
7937   Input Parameter:
7938 . dm   - The DMPlex object
7939 
7940   Output Parameter:
7941 . cellHeight - The height of a cell
7942 
7943   Level: developer
7944 
7945 .seealso DMPlexSetVTKCellHeight()
7946 @*/
7947 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
7948 {
7949   DM_Plex *mesh = (DM_Plex*) dm->data;
7950 
7951   PetscFunctionBegin;
7952   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7953   PetscValidPointer(cellHeight, 2);
7954   *cellHeight = mesh->vtkCellHeight;
7955   PetscFunctionReturn(0);
7956 }
7957 
7958 /*@C
7959   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
7960 
7961   Input Parameters:
7962 + dm   - The DMPlex object
7963 - cellHeight - The height of a cell
7964 
7965   Level: developer
7966 
7967 .seealso DMPlexGetVTKCellHeight()
7968 @*/
7969 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
7970 {
7971   DM_Plex *mesh = (DM_Plex*) dm->data;
7972 
7973   PetscFunctionBegin;
7974   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7975   mesh->vtkCellHeight = cellHeight;
7976   PetscFunctionReturn(0);
7977 }
7978 
7979 /*@
7980   DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions
7981 
7982   Input Parameter:
7983 . dm - The DMPlex object
7984 
7985   Output Parameters:
7986 + gcStart - The first ghost cell, or NULL
7987 - gcEnd   - The upper bound on ghost cells, or NULL
7988 
7989   Level: advanced
7990 
7991 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum()
7992 @*/
7993 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd)
7994 {
7995   DMLabel        ctLabel;
7996   PetscErrorCode ierr;
7997 
7998   PetscFunctionBegin;
7999   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8000   ierr = DMPlexGetCellTypeLabel(dm, &ctLabel);CHKERRQ(ierr);
8001   ierr = DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd);CHKERRQ(ierr);
8002   PetscFunctionReturn(0);
8003 }
8004 
8005 /* We can easily have a form that takes an IS instead */
8006 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
8007 {
8008   PetscSection   section, globalSection;
8009   PetscInt      *numbers, p;
8010   PetscErrorCode ierr;
8011 
8012   PetscFunctionBegin;
8013   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
8014   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
8015   for (p = pStart; p < pEnd; ++p) {
8016     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
8017   }
8018   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
8019   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8020   ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr);
8021   for (p = pStart; p < pEnd; ++p) {
8022     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
8023     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
8024     else                       numbers[p-pStart] += shift;
8025   }
8026   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
8027   if (globalSize) {
8028     PetscLayout layout;
8029     ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr);
8030     ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr);
8031     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
8032   }
8033   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
8034   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8035   PetscFunctionReturn(0);
8036 }
8037 
8038 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
8039 {
8040   PetscInt       cellHeight, cStart, cEnd;
8041   PetscErrorCode ierr;
8042 
8043   PetscFunctionBegin;
8044   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8045   if (includeHybrid) {ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);}
8046   else               {ierr = DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);}
8047   ierr = DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);CHKERRQ(ierr);
8048   PetscFunctionReturn(0);
8049 }
8050 
8051 /*@
8052   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
8053 
8054   Input Parameter:
8055 . dm   - The DMPlex object
8056 
8057   Output Parameter:
8058 . globalCellNumbers - Global cell numbers for all cells on this process
8059 
8060   Level: developer
8061 
8062 .seealso DMPlexGetVertexNumbering()
8063 @*/
8064 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
8065 {
8066   DM_Plex       *mesh = (DM_Plex*) dm->data;
8067   PetscErrorCode ierr;
8068 
8069   PetscFunctionBegin;
8070   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8071   if (!mesh->globalCellNumbers) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);CHKERRQ(ierr);}
8072   *globalCellNumbers = mesh->globalCellNumbers;
8073   PetscFunctionReturn(0);
8074 }
8075 
8076 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
8077 {
8078   PetscInt       vStart, vEnd;
8079   PetscErrorCode ierr;
8080 
8081   PetscFunctionBegin;
8082   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8083   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8084   ierr = DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);CHKERRQ(ierr);
8085   PetscFunctionReturn(0);
8086 }
8087 
8088 /*@
8089   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
8090 
8091   Input Parameter:
8092 . dm   - The DMPlex object
8093 
8094   Output Parameter:
8095 . globalVertexNumbers - Global vertex numbers for all vertices on this process
8096 
8097   Level: developer
8098 
8099 .seealso DMPlexGetCellNumbering()
8100 @*/
8101 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
8102 {
8103   DM_Plex       *mesh = (DM_Plex*) dm->data;
8104   PetscErrorCode ierr;
8105 
8106   PetscFunctionBegin;
8107   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8108   if (!mesh->globalVertexNumbers) {ierr = DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);CHKERRQ(ierr);}
8109   *globalVertexNumbers = mesh->globalVertexNumbers;
8110   PetscFunctionReturn(0);
8111 }
8112 
8113 /*@
8114   DMPlexCreatePointNumbering - Create a global numbering for all points on this process
8115 
8116   Input Parameter:
8117 . dm   - The DMPlex object
8118 
8119   Output Parameter:
8120 . globalPointNumbers - Global numbers for all points on this process
8121 
8122   Level: developer
8123 
8124 .seealso DMPlexGetCellNumbering()
8125 @*/
8126 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
8127 {
8128   IS             nums[4];
8129   PetscInt       depths[4], gdepths[4], starts[4];
8130   PetscInt       depth, d, shift = 0;
8131   PetscErrorCode ierr;
8132 
8133   PetscFunctionBegin;
8134   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8135   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8136   /* For unstratified meshes use dim instead of depth */
8137   if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);}
8138   for (d = 0; d <= depth; ++d) {
8139     PetscInt end;
8140 
8141     depths[d] = depth-d;
8142     ierr = DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);CHKERRQ(ierr);
8143     if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
8144   }
8145   ierr = PetscSortIntWithArray(depth+1, starts, depths);CHKERRQ(ierr);
8146   ierr = MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRMPI(ierr);
8147   for (d = 0; d <= depth; ++d) {
8148     PetscCheckFalse(starts[d] >= 0 && depths[d] != gdepths[d],PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
8149   }
8150   for (d = 0; d <= depth; ++d) {
8151     PetscInt pStart, pEnd, gsize;
8152 
8153     ierr = DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);CHKERRQ(ierr);
8154     ierr = DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr);
8155     shift += gsize;
8156   }
8157   ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);CHKERRQ(ierr);
8158   for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);}
8159   PetscFunctionReturn(0);
8160 }
8161 
8162 /*@
8163   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
8164 
8165   Input Parameter:
8166 . dm - The DMPlex object
8167 
8168   Output Parameter:
8169 . ranks - The rank field
8170 
8171   Options Database Keys:
8172 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
8173 
8174   Level: intermediate
8175 
8176 .seealso: DMView()
8177 @*/
8178 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
8179 {
8180   DM             rdm;
8181   PetscFE        fe;
8182   PetscScalar   *r;
8183   PetscMPIInt    rank;
8184   DMPolytopeType ct;
8185   PetscInt       dim, cStart, cEnd, c;
8186   PetscBool      simplex;
8187   PetscErrorCode ierr;
8188 
8189   PetscFunctionBeginUser;
8190   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8191   PetscValidPointer(ranks, 2);
8192   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRMPI(ierr);
8193   ierr = DMClone(dm, &rdm);CHKERRQ(ierr);
8194   ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr);
8195   ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8196   ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr);
8197   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
8198   ierr = PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe);CHKERRQ(ierr);
8199   ierr = PetscObjectSetName((PetscObject) fe, "rank");CHKERRQ(ierr);
8200   ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
8201   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
8202   ierr = DMCreateDS(rdm);CHKERRQ(ierr);
8203   ierr = DMCreateGlobalVector(rdm, ranks);CHKERRQ(ierr);
8204   ierr = PetscObjectSetName((PetscObject) *ranks, "partition");CHKERRQ(ierr);
8205   ierr = VecGetArray(*ranks, &r);CHKERRQ(ierr);
8206   for (c = cStart; c < cEnd; ++c) {
8207     PetscScalar *lr;
8208 
8209     ierr = DMPlexPointGlobalRef(rdm, c, r, &lr);CHKERRQ(ierr);
8210     if (lr) *lr = rank;
8211   }
8212   ierr = VecRestoreArray(*ranks, &r);CHKERRQ(ierr);
8213   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
8214   PetscFunctionReturn(0);
8215 }
8216 
8217 /*@
8218   DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
8219 
8220   Input Parameters:
8221 + dm    - The DMPlex
8222 - label - The DMLabel
8223 
8224   Output Parameter:
8225 . val - The label value field
8226 
8227   Options Database Keys:
8228 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer
8229 
8230   Level: intermediate
8231 
8232 .seealso: DMView()
8233 @*/
8234 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
8235 {
8236   DM             rdm;
8237   PetscFE        fe;
8238   PetscScalar   *v;
8239   PetscInt       dim, cStart, cEnd, c;
8240   PetscErrorCode ierr;
8241 
8242   PetscFunctionBeginUser;
8243   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8244   PetscValidPointer(label, 2);
8245   PetscValidPointer(val, 3);
8246   ierr = DMClone(dm, &rdm);CHKERRQ(ierr);
8247   ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr);
8248   ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);CHKERRQ(ierr);
8249   ierr = PetscObjectSetName((PetscObject) fe, "label_value");CHKERRQ(ierr);
8250   ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
8251   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
8252   ierr = DMCreateDS(rdm);CHKERRQ(ierr);
8253   ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8254   ierr = DMCreateGlobalVector(rdm, val);CHKERRQ(ierr);
8255   ierr = PetscObjectSetName((PetscObject) *val, "label_value");CHKERRQ(ierr);
8256   ierr = VecGetArray(*val, &v);CHKERRQ(ierr);
8257   for (c = cStart; c < cEnd; ++c) {
8258     PetscScalar *lv;
8259     PetscInt     cval;
8260 
8261     ierr = DMPlexPointGlobalRef(rdm, c, v, &lv);CHKERRQ(ierr);
8262     ierr = DMLabelGetValue(label, c, &cval);CHKERRQ(ierr);
8263     *lv = cval;
8264   }
8265   ierr = VecRestoreArray(*val, &v);CHKERRQ(ierr);
8266   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
8267   PetscFunctionReturn(0);
8268 }
8269 
8270 /*@
8271   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
8272 
8273   Input Parameter:
8274 . dm - The DMPlex object
8275 
8276   Notes:
8277   This is a useful diagnostic when creating meshes programmatically.
8278 
8279   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8280 
8281   Level: developer
8282 
8283 .seealso: DMCreate(), DMSetFromOptions()
8284 @*/
8285 PetscErrorCode DMPlexCheckSymmetry(DM dm)
8286 {
8287   PetscSection    coneSection, supportSection;
8288   const PetscInt *cone, *support;
8289   PetscInt        coneSize, c, supportSize, s;
8290   PetscInt        pStart, pEnd, p, pp, csize, ssize;
8291   PetscBool       storagecheck = PETSC_TRUE;
8292   PetscErrorCode  ierr;
8293 
8294   PetscFunctionBegin;
8295   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8296   ierr = DMViewFromOptions(dm, NULL, "-sym_dm_view");CHKERRQ(ierr);
8297   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
8298   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
8299   /* Check that point p is found in the support of its cone points, and vice versa */
8300   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
8301   for (p = pStart; p < pEnd; ++p) {
8302     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
8303     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
8304     for (c = 0; c < coneSize; ++c) {
8305       PetscBool dup = PETSC_FALSE;
8306       PetscInt  d;
8307       for (d = c-1; d >= 0; --d) {
8308         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
8309       }
8310       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
8311       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
8312       for (s = 0; s < supportSize; ++s) {
8313         if (support[s] == p) break;
8314       }
8315       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
8316         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);CHKERRQ(ierr);
8317         for (s = 0; s < coneSize; ++s) {
8318           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);CHKERRQ(ierr);
8319         }
8320         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8321         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);CHKERRQ(ierr);
8322         for (s = 0; s < supportSize; ++s) {
8323           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);CHKERRQ(ierr);
8324         }
8325         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8326         PetscCheckFalse(dup,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
8327         else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
8328       }
8329     }
8330     ierr = DMPlexGetTreeParent(dm, p, &pp, NULL);CHKERRQ(ierr);
8331     if (p != pp) { storagecheck = PETSC_FALSE; continue; }
8332     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
8333     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
8334     for (s = 0; s < supportSize; ++s) {
8335       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
8336       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8337       for (c = 0; c < coneSize; ++c) {
8338         ierr = DMPlexGetTreeParent(dm, cone[c], &pp, NULL);CHKERRQ(ierr);
8339         if (cone[c] != pp) { c = 0; break; }
8340         if (cone[c] == p) break;
8341       }
8342       if (c >= coneSize) {
8343         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);CHKERRQ(ierr);
8344         for (c = 0; c < supportSize; ++c) {
8345           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);CHKERRQ(ierr);
8346         }
8347         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8348         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);CHKERRQ(ierr);
8349         for (c = 0; c < coneSize; ++c) {
8350           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);CHKERRQ(ierr);
8351         }
8352         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8353         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
8354       }
8355     }
8356   }
8357   if (storagecheck) {
8358     ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
8359     ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
8360     PetscCheckFalse(csize != ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
8361   }
8362   PetscFunctionReturn(0);
8363 }
8364 
8365 /*
8366   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.
8367 */
8368 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit)
8369 {
8370   DMPolytopeType  cct;
8371   PetscInt        ptpoints[4];
8372   const PetscInt *cone, *ccone, *ptcone;
8373   PetscInt        coneSize, cp, cconeSize, ccp, npt = 0, pt;
8374   PetscErrorCode  ierr;
8375 
8376   PetscFunctionBegin;
8377   *unsplit = 0;
8378   switch (ct) {
8379     case DM_POLYTOPE_POINT_PRISM_TENSOR:
8380       ptpoints[npt++] = c;
8381       break;
8382     case DM_POLYTOPE_SEG_PRISM_TENSOR:
8383       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8384       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8385       for (cp = 0; cp < coneSize; ++cp) {
8386         ierr = DMPlexGetCellType(dm, cone[cp], &cct);CHKERRQ(ierr);
8387         if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp];
8388       }
8389       break;
8390     case DM_POLYTOPE_TRI_PRISM_TENSOR:
8391     case DM_POLYTOPE_QUAD_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 = DMPlexGetCone(dm, cone[cp], &ccone);CHKERRQ(ierr);
8396         ierr = DMPlexGetConeSize(dm, cone[cp], &cconeSize);CHKERRQ(ierr);
8397         for (ccp = 0; ccp < cconeSize; ++ccp) {
8398           ierr = DMPlexGetCellType(dm, ccone[ccp], &cct);CHKERRQ(ierr);
8399           if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) {
8400             PetscInt p;
8401             for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break;
8402             if (p == npt) ptpoints[npt++] = ccone[ccp];
8403           }
8404         }
8405       }
8406       break;
8407     default: break;
8408   }
8409   for (pt = 0; pt < npt; ++pt) {
8410     ierr = DMPlexGetCone(dm, ptpoints[pt], &ptcone);CHKERRQ(ierr);
8411     if (ptcone[0] == ptcone[1]) ++(*unsplit);
8412   }
8413   PetscFunctionReturn(0);
8414 }
8415 
8416 /*@
8417   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
8418 
8419   Input Parameters:
8420 + dm - The DMPlex object
8421 - cellHeight - Normally 0
8422 
8423   Notes:
8424   This is a useful diagnostic when creating meshes programmatically.
8425   Currently applicable only to homogeneous simplex or tensor meshes.
8426 
8427   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8428 
8429   Level: developer
8430 
8431 .seealso: DMCreate(), DMSetFromOptions()
8432 @*/
8433 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
8434 {
8435   DMPlexInterpolatedFlag interp;
8436   DMPolytopeType         ct;
8437   PetscInt               vStart, vEnd, cStart, cEnd, c;
8438   PetscErrorCode         ierr;
8439 
8440   PetscFunctionBegin;
8441   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8442   ierr = DMPlexIsInterpolated(dm, &interp);CHKERRQ(ierr);
8443   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8444   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8445   for (c = cStart; c < cEnd; ++c) {
8446     PetscInt *closure = NULL;
8447     PetscInt  coneSize, closureSize, cl, Nv = 0;
8448 
8449     ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
8450     PetscCheckFalse((PetscInt) ct < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has no cell type", c);
8451     if (ct == DM_POLYTOPE_UNKNOWN) continue;
8452     if (interp == DMPLEX_INTERPOLATED_FULL) {
8453       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8454       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));
8455     }
8456     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8457     for (cl = 0; cl < closureSize*2; cl += 2) {
8458       const PetscInt p = closure[cl];
8459       if ((p >= vStart) && (p < vEnd)) ++Nv;
8460     }
8461     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8462     /* Special Case: Tensor faces with identified vertices */
8463     if (Nv < DMPolytopeTypeGetNumVertices(ct)) {
8464       PetscInt unsplit;
8465 
8466       ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr);
8467       if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue;
8468     }
8469     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));
8470   }
8471   PetscFunctionReturn(0);
8472 }
8473 
8474 /*@
8475   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
8476 
8477   Not Collective
8478 
8479   Input Parameters:
8480 + dm - The DMPlex object
8481 - cellHeight - Normally 0
8482 
8483   Notes:
8484   This is a useful diagnostic when creating meshes programmatically.
8485   This routine is only relevant for meshes that are fully interpolated across all ranks.
8486   It will error out if a partially interpolated mesh is given on some rank.
8487   It will do nothing for locally uninterpolated mesh (as there is nothing to check).
8488 
8489   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8490 
8491   Level: developer
8492 
8493 .seealso: DMCreate(), DMPlexGetVTKCellHeight(), DMSetFromOptions()
8494 @*/
8495 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
8496 {
8497   PetscInt       dim, depth, vStart, vEnd, cStart, cEnd, c, h;
8498   PetscErrorCode ierr;
8499   DMPlexInterpolatedFlag interpEnum;
8500 
8501   PetscFunctionBegin;
8502   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8503   ierr = DMPlexIsInterpolated(dm, &interpEnum);CHKERRQ(ierr);
8504   if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0);
8505   if (interpEnum == DMPLEX_INTERPOLATED_PARTIAL) {
8506     PetscMPIInt rank;
8507     MPI_Comm    comm;
8508 
8509     ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
8510     ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
8511     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Mesh is only partially interpolated on rank %d, this is currently not supported", rank);
8512   }
8513 
8514   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8515   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8516   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8517   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
8518     ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr);
8519     for (c = cStart; c < cEnd; ++c) {
8520       const PetscInt      *cone, *ornt, *faceSizes, *faces;
8521       const DMPolytopeType *faceTypes;
8522       DMPolytopeType        ct;
8523       PetscInt              numFaces, coneSize, f;
8524       PetscInt             *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit;
8525 
8526       ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
8527       ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr);
8528       if (unsplit) continue;
8529       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8530       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8531       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
8532       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8533       for (cl = 0; cl < closureSize*2; cl += 2) {
8534         const PetscInt p = closure[cl];
8535         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
8536       }
8537       ierr = DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces);CHKERRQ(ierr);
8538       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);
8539       for (f = 0; f < numFaces; ++f) {
8540         DMPolytopeType fct;
8541         PetscInt       *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
8542 
8543         ierr = DMPlexGetCellType(dm, cone[f], &fct);CHKERRQ(ierr);
8544         ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
8545         for (cl = 0; cl < fclosureSize*2; cl += 2) {
8546           const PetscInt p = fclosure[cl];
8547           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
8548         }
8549         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]);
8550         for (v = 0; v < fnumCorners; ++v) {
8551           if (fclosure[v] != faces[fOff+v]) {
8552             PetscInt v1;
8553 
8554             ierr = PetscPrintf(PETSC_COMM_SELF, "face closure:");CHKERRQ(ierr);
8555             for (v1 = 0; v1 < fnumCorners; ++v1) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", fclosure[v1]);CHKERRQ(ierr);}
8556             ierr = PetscPrintf(PETSC_COMM_SELF, "\ncell face:");CHKERRQ(ierr);
8557             for (v1 = 0; v1 < fnumCorners; ++v1) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", faces[fOff+v1]);CHKERRQ(ierr);}
8558             ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8559             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]);
8560           }
8561         }
8562         ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
8563         fOff += faceSizes[f];
8564       }
8565       ierr = DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces);CHKERRQ(ierr);
8566       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8567     }
8568   }
8569   PetscFunctionReturn(0);
8570 }
8571 
8572 /*@
8573   DMPlexCheckGeometry - Check the geometry of mesh cells
8574 
8575   Input Parameter:
8576 . dm - The DMPlex object
8577 
8578   Notes:
8579   This is a useful diagnostic when creating meshes programmatically.
8580 
8581   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8582 
8583   Level: developer
8584 
8585 .seealso: DMCreate(), DMSetFromOptions()
8586 @*/
8587 PetscErrorCode DMPlexCheckGeometry(DM dm)
8588 {
8589   Vec            coordinates;
8590   PetscReal      detJ, J[9], refVol = 1.0;
8591   PetscReal      vol;
8592   PetscBool      periodic;
8593   PetscInt       dim, depth, dE, d, cStart, cEnd, c;
8594   PetscErrorCode ierr;
8595 
8596   PetscFunctionBegin;
8597   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8598   ierr = DMGetCoordinateDim(dm, &dE);CHKERRQ(ierr);
8599   if (dim != dE) PetscFunctionReturn(0);
8600   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8601   ierr = DMGetPeriodicity(dm, &periodic, NULL, NULL, NULL);CHKERRQ(ierr);
8602   for (d = 0; d < dim; ++d) refVol *= 2.0;
8603   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8604   /* Make sure local coordinates are created, because that step is collective */
8605   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8606   for (c = cStart; c < cEnd; ++c) {
8607     DMPolytopeType ct;
8608     PetscInt       unsplit;
8609     PetscBool      ignoreZeroVol = PETSC_FALSE;
8610 
8611     ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
8612     switch (ct) {
8613       case DM_POLYTOPE_SEG_PRISM_TENSOR:
8614       case DM_POLYTOPE_TRI_PRISM_TENSOR:
8615       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8616         ignoreZeroVol = PETSC_TRUE; break;
8617       default: break;
8618     }
8619     switch (ct) {
8620       case DM_POLYTOPE_TRI_PRISM:
8621       case DM_POLYTOPE_TRI_PRISM_TENSOR:
8622       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8623       case DM_POLYTOPE_PYRAMID:
8624         continue;
8625       default: break;
8626     }
8627     ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr);
8628     if (unsplit) continue;
8629     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);CHKERRQ(ierr);
8630     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);
8631     ierr = PetscInfo(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);CHKERRQ(ierr);
8632     if (depth > 1 && !periodic) {
8633       ierr = DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);CHKERRQ(ierr);
8634       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);
8635       ierr = PetscInfo(dm, "Cell %D FVM Volume %g\n", c, (double) vol);CHKERRQ(ierr);
8636     }
8637   }
8638   PetscFunctionReturn(0);
8639 }
8640 
8641 /*@
8642   DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex.
8643 
8644   Input Parameters:
8645 . dm - The DMPlex object
8646 
8647   Notes:
8648   This is mainly intended for debugging/testing purposes.
8649   It currently checks only meshes with no partition overlapping.
8650 
8651   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8652 
8653   Level: developer
8654 
8655 .seealso: DMGetPointSF(), DMSetFromOptions()
8656 @*/
8657 PetscErrorCode DMPlexCheckPointSF(DM dm)
8658 {
8659   PetscSF         pointSF;
8660   PetscInt        cellHeight, cStart, cEnd, l, nleaves, nroots, overlap;
8661   const PetscInt *locals, *rootdegree;
8662   PetscBool       distributed;
8663   PetscErrorCode  ierr;
8664 
8665   PetscFunctionBegin;
8666   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8667   ierr = DMGetPointSF(dm, &pointSF);CHKERRQ(ierr);
8668   ierr = DMPlexIsDistributed(dm, &distributed);CHKERRQ(ierr);
8669   if (!distributed) PetscFunctionReturn(0);
8670   ierr = DMPlexGetOverlap(dm, &overlap);CHKERRQ(ierr);
8671   if (overlap) {
8672     ierr = PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping");CHKERRQ(ierr);
8673     PetscFunctionReturn(0);
8674   }
8675   PetscCheckFalse(!pointSF,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but does not have PointSF attached");
8676   ierr = PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, NULL);CHKERRQ(ierr);
8677   PetscCheckFalse(nroots < 0,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set");
8678   ierr = PetscSFComputeDegreeBegin(pointSF, &rootdegree);CHKERRQ(ierr);
8679   ierr = PetscSFComputeDegreeEnd(pointSF, &rootdegree);CHKERRQ(ierr);
8680 
8681   /* 1) check there are no faces in 2D, cells in 3D, in interface */
8682   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8683   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8684   for (l = 0; l < nleaves; ++l) {
8685     const PetscInt point = locals[l];
8686 
8687     PetscCheckFalse(point >= cStart && point < cEnd,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D which is a cell", point);
8688   }
8689 
8690   /* 2) if some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
8691   for (l = 0; l < nleaves; ++l) {
8692     const PetscInt  point = locals[l];
8693     const PetscInt *cone;
8694     PetscInt        coneSize, c, idx;
8695 
8696     ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
8697     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
8698     for (c = 0; c < coneSize; ++c) {
8699       if (!rootdegree[cone[c]]) {
8700         ierr = PetscFindInt(cone[c], nleaves, locals, &idx);CHKERRQ(ierr);
8701         PetscCheckFalse(idx < 0,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D but not %D from its cone", point, cone[c]);
8702       }
8703     }
8704   }
8705   PetscFunctionReturn(0);
8706 }
8707 
8708 PetscErrorCode DMPlexCheckAll_Internal(DM dm, PetscInt cellHeight)
8709 {
8710   PetscErrorCode ierr;
8711 
8712   PetscFunctionBegin;
8713   ierr = DMPlexCheckSymmetry(dm);CHKERRQ(ierr);
8714   ierr = DMPlexCheckSkeleton(dm, cellHeight);CHKERRQ(ierr);
8715   ierr = DMPlexCheckFaces(dm, cellHeight);CHKERRQ(ierr);
8716   ierr = DMPlexCheckGeometry(dm);CHKERRQ(ierr);
8717   ierr = DMPlexCheckPointSF(dm);CHKERRQ(ierr);
8718   ierr = DMPlexCheckInterfaceCones(dm);CHKERRQ(ierr);
8719   PetscFunctionReturn(0);
8720 }
8721 
8722 typedef struct cell_stats
8723 {
8724   PetscReal min, max, sum, squaresum;
8725   PetscInt  count;
8726 } cell_stats_t;
8727 
8728 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
8729 {
8730   PetscInt i, N = *len;
8731 
8732   for (i = 0; i < N; i++) {
8733     cell_stats_t *A = (cell_stats_t *) a;
8734     cell_stats_t *B = (cell_stats_t *) b;
8735 
8736     B->min = PetscMin(A->min,B->min);
8737     B->max = PetscMax(A->max,B->max);
8738     B->sum += A->sum;
8739     B->squaresum += A->squaresum;
8740     B->count += A->count;
8741   }
8742 }
8743 
8744 /*@
8745   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
8746 
8747   Collective on dm
8748 
8749   Input Parameters:
8750 + dm        - The DMPlex object
8751 . output    - If true, statistics will be displayed on stdout
8752 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output
8753 
8754   Notes:
8755   This is mainly intended for debugging/testing purposes.
8756 
8757   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8758 
8759   Level: developer
8760 
8761 .seealso: DMSetFromOptions(), DMPlexComputeOrthogonalQuality()
8762 @*/
8763 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
8764 {
8765   DM             dmCoarse;
8766   cell_stats_t   stats, globalStats;
8767   MPI_Comm       comm = PetscObjectComm((PetscObject)dm);
8768   PetscReal      *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
8769   PetscReal      limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
8770   PetscInt       cdim, cStart, cEnd, c, eStart, eEnd, count = 0;
8771   PetscMPIInt    rank,size;
8772   PetscErrorCode ierr;
8773 
8774   PetscFunctionBegin;
8775   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8776   stats.min   = PETSC_MAX_REAL;
8777   stats.max   = PETSC_MIN_REAL;
8778   stats.sum   = stats.squaresum = 0.;
8779   stats.count = 0;
8780 
8781   ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr);
8782   ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
8783   ierr = DMGetCoordinateDim(dm,&cdim);CHKERRQ(ierr);
8784   ierr = PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ);CHKERRQ(ierr);
8785   ierr = DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd);CHKERRQ(ierr);
8786   ierr = DMPlexGetDepthStratum(dm,1,&eStart,&eEnd);CHKERRQ(ierr);
8787   for (c = cStart; c < cEnd; c++) {
8788     PetscInt  i;
8789     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
8790 
8791     ierr = DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);CHKERRQ(ierr);
8792     PetscCheckFalse(detJ < 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
8793     for (i = 0; i < PetscSqr(cdim); ++i) {
8794       frobJ    += J[i] * J[i];
8795       frobInvJ += invJ[i] * invJ[i];
8796     }
8797     cond2 = frobJ * frobInvJ;
8798     cond  = PetscSqrtReal(cond2);
8799 
8800     stats.min        = PetscMin(stats.min,cond);
8801     stats.max        = PetscMax(stats.max,cond);
8802     stats.sum       += cond;
8803     stats.squaresum += cond2;
8804     stats.count++;
8805     if (output && cond > limit) {
8806       PetscSection coordSection;
8807       Vec          coordsLocal;
8808       PetscScalar *coords = NULL;
8809       PetscInt     Nv, d, clSize, cl, *closure = NULL;
8810 
8811       ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8812       ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8813       ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr);
8814       ierr = PetscSynchronizedPrintf(comm, "[%d] Cell %D cond %g\n", rank, c, (double) cond);CHKERRQ(ierr);
8815       for (i = 0; i < Nv/cdim; ++i) {
8816         ierr = PetscSynchronizedPrintf(comm, "  Vertex %D: (", i);CHKERRQ(ierr);
8817         for (d = 0; d < cdim; ++d) {
8818           if (d > 0) {ierr = PetscSynchronizedPrintf(comm, ", ");CHKERRQ(ierr);}
8819           ierr = PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]));CHKERRQ(ierr);
8820         }
8821         ierr = PetscSynchronizedPrintf(comm, ")\n");CHKERRQ(ierr);
8822       }
8823       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
8824       for (cl = 0; cl < clSize*2; cl += 2) {
8825         const PetscInt edge = closure[cl];
8826 
8827         if ((edge >= eStart) && (edge < eEnd)) {
8828           PetscReal len;
8829 
8830           ierr = DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL);CHKERRQ(ierr);
8831           ierr = PetscSynchronizedPrintf(comm, "  Edge %D: length %g\n", edge, (double) len);CHKERRQ(ierr);
8832         }
8833       }
8834       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
8835       ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr);
8836     }
8837   }
8838   if (output) {ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);}
8839 
8840   if (size > 1) {
8841     PetscMPIInt   blockLengths[2] = {4,1};
8842     MPI_Aint      blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
8843     MPI_Datatype  blockTypes[2]   = {MPIU_REAL,MPIU_INT}, statType;
8844     MPI_Op        statReduce;
8845 
8846     ierr = MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);CHKERRMPI(ierr);
8847     ierr = MPI_Type_commit(&statType);CHKERRMPI(ierr);
8848     ierr = MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);CHKERRMPI(ierr);
8849     ierr = MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);CHKERRMPI(ierr);
8850     ierr = MPI_Op_free(&statReduce);CHKERRMPI(ierr);
8851     ierr = MPI_Type_free(&statType);CHKERRMPI(ierr);
8852   } else {
8853     ierr = PetscArraycpy(&globalStats,&stats,1);CHKERRQ(ierr);
8854   }
8855   if (rank == 0) {
8856     count = globalStats.count;
8857     min   = globalStats.min;
8858     max   = globalStats.max;
8859     mean  = globalStats.sum / globalStats.count;
8860     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
8861   }
8862 
8863   if (output) {
8864     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);
8865   }
8866   ierr = PetscFree2(J,invJ);CHKERRQ(ierr);
8867 
8868   ierr = DMGetCoarseDM(dm,&dmCoarse);CHKERRQ(ierr);
8869   if (dmCoarse) {
8870     PetscBool isplex;
8871 
8872     ierr = PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);CHKERRQ(ierr);
8873     if (isplex) {
8874       ierr = DMPlexCheckCellShape(dmCoarse,output,condLimit);CHKERRQ(ierr);
8875     }
8876   }
8877   PetscFunctionReturn(0);
8878 }
8879 
8880 /*@
8881   DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with
8882   orthogonal quality below given tolerance.
8883 
8884   Collective on dm
8885 
8886   Input Parameters:
8887 + dm   - The DMPlex object
8888 . fv   - Optional PetscFV object for pre-computed cell/face centroid information
8889 - atol - [0, 1] Absolute tolerance for tagging cells.
8890 
8891   Output Parameters:
8892 + OrthQual      - Vec containing orthogonal quality per cell
8893 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE
8894 
8895   Options Database Keys:
8896 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is
8897 supported.
8898 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector.
8899 
8900   Notes:
8901   Orthogonal quality is given by the following formula:
8902 
8903   \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]
8904 
8905   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
8906   is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the
8907   current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by
8908   calculating the cosine of the angle between these vectors.
8909 
8910   Orthogonal quality ranges from 1 (best) to 0 (worst).
8911 
8912   This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for
8913   pre-computed FVM cell data, but if it is not passed in then this data will be computed.
8914 
8915   Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance.
8916 
8917   Level: intermediate
8918 
8919 .seealso: DMPlexCheckCellShape(), DMCreateLabel()
8920 @*/
8921 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel)
8922 {
8923   PetscInt                nc, cellHeight, cStart, cEnd, cell, cellIter = 0;
8924   PetscInt                *idx;
8925   PetscScalar             *oqVals;
8926   const PetscScalar       *cellGeomArr, *faceGeomArr;
8927   PetscReal               *ci, *fi, *Ai;
8928   MPI_Comm                comm;
8929   Vec                     cellgeom, facegeom;
8930   DM                      dmFace, dmCell;
8931   IS                      glob;
8932   ISLocalToGlobalMapping  ltog;
8933   PetscViewer             vwr;
8934   PetscErrorCode          ierr;
8935 
8936   PetscFunctionBegin;
8937   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8938   if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);}
8939   PetscValidPointer(OrthQual, 4);
8940   PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol);
8941   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
8942   ierr = DMGetDimension(dm, &nc);CHKERRQ(ierr);
8943   PetscCheckFalse(nc < 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %D)", nc);
8944   {
8945     DMPlexInterpolatedFlag interpFlag;
8946 
8947     ierr = DMPlexIsInterpolated(dm, &interpFlag);CHKERRQ(ierr);
8948     if (interpFlag != DMPLEX_INTERPOLATED_FULL) {
8949       PetscMPIInt rank;
8950 
8951       ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
8952       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank);
8953     }
8954   }
8955   if (OrthQualLabel) {
8956     PetscValidPointer(OrthQualLabel, 5);
8957     ierr = DMCreateLabel(dm, "Orthogonal_Quality");CHKERRQ(ierr);
8958     ierr = DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel);CHKERRQ(ierr);
8959   } else {*OrthQualLabel = NULL;}
8960   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8961   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8962   ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob);CHKERRQ(ierr);
8963   ierr = ISLocalToGlobalMappingCreateIS(glob, &ltog);CHKERRQ(ierr);
8964   ierr = ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH);CHKERRQ(ierr);
8965   ierr = VecCreate(comm, OrthQual);CHKERRQ(ierr);
8966   ierr = VecSetType(*OrthQual, VECSTANDARD);CHKERRQ(ierr);
8967   ierr = VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE);CHKERRQ(ierr);
8968   ierr = VecSetLocalToGlobalMapping(*OrthQual, ltog);CHKERRQ(ierr);
8969   ierr = VecSetUp(*OrthQual);CHKERRQ(ierr);
8970   ierr = ISDestroy(&glob);CHKERRQ(ierr);
8971   ierr = ISLocalToGlobalMappingDestroy(&ltog);CHKERRQ(ierr);
8972   ierr = DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL);CHKERRQ(ierr);
8973   ierr = VecGetArrayRead(cellgeom, &cellGeomArr);CHKERRQ(ierr);
8974   ierr = VecGetArrayRead(facegeom, &faceGeomArr);CHKERRQ(ierr);
8975   ierr = VecGetDM(cellgeom, &dmCell);CHKERRQ(ierr);
8976   ierr = VecGetDM(facegeom, &dmFace);CHKERRQ(ierr);
8977   ierr = PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai);CHKERRQ(ierr);
8978   for (cell = cStart; cell < cEnd; cellIter++,cell++) {
8979     PetscInt           cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE;
8980     PetscInt           cellarr[2], *adj = NULL;
8981     PetscScalar        *cArr, *fArr;
8982     PetscReal          minvalc = 1.0, minvalf = 1.0;
8983     PetscFVCellGeom    *cg;
8984 
8985     idx[cellIter] = cell-cStart;
8986     cellarr[0] = cell;
8987     /* Make indexing into cellGeom easier */
8988     ierr = DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg);CHKERRQ(ierr);
8989     ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj);CHKERRQ(ierr);
8990     /* Technically 1 too big, but easier than fiddling with empty adjacency array */
8991     ierr = PetscCalloc2(adjSize, &cArr, adjSize, &fArr);CHKERRQ(ierr);
8992     for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) {
8993       PetscInt         i;
8994       const PetscInt   neigh = adj[cellneigh];
8995       PetscReal        normci = 0, normfi = 0, normai = 0;
8996       PetscFVCellGeom  *cgneigh;
8997       PetscFVFaceGeom  *fg;
8998 
8999       /* Don't count ourselves in the neighbor list */
9000       if (neigh == cell) continue;
9001       ierr = DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh);CHKERRQ(ierr);
9002       cellarr[1] = neigh;
9003       {
9004         PetscInt       numcovpts;
9005         const PetscInt *covpts;
9006 
9007         ierr = DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts);CHKERRQ(ierr);
9008         ierr = DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg);CHKERRQ(ierr);
9009         ierr = DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts);CHKERRQ(ierr);
9010       }
9011 
9012       /* Compute c_i, f_i and their norms */
9013       for (i = 0; i < nc; i++) {
9014         ci[i] = cgneigh->centroid[i] - cg->centroid[i];
9015         fi[i] = fg->centroid[i] - cg->centroid[i];
9016         Ai[i] = fg->normal[i];
9017         normci += PetscPowReal(ci[i], 2);
9018         normfi += PetscPowReal(fi[i], 2);
9019         normai += PetscPowReal(Ai[i], 2);
9020       }
9021       normci = PetscSqrtReal(normci);
9022       normfi = PetscSqrtReal(normfi);
9023       normai = PetscSqrtReal(normai);
9024 
9025       /* Normalize and compute for each face-cell-normal pair */
9026       for (i = 0; i < nc; i++) {
9027         ci[i] = ci[i]/normci;
9028         fi[i] = fi[i]/normfi;
9029         Ai[i] = Ai[i]/normai;
9030         /* PetscAbs because I don't know if normals are guaranteed to point out */
9031         cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]);
9032         fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]);
9033       }
9034       if (PetscRealPart(cArr[cellneighiter]) < minvalc) {
9035         minvalc = PetscRealPart(cArr[cellneighiter]);
9036       }
9037       if (PetscRealPart(fArr[cellneighiter]) < minvalf) {
9038         minvalf = PetscRealPart(fArr[cellneighiter]);
9039       }
9040     }
9041     ierr = PetscFree(adj);CHKERRQ(ierr);
9042     ierr = PetscFree2(cArr, fArr);CHKERRQ(ierr);
9043     /* Defer to cell if they're equal */
9044     oqVals[cellIter] = PetscMin(minvalf, minvalc);
9045     if (OrthQualLabel) {
9046       if (PetscRealPart(oqVals[cellIter]) <= atol) {ierr = DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE);CHKERRQ(ierr);}
9047     }
9048   }
9049   ierr = VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES);CHKERRQ(ierr);
9050   ierr = VecAssemblyBegin(*OrthQual);CHKERRQ(ierr);
9051   ierr = VecAssemblyEnd(*OrthQual);CHKERRQ(ierr);
9052   ierr = VecRestoreArrayRead(cellgeom, &cellGeomArr);CHKERRQ(ierr);
9053   ierr = VecRestoreArrayRead(facegeom, &faceGeomArr);CHKERRQ(ierr);
9054   ierr = PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL);CHKERRQ(ierr);
9055   if (OrthQualLabel) {
9056     if (vwr) {ierr = DMLabelView(*OrthQualLabel, vwr);CHKERRQ(ierr);}
9057   }
9058   ierr = PetscFree5(idx, oqVals, ci, fi, Ai);CHKERRQ(ierr);
9059   ierr = PetscViewerDestroy(&vwr);CHKERRQ(ierr);
9060   ierr = VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view");CHKERRQ(ierr);
9061   PetscFunctionReturn(0);
9062 }
9063 
9064 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect
9065  * interpolator construction */
9066 static PetscErrorCode DMGetFullDM(DM dm, DM *odm)
9067 {
9068   PetscSection   section, newSection, gsection;
9069   PetscSF        sf;
9070   PetscBool      hasConstraints, ghasConstraints;
9071   PetscErrorCode ierr;
9072 
9073   PetscFunctionBegin;
9074   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9075   PetscValidPointer(odm,2);
9076   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
9077   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
9078   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRMPI(ierr);
9079   if (!ghasConstraints) {
9080     ierr = PetscObjectReference((PetscObject)dm);CHKERRQ(ierr);
9081     *odm = dm;
9082     PetscFunctionReturn(0);
9083   }
9084   ierr = DMClone(dm, odm);CHKERRQ(ierr);
9085   ierr = DMCopyFields(dm, *odm);CHKERRQ(ierr);
9086   ierr = DMGetLocalSection(*odm, &newSection);CHKERRQ(ierr);
9087   ierr = DMGetPointSF(*odm, &sf);CHKERRQ(ierr);
9088   ierr = PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
9089   ierr = DMSetGlobalSection(*odm, gsection);CHKERRQ(ierr);
9090   ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
9091   PetscFunctionReturn(0);
9092 }
9093 
9094 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift)
9095 {
9096   DM             dmco, dmfo;
9097   Mat            interpo;
9098   Vec            rscale;
9099   Vec            cglobalo, clocal;
9100   Vec            fglobal, fglobalo, flocal;
9101   PetscBool      regular;
9102   PetscErrorCode ierr;
9103 
9104   PetscFunctionBegin;
9105   ierr = DMGetFullDM(dmc, &dmco);CHKERRQ(ierr);
9106   ierr = DMGetFullDM(dmf, &dmfo);CHKERRQ(ierr);
9107   ierr = DMSetCoarseDM(dmfo, dmco);CHKERRQ(ierr);
9108   ierr = DMPlexGetRegularRefinement(dmf, &regular);CHKERRQ(ierr);
9109   ierr = DMPlexSetRegularRefinement(dmfo, regular);CHKERRQ(ierr);
9110   ierr = DMCreateInterpolation(dmco, dmfo, &interpo, &rscale);CHKERRQ(ierr);
9111   ierr = DMCreateGlobalVector(dmco, &cglobalo);CHKERRQ(ierr);
9112   ierr = DMCreateLocalVector(dmc, &clocal);CHKERRQ(ierr);
9113   ierr = VecSet(cglobalo, 0.);CHKERRQ(ierr);
9114   ierr = VecSet(clocal, 0.);CHKERRQ(ierr);
9115   ierr = DMCreateGlobalVector(dmf, &fglobal);CHKERRQ(ierr);
9116   ierr = DMCreateGlobalVector(dmfo, &fglobalo);CHKERRQ(ierr);
9117   ierr = DMCreateLocalVector(dmf, &flocal);CHKERRQ(ierr);
9118   ierr = VecSet(fglobal, 0.);CHKERRQ(ierr);
9119   ierr = VecSet(fglobalo, 0.);CHKERRQ(ierr);
9120   ierr = VecSet(flocal, 0.);CHKERRQ(ierr);
9121   ierr = DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL);CHKERRQ(ierr);
9122   ierr = DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo);CHKERRQ(ierr);
9123   ierr = DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo);CHKERRQ(ierr);
9124   ierr = MatMult(interpo, cglobalo, fglobalo);CHKERRQ(ierr);
9125   ierr = DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal);CHKERRQ(ierr);
9126   ierr = DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal);CHKERRQ(ierr);
9127   ierr = DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal);CHKERRQ(ierr);
9128   ierr = DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal);CHKERRQ(ierr);
9129   *shift = fglobal;
9130   ierr = VecDestroy(&flocal);CHKERRQ(ierr);
9131   ierr = VecDestroy(&fglobalo);CHKERRQ(ierr);
9132   ierr = VecDestroy(&clocal);CHKERRQ(ierr);
9133   ierr = VecDestroy(&cglobalo);CHKERRQ(ierr);
9134   ierr = VecDestroy(&rscale);CHKERRQ(ierr);
9135   ierr = MatDestroy(&interpo);CHKERRQ(ierr);
9136   ierr = DMDestroy(&dmfo);CHKERRQ(ierr);
9137   ierr = DMDestroy(&dmco);CHKERRQ(ierr);
9138   PetscFunctionReturn(0);
9139 }
9140 
9141 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
9142 {
9143   PetscObject    shifto;
9144   Vec            shift;
9145 
9146   PetscErrorCode ierr;
9147 
9148   PetscFunctionBegin;
9149   if (!interp) {
9150     Vec rscale;
9151 
9152     ierr = DMCreateInterpolation(coarse, fine, &interp, &rscale);CHKERRQ(ierr);
9153     ierr = VecDestroy(&rscale);CHKERRQ(ierr);
9154   } else {
9155     ierr = PetscObjectReference((PetscObject)interp);CHKERRQ(ierr);
9156   }
9157   ierr = PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto);CHKERRQ(ierr);
9158   if (!shifto) {
9159     ierr = DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift);CHKERRQ(ierr);
9160     ierr = PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift);CHKERRQ(ierr);
9161     shifto = (PetscObject) shift;
9162     ierr = VecDestroy(&shift);CHKERRQ(ierr);
9163   }
9164   shift = (Vec) shifto;
9165   ierr = MatInterpolate(interp, coarseSol, fineSol);CHKERRQ(ierr);
9166   ierr = VecAXPY(fineSol, 1.0, shift);CHKERRQ(ierr);
9167   ierr = MatDestroy(&interp);CHKERRQ(ierr);
9168   PetscFunctionReturn(0);
9169 }
9170 
9171 /* Pointwise interpolation
9172      Just code FEM for now
9173      u^f = I u^c
9174      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
9175      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
9176      I_{ij} = psi^f_i phi^c_j
9177 */
9178 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
9179 {
9180   PetscSection   gsc, gsf;
9181   PetscInt       m, n;
9182   void          *ctx;
9183   DM             cdm;
9184   PetscBool      regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE;
9185   PetscErrorCode ierr;
9186 
9187   PetscFunctionBegin;
9188   ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
9189   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
9190   ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
9191   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
9192 
9193   ierr = PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);CHKERRQ(ierr);
9194   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr);
9195   ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
9196   ierr = MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);CHKERRQ(ierr);
9197   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
9198 
9199   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
9200   ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
9201   if (!isRefined || (regular && cdm == dmCoarse)) {ierr = DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx);CHKERRQ(ierr);}
9202   else                                            {ierr = DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
9203   ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr);
9204   if (scaling) {
9205     /* Use naive scaling */
9206     ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr);
9207   }
9208   PetscFunctionReturn(0);
9209 }
9210 
9211 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
9212 {
9213   PetscErrorCode ierr;
9214   VecScatter     ctx;
9215 
9216   PetscFunctionBegin;
9217   ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);CHKERRQ(ierr);
9218   ierr = MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);CHKERRQ(ierr);
9219   ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr);
9220   PetscFunctionReturn(0);
9221 }
9222 
9223 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux,
9224                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
9225                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
9226                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
9227 {
9228   const PetscInt Nc = uOff[1] - uOff[0];
9229   PetscInt       c;
9230   for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0;
9231 }
9232 
9233 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass)
9234 {
9235   DM             dmc;
9236   PetscDS        ds;
9237   Vec            ones, locmass;
9238   IS             cellIS;
9239   PetscFormKey   key;
9240   PetscInt       depth;
9241   PetscErrorCode ierr;
9242 
9243   PetscFunctionBegin;
9244   ierr = DMClone(dm, &dmc);CHKERRQ(ierr);
9245   ierr = DMCopyDisc(dm, dmc);CHKERRQ(ierr);
9246   ierr = DMGetDS(dmc, &ds);CHKERRQ(ierr);
9247   ierr = PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL);CHKERRQ(ierr);
9248   ierr = DMCreateGlobalVector(dmc, mass);CHKERRQ(ierr);
9249   ierr = DMGetLocalVector(dmc, &ones);CHKERRQ(ierr);
9250   ierr = DMGetLocalVector(dmc, &locmass);CHKERRQ(ierr);
9251   ierr = DMPlexGetDepth(dmc, &depth);CHKERRQ(ierr);
9252   ierr = DMGetStratumIS(dmc, "depth", depth, &cellIS);CHKERRQ(ierr);
9253   ierr = VecSet(locmass, 0.0);CHKERRQ(ierr);
9254   ierr = VecSet(ones, 1.0);CHKERRQ(ierr);
9255   key.label = NULL;
9256   key.value = 0;
9257   key.field = 0;
9258   key.part  = 0;
9259   ierr = DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL);CHKERRQ(ierr);
9260   ierr = ISDestroy(&cellIS);CHKERRQ(ierr);
9261   ierr = VecSet(*mass, 0.0);CHKERRQ(ierr);
9262   ierr = DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass);CHKERRQ(ierr);
9263   ierr = DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass);CHKERRQ(ierr);
9264   ierr = DMRestoreLocalVector(dmc, &ones);CHKERRQ(ierr);
9265   ierr = DMRestoreLocalVector(dmc, &locmass);CHKERRQ(ierr);
9266   ierr = DMDestroy(&dmc);CHKERRQ(ierr);
9267   PetscFunctionReturn(0);
9268 }
9269 
9270 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
9271 {
9272   PetscSection   gsc, gsf;
9273   PetscInt       m, n;
9274   void          *ctx;
9275   DM             cdm;
9276   PetscBool      regular;
9277   PetscErrorCode ierr;
9278 
9279   PetscFunctionBegin;
9280   if (dmFine == dmCoarse) {
9281     DM            dmc;
9282     PetscDS       ds;
9283     PetscWeakForm wf;
9284     Vec           u;
9285     IS            cellIS;
9286     PetscFormKey  key;
9287     PetscInt      depth;
9288 
9289     ierr = DMClone(dmFine, &dmc);CHKERRQ(ierr);
9290     ierr = DMCopyDisc(dmFine, dmc);CHKERRQ(ierr);
9291     ierr = DMGetDS(dmc, &ds);CHKERRQ(ierr);
9292     ierr = PetscDSGetWeakForm(ds, &wf);CHKERRQ(ierr);
9293     ierr = PetscWeakFormClear(wf);CHKERRQ(ierr);
9294     ierr = PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL);CHKERRQ(ierr);
9295     ierr = DMCreateMatrix(dmc, mass);CHKERRQ(ierr);
9296     ierr = DMGetGlobalVector(dmc, &u);CHKERRQ(ierr);
9297     ierr = DMPlexGetDepth(dmc, &depth);CHKERRQ(ierr);
9298     ierr = DMGetStratumIS(dmc, "depth", depth, &cellIS);CHKERRQ(ierr);
9299     ierr = MatZeroEntries(*mass);CHKERRQ(ierr);
9300     key.label = NULL;
9301     key.value = 0;
9302     key.field = 0;
9303     key.part  = 0;
9304     ierr = DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL);CHKERRQ(ierr);
9305     ierr = ISDestroy(&cellIS);CHKERRQ(ierr);
9306     ierr = DMRestoreGlobalVector(dmc, &u);CHKERRQ(ierr);
9307     ierr = DMDestroy(&dmc);CHKERRQ(ierr);
9308   } else {
9309     ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
9310     ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
9311     ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
9312     ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
9313 
9314     ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);CHKERRQ(ierr);
9315     ierr = MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
9316     ierr = MatSetType(*mass, dmCoarse->mattype);CHKERRQ(ierr);
9317     ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
9318 
9319     ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
9320     ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
9321     if (regular && cdm == dmCoarse) {ierr = DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
9322     else                            {ierr = DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
9323   }
9324   ierr = MatViewFromOptions(*mass, NULL, "-mass_mat_view");CHKERRQ(ierr);
9325   PetscFunctionReturn(0);
9326 }
9327 
9328 /*@
9329   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
9330 
9331   Input Parameter:
9332 . dm - The DMPlex object
9333 
9334   Output Parameter:
9335 . regular - The flag
9336 
9337   Level: intermediate
9338 
9339 .seealso: DMPlexSetRegularRefinement()
9340 @*/
9341 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
9342 {
9343   PetscFunctionBegin;
9344   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9345   PetscValidPointer(regular, 2);
9346   *regular = ((DM_Plex *) dm->data)->regularRefinement;
9347   PetscFunctionReturn(0);
9348 }
9349 
9350 /*@
9351   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
9352 
9353   Input Parameters:
9354 + dm - The DMPlex object
9355 - regular - The flag
9356 
9357   Level: intermediate
9358 
9359 .seealso: DMPlexGetRegularRefinement()
9360 @*/
9361 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
9362 {
9363   PetscFunctionBegin;
9364   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9365   ((DM_Plex *) dm->data)->regularRefinement = regular;
9366   PetscFunctionReturn(0);
9367 }
9368 
9369 /* anchors */
9370 /*@
9371   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
9372   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
9373 
9374   not collective
9375 
9376   Input Parameter:
9377 . dm - The DMPlex object
9378 
9379   Output Parameters:
9380 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
9381 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
9382 
9383   Level: intermediate
9384 
9385 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
9386 @*/
9387 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
9388 {
9389   DM_Plex *plex = (DM_Plex *)dm->data;
9390   PetscErrorCode ierr;
9391 
9392   PetscFunctionBegin;
9393   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9394   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);}
9395   if (anchorSection) *anchorSection = plex->anchorSection;
9396   if (anchorIS) *anchorIS = plex->anchorIS;
9397   PetscFunctionReturn(0);
9398 }
9399 
9400 /*@
9401   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
9402   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
9403   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
9404 
9405   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
9406   DMGetConstraints() and filling in the entries in the constraint matrix.
9407 
9408   collective on dm
9409 
9410   Input Parameters:
9411 + dm - The DMPlex object
9412 . 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).
9413 - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
9414 
9415   The reference counts of anchorSection and anchorIS are incremented.
9416 
9417   Level: intermediate
9418 
9419 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
9420 @*/
9421 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
9422 {
9423   DM_Plex        *plex = (DM_Plex *)dm->data;
9424   PetscMPIInt    result;
9425   PetscErrorCode ierr;
9426 
9427   PetscFunctionBegin;
9428   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9429   if (anchorSection) {
9430     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
9431     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRMPI(ierr);
9432     PetscCheckFalse(result != MPI_CONGRUENT && result != MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
9433   }
9434   if (anchorIS) {
9435     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
9436     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRMPI(ierr);
9437     PetscCheckFalse(result != MPI_CONGRUENT && result != MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
9438   }
9439 
9440   ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr);
9441   ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr);
9442   plex->anchorSection = anchorSection;
9443 
9444   ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr);
9445   ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr);
9446   plex->anchorIS = anchorIS;
9447 
9448   if (PetscUnlikelyDebug(anchorIS && anchorSection)) {
9449     PetscInt size, a, pStart, pEnd;
9450     const PetscInt *anchors;
9451 
9452     ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
9453     ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr);
9454     ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr);
9455     for (a = 0; a < size; a++) {
9456       PetscInt p;
9457 
9458       p = anchors[a];
9459       if (p >= pStart && p < pEnd) {
9460         PetscInt dof;
9461 
9462         ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
9463         if (dof) {
9464           PetscErrorCode ierr2;
9465 
9466           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
9467           SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
9468         }
9469       }
9470     }
9471     ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr);
9472   }
9473   /* reset the generic constraints */
9474   ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr);
9475   PetscFunctionReturn(0);
9476 }
9477 
9478 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
9479 {
9480   PetscSection anchorSection;
9481   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
9482   PetscErrorCode ierr;
9483 
9484   PetscFunctionBegin;
9485   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9486   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
9487   ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr);
9488   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
9489   if (numFields) {
9490     PetscInt f;
9491     ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr);
9492 
9493     for (f = 0; f < numFields; f++) {
9494       PetscInt numComp;
9495 
9496       ierr = PetscSectionGetFieldComponents(section,f,&numComp);CHKERRQ(ierr);
9497       ierr = PetscSectionSetFieldComponents(*cSec,f,numComp);CHKERRQ(ierr);
9498     }
9499   }
9500   ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
9501   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
9502   pStart = PetscMax(pStart,sStart);
9503   pEnd   = PetscMin(pEnd,sEnd);
9504   pEnd   = PetscMax(pStart,pEnd);
9505   ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr);
9506   for (p = pStart; p < pEnd; p++) {
9507     ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
9508     if (dof) {
9509       ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
9510       ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr);
9511       for (f = 0; f < numFields; f++) {
9512         ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
9513         ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr);
9514       }
9515     }
9516   }
9517   ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr);
9518   ierr = PetscObjectSetName((PetscObject) *cSec, "Constraint Section");CHKERRQ(ierr);
9519   PetscFunctionReturn(0);
9520 }
9521 
9522 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
9523 {
9524   PetscSection   aSec;
9525   PetscInt       pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
9526   const PetscInt *anchors;
9527   PetscInt       numFields, f;
9528   IS             aIS;
9529   PetscErrorCode ierr;
9530   MatType        mtype;
9531   PetscBool      iscuda,iskokkos;
9532 
9533   PetscFunctionBegin;
9534   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9535   ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr);
9536   ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr);
9537   ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr);
9538   ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr);
9539   ierr = PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda);CHKERRQ(ierr);
9540   if (!iscuda) { ierr = PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda);CHKERRQ(ierr); }
9541   ierr = PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos);CHKERRQ(ierr);
9542   if (!iskokkos) { ierr = PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos);CHKERRQ(ierr); }
9543   if (iscuda) mtype = MATSEQAIJCUSPARSE;
9544   else if (iskokkos) mtype = MATSEQAIJKOKKOS;
9545   else mtype = MATSEQAIJ;
9546   ierr = MatSetType(*cMat,mtype);CHKERRQ(ierr);
9547   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
9548   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
9549   /* cSec will be a subset of aSec and section */
9550   ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
9551   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
9552   ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr);
9553   i[0] = 0;
9554   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
9555   for (p = pStart; p < pEnd; p++) {
9556     PetscInt rDof, rOff, r;
9557 
9558     ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
9559     if (!rDof) continue;
9560     ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
9561     if (numFields) {
9562       for (f = 0; f < numFields; f++) {
9563         annz = 0;
9564         for (r = 0; r < rDof; r++) {
9565           a = anchors[rOff + r];
9566           if (a < sStart || a >= sEnd) continue;
9567           ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
9568           annz += aDof;
9569         }
9570         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
9571         ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr);
9572         for (q = 0; q < dof; q++) {
9573           i[off + q + 1] = i[off + q] + annz;
9574         }
9575       }
9576     } else {
9577       annz = 0;
9578       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
9579       for (q = 0; q < dof; q++) {
9580         a = anchors[rOff + q];
9581         if (a < sStart || a >= sEnd) continue;
9582         ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
9583         annz += aDof;
9584       }
9585       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
9586       ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr);
9587       for (q = 0; q < dof; q++) {
9588         i[off + q + 1] = i[off + q] + annz;
9589       }
9590     }
9591   }
9592   nnz = i[m];
9593   ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr);
9594   offset = 0;
9595   for (p = pStart; p < pEnd; p++) {
9596     if (numFields) {
9597       for (f = 0; f < numFields; f++) {
9598         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
9599         for (q = 0; q < dof; q++) {
9600           PetscInt rDof, rOff, r;
9601           ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
9602           ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
9603           for (r = 0; r < rDof; r++) {
9604             PetscInt s;
9605 
9606             a = anchors[rOff + r];
9607             if (a < sStart || a >= sEnd) continue;
9608             ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
9609             ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr);
9610             for (s = 0; s < aDof; s++) {
9611               j[offset++] = aOff + s;
9612             }
9613           }
9614         }
9615       }
9616     } else {
9617       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
9618       for (q = 0; q < dof; q++) {
9619         PetscInt rDof, rOff, r;
9620         ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
9621         ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
9622         for (r = 0; r < rDof; r++) {
9623           PetscInt s;
9624 
9625           a = anchors[rOff + r];
9626           if (a < sStart || a >= sEnd) continue;
9627           ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
9628           ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr);
9629           for (s = 0; s < aDof; s++) {
9630             j[offset++] = aOff + s;
9631           }
9632         }
9633       }
9634     }
9635   }
9636   ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr);
9637   ierr = PetscFree(i);CHKERRQ(ierr);
9638   ierr = PetscFree(j);CHKERRQ(ierr);
9639   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
9640   PetscFunctionReturn(0);
9641 }
9642 
9643 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
9644 {
9645   DM_Plex        *plex = (DM_Plex *)dm->data;
9646   PetscSection   anchorSection, section, cSec;
9647   Mat            cMat;
9648   PetscErrorCode ierr;
9649 
9650   PetscFunctionBegin;
9651   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9652   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
9653   if (anchorSection) {
9654     PetscInt Nf;
9655 
9656     ierr = DMGetLocalSection(dm,&section);CHKERRQ(ierr);
9657     ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr);
9658     ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr);
9659     ierr = DMGetNumFields(dm,&Nf);CHKERRQ(ierr);
9660     if (Nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);}
9661     ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr);
9662     ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr);
9663     ierr = MatDestroy(&cMat);CHKERRQ(ierr);
9664   }
9665   PetscFunctionReturn(0);
9666 }
9667 
9668 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
9669 {
9670   IS             subis;
9671   PetscSection   section, subsection;
9672   PetscErrorCode ierr;
9673 
9674   PetscFunctionBegin;
9675   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
9676   PetscCheckFalse(!section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
9677   PetscCheckFalse(!subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
9678   /* Create subdomain */
9679   ierr = DMPlexFilter(dm, label, value, subdm);CHKERRQ(ierr);
9680   /* Create submodel */
9681   ierr = DMPlexGetSubpointIS(*subdm, &subis);CHKERRQ(ierr);
9682   ierr = PetscSectionCreateSubmeshSection(section, subis, &subsection);CHKERRQ(ierr);
9683   ierr = DMSetLocalSection(*subdm, subsection);CHKERRQ(ierr);
9684   ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
9685   ierr = DMCopyDisc(dm, *subdm);CHKERRQ(ierr);
9686   /* Create map from submodel to global model */
9687   if (is) {
9688     PetscSection    sectionGlobal, subsectionGlobal;
9689     IS              spIS;
9690     const PetscInt *spmap;
9691     PetscInt       *subIndices;
9692     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
9693     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
9694 
9695     ierr = DMPlexGetSubpointIS(*subdm, &spIS);CHKERRQ(ierr);
9696     ierr = ISGetIndices(spIS, &spmap);CHKERRQ(ierr);
9697     ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
9698     ierr = DMGetGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
9699     ierr = DMGetGlobalSection(*subdm, &subsectionGlobal);CHKERRQ(ierr);
9700     ierr = PetscSectionGetChart(subsection, &pStart, &pEnd);CHKERRQ(ierr);
9701     for (p = pStart; p < pEnd; ++p) {
9702       PetscInt gdof, pSubSize  = 0;
9703 
9704       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
9705       if (gdof > 0) {
9706         for (f = 0; f < Nf; ++f) {
9707           PetscInt fdof, fcdof;
9708 
9709           ierr     = PetscSectionGetFieldDof(subsection, p, f, &fdof);CHKERRQ(ierr);
9710           ierr     = PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);CHKERRQ(ierr);
9711           pSubSize += fdof-fcdof;
9712         }
9713         subSize += pSubSize;
9714         if (pSubSize) {
9715           if (bs < 0) {
9716             bs = pSubSize;
9717           } else if (bs != pSubSize) {
9718             /* Layout does not admit a pointwise block size */
9719             bs = 1;
9720           }
9721         }
9722       }
9723     }
9724     /* Must have same blocksize on all procs (some might have no points) */
9725     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
9726     ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr);
9727     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
9728     else                            {bs = bsMinMax[0];}
9729     ierr = PetscMalloc1(subSize, &subIndices);CHKERRQ(ierr);
9730     for (p = pStart; p < pEnd; ++p) {
9731       PetscInt gdof, goff;
9732 
9733       ierr = PetscSectionGetDof(subsectionGlobal, p, &gdof);CHKERRQ(ierr);
9734       if (gdof > 0) {
9735         const PetscInt point = spmap[p];
9736 
9737         ierr = PetscSectionGetOffset(sectionGlobal, point, &goff);CHKERRQ(ierr);
9738         for (f = 0; f < Nf; ++f) {
9739           PetscInt fdof, fcdof, fc, f2, poff = 0;
9740 
9741           /* Can get rid of this loop by storing field information in the global section */
9742           for (f2 = 0; f2 < f; ++f2) {
9743             ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
9744             ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
9745             poff += fdof-fcdof;
9746           }
9747           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
9748           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
9749           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
9750             subIndices[subOff] = goff+poff+fc;
9751           }
9752         }
9753       }
9754     }
9755     ierr = ISRestoreIndices(spIS, &spmap);CHKERRQ(ierr);
9756     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);
9757     if (bs > 1) {
9758       /* We need to check that the block size does not come from non-contiguous fields */
9759       PetscInt i, j, set = 1;
9760       for (i = 0; i < subSize; i += bs) {
9761         for (j = 0; j < bs; ++j) {
9762           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
9763         }
9764       }
9765       if (set) {ierr = ISSetBlockSize(*is, bs);CHKERRQ(ierr);}
9766     }
9767     /* Attach nullspace */
9768     for (f = 0; f < Nf; ++f) {
9769       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
9770       if ((*subdm)->nullspaceConstructors[f]) break;
9771     }
9772     if (f < Nf) {
9773       MatNullSpace nullSpace;
9774       ierr = (*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace);CHKERRQ(ierr);
9775 
9776       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
9777       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
9778     }
9779   }
9780   PetscFunctionReturn(0);
9781 }
9782 
9783 /*@
9784   DMPlexMonitorThroughput - Report the cell throughput of FE integration
9785 
9786   Input Parameter:
9787 - dm - The DM
9788 
9789   Level: developer
9790 
9791   Options Database Keys:
9792 . -dm_plex_monitor_throughput - Activate the monitor
9793 
9794 .seealso: DMSetFromOptions(), DMPlexCreate()
9795 @*/
9796 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy)
9797 {
9798 #if defined(PETSC_USE_LOG)
9799   PetscStageLog      stageLog;
9800   PetscLogEvent      event;
9801   PetscLogStage      stage;
9802   PetscEventPerfInfo eventInfo;
9803   PetscReal          cellRate, flopRate;
9804   PetscInt           cStart, cEnd, Nf, N;
9805   const char        *name;
9806   PetscErrorCode     ierr;
9807 #endif
9808 
9809   PetscFunctionBegin;
9810   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9811 #if defined(PETSC_USE_LOG)
9812   ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
9813   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9814   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
9815   ierr = PetscLogGetStageLog(&stageLog);CHKERRQ(ierr);
9816   ierr = PetscStageLogGetCurrent(stageLog, &stage);CHKERRQ(ierr);
9817   ierr = PetscLogEventGetId("DMPlexResidualFE", &event);CHKERRQ(ierr);
9818   ierr = PetscLogEventGetPerfInfo(stage, event, &eventInfo);CHKERRQ(ierr);
9819   N        = (cEnd - cStart)*Nf*eventInfo.count;
9820   flopRate = eventInfo.flops/eventInfo.time;
9821   cellRate = N/eventInfo.time;
9822   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);
9823 #else
9824   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log.");
9825 #endif
9826   PetscFunctionReturn(0);
9827 }
9828