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