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