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