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