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