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