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