xref: /petsc/src/dm/impls/plex/plex.c (revision d410b0cf18e1798d3d4c14858e0c2ffdbe2fea69)
1 #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <petsc/private/isimpl.h>
3 #include <petsc/private/vecimpl.h>
4 #include <petsc/private/glvisvecimpl.h>
5 #include <petscsf.h>
6 #include <petscds.h>
7 #include <petscdraw.h>
8 #include <petscdmfield.h>
9 #include <petscdmplextransform.h>
10 
11 /* Logging support */
12 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF,DMPLEX_LocatePoints;
13 
14 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
15 
16 /*@
17   DMPlexIsSimplex - Is the first cell in this mesh a simplex?
18 
19   Input Parameter:
20 . dm      - The DMPlex object
21 
22   Output Parameter:
23 . simplex - Flag checking for a simplex
24 
25   Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
26   If the mesh has no cells, this returns PETSC_FALSE.
27 
28   Level: intermediate
29 
30 .seealso DMPlexGetSimplexOrBoxCells(), DMPlexGetCellType(), DMPlexGetHeightStratum(), DMPolytopeTypeGetNumVertices()
31 @*/
32 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex)
33 {
34   DMPolytopeType ct;
35   PetscInt       cStart, cEnd;
36   PetscErrorCode ierr;
37 
38   PetscFunctionBegin;
39   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
40   if (cEnd <= cStart) {*simplex = PETSC_FALSE; PetscFunctionReturn(0);}
41   ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr);
42   *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
43   PetscFunctionReturn(0);
44 }
45 
46 /*@
47   DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells
48 
49   Input Parameters:
50 + dm     - The DMPlex object
51 - height - The cell height in the Plex, 0 is the default
52 
53   Output Parameters:
54 + cStart - The first "normal" cell
55 - cEnd   - The upper bound on "normal"" cells
56 
57   Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
58 
59   Level: developer
60 
61 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum()
62 @*/
63 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd)
64 {
65   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
66   PetscInt       cS, cE, c;
67   PetscErrorCode ierr;
68 
69   PetscFunctionBegin;
70   ierr = DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE);CHKERRQ(ierr);
71   for (c = cS; c < cE; ++c) {
72     DMPolytopeType cct;
73 
74     ierr = DMPlexGetCellType(dm, c, &cct);CHKERRQ(ierr);
75     if ((PetscInt) cct < 0) break;
76     switch (cct) {
77       case DM_POLYTOPE_POINT:
78       case DM_POLYTOPE_SEGMENT:
79       case DM_POLYTOPE_TRIANGLE:
80       case DM_POLYTOPE_QUADRILATERAL:
81       case DM_POLYTOPE_TETRAHEDRON:
82       case DM_POLYTOPE_HEXAHEDRON:
83         ct = cct;
84         break;
85       default: break;
86     }
87     if (ct != DM_POLYTOPE_UNKNOWN) break;
88   }
89   if (ct != DM_POLYTOPE_UNKNOWN) {
90     DMLabel ctLabel;
91 
92     ierr = DMPlexGetCellTypeLabel(dm, &ctLabel);CHKERRQ(ierr);
93     ierr = DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE);CHKERRQ(ierr);
94   }
95   if (cStart) *cStart = cS;
96   if (cEnd)   *cEnd   = cE;
97   PetscFunctionReturn(0);
98 }
99 
100 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
101 {
102   PetscInt       cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd;
103   PetscInt       vcdof[2] = {0,0}, globalvcdof[2];
104   PetscErrorCode ierr;
105 
106   PetscFunctionBegin;
107   *ft  = PETSC_VTK_INVALID;
108   ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
109   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
110   ierr = DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
111   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
112   if (field >= 0) {
113     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]);CHKERRQ(ierr);}
114     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]);CHKERRQ(ierr);}
115   } else {
116     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vcdof[0]);CHKERRQ(ierr);}
117     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &vcdof[1]);CHKERRQ(ierr);}
118   }
119   ierr = MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
120   if (globalvcdof[0]) {
121     *sStart = vStart;
122     *sEnd   = vEnd;
123     if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
124     else                        *ft = PETSC_VTK_POINT_FIELD;
125   } else if (globalvcdof[1]) {
126     *sStart = cStart;
127     *sEnd   = cEnd;
128     if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
129     else                        *ft = PETSC_VTK_CELL_FIELD;
130   } else {
131     if (field >= 0) {
132       const char *fieldname;
133 
134       ierr = PetscSectionGetFieldName(section, field, &fieldname);CHKERRQ(ierr);
135       ierr = PetscInfo2((PetscObject) dm, "Could not classify VTK output type of section field %D \"%s\"\n", field, fieldname);CHKERRQ(ierr);
136     } else {
137       ierr = PetscInfo((PetscObject) dm, "Could not classify VTK output type of section\"%s\"\n");CHKERRQ(ierr);
138     }
139   }
140   PetscFunctionReturn(0);
141 }
142 
143 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
144 {
145   DM                 dm;
146   PetscSection       s;
147   PetscDraw          draw, popup;
148   DM                 cdm;
149   PetscSection       coordSection;
150   Vec                coordinates;
151   const PetscScalar *coords, *array;
152   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
153   PetscReal          vbound[2], time;
154   PetscBool          isnull, flg;
155   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
156   const char        *name;
157   char               title[PETSC_MAX_PATH_LEN];
158   PetscErrorCode     ierr;
159 
160   PetscFunctionBegin;
161   ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr);
162   ierr = PetscDrawIsNull(draw, &isnull);CHKERRQ(ierr);
163   if (isnull) PetscFunctionReturn(0);
164 
165   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
166   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
167   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D. Use PETSCVIEWERGLVIS", dim);
168   ierr = DMGetLocalSection(dm, &s);CHKERRQ(ierr);
169   ierr = PetscSectionGetNumFields(s, &Nf);CHKERRQ(ierr);
170   ierr = DMGetCoarsenLevel(dm, &level);CHKERRQ(ierr);
171   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
172   ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr);
173   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
174   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
175   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
176 
177   ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
178   ierr = DMGetOutputSequenceNumber(dm, &step, &time);CHKERRQ(ierr);
179 
180   ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr);
181   ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr);
182   for (c = 0; c < N; c += dim) {
183     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
184     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
185   }
186   ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr);
187   ierr = PetscDrawClear(draw);CHKERRQ(ierr);
188 
189   /* Could implement something like DMDASelectFields() */
190   for (f = 0; f < Nf; ++f) {
191     DM   fdm = dm;
192     Vec  fv  = v;
193     IS   fis;
194     char prefix[PETSC_MAX_PATH_LEN];
195     const char *fname;
196 
197     ierr = PetscSectionGetFieldComponents(s, f, &Nc);CHKERRQ(ierr);
198     ierr = PetscSectionGetFieldName(s, f, &fname);CHKERRQ(ierr);
199 
200     if (v->hdr.prefix) {ierr = PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix));CHKERRQ(ierr);}
201     else               {prefix[0] = '\0';}
202     if (Nf > 1) {
203       ierr = DMCreateSubDM(dm, 1, &f, &fis, &fdm);CHKERRQ(ierr);
204       ierr = VecGetSubVector(v, fis, &fv);CHKERRQ(ierr);
205       ierr = PetscStrlcat(prefix, fname,sizeof(prefix));CHKERRQ(ierr);
206       ierr = PetscStrlcat(prefix, "_",sizeof(prefix));CHKERRQ(ierr);
207     }
208     for (comp = 0; comp < Nc; ++comp, ++w) {
209       PetscInt nmax = 2;
210 
211       ierr = PetscViewerDrawGetDraw(viewer, w, &draw);CHKERRQ(ierr);
212       if (Nc > 1) {ierr = PetscSNPrintf(title, sizeof(title), "%s:%s_%D Step: %D Time: %.4g", name, fname, comp, step, time);CHKERRQ(ierr);}
213       else        {ierr = PetscSNPrintf(title, sizeof(title), "%s:%s Step: %D Time: %.4g", name, fname, step, time);CHKERRQ(ierr);}
214       ierr = PetscDrawSetTitle(draw, title);CHKERRQ(ierr);
215 
216       /* TODO Get max and min only for this component */
217       ierr = PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);CHKERRQ(ierr);
218       if (!flg) {
219         ierr = VecMin(fv, NULL, &vbound[0]);CHKERRQ(ierr);
220         ierr = VecMax(fv, NULL, &vbound[1]);CHKERRQ(ierr);
221         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
222       }
223       ierr = PetscDrawGetPopup(draw, &popup);CHKERRQ(ierr);
224       ierr = PetscDrawScalePopup(popup, vbound[0], vbound[1]);CHKERRQ(ierr);
225       ierr = PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);CHKERRQ(ierr);
226 
227       ierr = VecGetArrayRead(fv, &array);CHKERRQ(ierr);
228       for (c = cStart; c < cEnd; ++c) {
229         PetscScalar *coords = NULL, *a = NULL;
230         PetscInt     numCoords, color[4] = {-1,-1,-1,-1};
231 
232         ierr = DMPlexPointLocalRead(fdm, c, array, &a);CHKERRQ(ierr);
233         if (a) {
234           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
235           color[1] = color[2] = color[3] = color[0];
236         } else {
237           PetscScalar *vals = NULL;
238           PetscInt     numVals, va;
239 
240           ierr = DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);CHKERRQ(ierr);
241           if (numVals % Nc) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %D does not divide the number of values in the closure %D", Nc, numVals);
242           switch (numVals/Nc) {
243           case 3: /* P1 Triangle */
244           case 4: /* P1 Quadrangle */
245             for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]);
246             break;
247           case 6: /* P2 Triangle */
248           case 8: /* P2 Quadrangle */
249             for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]);
250             break;
251           default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc);
252           }
253           ierr = DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);CHKERRQ(ierr);
254         }
255         ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr);
256         switch (numCoords) {
257         case 6:
258         case 12: /* Localized triangle */
259           ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2]);CHKERRQ(ierr);
260           break;
261         case 8:
262         case 16: /* Localized quadrilateral */
263           ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2]);CHKERRQ(ierr);
264           ierr = PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0]);CHKERRQ(ierr);
265           break;
266         default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
267         }
268         ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr);
269       }
270       ierr = VecRestoreArrayRead(fv, &array);CHKERRQ(ierr);
271       ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
272       ierr = PetscDrawPause(draw);CHKERRQ(ierr);
273       ierr = PetscDrawSave(draw);CHKERRQ(ierr);
274     }
275     if (Nf > 1) {
276       ierr = VecRestoreSubVector(v, fis, &fv);CHKERRQ(ierr);
277       ierr = ISDestroy(&fis);CHKERRQ(ierr);
278       ierr = DMDestroy(&fdm);CHKERRQ(ierr);
279     }
280   }
281   PetscFunctionReturn(0);
282 }
283 
284 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
285 {
286   DM                      dm;
287   Vec                     locv;
288   const char              *name;
289   PetscSection            section;
290   PetscInt                pStart, pEnd;
291   PetscInt                numFields;
292   PetscViewerVTKFieldType ft;
293   PetscErrorCode          ierr;
294 
295   PetscFunctionBegin;
296   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
297   ierr = DMCreateLocalVector(dm, &locv);CHKERRQ(ierr); /* VTK viewer requires exclusive ownership of the vector */
298   ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
299   ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
300   ierr = VecCopy(v, locv);CHKERRQ(ierr);
301   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
302   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
303   if (!numFields) {
304     ierr = DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);CHKERRQ(ierr);
305     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv);CHKERRQ(ierr);
306   } else {
307     PetscInt f;
308 
309     for (f = 0; f < numFields; f++) {
310       ierr = DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft);CHKERRQ(ierr);
311       if (ft == PETSC_VTK_INVALID) continue;
312       ierr = PetscObjectReference((PetscObject)locv);CHKERRQ(ierr);
313       ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv);CHKERRQ(ierr);
314     }
315     ierr = VecDestroy(&locv);CHKERRQ(ierr);
316   }
317   PetscFunctionReturn(0);
318 }
319 
320 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
321 {
322   DM             dm;
323   PetscBool      isvtk, ishdf5, isdraw, isglvis;
324   PetscErrorCode ierr;
325 
326   PetscFunctionBegin;
327   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
328   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
329   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);CHKERRQ(ierr);
330   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);CHKERRQ(ierr);
331   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);CHKERRQ(ierr);
332   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);CHKERRQ(ierr);
333   if (isvtk || ishdf5 || isdraw || isglvis) {
334     PetscInt    i,numFields;
335     PetscObject fe;
336     PetscBool   fem = PETSC_FALSE;
337     Vec         locv = v;
338     const char  *name;
339     PetscInt    step;
340     PetscReal   time;
341 
342     ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr);
343     for (i=0; i<numFields; i++) {
344       ierr = DMGetField(dm, i, NULL, &fe);CHKERRQ(ierr);
345       if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; }
346     }
347     if (fem) {
348       PetscObject isZero;
349 
350       ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
351       ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
352       ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
353       ierr = PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero);CHKERRQ(ierr);
354       ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero);CHKERRQ(ierr);
355       ierr = VecCopy(v, locv);CHKERRQ(ierr);
356       ierr = DMGetOutputSequenceNumber(dm, NULL, &time);CHKERRQ(ierr);
357       ierr = DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);CHKERRQ(ierr);
358     }
359     if (isvtk) {
360       ierr = VecView_Plex_Local_VTK(locv, viewer);CHKERRQ(ierr);
361     } else if (ishdf5) {
362 #if defined(PETSC_HAVE_HDF5)
363       ierr = VecView_Plex_Local_HDF5_Internal(locv, viewer);CHKERRQ(ierr);
364 #else
365       SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
366 #endif
367     } else if (isdraw) {
368       ierr = VecView_Plex_Local_Draw(locv, viewer);CHKERRQ(ierr);
369     } else if (isglvis) {
370       ierr = DMGetOutputSequenceNumber(dm, &step, NULL);CHKERRQ(ierr);
371       ierr = PetscViewerGLVisSetSnapId(viewer, step);CHKERRQ(ierr);
372       ierr = VecView_GLVis(locv, viewer);CHKERRQ(ierr);
373     }
374     if (fem) {
375       ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL);CHKERRQ(ierr);
376       ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
377     }
378   } else {
379     PetscBool isseq;
380 
381     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
382     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
383     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
384   }
385   PetscFunctionReturn(0);
386 }
387 
388 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
389 {
390   DM             dm;
391   PetscBool      isvtk, ishdf5, isdraw, isglvis, isexodusii;
392   PetscErrorCode ierr;
393 
394   PetscFunctionBegin;
395   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
396   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
397   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,      &isvtk);CHKERRQ(ierr);
398   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5);CHKERRQ(ierr);
399   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,     &isdraw);CHKERRQ(ierr);
400   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS,    &isglvis);CHKERRQ(ierr);
401   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii);CHKERRQ(ierr);
402   if (isvtk || isdraw || isglvis) {
403     Vec         locv;
404     PetscObject isZero;
405     const char *name;
406 
407     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
408     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
409     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
410     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
411     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
412     ierr = PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero);CHKERRQ(ierr);
413     ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero);CHKERRQ(ierr);
414     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
415     ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL);CHKERRQ(ierr);
416     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
417   } else if (ishdf5) {
418 #if defined(PETSC_HAVE_HDF5)
419     ierr = VecView_Plex_HDF5_Internal(v, viewer);CHKERRQ(ierr);
420 #else
421     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
422 #endif
423   } else if (isexodusii) {
424 #if defined(PETSC_HAVE_EXODUSII)
425     ierr = VecView_PlexExodusII_Internal(v, viewer);CHKERRQ(ierr);
426 #else
427     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
428 #endif
429   } else {
430     PetscBool isseq;
431 
432     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
433     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
434     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
435   }
436   PetscFunctionReturn(0);
437 }
438 
439 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
440 {
441   DM                dm;
442   MPI_Comm          comm;
443   PetscViewerFormat format;
444   Vec               v;
445   PetscBool         isvtk, ishdf5;
446   PetscErrorCode    ierr;
447 
448   PetscFunctionBegin;
449   ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr);
450   ierr = PetscObjectGetComm((PetscObject) originalv, &comm);CHKERRQ(ierr);
451   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
452   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
453   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
454   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);CHKERRQ(ierr);
455   if (format == PETSC_VIEWER_NATIVE) {
456     /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
457     /* this need a better fix */
458     if (dm->useNatural) {
459       if (dm->sfNatural) {
460         const char *vecname;
461         PetscInt    n, nroots;
462 
463         ierr = VecGetLocalSize(originalv, &n);CHKERRQ(ierr);
464         ierr = PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
465         if (n == nroots) {
466           ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr);
467           ierr = DMPlexGlobalToNaturalBegin(dm, originalv, v);CHKERRQ(ierr);
468           ierr = DMPlexGlobalToNaturalEnd(dm, originalv, v);CHKERRQ(ierr);
469           ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr);
470           ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr);
471         } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
472       } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
473     } else v = originalv;
474   } else v = originalv;
475 
476   if (ishdf5) {
477 #if defined(PETSC_HAVE_HDF5)
478     ierr = VecView_Plex_HDF5_Native_Internal(v, viewer);CHKERRQ(ierr);
479 #else
480     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
481 #endif
482   } else if (isvtk) {
483     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
484   } else {
485     PetscBool isseq;
486 
487     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
488     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
489     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
490   }
491   if (v != originalv) {ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr);}
492   PetscFunctionReturn(0);
493 }
494 
495 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
496 {
497   DM             dm;
498   PetscBool      ishdf5;
499   PetscErrorCode ierr;
500 
501   PetscFunctionBegin;
502   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
503   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
504   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
505   if (ishdf5) {
506     DM          dmBC;
507     Vec         gv;
508     const char *name;
509 
510     ierr = DMGetOutputDM(dm, &dmBC);CHKERRQ(ierr);
511     ierr = DMGetGlobalVector(dmBC, &gv);CHKERRQ(ierr);
512     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
513     ierr = PetscObjectSetName((PetscObject) gv, name);CHKERRQ(ierr);
514     ierr = VecLoad_Default(gv, viewer);CHKERRQ(ierr);
515     ierr = DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr);
516     ierr = DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr);
517     ierr = DMRestoreGlobalVector(dmBC, &gv);CHKERRQ(ierr);
518   } else {
519     ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr);
520   }
521   PetscFunctionReturn(0);
522 }
523 
524 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
525 {
526   DM             dm;
527   PetscBool      ishdf5,isexodusii;
528   PetscErrorCode ierr;
529 
530   PetscFunctionBegin;
531   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
532   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
533   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5);CHKERRQ(ierr);
534   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii);CHKERRQ(ierr);
535   if (ishdf5) {
536 #if defined(PETSC_HAVE_HDF5)
537     ierr = VecLoad_Plex_HDF5_Internal(v, viewer);CHKERRQ(ierr);
538 #else
539     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
540 #endif
541   } else if (isexodusii) {
542 #if defined(PETSC_HAVE_EXODUSII)
543     ierr = VecLoad_PlexExodusII_Internal(v, viewer);CHKERRQ(ierr);
544 #else
545     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
546 #endif
547   } else {
548     ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr);
549   }
550   PetscFunctionReturn(0);
551 }
552 
553 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
554 {
555   DM                dm;
556   PetscViewerFormat format;
557   PetscBool         ishdf5;
558   PetscErrorCode    ierr;
559 
560   PetscFunctionBegin;
561   ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr);
562   if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
563   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
564   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
565   if (format == PETSC_VIEWER_NATIVE) {
566     if (dm->useNatural) {
567       if (dm->sfNatural) {
568         if (ishdf5) {
569 #if defined(PETSC_HAVE_HDF5)
570           Vec         v;
571           const char *vecname;
572 
573           ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr);
574           ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr);
575           ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr);
576           ierr = VecLoad_Plex_HDF5_Native_Internal(v, viewer);CHKERRQ(ierr);
577           ierr = DMPlexNaturalToGlobalBegin(dm, v, originalv);CHKERRQ(ierr);
578           ierr = DMPlexNaturalToGlobalEnd(dm, v, originalv);CHKERRQ(ierr);
579           ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr);
580 #else
581           SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
582 #endif
583         } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
584       }
585     } else {
586       ierr = VecLoad_Default(originalv, viewer);CHKERRQ(ierr);
587     }
588   }
589   PetscFunctionReturn(0);
590 }
591 
592 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
593 {
594   PetscSection       coordSection;
595   Vec                coordinates;
596   DMLabel            depthLabel, celltypeLabel;
597   const char        *name[4];
598   const PetscScalar *a;
599   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
600   PetscErrorCode     ierr;
601 
602   PetscFunctionBegin;
603   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
604   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
605   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
606   ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr);
607   ierr = DMPlexGetCellTypeLabel(dm, &celltypeLabel);CHKERRQ(ierr);
608   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
609   ierr = PetscSectionGetChart(coordSection, &pStart, &pEnd);CHKERRQ(ierr);
610   ierr = VecGetArrayRead(coordinates, &a);CHKERRQ(ierr);
611   name[0]     = "vertex";
612   name[1]     = "edge";
613   name[dim-1] = "face";
614   name[dim]   = "cell";
615   for (c = cStart; c < cEnd; ++c) {
616     PetscInt *closure = NULL;
617     PetscInt  closureSize, cl, ct;
618 
619     ierr = DMLabelGetValue(celltypeLabel, c, &ct);CHKERRQ(ierr);
620     ierr = PetscViewerASCIIPrintf(viewer, "Geometry for cell %D polytope type %s:\n", c, DMPolytopeTypes[ct]);CHKERRQ(ierr);
621     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
622     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
623     for (cl = 0; cl < closureSize*2; cl += 2) {
624       PetscInt point = closure[cl], depth, dof, off, d, p;
625 
626       if ((point < pStart) || (point >= pEnd)) continue;
627       ierr = PetscSectionGetDof(coordSection, point, &dof);CHKERRQ(ierr);
628       if (!dof) continue;
629       ierr = DMLabelGetValue(depthLabel, point, &depth);CHKERRQ(ierr);
630       ierr = PetscSectionGetOffset(coordSection, point, &off);CHKERRQ(ierr);
631       ierr = PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);CHKERRQ(ierr);
632       for (p = 0; p < dof/dim; ++p) {
633         ierr = PetscViewerASCIIPrintf(viewer, " (");CHKERRQ(ierr);
634         for (d = 0; d < dim; ++d) {
635           if (d > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
636           ierr = PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]));CHKERRQ(ierr);
637         }
638         ierr = PetscViewerASCIIPrintf(viewer, ")");CHKERRQ(ierr);
639       }
640       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
641     }
642     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
643     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
644   }
645   ierr = VecRestoreArrayRead(coordinates, &a);CHKERRQ(ierr);
646   PetscFunctionReturn(0);
647 }
648 
649 typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem;
650 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL};
651 
652 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[])
653 {
654   PetscInt       i;
655   PetscErrorCode ierr;
656 
657   PetscFunctionBegin;
658   if (dim > 3) {
659     for (i = 0; i < dim; ++i) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i]));CHKERRQ(ierr);}
660   } else {
661     PetscReal coords[3], trcoords[3];
662 
663     for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]);
664     switch (cs) {
665       case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break;
666       case CS_POLAR:
667         if (dim != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %D", dim);
668         trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
669         trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
670         break;
671       case CS_CYLINDRICAL:
672         if (dim != 3) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %D", dim);
673         trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
674         trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
675         trcoords[2] = coords[2];
676         break;
677       case CS_SPHERICAL:
678         if (dim != 3) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %D", dim);
679         trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2]));
680         trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]);
681         trcoords[2] = PetscAtan2Real(coords[1], coords[0]);
682         break;
683     }
684     for (i = 0; i < dim; ++i) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i]);CHKERRQ(ierr);}
685   }
686   PetscFunctionReturn(0);
687 }
688 
689 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
690 {
691   DM_Plex          *mesh = (DM_Plex*) dm->data;
692   DM                cdm;
693   PetscSection      coordSection;
694   Vec               coordinates;
695   PetscViewerFormat format;
696   PetscErrorCode    ierr;
697 
698   PetscFunctionBegin;
699   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
700   ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr);
701   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
702   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
703   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
704     const char *name;
705     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
706     PetscInt    pStart, pEnd, p, numLabels, l;
707     PetscMPIInt rank, size;
708 
709     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRMPI(ierr);
710     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRMPI(ierr);
711     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
712     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
713     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
714     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
715     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
716     if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
717     else      {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
718     if (cellHeight) {ierr = PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);CHKERRQ(ierr);}
719     ierr = PetscViewerASCIIPrintf(viewer, "Supports:\n", name);CHKERRQ(ierr);
720     ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
721     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %D\n", rank, maxSupportSize);CHKERRQ(ierr);
722     for (p = pStart; p < pEnd; ++p) {
723       PetscInt dof, off, s;
724 
725       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
726       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
727       for (s = off; s < off+dof; ++s) {
728         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
729       }
730     }
731     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
732     ierr = PetscViewerASCIIPrintf(viewer, "Cones:\n", name);CHKERRQ(ierr);
733     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %D\n", rank, maxConeSize);CHKERRQ(ierr);
734     for (p = pStart; p < pEnd; ++p) {
735       PetscInt dof, off, c;
736 
737       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
738       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
739       for (c = off; c < off+dof; ++c) {
740         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
741       }
742     }
743     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
744     ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
745     if (coordSection && coordinates) {
746       CoordSystem        cs = CS_CARTESIAN;
747       const PetscScalar *array;
748       PetscInt           Nf, Nc, pStart, pEnd, p;
749       PetscMPIInt        rank;
750       const char        *name;
751 
752       ierr = PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL);CHKERRQ(ierr);
753       ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank);CHKERRMPI(ierr);
754       ierr = PetscSectionGetNumFields(coordSection, &Nf);CHKERRQ(ierr);
755       if (Nf != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %D", Nf);
756       ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
757       ierr = PetscSectionGetChart(coordSection, &pStart, &pEnd);CHKERRQ(ierr);
758       ierr = PetscObjectGetName((PetscObject) coordinates, &name);CHKERRQ(ierr);
759       ierr = PetscViewerASCIIPrintf(viewer, "%s with %D fields\n", name, Nf);CHKERRQ(ierr);
760       ierr = PetscViewerASCIIPrintf(viewer, "  field 0 with %D components\n", Nc);CHKERRQ(ierr);
761       if (cs != CS_CARTESIAN) {ierr = PetscViewerASCIIPrintf(viewer, "  output coordinate system: %s\n", CoordSystems[cs]);CHKERRQ(ierr);}
762 
763       ierr = VecGetArrayRead(coordinates, &array);CHKERRQ(ierr);
764       ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
765       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank);CHKERRQ(ierr);
766       for (p = pStart; p < pEnd; ++p) {
767         PetscInt dof, off;
768 
769         ierr = PetscSectionGetDof(coordSection, p, &dof);CHKERRQ(ierr);
770         ierr = PetscSectionGetOffset(coordSection, p, &off);CHKERRQ(ierr);
771         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "  (%4D) dim %2D offset %3D", p, dof, off);CHKERRQ(ierr);
772         ierr = DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off]);CHKERRQ(ierr);
773         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\n");CHKERRQ(ierr);
774       }
775       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
776       ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
777       ierr = VecRestoreArrayRead(coordinates, &array);CHKERRQ(ierr);
778     }
779     ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
780     if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);}
781     for (l = 0; l < numLabels; ++l) {
782       DMLabel     label;
783       PetscBool   isdepth;
784       const char *name;
785 
786       ierr = DMGetLabelName(dm, l, &name);CHKERRQ(ierr);
787       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
788       if (isdepth) continue;
789       ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
790       ierr = DMLabelView(label, viewer);CHKERRQ(ierr);
791     }
792     if (size > 1) {
793       PetscSF sf;
794 
795       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
796       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
797     }
798     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
799   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
800     const char  *name, *color;
801     const char  *defcolors[3]  = {"gray", "orange", "green"};
802     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
803     char         lname[PETSC_MAX_PATH_LEN];
804     PetscReal    scale         = 2.0;
805     PetscReal    tikzscale     = 1.0;
806     PetscBool    useNumbers    = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE;
807     double       tcoords[3];
808     PetscScalar *coords;
809     PetscInt     numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n;
810     PetscMPIInt  rank, size;
811     char         **names, **colors, **lcolors;
812     PetscBool    flg, lflg;
813     PetscBT      wp = NULL;
814     PetscInt     pEnd, pStart;
815 
816     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
817     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
818     ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
819     numLabels  = PetscMax(numLabels, 10);
820     numColors  = 10;
821     numLColors = 10;
822     ierr = PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);CHKERRQ(ierr);
823     ierr = PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);CHKERRQ(ierr);
824     ierr = PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL);CHKERRQ(ierr);
825     ierr = PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);CHKERRQ(ierr);
826     for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers;
827     for (d = 0; d < 4; ++d) drawColors[d]  = PETSC_TRUE;
828     n = 4;
829     ierr = PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg);CHKERRQ(ierr);
830     if (flg && n != dim+1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %D != %D dim+1", n, dim+1);
831     ierr = PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg);CHKERRQ(ierr);
832     if (flg && n != dim+1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %D != %D dim+1", n, dim+1);
833     ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);CHKERRQ(ierr);
834     if (!useLabels) numLabels = 0;
835     ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);CHKERRQ(ierr);
836     if (!useColors) {
837       numColors = 3;
838       for (c = 0; c < numColors; ++c) {ierr = PetscStrallocpy(defcolors[c], &colors[c]);CHKERRQ(ierr);}
839     }
840     ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);CHKERRQ(ierr);
841     if (!useColors) {
842       numLColors = 4;
843       for (c = 0; c < numLColors; ++c) {ierr = PetscStrallocpy(deflcolors[c], &lcolors[c]);CHKERRQ(ierr);}
844     }
845     ierr = PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg);CHKERRQ(ierr);
846     plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3);
847     ierr = PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg);CHKERRQ(ierr);
848     if (flg && plotEdges && depth < dim) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated");
849     if (depth < dim) plotEdges = PETSC_FALSE;
850     ierr = PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL);CHKERRQ(ierr);
851 
852     /* filter points with labelvalue != labeldefaultvalue */
853     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
854     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
855     ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
856     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
857     if (lflg) {
858       DMLabel lbl;
859 
860       ierr = DMGetLabel(dm, lname, &lbl);CHKERRQ(ierr);
861       if (lbl) {
862         PetscInt val, defval;
863 
864         ierr = DMLabelGetDefaultValue(lbl, &defval);CHKERRQ(ierr);
865         ierr = PetscBTCreate(pEnd-pStart, &wp);CHKERRQ(ierr);
866         for (c = pStart;  c < pEnd; c++) {
867           PetscInt *closure = NULL;
868           PetscInt  closureSize;
869 
870           ierr = DMLabelGetValue(lbl, c, &val);CHKERRQ(ierr);
871           if (val == defval) continue;
872 
873           ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
874           for (p = 0; p < closureSize*2; p += 2) {
875             ierr = PetscBTSet(wp, closure[p] - pStart);CHKERRQ(ierr);
876           }
877           ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
878         }
879       }
880     }
881 
882     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRMPI(ierr);
883     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRMPI(ierr);
884     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
885     ierr = PetscViewerASCIIPrintf(viewer, "\
886 \\documentclass[tikz]{standalone}\n\n\
887 \\usepackage{pgflibraryshapes}\n\
888 \\usetikzlibrary{backgrounds}\n\
889 \\usetikzlibrary{arrows}\n\
890 \\begin{document}\n");CHKERRQ(ierr);
891     if (size > 1) {
892       ierr = PetscViewerASCIIPrintf(viewer, "%s for process ", name);CHKERRQ(ierr);
893       for (p = 0; p < size; ++p) {
894         if (p > 0 && p == size-1) {
895           ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
896         } else if (p > 0) {
897           ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
898         }
899         ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
900       }
901       ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n");CHKERRQ(ierr);
902     }
903     if (drawHasse) {
904       PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart));
905 
906       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%D}\n", vStart);CHKERRQ(ierr);
907       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%D}\n", vEnd-1);CHKERRQ(ierr);
908       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%D}\n", vEnd-vStart);CHKERRQ(ierr);
909       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.);CHKERRQ(ierr);
910       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%D}\n", eStart);CHKERRQ(ierr);
911       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%D}\n", eEnd-1);CHKERRQ(ierr);
912       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.);CHKERRQ(ierr);
913       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%D}\n", eEnd-eStart);CHKERRQ(ierr);
914       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%D}\n", cStart);CHKERRQ(ierr);
915       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%D}\n", cEnd-1);CHKERRQ(ierr);
916       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%D}\n", cEnd-cStart);CHKERRQ(ierr);
917       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.);CHKERRQ(ierr);
918     }
919     ierr = PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale);CHKERRQ(ierr);
920 
921     /* Plot vertices */
922     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
923     ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
924     for (v = vStart; v < vEnd; ++v) {
925       PetscInt  off, dof, d;
926       PetscBool isLabeled = PETSC_FALSE;
927 
928       if (wp && !PetscBTLookup(wp,v - pStart)) continue;
929       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
930       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
931       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");CHKERRQ(ierr);
932       if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
933       for (d = 0; d < dof; ++d) {
934         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
935         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
936       }
937       /* Rotate coordinates since PGF makes z point out of the page instead of up */
938       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
939       for (d = 0; d < dof; ++d) {
940         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
941         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d]);CHKERRQ(ierr);
942       }
943       if (drawHasse) color = colors[0%numColors];
944       else           color = colors[rank%numColors];
945       for (l = 0; l < numLabels; ++l) {
946         PetscInt val;
947         ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr);
948         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
949       }
950       if (drawNumbers[0]) {
951         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);CHKERRQ(ierr);
952       } else if (drawColors[0]) {
953         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);CHKERRQ(ierr);
954       } else {
955         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [] {};\n", v, rank);CHKERRQ(ierr);
956       }
957     }
958     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
959     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
960     /* Plot edges */
961     if (plotEdges) {
962       ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
963       ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
964       for (e = eStart; e < eEnd; ++e) {
965         const PetscInt *cone;
966         PetscInt        coneSize, offA, offB, dof, d;
967 
968         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
969         ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
970         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
971         ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
972         ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
973         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
974         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
975         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
976         for (d = 0; d < dof; ++d) {
977           tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
978           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
979         }
980         /* Rotate coordinates since PGF makes z point out of the page instead of up */
981         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
982         for (d = 0; d < dof; ++d) {
983           if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
984           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);CHKERRQ(ierr);
985         }
986         if (drawHasse) color = colors[1%numColors];
987         else           color = colors[rank%numColors];
988         for (l = 0; l < numLabels; ++l) {
989           PetscInt val;
990           ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr);
991           if (val >= 0) {color = lcolors[l%numLColors]; break;}
992         }
993         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);CHKERRQ(ierr);
994       }
995       ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
996       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
997       ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
998     }
999     /* Plot cells */
1000     if (dim == 3 || !drawNumbers[1]) {
1001       for (e = eStart; e < eEnd; ++e) {
1002         const PetscInt *cone;
1003 
1004         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
1005         color = colors[rank%numColors];
1006         for (l = 0; l < numLabels; ++l) {
1007           PetscInt val;
1008           ierr = DMGetLabelValue(dm, names[l], e, &val);CHKERRQ(ierr);
1009           if (val >= 0) {color = lcolors[l%numLColors]; break;}
1010         }
1011         ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
1012         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);CHKERRQ(ierr);
1013       }
1014     } else {
1015        DMPolytopeType ct;
1016 
1017       /* Drawing a 2D polygon */
1018       for (c = cStart; c < cEnd; ++c) {
1019         if (wp && !PetscBTLookup(wp, c - pStart)) continue;
1020         ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
1021         if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR ||
1022             ct == DM_POLYTOPE_TRI_PRISM_TENSOR ||
1023             ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
1024           const PetscInt *cone;
1025           PetscInt        coneSize, e;
1026 
1027           ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1028           ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
1029           for (e = 0; e < coneSize; ++e) {
1030             const PetscInt *econe;
1031 
1032             ierr = DMPlexGetCone(dm, cone[e], &econe);CHKERRQ(ierr);
1033             ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d) -- (%D_%d);\n", colors[rank%numColors], econe[0], rank, cone[e], rank, econe[1], rank);CHKERRQ(ierr);
1034           }
1035         } else {
1036           PetscInt *closure = NULL;
1037           PetscInt  closureSize, Nv = 0, v;
1038 
1039           ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1040           for (p = 0; p < closureSize*2; p += 2) {
1041             const PetscInt point = closure[p];
1042 
1043             if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point;
1044           }
1045           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
1046           for (v = 0; v <= Nv; ++v) {
1047             const PetscInt vertex = closure[v%Nv];
1048 
1049             if (v > 0) {
1050               if (plotEdges) {
1051                 const PetscInt *edge;
1052                 PetscInt        endpoints[2], ne;
1053 
1054                 endpoints[0] = closure[v-1]; endpoints[1] = vertex;
1055                 ierr = DMPlexGetJoin(dm, 2, endpoints, &ne, &edge);CHKERRQ(ierr);
1056                 if (ne != 1) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %D, %D", endpoints[0], endpoints[1]);
1057                 ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d) -- ", edge[0], rank);CHKERRQ(ierr);
1058                 ierr = DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge);CHKERRQ(ierr);
1059               } else {
1060                 ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);
1061               }
1062             }
1063             ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", vertex, rank);CHKERRQ(ierr);
1064           }
1065           ierr = PetscViewerASCIISynchronizedPrintf(viewer, ";\n");CHKERRQ(ierr);
1066           ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1067         }
1068       }
1069     }
1070     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
1071     for (c = cStart; c < cEnd; ++c) {
1072       double    ccoords[3] = {0.0, 0.0, 0.0};
1073       PetscBool isLabeled  = PETSC_FALSE;
1074       PetscInt *closure    = NULL;
1075       PetscInt  closureSize, dof, d, n = 0;
1076 
1077       if (wp && !PetscBTLookup(wp,c - pStart)) continue;
1078       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1079       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");CHKERRQ(ierr);
1080       for (p = 0; p < closureSize*2; p += 2) {
1081         const PetscInt point = closure[p];
1082         PetscInt       off;
1083 
1084         if ((point < vStart) || (point >= vEnd)) continue;
1085         ierr = PetscSectionGetDof(coordSection, point, &dof);CHKERRQ(ierr);
1086         ierr = PetscSectionGetOffset(coordSection, point, &off);CHKERRQ(ierr);
1087         for (d = 0; d < dof; ++d) {
1088           tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
1089           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1090         }
1091         /* Rotate coordinates since PGF makes z point out of the page instead of up */
1092         if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
1093         for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];}
1094         ++n;
1095       }
1096       for (d = 0; d < dof; ++d) {ccoords[d] /= n;}
1097       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1098       for (d = 0; d < dof; ++d) {
1099         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
1100         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d]);CHKERRQ(ierr);
1101       }
1102       if (drawHasse) color = colors[depth%numColors];
1103       else           color = colors[rank%numColors];
1104       for (l = 0; l < numLabels; ++l) {
1105         PetscInt val;
1106         ierr = DMGetLabelValue(dm, names[l], c, &val);CHKERRQ(ierr);
1107         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
1108       }
1109       if (drawNumbers[dim]) {
1110         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", c, rank, color, c);CHKERRQ(ierr);
1111       } else if (drawColors[dim]) {
1112         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color);CHKERRQ(ierr);
1113       } else {
1114         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [] {};\n", c, rank);CHKERRQ(ierr);
1115       }
1116     }
1117     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
1118     if (drawHasse) {
1119       color = colors[depth%numColors];
1120       ierr = PetscViewerASCIIPrintf(viewer, "%% Cells\n");CHKERRQ(ierr);
1121       ierr = PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n");CHKERRQ(ierr);
1122       ierr = PetscViewerASCIIPrintf(viewer, "{\n");CHKERRQ(ierr);
1123       ierr = PetscViewerASCIIPrintf(viewer, "  \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color);CHKERRQ(ierr);
1124       ierr = PetscViewerASCIIPrintf(viewer, "}\n");CHKERRQ(ierr);
1125 
1126       color = colors[1%numColors];
1127       ierr = PetscViewerASCIIPrintf(viewer, "%% Edges\n");CHKERRQ(ierr);
1128       ierr = PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n");CHKERRQ(ierr);
1129       ierr = PetscViewerASCIIPrintf(viewer, "{\n");CHKERRQ(ierr);
1130       ierr = PetscViewerASCIIPrintf(viewer, "  \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color);CHKERRQ(ierr);
1131       ierr = PetscViewerASCIIPrintf(viewer, "}\n");CHKERRQ(ierr);
1132 
1133       color = colors[0%numColors];
1134       ierr = PetscViewerASCIIPrintf(viewer, "%% Vertices\n");CHKERRQ(ierr);
1135       ierr = PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n");CHKERRQ(ierr);
1136       ierr = PetscViewerASCIIPrintf(viewer, "{\n");CHKERRQ(ierr);
1137       ierr = PetscViewerASCIIPrintf(viewer, "  \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color);CHKERRQ(ierr);
1138       ierr = PetscViewerASCIIPrintf(viewer, "}\n");CHKERRQ(ierr);
1139 
1140       for (p = pStart; p < pEnd; ++p) {
1141         const PetscInt *cone;
1142         PetscInt        coneSize, cp;
1143 
1144         ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1145         ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1146         for (cp = 0; cp < coneSize; ++cp) {
1147           ierr = PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%D_%d) -- (%D_%d);\n", cone[cp], rank, p, rank);CHKERRQ(ierr);
1148         }
1149       }
1150     }
1151     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
1152     ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
1153     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");CHKERRQ(ierr);
1154     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
1155     for (l = 0; l < numLabels;  ++l) {ierr = PetscFree(names[l]);CHKERRQ(ierr);}
1156     for (c = 0; c < numColors;  ++c) {ierr = PetscFree(colors[c]);CHKERRQ(ierr);}
1157     for (c = 0; c < numLColors; ++c) {ierr = PetscFree(lcolors[c]);CHKERRQ(ierr);}
1158     ierr = PetscFree3(names, colors, lcolors);CHKERRQ(ierr);
1159     ierr = PetscBTDestroy(&wp);CHKERRQ(ierr);
1160   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
1161     Vec                    cown,acown;
1162     VecScatter             sct;
1163     ISLocalToGlobalMapping g2l;
1164     IS                     gid,acis;
1165     MPI_Comm               comm,ncomm = MPI_COMM_NULL;
1166     MPI_Group              ggroup,ngroup;
1167     PetscScalar            *array,nid;
1168     const PetscInt         *idxs;
1169     PetscInt               *idxs2,*start,*adjacency,*work;
1170     PetscInt64             lm[3],gm[3];
1171     PetscInt               i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight;
1172     PetscMPIInt            d1,d2,rank;
1173 
1174     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1175     ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
1176 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1177     ierr = MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm);CHKERRMPI(ierr);
1178 #endif
1179     if (ncomm != MPI_COMM_NULL) {
1180       ierr = MPI_Comm_group(comm,&ggroup);CHKERRMPI(ierr);
1181       ierr = MPI_Comm_group(ncomm,&ngroup);CHKERRMPI(ierr);
1182       d1   = 0;
1183       ierr = MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2);CHKERRMPI(ierr);
1184       nid  = d2;
1185       ierr = MPI_Group_free(&ggroup);CHKERRMPI(ierr);
1186       ierr = MPI_Group_free(&ngroup);CHKERRMPI(ierr);
1187       ierr = MPI_Comm_free(&ncomm);CHKERRMPI(ierr);
1188     } else nid = 0.0;
1189 
1190     /* Get connectivity */
1191     ierr = DMPlexGetVTKCellHeight(dm,&cellHeight);CHKERRQ(ierr);
1192     ierr = DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid);CHKERRQ(ierr);
1193 
1194     /* filter overlapped local cells */
1195     ierr = DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd);CHKERRQ(ierr);
1196     ierr = ISGetIndices(gid,&idxs);CHKERRQ(ierr);
1197     ierr = ISGetLocalSize(gid,&cum);CHKERRQ(ierr);
1198     ierr = PetscMalloc1(cum,&idxs2);CHKERRQ(ierr);
1199     for (c = cStart, cum = 0; c < cEnd; c++) {
1200       if (idxs[c-cStart] < 0) continue;
1201       idxs2[cum++] = idxs[c-cStart];
1202     }
1203     ierr = ISRestoreIndices(gid,&idxs);CHKERRQ(ierr);
1204     if (numVertices != cum) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %D != %D",numVertices,cum);
1205     ierr = ISDestroy(&gid);CHKERRQ(ierr);
1206     ierr = ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid);CHKERRQ(ierr);
1207 
1208     /* support for node-aware cell locality */
1209     ierr = ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis);CHKERRQ(ierr);
1210     ierr = VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown);CHKERRQ(ierr);
1211     ierr = VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown);CHKERRQ(ierr);
1212     ierr = VecGetArray(cown,&array);CHKERRQ(ierr);
1213     for (c = 0; c < numVertices; c++) array[c] = nid;
1214     ierr = VecRestoreArray(cown,&array);CHKERRQ(ierr);
1215     ierr = VecScatterCreate(cown,acis,acown,NULL,&sct);CHKERRQ(ierr);
1216     ierr = VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1217     ierr = VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1218     ierr = ISDestroy(&acis);CHKERRQ(ierr);
1219     ierr = VecScatterDestroy(&sct);CHKERRQ(ierr);
1220     ierr = VecDestroy(&cown);CHKERRQ(ierr);
1221 
1222     /* compute edgeCut */
1223     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]);
1224     ierr = PetscMalloc1(cum,&work);CHKERRQ(ierr);
1225     ierr = ISLocalToGlobalMappingCreateIS(gid,&g2l);CHKERRQ(ierr);
1226     ierr = ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH);CHKERRQ(ierr);
1227     ierr = ISDestroy(&gid);CHKERRQ(ierr);
1228     ierr = VecGetArray(acown,&array);CHKERRQ(ierr);
1229     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
1230       PetscInt totl;
1231 
1232       totl = start[c+1]-start[c];
1233       ierr = ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work);CHKERRQ(ierr);
1234       for (i = 0; i < totl; i++) {
1235         if (work[i] < 0) {
1236           ect  += 1;
1237           ectn += (array[i + start[c]] != nid) ? 0 : 1;
1238         }
1239       }
1240     }
1241     ierr  = PetscFree(work);CHKERRQ(ierr);
1242     ierr  = VecRestoreArray(acown,&array);CHKERRQ(ierr);
1243     lm[0] = numVertices > 0 ?  numVertices : PETSC_MAX_INT;
1244     lm[1] = -numVertices;
1245     ierr  = MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm);CHKERRMPI(ierr);
1246     ierr  = PetscViewerASCIIPrintf(viewer,"  Cell balance: %.2f (max %D, min %D",-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0]);CHKERRQ(ierr);
1247     lm[0] = ect; /* edgeCut */
1248     lm[1] = ectn; /* node-aware edgeCut */
1249     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
1250     ierr  = MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm);CHKERRMPI(ierr);
1251     ierr  = PetscViewerASCIIPrintf(viewer,", empty %D)\n",(PetscInt)gm[2]);CHKERRQ(ierr);
1252 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1253     ierr  = PetscViewerASCIIPrintf(viewer,"  Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.);CHKERRQ(ierr);
1254 #else
1255     ierr  = PetscViewerASCIIPrintf(viewer,"  Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0);CHKERRQ(ierr);
1256 #endif
1257     ierr  = ISLocalToGlobalMappingDestroy(&g2l);CHKERRQ(ierr);
1258     ierr  = PetscFree(start);CHKERRQ(ierr);
1259     ierr  = PetscFree(adjacency);CHKERRQ(ierr);
1260     ierr  = VecDestroy(&acown);CHKERRQ(ierr);
1261   } else {
1262     const char    *name;
1263     PetscInt      *sizes, *hybsizes, *ghostsizes;
1264     PetscInt       locDepth, depth, cellHeight, dim, d;
1265     PetscInt       pStart, pEnd, p, gcStart, gcEnd, gcNum;
1266     PetscInt       numLabels, l;
1267     DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN;
1268     MPI_Comm       comm;
1269     PetscMPIInt    size, rank;
1270 
1271     ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
1272     ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr);
1273     ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
1274     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1275     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
1276     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
1277     if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
1278     else      {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
1279     if (cellHeight) {ierr = PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);CHKERRQ(ierr);}
1280     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
1281     ierr = MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRMPI(ierr);
1282     ierr = DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd);CHKERRQ(ierr);
1283     gcNum = gcEnd - gcStart;
1284     ierr = PetscCalloc3(size,&sizes,size,&hybsizes,size,&ghostsizes);CHKERRQ(ierr);
1285     for (d = 0; d <= depth; d++) {
1286       PetscInt Nc[2] = {0, 0}, ict;
1287 
1288       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
1289       if (pStart < pEnd) {ierr = DMPlexGetCellType(dm, pStart, &ct0);CHKERRQ(ierr);}
1290       ict  = ct0;
1291       ierr = MPI_Bcast(&ict, 1, MPIU_INT, 0, comm);CHKERRMPI(ierr);
1292       ct0  = (DMPolytopeType) ict;
1293       for (p = pStart; p < pEnd; ++p) {
1294         DMPolytopeType ct;
1295 
1296         ierr = DMPlexGetCellType(dm, p, &ct);CHKERRQ(ierr);
1297         if (ct == ct0) ++Nc[0];
1298         else           ++Nc[1];
1299       }
1300       ierr = MPI_Gather(&Nc[0], 1, MPIU_INT, sizes,    1, MPIU_INT, 0, comm);CHKERRMPI(ierr);
1301       ierr = MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRMPI(ierr);
1302       if (d == depth) {ierr = MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm);CHKERRMPI(ierr);}
1303       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", (depth == 1) && d ? dim : d);CHKERRQ(ierr);
1304       for (p = 0; p < size; ++p) {
1305         if (rank == 0) {
1306           ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]+hybsizes[p]);CHKERRQ(ierr);
1307           if (hybsizes[p]   > 0) {ierr = PetscViewerASCIIPrintf(viewer, " (%D)", hybsizes[p]);CHKERRQ(ierr);}
1308           if (ghostsizes[p] > 0) {ierr = PetscViewerASCIIPrintf(viewer, " [%D]", ghostsizes[p]);CHKERRQ(ierr);}
1309         }
1310       }
1311       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
1312     }
1313     ierr = PetscFree3(sizes,hybsizes,ghostsizes);CHKERRQ(ierr);
1314     {
1315       const PetscReal      *maxCell;
1316       const PetscReal      *L;
1317       const DMBoundaryType *bd;
1318       PetscBool             per, localized;
1319 
1320       ierr = DMGetPeriodicity(dm, &per, &maxCell, &L, &bd);CHKERRQ(ierr);
1321       ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
1322       if (per) {
1323         ierr = PetscViewerASCIIPrintf(viewer, "Periodic mesh (");CHKERRQ(ierr);
1324         ierr = PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);CHKERRQ(ierr);
1325         for (d = 0; d < dim; ++d) {
1326           if (bd && d > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
1327           if (bd)    {ierr = PetscViewerASCIIPrintf(viewer, "%s", DMBoundaryTypes[bd[d]]);CHKERRQ(ierr);}
1328         }
1329         ierr = PetscViewerASCIIPrintf(viewer, ") coordinates %s\n", localized ? "localized" : "not localized");CHKERRQ(ierr);
1330         ierr = PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);CHKERRQ(ierr);
1331       }
1332     }
1333     ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
1334     if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);}
1335     for (l = 0; l < numLabels; ++l) {
1336       DMLabel         label;
1337       const char     *name;
1338       IS              valueIS;
1339       const PetscInt *values;
1340       PetscInt        numValues, v;
1341 
1342       ierr = DMGetLabelName(dm, l, &name);CHKERRQ(ierr);
1343       ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
1344       ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
1345       ierr = PetscViewerASCIIPrintf(viewer, "  %s: %D strata with value/size (", name, numValues);CHKERRQ(ierr);
1346       ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
1347       ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
1348       ierr = PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);CHKERRQ(ierr);
1349       for (v = 0; v < numValues; ++v) {
1350         PetscInt size;
1351 
1352         ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr);
1353         if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
1354         ierr = PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);CHKERRQ(ierr);
1355       }
1356       ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr);
1357       ierr = PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);CHKERRQ(ierr);
1358       ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
1359       ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
1360     }
1361     {
1362       char    **labelNames;
1363       PetscInt  Nl = numLabels;
1364       PetscBool flg;
1365 
1366       ierr = PetscMalloc1(Nl, &labelNames);CHKERRQ(ierr);
1367       ierr = PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg);CHKERRQ(ierr);
1368       for (l = 0; l < Nl; ++l) {
1369         DMLabel label;
1370 
1371         ierr = DMHasLabel(dm, labelNames[l], &flg);CHKERRQ(ierr);
1372         if (flg) {
1373           ierr = DMGetLabel(dm, labelNames[l], &label);CHKERRQ(ierr);
1374           ierr = DMLabelView(label, viewer);CHKERRQ(ierr);
1375         }
1376         ierr = PetscFree(labelNames[l]);CHKERRQ(ierr);
1377       }
1378       ierr = PetscFree(labelNames);CHKERRQ(ierr);
1379     }
1380     /* If no fields are specified, people do not want to see adjacency */
1381     if (dm->Nf) {
1382       PetscInt f;
1383 
1384       for (f = 0; f < dm->Nf; ++f) {
1385         const char *name;
1386 
1387         ierr = PetscObjectGetName(dm->fields[f].disc, &name);CHKERRQ(ierr);
1388         if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Field %s:\n", name);CHKERRQ(ierr);}
1389         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1390         if (dm->fields[f].label) {ierr = DMLabelView(dm->fields[f].label, viewer);CHKERRQ(ierr);}
1391         if (dm->fields[f].adjacency[0]) {
1392           if (dm->fields[f].adjacency[1]) {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n");CHKERRQ(ierr);}
1393           else                            {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FVM\n");CHKERRQ(ierr);}
1394         } else {
1395           if (dm->fields[f].adjacency[1]) {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FEM\n");CHKERRQ(ierr);}
1396           else                            {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n");CHKERRQ(ierr);}
1397         }
1398         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1399       }
1400     }
1401     ierr = DMGetCoarseDM(dm, &cdm);CHKERRQ(ierr);
1402     if (cdm) {
1403       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1404       ierr = DMPlexView_Ascii(cdm, viewer);CHKERRQ(ierr);
1405       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1406     }
1407   }
1408   PetscFunctionReturn(0);
1409 }
1410 
1411 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[])
1412 {
1413   DMPolytopeType ct;
1414   PetscMPIInt    rank;
1415   PetscErrorCode ierr;
1416 
1417   PetscFunctionBegin;
1418   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRMPI(ierr);
1419   ierr = DMPlexGetCellType(dm, cell, &ct);CHKERRQ(ierr);
1420   switch (ct) {
1421   case DM_POLYTOPE_TRIANGLE:
1422     ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1423                              PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1424                              PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1425                              PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr);
1426     ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1427     ierr = PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1428     ierr = PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1429     break;
1430   case DM_POLYTOPE_QUADRILATERAL:
1431     ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1432                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1433                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1434                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr);
1435     ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]),
1436                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1437                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1438                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr);
1439     ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1440     ierr = PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1441     ierr = PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1442     ierr = PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1443     break;
1444   default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1445   }
1446   PetscFunctionReturn(0);
1447 }
1448 
1449 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1450 {
1451   DMPolytopeType ct;
1452   PetscReal      centroid[2] = {0., 0.};
1453   PetscMPIInt    rank;
1454   PetscInt       fillColor, v, e, d;
1455   PetscErrorCode ierr;
1456 
1457   PetscFunctionBegin;
1458   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRMPI(ierr);
1459   ierr = DMPlexGetCellType(dm, cell, &ct);CHKERRQ(ierr);
1460   fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2;
1461   switch (ct) {
1462   case DM_POLYTOPE_TRIANGLE:
1463     {
1464       PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.};
1465 
1466       for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;}
1467       for (e = 0; e < 3; ++e) {
1468         refCoords[0] = refVertices[e*2+0];
1469         refCoords[1] = refVertices[e*2+1];
1470         for (d = 1; d <= edgeDiv; ++d) {
1471           refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv;
1472           refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv;
1473         }
1474         ierr = DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords);CHKERRQ(ierr);
1475         for (d = 0; d < edgeDiv; ++d) {
1476           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);
1477           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);
1478         }
1479       }
1480     }
1481     break;
1482   default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1483   }
1484   PetscFunctionReturn(0);
1485 }
1486 
1487 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1488 {
1489   PetscDraw          draw;
1490   DM                 cdm;
1491   PetscSection       coordSection;
1492   Vec                coordinates;
1493   const PetscScalar *coords;
1494   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
1495   PetscReal         *refCoords, *edgeCoords;
1496   PetscBool          isnull, drawAffine = PETSC_TRUE;
1497   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4;
1498   PetscErrorCode     ierr;
1499 
1500   PetscFunctionBegin;
1501   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
1502   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
1503   ierr = PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL);CHKERRQ(ierr);
1504   if (!drawAffine) {ierr = PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords);CHKERRQ(ierr);}
1505   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
1506   ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr);
1507   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
1508   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1509   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1510 
1511   ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr);
1512   ierr = PetscDrawIsNull(draw, &isnull);CHKERRQ(ierr);
1513   if (isnull) PetscFunctionReturn(0);
1514   ierr = PetscDrawSetTitle(draw, "Mesh");CHKERRQ(ierr);
1515 
1516   ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr);
1517   ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr);
1518   for (c = 0; c < N; c += dim) {
1519     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
1520     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1521   }
1522   ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr);
1523   ierr = MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
1524   ierr = MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
1525   ierr = PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);CHKERRQ(ierr);
1526   ierr = PetscDrawClear(draw);CHKERRQ(ierr);
1527 
1528   for (c = cStart; c < cEnd; ++c) {
1529     PetscScalar *coords = NULL;
1530     PetscInt     numCoords;
1531 
1532     ierr = DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords);CHKERRQ(ierr);
1533     if (drawAffine) {
1534       ierr = DMPlexDrawCell(dm, draw, c, coords);CHKERRQ(ierr);
1535     } else {
1536       ierr = DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords);CHKERRQ(ierr);
1537     }
1538     ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr);
1539   }
1540   if (!drawAffine) {ierr = PetscFree2(refCoords, edgeCoords);CHKERRQ(ierr);}
1541   ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
1542   ierr = PetscDrawPause(draw);CHKERRQ(ierr);
1543   ierr = PetscDrawSave(draw);CHKERRQ(ierr);
1544   PetscFunctionReturn(0);
1545 }
1546 
1547 #if defined(PETSC_HAVE_EXODUSII)
1548 #include <exodusII.h>
1549 #include <petscviewerexodusii.h>
1550 #endif
1551 
1552 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1553 {
1554   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus;
1555   char           name[PETSC_MAX_PATH_LEN];
1556   PetscErrorCode ierr;
1557 
1558   PetscFunctionBegin;
1559   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1560   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1561   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII,    &iascii);CHKERRQ(ierr);
1562   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,      &isvtk);CHKERRQ(ierr);
1563   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5);CHKERRQ(ierr);
1564   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,     &isdraw);CHKERRQ(ierr);
1565   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS,    &isglvis);CHKERRQ(ierr);
1566   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus);CHKERRQ(ierr);
1567   if (iascii) {
1568     PetscViewerFormat format;
1569     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1570     if (format == PETSC_VIEWER_ASCII_GLVIS) {
1571       ierr = DMPlexView_GLVis(dm, viewer);CHKERRQ(ierr);
1572     } else {
1573       ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
1574     }
1575   } else if (ishdf5) {
1576 #if defined(PETSC_HAVE_HDF5)
1577     ierr = DMPlexView_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
1578 #else
1579     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1580 #endif
1581   } else if (isvtk) {
1582     ierr = DMPlexVTKWriteAll((PetscObject) dm,viewer);CHKERRQ(ierr);
1583   } else if (isdraw) {
1584     ierr = DMPlexView_Draw(dm, viewer);CHKERRQ(ierr);
1585   } else if (isglvis) {
1586     ierr = DMPlexView_GLVis(dm, viewer);CHKERRQ(ierr);
1587 #if defined(PETSC_HAVE_EXODUSII)
1588   } else if (isexodus) {
1589 /*
1590       exodusII requires that all sets be part of exactly one cell set.
1591       If the dm does not have a "Cell Sets" label defined, we create one
1592       with ID 1, containig all cells.
1593       Note that if the Cell Sets label is defined but does not cover all cells,
1594       we may still have a problem. This should probably be checked here or in the viewer;
1595     */
1596     PetscInt numCS;
1597     ierr = DMGetLabelSize(dm,"Cell Sets",&numCS);CHKERRQ(ierr);
1598     if (!numCS) {
1599       PetscInt cStart, cEnd, c;
1600       ierr = DMCreateLabel(dm, "Cell Sets");CHKERRQ(ierr);
1601       ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1602       for (c = cStart; c < cEnd; ++c) {ierr = DMSetLabelValue(dm, "Cell Sets", c, 1);CHKERRQ(ierr);}
1603     }
1604     ierr = DMView_PlexExodusII(dm, viewer);CHKERRQ(ierr);
1605 #endif
1606   } else {
1607     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1608   }
1609   /* Optionally view the partition */
1610   ierr = PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);CHKERRQ(ierr);
1611   if (flg) {
1612     Vec ranks;
1613     ierr = DMPlexCreateRankField(dm, &ranks);CHKERRQ(ierr);
1614     ierr = VecView(ranks, viewer);CHKERRQ(ierr);
1615     ierr = VecDestroy(&ranks);CHKERRQ(ierr);
1616   }
1617   /* Optionally view a label */
1618   ierr = PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg);CHKERRQ(ierr);
1619   if (flg) {
1620     DMLabel label;
1621     Vec     val;
1622 
1623     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
1624     if (!label) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
1625     ierr = DMPlexCreateLabelField(dm, label, &val);CHKERRQ(ierr);
1626     ierr = VecView(val, viewer);CHKERRQ(ierr);
1627     ierr = VecDestroy(&val);CHKERRQ(ierr);
1628   }
1629   PetscFunctionReturn(0);
1630 }
1631 
1632 /*@
1633   DMPlexTopologyView - Saves a DMPlex topology into a file
1634 
1635   Collective on DM
1636 
1637   Input Parameters:
1638 + dm     - The DM whose topology is to be saved
1639 - viewer - The PetscViewer for saving
1640 
1641   Level: advanced
1642 
1643 .seealso: DMView(), DMPlexCoordinatesView(), DMPlexLabelsView(), DMPlexTopologyLoad()
1644 @*/
1645 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
1646 {
1647   PetscBool      ishdf5;
1648   PetscErrorCode ierr;
1649 
1650   PetscFunctionBegin;
1651   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1652   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1653   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1654   if (ishdf5) {
1655 #if defined(PETSC_HAVE_HDF5)
1656     PetscViewerFormat format;
1657     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1658     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1659       IS globalPointNumbering;
1660 
1661       ierr = DMPlexCreatePointNumbering(dm, &globalPointNumbering);CHKERRQ(ierr);
1662       ierr = DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer);CHKERRQ(ierr);
1663       ierr = ISDestroy(&globalPointNumbering);CHKERRQ(ierr);
1664     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
1665 #else
1666     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1667 #endif
1668   }
1669   PetscFunctionReturn(0);
1670 }
1671 
1672 /*@
1673   DMPlexCoordinatesView - Saves DMPlex coordinates into a file
1674 
1675   Collective on DM
1676 
1677   Input Parameters:
1678 + dm     - The DM whose coordinates are to be saved
1679 - viewer - The PetscViewer for saving
1680 
1681   Level: advanced
1682 
1683 .seealso: DMView(), DMPlexTopologyView(), DMPlexLabelsView(), DMPlexCoordinatesLoad()
1684 @*/
1685 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
1686 {
1687   PetscBool      ishdf5;
1688   PetscErrorCode ierr;
1689 
1690   PetscFunctionBegin;
1691   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1692   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1693   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1694   if (ishdf5) {
1695 #if defined(PETSC_HAVE_HDF5)
1696     PetscViewerFormat format;
1697     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1698     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1699       ierr = DMPlexCoordinatesView_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
1700     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1701 #else
1702     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1703 #endif
1704   }
1705   PetscFunctionReturn(0);
1706 }
1707 
1708 /*@
1709   DMPlexLabelsView - Saves DMPlex labels into a file
1710 
1711   Collective on DM
1712 
1713   Input Parameters:
1714 + dm     - The DM whose labels are to be saved
1715 - viewer - The PetscViewer for saving
1716 
1717   Level: advanced
1718 
1719 .seealso: DMView(), DMPlexTopologyView(), DMPlexCoordinatesView(), DMPlexLabelsLoad()
1720 @*/
1721 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
1722 {
1723   PetscBool      ishdf5;
1724   PetscErrorCode ierr;
1725 
1726   PetscFunctionBegin;
1727   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1728   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1729   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1730   if (ishdf5) {
1731 #if defined(PETSC_HAVE_HDF5)
1732     IS                globalPointNumbering;
1733     PetscViewerFormat format;
1734 
1735     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1736     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1737       ierr = DMPlexCreatePointNumbering(dm, &globalPointNumbering);CHKERRQ(ierr);
1738       ierr = DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer);CHKERRQ(ierr);
1739       ierr = ISDestroy(&globalPointNumbering);CHKERRQ(ierr);
1740     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1741 #else
1742     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1743 #endif
1744   }
1745   PetscFunctionReturn(0);
1746 }
1747 
1748 /*@
1749   DMPlexSectionView - Saves a section associated with a DMPlex
1750 
1751   Collective on DM
1752 
1753   Input Parameters:
1754 + dm         - The DM that contains the topology on which the section to be saved is defined
1755 . viewer     - The PetscViewer for saving
1756 - sectiondm  - The DM that contains the section to be saved
1757 
1758   Level: advanced
1759 
1760   Notes:
1761   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.
1762 
1763   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.
1764 
1765 .seealso: DMView(), DMPlexTopologyView(), DMPlexCoordinatesView(), DMPlexLabelsView(), DMPlexGlobalVectorView(), DMPlexLocalVectorView(), PetscSectionView(), DMPlexSectionLoad()
1766 @*/
1767 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
1768 {
1769   PetscBool      ishdf5;
1770   PetscErrorCode ierr;
1771 
1772   PetscFunctionBegin;
1773   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1774   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1775   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
1776   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
1777   if (ishdf5) {
1778 #if defined(PETSC_HAVE_HDF5)
1779     ierr = DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm);CHKERRQ(ierr);
1780 #else
1781     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1782 #endif
1783   }
1784   PetscFunctionReturn(0);
1785 }
1786 
1787 /*@
1788   DMPlexGlobalVectorView - Saves a global vector
1789 
1790   Collective on DM
1791 
1792   Input Parameters:
1793 + dm        - The DM that represents the topology
1794 . viewer    - The PetscViewer to save data with
1795 . sectiondm - The DM that contains the global section on which vec is defined
1796 - vec       - The global vector to be saved
1797 
1798   Level: advanced
1799 
1800   Notes:
1801   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.
1802 
1803   Typical calling sequence
1804 $       DMCreate(PETSC_COMM_WORLD, &dm);
1805 $       DMSetType(dm, DMPLEX);
1806 $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
1807 $       DMClone(dm, &sectiondm);
1808 $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
1809 $       PetscSectionCreate(PETSC_COMM_WORLD, &section);
1810 $       DMPlexGetChart(sectiondm, &pStart, &pEnd);
1811 $       PetscSectionSetChart(section, pStart, pEnd);
1812 $       PetscSectionSetUp(section);
1813 $       DMSetLocalSection(sectiondm, section);
1814 $       PetscSectionDestroy(&section);
1815 $       DMGetGlobalVector(sectiondm, &vec);
1816 $       PetscObjectSetName((PetscObject)vec, "vec_name");
1817 $       DMPlexTopologyView(dm, viewer);
1818 $       DMPlexSectionView(dm, viewer, sectiondm);
1819 $       DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
1820 $       DMRestoreGlobalVector(sectiondm, &vec);
1821 $       DMDestroy(&sectiondm);
1822 $       DMDestroy(&dm);
1823 
1824 .seealso: DMPlexTopologyView(), DMPlexSectionView(), DMPlexLocalVectorView(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad()
1825 @*/
1826 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
1827 {
1828   PetscBool       ishdf5;
1829   PetscErrorCode  ierr;
1830 
1831   PetscFunctionBegin;
1832   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1833   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1834   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
1835   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
1836   /* Check consistency */
1837   {
1838     PetscSection  section;
1839     PetscBool     includesConstraints;
1840     PetscInt      m, m1;
1841 
1842     ierr = VecGetLocalSize(vec, &m1);CHKERRQ(ierr);
1843     ierr = DMGetGlobalSection(sectiondm, &section);CHKERRQ(ierr);
1844     ierr = PetscSectionGetIncludesConstraints(section, &includesConstraints);CHKERRQ(ierr);
1845     if (includesConstraints) {ierr = PetscSectionGetStorageSize(section, &m);CHKERRQ(ierr);}
1846     else {ierr = PetscSectionGetConstrainedStorageSize(section, &m);CHKERRQ(ierr);}
1847     if (m1 != m) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%D) != global section storage size (%D)", m1, m);
1848   }
1849   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1850   if (ishdf5) {
1851 #if defined(PETSC_HAVE_HDF5)
1852     ierr = DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec);CHKERRQ(ierr);
1853 #else
1854     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1855 #endif
1856   }
1857   PetscFunctionReturn(0);
1858 }
1859 
1860 /*@
1861   DMPlexLocalVectorView - Saves a local vector
1862 
1863   Collective on DM
1864 
1865   Input Parameters:
1866 + dm        - The DM that represents the topology
1867 . viewer    - The PetscViewer to save data with
1868 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm
1869 - vec       - The local vector to be saved
1870 
1871   Level: advanced
1872 
1873   Notes:
1874   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.
1875 
1876   Typical calling sequence
1877 $       DMCreate(PETSC_COMM_WORLD, &dm);
1878 $       DMSetType(dm, DMPLEX);
1879 $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
1880 $       DMClone(dm, &sectiondm);
1881 $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
1882 $       PetscSectionCreate(PETSC_COMM_WORLD, &section);
1883 $       DMPlexGetChart(sectiondm, &pStart, &pEnd);
1884 $       PetscSectionSetChart(section, pStart, pEnd);
1885 $       PetscSectionSetUp(section);
1886 $       DMSetLocalSection(sectiondm, section);
1887 $       DMGetLocalVector(sectiondm, &vec);
1888 $       PetscObjectSetName((PetscObject)vec, "vec_name");
1889 $       DMPlexTopologyView(dm, viewer);
1890 $       DMPlexSectionView(dm, viewer, sectiondm);
1891 $       DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
1892 $       DMRestoreLocalVector(sectiondm, &vec);
1893 $       DMDestroy(&sectiondm);
1894 $       DMDestroy(&dm);
1895 
1896 .seealso: DMPlexTopologyView(), DMPlexSectionView(), DMPlexGlobalVectorView(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad()
1897 @*/
1898 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
1899 {
1900   PetscBool       ishdf5;
1901   PetscErrorCode  ierr;
1902 
1903   PetscFunctionBegin;
1904   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1905   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1906   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
1907   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
1908   /* Check consistency */
1909   {
1910     PetscSection  section;
1911     PetscBool     includesConstraints;
1912     PetscInt      m, m1;
1913 
1914     ierr = VecGetLocalSize(vec, &m1);CHKERRQ(ierr);
1915     ierr = DMGetLocalSection(sectiondm, &section);CHKERRQ(ierr);
1916     ierr = PetscSectionGetIncludesConstraints(section, &includesConstraints);CHKERRQ(ierr);
1917     if (includesConstraints) {ierr = PetscSectionGetStorageSize(section, &m);CHKERRQ(ierr);}
1918     else {ierr = PetscSectionGetConstrainedStorageSize(section, &m);CHKERRQ(ierr);}
1919     if (m1 != m) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%D) != local section storage size (%D)", m1, m);
1920   }
1921   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1922   if (ishdf5) {
1923 #if defined(PETSC_HAVE_HDF5)
1924     ierr = DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec);CHKERRQ(ierr);
1925 #else
1926     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1927 #endif
1928   }
1929   PetscFunctionReturn(0);
1930 }
1931 
1932 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1933 {
1934   PetscBool      ishdf5;
1935   PetscErrorCode ierr;
1936 
1937   PetscFunctionBegin;
1938   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1939   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1940   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);CHKERRQ(ierr);
1941   if (ishdf5) {
1942 #if defined(PETSC_HAVE_HDF5)
1943     PetscViewerFormat format;
1944     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1945     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
1946       ierr = DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);CHKERRQ(ierr);
1947     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1948       ierr = DMPlexLoad_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
1949     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1950     PetscFunctionReturn(0);
1951 #else
1952     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1953 #endif
1954   } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
1955 }
1956 
1957 /*@
1958   DMPlexTopologyLoad - Loads a topology into a DMPlex
1959 
1960   Collective on DM
1961 
1962   Input Parameters:
1963 + dm     - The DM into which the topology is loaded
1964 - viewer - The PetscViewer for the saved topology
1965 
1966   Output Parameters:
1967 . 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
1968 
1969   Level: advanced
1970 
1971 .seealso: DMLoad(), DMPlexCoordinatesLoad(), DMPlexLabelsLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat()
1972 @*/
1973 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
1974 {
1975   PetscBool      ishdf5;
1976   PetscErrorCode ierr;
1977 
1978   PetscFunctionBegin;
1979   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1980   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1981   if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3);
1982   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1983   if (ishdf5) {
1984 #if defined(PETSC_HAVE_HDF5)
1985     PetscViewerFormat format;
1986     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1987     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1988       ierr = DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF);CHKERRQ(ierr);
1989     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1990 #else
1991     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1992 #endif
1993   }
1994   PetscFunctionReturn(0);
1995 }
1996 
1997 /*@
1998   DMPlexCoordinatesLoad - Loads coordinates into a DMPlex
1999 
2000   Collective on DM
2001 
2002   Input Parameters:
2003 + dm     - The DM into which the coordinates are loaded
2004 - viewer - The PetscViewer for the saved coordinates
2005 
2006   Level: advanced
2007 
2008 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexLabelsLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat()
2009 @*/
2010 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer)
2011 {
2012   PetscBool      ishdf5;
2013   PetscErrorCode ierr;
2014 
2015   PetscFunctionBegin;
2016   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2017   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2018   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
2019   if (ishdf5) {
2020 #if defined(PETSC_HAVE_HDF5)
2021     PetscViewerFormat format;
2022     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
2023     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2024       ierr = DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
2025     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2026 #else
2027     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2028 #endif
2029   }
2030   PetscFunctionReturn(0);
2031 }
2032 
2033 /*@
2034   DMPlexLabelsLoad - Loads labels into a DMPlex
2035 
2036   Collective on DM
2037 
2038   Input Parameters:
2039 + dm     - The DM into which the labels are loaded
2040 - viewer - The PetscViewer for the saved labels
2041 
2042   Level: advanced
2043 
2044 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexCoordinatesLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat()
2045 @*/
2046 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer)
2047 {
2048   PetscBool      ishdf5;
2049   PetscErrorCode ierr;
2050 
2051   PetscFunctionBegin;
2052   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2053   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2054   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
2055   if (ishdf5) {
2056 #if defined(PETSC_HAVE_HDF5)
2057     PetscViewerFormat format;
2058 
2059     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
2060     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2061       ierr = DMPlexLabelsLoad_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
2062     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
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   DMPlexSectionLoad - Loads section into a DMPlex
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 section (sectionA)
2078 . sectiondm   - The DM into which the on-disk section (sectionA) is migrated
2079 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
2080 
2081   Output Parameters
2082 + 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)
2083 - 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)
2084 
2085   Level: advanced
2086 
2087   Notes:
2088   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.
2089 
2090   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.
2091 
2092   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.
2093 
2094   Example using 2 processes:
2095 $  NX (number of points on dm): 4
2096 $  sectionA                   : the on-disk section
2097 $  vecA                       : a vector associated with sectionA
2098 $  sectionB                   : sectiondm's local section constructed in this function
2099 $  vecB (local)               : a vector associated with sectiondm's local section
2100 $  vecB (global)              : a vector associated with sectiondm's global section
2101 $
2102 $                                     rank 0    rank 1
2103 $  vecA (global)                  : [.0 .4 .1 | .2 .3]        <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
2104 $  sectionA->atlasOff             :       0 2 | 1             <- loaded in PetscSectionLoad()
2105 $  sectionA->atlasDof             :       1 3 | 1             <- loaded in PetscSectionLoad()
2106 $  sectionA's global point numbers:       0 2 | 3             <- loaded in DMPlexSectionLoad()
2107 $  [0, NX)                        :       0 1 | 2 3           <- conceptual partition used in globalToLocalPointSF
2108 $  sectionB's global point numbers:     0 1 3 | 3 2           <- associated with [0, NX) by globalToLocalPointSF
2109 $  sectionB->atlasDof             :     1 0 1 | 1 3
2110 $  sectionB->atlasOff (no perm)   :     0 1 1 | 0 1
2111 $  vecB (local)                   :   [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
2112 $  vecB (global)                  :    [.0 .4 | .1 .2 .3]     <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
2113 $
2114 $  where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.
2115 
2116 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexCoordinatesLoad(), DMPlexLabelsLoad(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad(), PetscSectionLoad(), DMPlexSectionView()
2117 @*/
2118 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF)
2119 {
2120   PetscBool      ishdf5;
2121   PetscErrorCode ierr;
2122 
2123   PetscFunctionBegin;
2124   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2125   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2126   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2127   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4);
2128   if (globalDofSF) PetscValidPointer(globalDofSF, 5);
2129   if (localDofSF) PetscValidPointer(localDofSF, 6);
2130   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
2131   if (ishdf5) {
2132 #if defined(PETSC_HAVE_HDF5)
2133     ierr = DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF);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   DMPlexGlobalVectorLoad - Loads on-disk vector data into a global 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 global section on which vec is defined
2150 . sf        - The SF that migrates the on-disk vector data into vec
2151 - vec       - The global 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, &gsf, NULL);
2166 $       DMGetGlobalVector(sectiondm, &vec);
2167 $       PetscObjectSetName((PetscObject)vec, "vec_name");
2168 $       DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec);
2169 $       DMRestoreGlobalVector(sectiondm, &vec);
2170 $       PetscSFDestroy(&gsf);
2171 $       PetscSFDestroy(&sfX);
2172 $       DMDestroy(&sectiondm);
2173 $       DMDestroy(&dm);
2174 
2175 .seealso: DMPlexTopologyLoad(), DMPlexSectionLoad(), DMPlexLocalVectorLoad(), DMPlexGlobalVectorView(), DMPlexLocalVectorView()
2176 @*/
2177 PetscErrorCode DMPlexGlobalVectorLoad(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 = DMGetGlobalSection(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, "Global vector size (%D) != global 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 /*@
2213   DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector
2214 
2215   Collective on DM
2216 
2217   Input Parameters:
2218 + dm        - The DM that represents the topology
2219 . viewer    - The PetscViewer that represents the on-disk vector data
2220 . sectiondm - The DM that contains the local section on which vec is defined
2221 . sf        - The SF that migrates the on-disk vector data into vec
2222 - vec       - The local vector to set values of
2223 
2224   Level: advanced
2225 
2226   Notes:
2227   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.
2228 
2229   Typical calling sequence
2230 $       DMCreate(PETSC_COMM_WORLD, &dm);
2231 $       DMSetType(dm, DMPLEX);
2232 $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
2233 $       DMPlexTopologyLoad(dm, viewer, &sfX);
2234 $       DMClone(dm, &sectiondm);
2235 $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2236 $       DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf);
2237 $       DMGetLocalVector(sectiondm, &vec);
2238 $       PetscObjectSetName((PetscObject)vec, "vec_name");
2239 $       DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec);
2240 $       DMRestoreLocalVector(sectiondm, &vec);
2241 $       PetscSFDestroy(&lsf);
2242 $       PetscSFDestroy(&sfX);
2243 $       DMDestroy(&sectiondm);
2244 $       DMDestroy(&dm);
2245 
2246 .seealso: DMPlexTopologyLoad(), DMPlexSectionLoad(), DMPlexGlobalVectorLoad(), DMPlexGlobalVectorView(), DMPlexLocalVectorView()
2247 @*/
2248 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2249 {
2250   PetscBool       ishdf5;
2251   PetscErrorCode  ierr;
2252 
2253   PetscFunctionBegin;
2254   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2255   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2256   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2257   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
2258   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
2259   /* Check consistency */
2260   {
2261     PetscSection  section;
2262     PetscBool     includesConstraints;
2263     PetscInt      m, m1;
2264 
2265     ierr = VecGetLocalSize(vec, &m1);CHKERRQ(ierr);
2266     ierr = DMGetLocalSection(sectiondm, &section);CHKERRQ(ierr);
2267     ierr = PetscSectionGetIncludesConstraints(section, &includesConstraints);CHKERRQ(ierr);
2268     if (includesConstraints) {ierr = PetscSectionGetStorageSize(section, &m);CHKERRQ(ierr);}
2269     else {ierr = PetscSectionGetConstrainedStorageSize(section, &m);CHKERRQ(ierr);}
2270     if (m1 != m) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%D) != local section storage size (%D)", m1, m);
2271   }
2272   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
2273   if (ishdf5) {
2274 #if defined(PETSC_HAVE_HDF5)
2275     ierr = DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec);CHKERRQ(ierr);
2276 #else
2277     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2278 #endif
2279   }
2280   PetscFunctionReturn(0);
2281 }
2282 
2283 PetscErrorCode DMDestroy_Plex(DM dm)
2284 {
2285   DM_Plex       *mesh = (DM_Plex*) dm->data;
2286   PetscErrorCode ierr;
2287 
2288   PetscFunctionBegin;
2289   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);CHKERRQ(ierr);
2290   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);CHKERRQ(ierr);
2291   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL);CHKERRQ(ierr);
2292   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL);CHKERRQ(ierr);
2293   if (--mesh->refct > 0) PetscFunctionReturn(0);
2294   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
2295   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
2296   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
2297   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
2298   ierr = PetscSectionDestroy(&mesh->subdomainSection);CHKERRQ(ierr);
2299   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
2300   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
2301   ierr = PetscFree(mesh->tetgenOpts);CHKERRQ(ierr);
2302   ierr = PetscFree(mesh->triangleOpts);CHKERRQ(ierr);
2303   ierr = PetscFree(mesh->transformType);CHKERRQ(ierr);
2304   ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr);
2305   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
2306   ierr = ISDestroy(&mesh->subpointIS);CHKERRQ(ierr);
2307   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
2308   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
2309   ierr = PetscSectionDestroy(&mesh->anchorSection);CHKERRQ(ierr);
2310   ierr = ISDestroy(&mesh->anchorIS);CHKERRQ(ierr);
2311   ierr = PetscSectionDestroy(&mesh->parentSection);CHKERRQ(ierr);
2312   ierr = PetscFree(mesh->parents);CHKERRQ(ierr);
2313   ierr = PetscFree(mesh->childIDs);CHKERRQ(ierr);
2314   ierr = PetscSectionDestroy(&mesh->childSection);CHKERRQ(ierr);
2315   ierr = PetscFree(mesh->children);CHKERRQ(ierr);
2316   ierr = DMDestroy(&mesh->referenceTree);CHKERRQ(ierr);
2317   ierr = PetscGridHashDestroy(&mesh->lbox);CHKERRQ(ierr);
2318   ierr = PetscFree(mesh->neighbors);CHKERRQ(ierr);
2319   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
2320   ierr = PetscFree(mesh);CHKERRQ(ierr);
2321   PetscFunctionReturn(0);
2322 }
2323 
2324 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
2325 {
2326   PetscSection           sectionGlobal;
2327   PetscInt               bs = -1, mbs;
2328   PetscInt               localSize;
2329   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
2330   PetscErrorCode         ierr;
2331   MatType                mtype;
2332   ISLocalToGlobalMapping ltog;
2333 
2334   PetscFunctionBegin;
2335   ierr = MatInitializePackage();CHKERRQ(ierr);
2336   mtype = dm->mattype;
2337   ierr = DMGetGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
2338   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
2339   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
2340   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
2341   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
2342   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
2343   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
2344   ierr = MatGetBlockSize(*J, &mbs);CHKERRQ(ierr);
2345   if (mbs > 1) bs = mbs;
2346   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
2347   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
2348   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
2349   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
2350   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
2351   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
2352   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
2353   ierr = PetscStrcmp(mtype, MATIS, &isMatIS);CHKERRQ(ierr);
2354   if (!isShell) {
2355     PetscSection subSection;
2356     PetscBool    fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
2357     PetscInt    *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize;
2358     PetscInt     pStart, pEnd, p, dof, cdof;
2359 
2360     /* Set localtoglobalmapping on the matrix for MatSetValuesLocal() to work (it also creates the local matrices in case of MATIS) */
2361     if (isMatIS) { /* need a different l2g map than the one computed by DMGetLocalToGlobalMapping */
2362       PetscSection section;
2363       PetscInt     size;
2364 
2365       ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
2366       ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
2367       ierr = PetscMalloc1(size,&ltogidx);CHKERRQ(ierr);
2368       ierr = DMPlexGetSubdomainSection(dm, &subSection);CHKERRQ(ierr);
2369     } else {
2370       ierr = DMGetLocalToGlobalMapping(dm,&ltog);CHKERRQ(ierr);
2371     }
2372     ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
2373     for (p = pStart, lsize = 0; p < pEnd; ++p) {
2374       PetscInt bdof;
2375 
2376       ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
2377       ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
2378       dof  = dof < 0 ? -(dof+1) : dof;
2379       bdof = cdof && (dof-cdof) ? 1 : dof;
2380       if (dof) {
2381         if (bs < 0)          {bs = bdof;}
2382         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
2383       }
2384       if (isMatIS) {
2385         PetscInt loff,c,off;
2386         ierr = PetscSectionGetOffset(subSection, p, &loff);CHKERRQ(ierr);
2387         ierr = PetscSectionGetOffset(sectionGlobal, p, &off);CHKERRQ(ierr);
2388         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
2389       }
2390     }
2391     /* Must have same blocksize on all procs (some might have no points) */
2392     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
2393     ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr);
2394     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
2395     else                            {bs = bsMinMax[0];}
2396     bs = PetscMax(1,bs);
2397     if (isMatIS) { /* Must reduce indices by blocksize */
2398       PetscInt l;
2399 
2400       lsize = lsize/bs;
2401       if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] = ltogidx[l*bs]/bs;
2402       ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);CHKERRQ(ierr);
2403     }
2404     ierr = MatSetLocalToGlobalMapping(*J,ltog,ltog);CHKERRQ(ierr);
2405     if (isMatIS) {
2406       ierr = ISLocalToGlobalMappingDestroy(&ltog);CHKERRQ(ierr);
2407     }
2408     ierr = PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);CHKERRQ(ierr);
2409     ierr = DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
2410     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
2411   }
2412   ierr = MatSetDM(*J, dm);CHKERRQ(ierr);
2413   PetscFunctionReturn(0);
2414 }
2415 
2416 /*@
2417   DMPlexGetSubdomainSection - Returns the section associated with the subdomain
2418 
2419   Not collective
2420 
2421   Input Parameter:
2422 . mesh - The DMPlex
2423 
2424   Output Parameters:
2425 . subsection - The subdomain section
2426 
2427   Level: developer
2428 
2429 .seealso:
2430 @*/
2431 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
2432 {
2433   DM_Plex       *mesh = (DM_Plex*) dm->data;
2434   PetscErrorCode ierr;
2435 
2436   PetscFunctionBegin;
2437   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2438   if (!mesh->subdomainSection) {
2439     PetscSection section;
2440     PetscSF      sf;
2441 
2442     ierr = PetscSFCreate(PETSC_COMM_SELF,&sf);CHKERRQ(ierr);
2443     ierr = DMGetLocalSection(dm,&section);CHKERRQ(ierr);
2444     ierr = PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);CHKERRQ(ierr);
2445     ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
2446   }
2447   *subsection = mesh->subdomainSection;
2448   PetscFunctionReturn(0);
2449 }
2450 
2451 /*@
2452   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
2453 
2454   Not collective
2455 
2456   Input Parameter:
2457 . mesh - The DMPlex
2458 
2459   Output Parameters:
2460 + pStart - The first mesh point
2461 - pEnd   - The upper bound for mesh points
2462 
2463   Level: beginner
2464 
2465 .seealso: DMPlexCreate(), DMPlexSetChart()
2466 @*/
2467 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
2468 {
2469   DM_Plex       *mesh = (DM_Plex*) dm->data;
2470   PetscErrorCode ierr;
2471 
2472   PetscFunctionBegin;
2473   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2474   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
2475   PetscFunctionReturn(0);
2476 }
2477 
2478 /*@
2479   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
2480 
2481   Not collective
2482 
2483   Input Parameters:
2484 + mesh - The DMPlex
2485 . pStart - The first mesh point
2486 - pEnd   - The upper bound for mesh points
2487 
2488   Output Parameters:
2489 
2490   Level: beginner
2491 
2492 .seealso: DMPlexCreate(), DMPlexGetChart()
2493 @*/
2494 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
2495 {
2496   DM_Plex       *mesh = (DM_Plex*) dm->data;
2497   PetscErrorCode ierr;
2498 
2499   PetscFunctionBegin;
2500   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2501   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
2502   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
2503   PetscFunctionReturn(0);
2504 }
2505 
2506 /*@
2507   DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
2508 
2509   Not collective
2510 
2511   Input Parameters:
2512 + mesh - The DMPlex
2513 - p - The point, which must lie in the chart set with DMPlexSetChart()
2514 
2515   Output Parameter:
2516 . size - The cone size for point p
2517 
2518   Level: beginner
2519 
2520 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2521 @*/
2522 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
2523 {
2524   DM_Plex       *mesh = (DM_Plex*) dm->data;
2525   PetscErrorCode ierr;
2526 
2527   PetscFunctionBegin;
2528   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2529   PetscValidPointer(size, 3);
2530   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
2531   PetscFunctionReturn(0);
2532 }
2533 
2534 /*@
2535   DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
2536 
2537   Not collective
2538 
2539   Input Parameters:
2540 + mesh - The DMPlex
2541 . p - The point, which must lie in the chart set with DMPlexSetChart()
2542 - size - The cone size for point p
2543 
2544   Output Parameter:
2545 
2546   Note:
2547   This should be called after DMPlexSetChart().
2548 
2549   Level: beginner
2550 
2551 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
2552 @*/
2553 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
2554 {
2555   DM_Plex       *mesh = (DM_Plex*) dm->data;
2556   PetscErrorCode ierr;
2557 
2558   PetscFunctionBegin;
2559   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2560   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
2561 
2562   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
2563   PetscFunctionReturn(0);
2564 }
2565 
2566 /*@
2567   DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG
2568 
2569   Not collective
2570 
2571   Input Parameters:
2572 + mesh - The DMPlex
2573 . p - The point, which must lie in the chart set with DMPlexSetChart()
2574 - size - The additional cone size for point p
2575 
2576   Output Parameter:
2577 
2578   Note:
2579   This should be called after DMPlexSetChart().
2580 
2581   Level: beginner
2582 
2583 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
2584 @*/
2585 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
2586 {
2587   DM_Plex       *mesh = (DM_Plex*) dm->data;
2588   PetscInt       csize;
2589   PetscErrorCode ierr;
2590 
2591   PetscFunctionBegin;
2592   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2593   ierr = PetscSectionAddDof(mesh->coneSection, p, size);CHKERRQ(ierr);
2594   ierr = PetscSectionGetDof(mesh->coneSection, p, &csize);CHKERRQ(ierr);
2595 
2596   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
2597   PetscFunctionReturn(0);
2598 }
2599 
2600 /*@C
2601   DMPlexGetCone - Return the points on the in-edges for this point in the DAG
2602 
2603   Not collective
2604 
2605   Input Parameters:
2606 + dm - The DMPlex
2607 - p - The point, which must lie in the chart set with DMPlexSetChart()
2608 
2609   Output Parameter:
2610 . cone - An array of points which are on the in-edges for point p
2611 
2612   Level: beginner
2613 
2614   Fortran Notes:
2615   Since it returns an array, this routine is only available in Fortran 90, and you must
2616   include petsc.h90 in your code.
2617   You must also call DMPlexRestoreCone() after you finish using the returned array.
2618   DMPlexRestoreCone() is not needed/available in C.
2619 
2620 .seealso: DMPlexGetConeSize(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart()
2621 @*/
2622 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
2623 {
2624   DM_Plex       *mesh = (DM_Plex*) dm->data;
2625   PetscInt       off;
2626   PetscErrorCode ierr;
2627 
2628   PetscFunctionBegin;
2629   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2630   PetscValidPointer(cone, 3);
2631   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2632   *cone = &mesh->cones[off];
2633   PetscFunctionReturn(0);
2634 }
2635 
2636 /*@C
2637   DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
2638 
2639   Not collective
2640 
2641   Input Parameters:
2642 + dm - The DMPlex
2643 - p - The IS of points, which must lie in the chart set with DMPlexSetChart()
2644 
2645   Output Parameters:
2646 + pConesSection - PetscSection describing the layout of pCones
2647 - pCones - An array of points which are on the in-edges for the point set p
2648 
2649   Level: intermediate
2650 
2651 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart()
2652 @*/
2653 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
2654 {
2655   PetscSection        cs, newcs;
2656   PetscInt            *cones;
2657   PetscInt            *newarr=NULL;
2658   PetscInt            n;
2659   PetscErrorCode      ierr;
2660 
2661   PetscFunctionBegin;
2662   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
2663   ierr = DMPlexGetConeSection(dm, &cs);CHKERRQ(ierr);
2664   ierr = PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL);CHKERRQ(ierr);
2665   if (pConesSection) *pConesSection = newcs;
2666   if (pCones) {
2667     ierr = PetscSectionGetStorageSize(newcs, &n);CHKERRQ(ierr);
2668     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones);CHKERRQ(ierr);
2669   }
2670   PetscFunctionReturn(0);
2671 }
2672 
2673 /*@
2674   DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.
2675 
2676   Not collective
2677 
2678   Input Parameters:
2679 + dm - The DMPlex
2680 - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2681 
2682   Output Parameter:
2683 . expandedPoints - An array of vertices recursively expanded from input points
2684 
2685   Level: advanced
2686 
2687   Notes:
2688   Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections.
2689   There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate.
2690 
2691 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexRestoreConeRecursive(), DMPlexGetDepth()
2692 @*/
2693 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
2694 {
2695   IS                  *expandedPointsAll;
2696   PetscInt            depth;
2697   PetscErrorCode      ierr;
2698 
2699   PetscFunctionBegin;
2700   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2701   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
2702   PetscValidPointer(expandedPoints, 3);
2703   ierr = DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);CHKERRQ(ierr);
2704   *expandedPoints = expandedPointsAll[0];
2705   ierr = PetscObjectReference((PetscObject)expandedPointsAll[0]);CHKERRQ(ierr);
2706   ierr = DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);CHKERRQ(ierr);
2707   PetscFunctionReturn(0);
2708 }
2709 
2710 /*@
2711   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).
2712 
2713   Not collective
2714 
2715   Input Parameters:
2716 + dm - The DMPlex
2717 - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2718 
2719   Output Parameters:
2720 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
2721 . expandedPoints - (optional) An array of index sets with recursively expanded cones
2722 - sections - (optional) An array of sections which describe mappings from points to their cone points
2723 
2724   Level: advanced
2725 
2726   Notes:
2727   Like DMPlexGetConeTuple() but recursive.
2728 
2729   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.
2730   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.
2731 
2732   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:
2733   (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d];
2734   (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d].
2735 
2736 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexRestoreConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth()
2737 @*/
2738 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
2739 {
2740   const PetscInt      *arr0=NULL, *cone=NULL;
2741   PetscInt            *arr=NULL, *newarr=NULL;
2742   PetscInt            d, depth_, i, n, newn, cn, co, start, end;
2743   IS                  *expandedPoints_;
2744   PetscSection        *sections_;
2745   PetscErrorCode      ierr;
2746 
2747   PetscFunctionBegin;
2748   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2749   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
2750   if (depth) PetscValidIntPointer(depth, 3);
2751   if (expandedPoints) PetscValidPointer(expandedPoints, 4);
2752   if (sections) PetscValidPointer(sections, 5);
2753   ierr = ISGetLocalSize(points, &n);CHKERRQ(ierr);
2754   ierr = ISGetIndices(points, &arr0);CHKERRQ(ierr);
2755   ierr = DMPlexGetDepth(dm, &depth_);CHKERRQ(ierr);
2756   ierr = PetscCalloc1(depth_, &expandedPoints_);CHKERRQ(ierr);
2757   ierr = PetscCalloc1(depth_, &sections_);CHKERRQ(ierr);
2758   arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */
2759   for (d=depth_-1; d>=0; d--) {
2760     ierr = PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]);CHKERRQ(ierr);
2761     ierr = PetscSectionSetChart(sections_[d], 0, n);CHKERRQ(ierr);
2762     for (i=0; i<n; i++) {
2763       ierr = DMPlexGetDepthStratum(dm, d+1, &start, &end);CHKERRQ(ierr);
2764       if (arr[i] >= start && arr[i] < end) {
2765         ierr = DMPlexGetConeSize(dm, arr[i], &cn);CHKERRQ(ierr);
2766         ierr = PetscSectionSetDof(sections_[d], i, cn);CHKERRQ(ierr);
2767       } else {
2768         ierr = PetscSectionSetDof(sections_[d], i, 1);CHKERRQ(ierr);
2769       }
2770     }
2771     ierr = PetscSectionSetUp(sections_[d]);CHKERRQ(ierr);
2772     ierr = PetscSectionGetStorageSize(sections_[d], &newn);CHKERRQ(ierr);
2773     ierr = PetscMalloc1(newn, &newarr);CHKERRQ(ierr);
2774     for (i=0; i<n; i++) {
2775       ierr = PetscSectionGetDof(sections_[d], i, &cn);CHKERRQ(ierr);
2776       ierr = PetscSectionGetOffset(sections_[d], i, &co);CHKERRQ(ierr);
2777       if (cn > 1) {
2778         ierr = DMPlexGetCone(dm, arr[i], &cone);CHKERRQ(ierr);
2779         ierr = PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt));CHKERRQ(ierr);
2780       } else {
2781         newarr[co] = arr[i];
2782       }
2783     }
2784     ierr = ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]);CHKERRQ(ierr);
2785     arr = newarr;
2786     n = newn;
2787   }
2788   ierr = ISRestoreIndices(points, &arr0);CHKERRQ(ierr);
2789   *depth = depth_;
2790   if (expandedPoints) *expandedPoints = expandedPoints_;
2791   else {
2792     for (d=0; d<depth_; d++) {ierr = ISDestroy(&expandedPoints_[d]);CHKERRQ(ierr);}
2793     ierr = PetscFree(expandedPoints_);CHKERRQ(ierr);
2794   }
2795   if (sections) *sections = sections_;
2796   else {
2797     for (d=0; d<depth_; d++) {ierr = PetscSectionDestroy(&sections_[d]);CHKERRQ(ierr);}
2798     ierr = PetscFree(sections_);CHKERRQ(ierr);
2799   }
2800   PetscFunctionReturn(0);
2801 }
2802 
2803 /*@
2804   DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive
2805 
2806   Not collective
2807 
2808   Input Parameters:
2809 + dm - The DMPlex
2810 - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2811 
2812   Output Parameters:
2813 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
2814 . expandedPoints - (optional) An array of recursively expanded cones
2815 - sections - (optional) An array of sections which describe mappings from points to their cone points
2816 
2817   Level: advanced
2818 
2819   Notes:
2820   See DMPlexGetConeRecursive() for details.
2821 
2822 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth()
2823 @*/
2824 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
2825 {
2826   PetscInt            d, depth_;
2827   PetscErrorCode      ierr;
2828 
2829   PetscFunctionBegin;
2830   ierr = DMPlexGetDepth(dm, &depth_);CHKERRQ(ierr);
2831   if (depth && *depth != depth_) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
2832   if (depth) *depth = 0;
2833   if (expandedPoints) {
2834     for (d=0; d<depth_; d++) {ierr = ISDestroy(&((*expandedPoints)[d]));CHKERRQ(ierr);}
2835     ierr = PetscFree(*expandedPoints);CHKERRQ(ierr);
2836   }
2837   if (sections)  {
2838     for (d=0; d<depth_; d++) {ierr = PetscSectionDestroy(&((*sections)[d]));CHKERRQ(ierr);}
2839     ierr = PetscFree(*sections);CHKERRQ(ierr);
2840   }
2841   PetscFunctionReturn(0);
2842 }
2843 
2844 /*@
2845   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
2846 
2847   Not collective
2848 
2849   Input Parameters:
2850 + mesh - The DMPlex
2851 . p - The point, which must lie in the chart set with DMPlexSetChart()
2852 - cone - An array of points which are on the in-edges for point p
2853 
2854   Output Parameter:
2855 
2856   Note:
2857   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
2858 
2859   Level: beginner
2860 
2861 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
2862 @*/
2863 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
2864 {
2865   DM_Plex       *mesh = (DM_Plex*) dm->data;
2866   PetscInt       pStart, pEnd;
2867   PetscInt       dof, off, c;
2868   PetscErrorCode ierr;
2869 
2870   PetscFunctionBegin;
2871   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2872   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2873   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
2874   if (dof) PetscValidPointer(cone, 3);
2875   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2876   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);
2877   for (c = 0; c < dof; ++c) {
2878     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);
2879     mesh->cones[off+c] = cone[c];
2880   }
2881   PetscFunctionReturn(0);
2882 }
2883 
2884 /*@C
2885   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
2886 
2887   Not collective
2888 
2889   Input Parameters:
2890 + mesh - The DMPlex
2891 - p - The point, which must lie in the chart set with DMPlexSetChart()
2892 
2893   Output Parameter:
2894 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
2895                     integer giving the prescription for cone traversal.
2896 
2897   Level: beginner
2898 
2899   Notes:
2900   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
2901   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
2902   of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv()
2903   with the identity.
2904 
2905   Fortran Notes:
2906   Since it returns an array, this routine is only available in Fortran 90, and you must
2907   include petsc.h90 in your code.
2908   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
2909   DMPlexRestoreConeOrientation() is not needed/available in C.
2910 
2911 .seealso: DMPolytopeTypeComposeOrientation(), DMPolytopeTypeComposeOrientationInv(), DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
2912 @*/
2913 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
2914 {
2915   DM_Plex       *mesh = (DM_Plex*) dm->data;
2916   PetscInt       off;
2917   PetscErrorCode ierr;
2918 
2919   PetscFunctionBegin;
2920   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2921   if (PetscDefined(USE_DEBUG)) {
2922     PetscInt dof;
2923     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
2924     if (dof) PetscValidPointer(coneOrientation, 3);
2925   }
2926   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2927 
2928   *coneOrientation = &mesh->coneOrientations[off];
2929   PetscFunctionReturn(0);
2930 }
2931 
2932 /*@
2933   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
2934 
2935   Not collective
2936 
2937   Input Parameters:
2938 + mesh - The DMPlex
2939 . p - The point, which must lie in the chart set with DMPlexSetChart()
2940 - coneOrientation - An array of orientations
2941   Output Parameter:
2942 
2943   Notes:
2944   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
2945 
2946   The meaning of coneOrientation is detailed in DMPlexGetConeOrientation().
2947 
2948   Level: beginner
2949 
2950 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2951 @*/
2952 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
2953 {
2954   DM_Plex       *mesh = (DM_Plex*) dm->data;
2955   PetscInt       pStart, pEnd;
2956   PetscInt       dof, off, c;
2957   PetscErrorCode ierr;
2958 
2959   PetscFunctionBegin;
2960   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2961   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2962   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
2963   if (dof) PetscValidPointer(coneOrientation, 3);
2964   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2965   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);
2966   for (c = 0; c < dof; ++c) {
2967     PetscInt cdof, o = coneOrientation[c];
2968 
2969     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
2970     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);
2971     mesh->coneOrientations[off+c] = o;
2972   }
2973   PetscFunctionReturn(0);
2974 }
2975 
2976 /*@
2977   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
2978 
2979   Not collective
2980 
2981   Input Parameters:
2982 + mesh - The DMPlex
2983 . p - The point, which must lie in the chart set with DMPlexSetChart()
2984 . conePos - The local index in the cone where the point should be put
2985 - conePoint - The mesh point to insert
2986 
2987   Level: beginner
2988 
2989 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2990 @*/
2991 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
2992 {
2993   DM_Plex       *mesh = (DM_Plex*) dm->data;
2994   PetscInt       pStart, pEnd;
2995   PetscInt       dof, off;
2996   PetscErrorCode ierr;
2997 
2998   PetscFunctionBegin;
2999   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3000   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3001   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);
3002   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);
3003   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
3004   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
3005   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);
3006   mesh->cones[off+conePos] = conePoint;
3007   PetscFunctionReturn(0);
3008 }
3009 
3010 /*@
3011   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
3012 
3013   Not collective
3014 
3015   Input Parameters:
3016 + mesh - The DMPlex
3017 . p - The point, which must lie in the chart set with DMPlexSetChart()
3018 . conePos - The local index in the cone where the point should be put
3019 - coneOrientation - The point orientation to insert
3020 
3021   Level: beginner
3022 
3023   Notes:
3024   The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation().
3025 
3026 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
3027 @*/
3028 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
3029 {
3030   DM_Plex       *mesh = (DM_Plex*) dm->data;
3031   PetscInt       pStart, pEnd;
3032   PetscInt       dof, off;
3033   PetscErrorCode ierr;
3034 
3035   PetscFunctionBegin;
3036   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3037   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3038   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);
3039   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
3040   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
3041   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);
3042   mesh->coneOrientations[off+conePos] = coneOrientation;
3043   PetscFunctionReturn(0);
3044 }
3045 
3046 /*@
3047   DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
3048 
3049   Not collective
3050 
3051   Input Parameters:
3052 + mesh - The DMPlex
3053 - p - The point, which must lie in the chart set with DMPlexSetChart()
3054 
3055   Output Parameter:
3056 . size - The support size for point p
3057 
3058   Level: beginner
3059 
3060 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
3061 @*/
3062 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
3063 {
3064   DM_Plex       *mesh = (DM_Plex*) dm->data;
3065   PetscErrorCode ierr;
3066 
3067   PetscFunctionBegin;
3068   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3069   PetscValidPointer(size, 3);
3070   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
3071   PetscFunctionReturn(0);
3072 }
3073 
3074 /*@
3075   DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
3076 
3077   Not collective
3078 
3079   Input Parameters:
3080 + mesh - The DMPlex
3081 . p - The point, which must lie in the chart set with DMPlexSetChart()
3082 - size - The support size for point p
3083 
3084   Output Parameter:
3085 
3086   Note:
3087   This should be called after DMPlexSetChart().
3088 
3089   Level: beginner
3090 
3091 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
3092 @*/
3093 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
3094 {
3095   DM_Plex       *mesh = (DM_Plex*) dm->data;
3096   PetscErrorCode ierr;
3097 
3098   PetscFunctionBegin;
3099   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3100   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
3101 
3102   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
3103   PetscFunctionReturn(0);
3104 }
3105 
3106 /*@C
3107   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
3108 
3109   Not collective
3110 
3111   Input Parameters:
3112 + mesh - The DMPlex
3113 - p - The point, which must lie in the chart set with DMPlexSetChart()
3114 
3115   Output Parameter:
3116 . support - An array of points which are on the out-edges for point p
3117 
3118   Level: beginner
3119 
3120   Fortran Notes:
3121   Since it returns an array, this routine is only available in Fortran 90, and you must
3122   include petsc.h90 in your code.
3123   You must also call DMPlexRestoreSupport() after you finish using the returned array.
3124   DMPlexRestoreSupport() is not needed/available in C.
3125 
3126 .seealso: DMPlexGetSupportSize(), DMPlexSetSupport(), DMPlexGetCone(), DMPlexSetChart()
3127 @*/
3128 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
3129 {
3130   DM_Plex       *mesh = (DM_Plex*) dm->data;
3131   PetscInt       off;
3132   PetscErrorCode ierr;
3133 
3134   PetscFunctionBegin;
3135   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3136   PetscValidPointer(support, 3);
3137   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
3138   *support = &mesh->supports[off];
3139   PetscFunctionReturn(0);
3140 }
3141 
3142 /*@
3143   DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers
3144 
3145   Not collective
3146 
3147   Input Parameters:
3148 + mesh - The DMPlex
3149 . p - The point, which must lie in the chart set with DMPlexSetChart()
3150 - support - An array of points which are on the out-edges for point p
3151 
3152   Output Parameter:
3153 
3154   Note:
3155   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
3156 
3157   Level: beginner
3158 
3159 .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
3160 @*/
3161 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
3162 {
3163   DM_Plex       *mesh = (DM_Plex*) dm->data;
3164   PetscInt       pStart, pEnd;
3165   PetscInt       dof, off, c;
3166   PetscErrorCode ierr;
3167 
3168   PetscFunctionBegin;
3169   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3170   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
3171   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
3172   if (dof) PetscValidPointer(support, 3);
3173   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
3174   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);
3175   for (c = 0; c < dof; ++c) {
3176     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);
3177     mesh->supports[off+c] = support[c];
3178   }
3179   PetscFunctionReturn(0);
3180 }
3181 
3182 /*@
3183   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
3184 
3185   Not collective
3186 
3187   Input Parameters:
3188 + mesh - The DMPlex
3189 . p - The point, which must lie in the chart set with DMPlexSetChart()
3190 . supportPos - The local index in the cone where the point should be put
3191 - supportPoint - The mesh point to insert
3192 
3193   Level: beginner
3194 
3195 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
3196 @*/
3197 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
3198 {
3199   DM_Plex       *mesh = (DM_Plex*) dm->data;
3200   PetscInt       pStart, pEnd;
3201   PetscInt       dof, off;
3202   PetscErrorCode ierr;
3203 
3204   PetscFunctionBegin;
3205   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3206   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
3207   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
3208   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
3209   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);
3210   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);
3211   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);
3212   mesh->supports[off+supportPos] = supportPoint;
3213   PetscFunctionReturn(0);
3214 }
3215 
3216 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */
3217 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o)
3218 {
3219   switch (ct) {
3220     case DM_POLYTOPE_SEGMENT:
3221       if (o == -1) return -2;
3222       break;
3223     case DM_POLYTOPE_TRIANGLE:
3224       if (o == -3) return -1;
3225       if (o == -2) return -3;
3226       if (o == -1) return -2;
3227       break;
3228     case DM_POLYTOPE_QUADRILATERAL:
3229       if (o == -4) return -2;
3230       if (o == -3) return -1;
3231       if (o == -2) return -4;
3232       if (o == -1) return -3;
3233       break;
3234     default: return o;
3235   }
3236   return o;
3237 }
3238 
3239 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */
3240 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o)
3241 {
3242   switch (ct) {
3243     case DM_POLYTOPE_SEGMENT:
3244       if ((o == -2) || (o == 1)) return -1;
3245       if (o == -1) return 0;
3246       break;
3247     case DM_POLYTOPE_TRIANGLE:
3248       if (o == -3) return -2;
3249       if (o == -2) return -1;
3250       if (o == -1) return -3;
3251       break;
3252     case DM_POLYTOPE_QUADRILATERAL:
3253       if (o == -4) return -2;
3254       if (o == -3) return -1;
3255       if (o == -2) return -4;
3256       if (o == -1) return -3;
3257       break;
3258     default: return o;
3259   }
3260   return o;
3261 }
3262 
3263 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */
3264 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm)
3265 {
3266   PetscInt       pStart, pEnd, p;
3267   PetscErrorCode ierr;
3268 
3269   PetscFunctionBegin;
3270   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3271   for (p = pStart; p < pEnd; ++p) {
3272     const PetscInt *cone, *ornt;
3273     PetscInt        coneSize, c;
3274 
3275     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
3276     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
3277     ierr = DMPlexGetConeOrientation(dm, p, &ornt);CHKERRQ(ierr);
3278     for (c = 0; c < coneSize; ++c) {
3279       DMPolytopeType ct;
3280       const PetscInt o = ornt[c];
3281 
3282       ierr = DMPlexGetCellType(dm, cone[c], &ct);CHKERRQ(ierr);
3283       switch (ct) {
3284         case DM_POLYTOPE_SEGMENT:
3285           if ((o == -2) || (o == 1)) {ierr = DMPlexInsertConeOrientation(dm, p, c, -1);CHKERRQ(ierr);}
3286           if (o == -1) {ierr = DMPlexInsertConeOrientation(dm, p, c, 0);CHKERRQ(ierr);}
3287           break;
3288         case DM_POLYTOPE_TRIANGLE:
3289           if (o == -3) {ierr = DMPlexInsertConeOrientation(dm, p, c, -2);CHKERRQ(ierr);}
3290           if (o == -2) {ierr = DMPlexInsertConeOrientation(dm, p, c, -1);CHKERRQ(ierr);}
3291           if (o == -1) {ierr = DMPlexInsertConeOrientation(dm, p, c, -3);CHKERRQ(ierr);}
3292           break;
3293         case DM_POLYTOPE_QUADRILATERAL:
3294           if (o == -4) {ierr = DMPlexInsertConeOrientation(dm, p, c, -2);CHKERRQ(ierr);}
3295           if (o == -3) {ierr = DMPlexInsertConeOrientation(dm, p, c, -1);CHKERRQ(ierr);}
3296           if (o == -2) {ierr = DMPlexInsertConeOrientation(dm, p, c, -4);CHKERRQ(ierr);}
3297           if (o == -1) {ierr = DMPlexInsertConeOrientation(dm, p, c, -3);CHKERRQ(ierr);}
3298           break;
3299         default: break;
3300       }
3301     }
3302   }
3303   PetscFunctionReturn(0);
3304 }
3305 
3306 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3307 {
3308   DMPolytopeType  ct = DM_POLYTOPE_UNKNOWN;
3309   PetscInt       *closure;
3310   const PetscInt *tmp = NULL, *tmpO = NULL;
3311   PetscInt        off = 0, tmpSize, t;
3312   PetscErrorCode  ierr;
3313 
3314   PetscFunctionBeginHot;
3315   if (ornt) {
3316     ierr = DMPlexGetCellType(dm, p, &ct);CHKERRQ(ierr);
3317     if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3318   }
3319   if (*points) {
3320     closure = *points;
3321   } else {
3322     PetscInt maxConeSize, maxSupportSize;
3323     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3324     ierr = DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure);CHKERRQ(ierr);
3325   }
3326   if (useCone) {
3327     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
3328     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
3329     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
3330   } else {
3331     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
3332     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
3333   }
3334   if (ct == DM_POLYTOPE_UNKNOWN) {
3335     closure[off++] = p;
3336     closure[off++] = 0;
3337     for (t = 0; t < tmpSize; ++t) {
3338       closure[off++] = tmp[t];
3339       closure[off++] = tmpO ? tmpO[t] : 0;
3340     }
3341   } else {
3342     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt);CHKERRQ(ierr);
3343 
3344     /* We assume that cells with a valid type have faces with a valid type */
3345     closure[off++] = p;
3346     closure[off++] = ornt;
3347     for (t = 0; t < tmpSize; ++t) {
3348       DMPolytopeType ft;
3349 
3350       ierr = DMPlexGetCellType(dm, tmp[t], &ft);CHKERRQ(ierr);
3351       closure[off++] = tmp[arr[t]];
3352       closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0;
3353     }
3354   }
3355   if (numPoints) *numPoints = tmpSize+1;
3356   if (points)    *points    = closure;
3357   PetscFunctionReturn(0);
3358 }
3359 
3360 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */
3361 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points)
3362 {
3363   const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
3364   const PetscInt *cone, *ornt;
3365   PetscInt       *pts,  *closure = NULL;
3366   DMPolytopeType  ft;
3367   PetscInt        maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize;
3368   PetscInt        dim, coneSize, c, d, clSize, cl;
3369   PetscErrorCode  ierr;
3370 
3371   PetscFunctionBeginHot;
3372   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
3373   ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
3374   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
3375   ierr = DMPlexGetConeOrientation(dm, point, &ornt);CHKERRQ(ierr);
3376   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3377   coneSeries    = (maxConeSize    > 1) ? ((PetscPowInt(maxConeSize,    dim+1)-1)/(maxConeSize-1))    : dim+1;
3378   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1;
3379   maxSize       = PetscMax(coneSeries, supportSeries);
3380   if (*points) {pts  = *points;}
3381   else         {ierr = DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts);CHKERRQ(ierr);}
3382   c    = 0;
3383   pts[c++] = point;
3384   pts[c++] = o;
3385   ierr = DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft);CHKERRQ(ierr);
3386   ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure);CHKERRQ(ierr);
3387   for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];}
3388   ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure);CHKERRQ(ierr);
3389   for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];}
3390   ierr = DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure);CHKERRQ(ierr);
3391   for (d = 2; d < coneSize; ++d) {
3392     ierr = DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft);CHKERRQ(ierr);
3393     pts[c++] = cone[arr[d*2+0]];
3394     pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]);
3395   }
3396   if (dim >= 3) {
3397     for (d = 2; d < coneSize; ++d) {
3398       const PetscInt  fpoint = cone[arr[d*2+0]];
3399       const PetscInt *fcone, *fornt;
3400       PetscInt        fconeSize, fc, i;
3401 
3402       ierr = DMPlexGetCellType(dm, fpoint, &ft);CHKERRQ(ierr);
3403       const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]));
3404       ierr = DMPlexGetConeSize(dm, fpoint, &fconeSize);CHKERRQ(ierr);
3405       ierr = DMPlexGetCone(dm, fpoint, &fcone);CHKERRQ(ierr);
3406       ierr = DMPlexGetConeOrientation(dm, fpoint, &fornt);CHKERRQ(ierr);
3407       for (fc = 0; fc < fconeSize; ++fc) {
3408         const PetscInt cp = fcone[farr[fc*2+0]];
3409         const PetscInt co = farr[fc*2+1];
3410 
3411         for (i = 0; i < c; i += 2) if (pts[i] == cp) break;
3412         if (i == c) {
3413           ierr = DMPlexGetCellType(dm, cp, &ft);CHKERRQ(ierr);
3414           pts[c++] = cp;
3415           pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]);
3416         }
3417       }
3418     }
3419   }
3420   *numPoints = c/2;
3421   *points    = pts;
3422   PetscFunctionReturn(0);
3423 }
3424 
3425 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3426 {
3427   DMPolytopeType ct;
3428   PetscInt      *closure, *fifo;
3429   PetscInt       closureSize = 0, fifoStart = 0, fifoSize = 0;
3430   PetscInt       maxConeSize, maxSupportSize, coneSeries, supportSeries;
3431   PetscInt       depth, maxSize;
3432   PetscErrorCode ierr;
3433 
3434   PetscFunctionBeginHot;
3435   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3436   if (depth == 1) {
3437     ierr = DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points);CHKERRQ(ierr);
3438     PetscFunctionReturn(0);
3439   }
3440   ierr = DMPlexGetCellType(dm, p, &ct);CHKERRQ(ierr);
3441   if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3442   if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
3443     ierr = DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points);CHKERRQ(ierr);
3444     PetscFunctionReturn(0);
3445   }
3446   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3447   coneSeries    = (maxConeSize    > 1) ? ((PetscPowInt(maxConeSize,    depth+1)-1)/(maxConeSize-1))    : depth+1;
3448   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1;
3449   maxSize       = PetscMax(coneSeries, supportSeries);
3450   ierr = DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo);CHKERRQ(ierr);
3451   if (*points) {closure = *points;}
3452   else         {ierr = DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure);CHKERRQ(ierr);}
3453   closure[closureSize++] = p;
3454   closure[closureSize++] = ornt;
3455   fifo[fifoSize++]       = p;
3456   fifo[fifoSize++]       = ornt;
3457   fifo[fifoSize++]       = ct;
3458   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
3459   while (fifoSize - fifoStart) {
3460     const PetscInt       q    = fifo[fifoStart++];
3461     const PetscInt       o    = fifo[fifoStart++];
3462     const DMPolytopeType qt   = (DMPolytopeType) fifo[fifoStart++];
3463     const PetscInt      *qarr = DMPolytopeTypeGetArrangment(qt, o);
3464     const PetscInt      *tmp, *tmpO;
3465     PetscInt             tmpSize, t;
3466 
3467     if (PetscDefined(USE_DEBUG)) {
3468       PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2;
3469       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);
3470     }
3471     if (useCone) {
3472       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
3473       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
3474       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
3475     } else {
3476       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
3477       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
3478       tmpO = NULL;
3479     }
3480     for (t = 0; t < tmpSize; ++t) {
3481       const PetscInt ip = useCone && qarr ? qarr[t*2]   : t;
3482       const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0;
3483       const PetscInt cp = tmp[ip];
3484       ierr = DMPlexGetCellType(dm, cp, &ct);CHKERRQ(ierr);
3485       const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0;
3486       PetscInt       c;
3487 
3488       /* Check for duplicate */
3489       for (c = 0; c < closureSize; c += 2) {
3490         if (closure[c] == cp) break;
3491       }
3492       if (c == closureSize) {
3493         closure[closureSize++] = cp;
3494         closure[closureSize++] = co;
3495         fifo[fifoSize++]       = cp;
3496         fifo[fifoSize++]       = co;
3497         fifo[fifoSize++]       = ct;
3498       }
3499     }
3500   }
3501   ierr = DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo);CHKERRQ(ierr);
3502   if (numPoints) *numPoints = closureSize/2;
3503   if (points)    *points    = closure;
3504   PetscFunctionReturn(0);
3505 }
3506 
3507 /*@C
3508   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
3509 
3510   Not collective
3511 
3512   Input Parameters:
3513 + dm      - The DMPlex
3514 . p       - The mesh point
3515 - useCone - PETSC_TRUE for the closure, otherwise return the star
3516 
3517   Input/Output Parameter:
3518 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...];
3519            if NULL on input, internal storage will be returned, otherwise the provided array is used
3520 
3521   Output Parameter:
3522 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints
3523 
3524   Note:
3525   If using internal storage (points is NULL on input), each call overwrites the last output.
3526 
3527   Fortran Notes:
3528   Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code.
3529 
3530   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3531 
3532   Level: beginner
3533 
3534 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
3535 @*/
3536 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3537 {
3538   PetscErrorCode ierr;
3539 
3540   PetscFunctionBeginHot;
3541   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3542   if (numPoints) PetscValidIntPointer(numPoints, 4);
3543   if (points)    PetscValidPointer(points, 5);
3544   ierr = DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points);CHKERRQ(ierr);
3545   PetscFunctionReturn(0);
3546 }
3547 
3548 /*@C
3549   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
3550 
3551   Not collective
3552 
3553   Input Parameters:
3554 + dm        - The DMPlex
3555 . p         - The mesh point
3556 . useCone   - PETSC_TRUE for the closure, otherwise return the star
3557 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints
3558 - points    - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
3559 
3560   Note:
3561   If not using internal storage (points is not NULL on input), this call is unnecessary
3562 
3563   Fortran Notes:
3564   Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code.
3565 
3566   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3567 
3568   Level: beginner
3569 
3570 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
3571 @*/
3572 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3573 {
3574   PetscErrorCode ierr;
3575 
3576   PetscFunctionBeginHot;
3577   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3578   if (numPoints) *numPoints = 0;
3579   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, points);CHKERRQ(ierr);
3580   PetscFunctionReturn(0);
3581 }
3582 
3583 /*@
3584   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
3585 
3586   Not collective
3587 
3588   Input Parameter:
3589 . mesh - The DMPlex
3590 
3591   Output Parameters:
3592 + maxConeSize - The maximum number of in-edges
3593 - maxSupportSize - The maximum number of out-edges
3594 
3595   Level: beginner
3596 
3597 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
3598 @*/
3599 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
3600 {
3601   DM_Plex *mesh = (DM_Plex*) dm->data;
3602 
3603   PetscFunctionBegin;
3604   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3605   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
3606   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
3607   PetscFunctionReturn(0);
3608 }
3609 
3610 PetscErrorCode DMSetUp_Plex(DM dm)
3611 {
3612   DM_Plex       *mesh = (DM_Plex*) dm->data;
3613   PetscInt       size;
3614   PetscErrorCode ierr;
3615 
3616   PetscFunctionBegin;
3617   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3618   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
3619   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
3620   ierr = PetscMalloc1(size, &mesh->cones);CHKERRQ(ierr);
3621   ierr = PetscCalloc1(size, &mesh->coneOrientations);CHKERRQ(ierr);
3622   ierr = PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt));CHKERRQ(ierr);
3623   if (mesh->maxSupportSize) {
3624     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
3625     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
3626     ierr = PetscMalloc1(size, &mesh->supports);CHKERRQ(ierr);
3627     ierr = PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt));CHKERRQ(ierr);
3628   }
3629   PetscFunctionReturn(0);
3630 }
3631 
3632 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
3633 {
3634   PetscErrorCode ierr;
3635 
3636   PetscFunctionBegin;
3637   if (subdm) {ierr = DMClone(dm, subdm);CHKERRQ(ierr);}
3638   ierr = DMCreateSectionSubDM(dm, numFields, fields, is, subdm);CHKERRQ(ierr);
3639   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
3640   if (dm->useNatural && dm->sfMigration) {
3641     PetscSF        sfMigrationInv,sfNatural;
3642     PetscSection   section, sectionSeq;
3643 
3644     (*subdm)->sfMigration = dm->sfMigration;
3645     ierr = PetscObjectReference((PetscObject) dm->sfMigration);CHKERRQ(ierr);
3646     ierr = DMGetLocalSection((*subdm), &section);CHKERRQ(ierr);
3647     ierr = PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);CHKERRQ(ierr);
3648     ierr = PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq);CHKERRQ(ierr);
3649     ierr = PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);CHKERRQ(ierr);
3650 
3651     ierr = DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);CHKERRQ(ierr);
3652     (*subdm)->sfNatural = sfNatural;
3653     ierr = PetscSectionDestroy(&sectionSeq);CHKERRQ(ierr);
3654     ierr = PetscSFDestroy(&sfMigrationInv);CHKERRQ(ierr);
3655   }
3656   PetscFunctionReturn(0);
3657 }
3658 
3659 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
3660 {
3661   PetscErrorCode ierr;
3662   PetscInt       i = 0;
3663 
3664   PetscFunctionBegin;
3665   ierr = DMClone(dms[0], superdm);CHKERRQ(ierr);
3666   ierr = DMCreateSectionSuperDM(dms, len, is, superdm);CHKERRQ(ierr);
3667   (*superdm)->useNatural = PETSC_FALSE;
3668   for (i = 0; i < len; i++) {
3669     if (dms[i]->useNatural && dms[i]->sfMigration) {
3670       PetscSF        sfMigrationInv,sfNatural;
3671       PetscSection   section, sectionSeq;
3672 
3673       (*superdm)->sfMigration = dms[i]->sfMigration;
3674       ierr = PetscObjectReference((PetscObject) dms[i]->sfMigration);CHKERRQ(ierr);
3675       (*superdm)->useNatural = PETSC_TRUE;
3676       ierr = DMGetLocalSection((*superdm), &section);CHKERRQ(ierr);
3677       ierr = PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);CHKERRQ(ierr);
3678       ierr = PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq);CHKERRQ(ierr);
3679       ierr = PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);CHKERRQ(ierr);
3680 
3681       ierr = DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);CHKERRQ(ierr);
3682       (*superdm)->sfNatural = sfNatural;
3683       ierr = PetscSectionDestroy(&sectionSeq);CHKERRQ(ierr);
3684       ierr = PetscSFDestroy(&sfMigrationInv);CHKERRQ(ierr);
3685       break;
3686     }
3687   }
3688   PetscFunctionReturn(0);
3689 }
3690 
3691 /*@
3692   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
3693 
3694   Not collective
3695 
3696   Input Parameter:
3697 . mesh - The DMPlex
3698 
3699   Output Parameter:
3700 
3701   Note:
3702   This should be called after all calls to DMPlexSetCone()
3703 
3704   Level: beginner
3705 
3706 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
3707 @*/
3708 PetscErrorCode DMPlexSymmetrize(DM dm)
3709 {
3710   DM_Plex       *mesh = (DM_Plex*) dm->data;
3711   PetscInt      *offsets;
3712   PetscInt       supportSize;
3713   PetscInt       pStart, pEnd, p;
3714   PetscErrorCode ierr;
3715 
3716   PetscFunctionBegin;
3717   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3718   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
3719   ierr = PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0);CHKERRQ(ierr);
3720   /* Calculate support sizes */
3721   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3722   for (p = pStart; p < pEnd; ++p) {
3723     PetscInt dof, off, c;
3724 
3725     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
3726     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
3727     for (c = off; c < off+dof; ++c) {
3728       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
3729     }
3730   }
3731   for (p = pStart; p < pEnd; ++p) {
3732     PetscInt dof;
3733 
3734     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
3735 
3736     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
3737   }
3738   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
3739   /* Calculate supports */
3740   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
3741   ierr = PetscMalloc1(supportSize, &mesh->supports);CHKERRQ(ierr);
3742   ierr = PetscCalloc1(pEnd - pStart, &offsets);CHKERRQ(ierr);
3743   for (p = pStart; p < pEnd; ++p) {
3744     PetscInt dof, off, c;
3745 
3746     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
3747     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
3748     for (c = off; c < off+dof; ++c) {
3749       const PetscInt q = mesh->cones[c];
3750       PetscInt       offS;
3751 
3752       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
3753 
3754       mesh->supports[offS+offsets[q]] = p;
3755       ++offsets[q];
3756     }
3757   }
3758   ierr = PetscFree(offsets);CHKERRQ(ierr);
3759   ierr = PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0);CHKERRQ(ierr);
3760   PetscFunctionReturn(0);
3761 }
3762 
3763 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
3764 {
3765   IS             stratumIS;
3766   PetscErrorCode ierr;
3767 
3768   PetscFunctionBegin;
3769   if (pStart >= pEnd) PetscFunctionReturn(0);
3770   if (PetscDefined(USE_DEBUG)) {
3771     PetscInt  qStart, qEnd, numLevels, level;
3772     PetscBool overlap = PETSC_FALSE;
3773     ierr = DMLabelGetNumValues(label, &numLevels);CHKERRQ(ierr);
3774     for (level = 0; level < numLevels; level++) {
3775       ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr);
3776       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;}
3777     }
3778     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);
3779   }
3780   ierr = ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS);CHKERRQ(ierr);
3781   ierr = DMLabelSetStratumIS(label, depth, stratumIS);CHKERRQ(ierr);
3782   ierr = ISDestroy(&stratumIS);CHKERRQ(ierr);
3783   PetscFunctionReturn(0);
3784 }
3785 
3786 /*@
3787   DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
3788   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
3789   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
3790   the DAG.
3791 
3792   Collective on dm
3793 
3794   Input Parameter:
3795 . mesh - The DMPlex
3796 
3797   Output Parameter:
3798 
3799   Notes:
3800   Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
3801   meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on
3802   until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
3803   manually via DMGetLabel().  The height is defined implicitly by height = maxDimension - depth, and can be accessed
3804   via DMPlexGetHeightStratum().  For example, cells have height 0 and faces have height 1.
3805 
3806   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
3807   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
3808   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
3809   to interpolate only that one (e0), so that
3810 $  cone(c0) = {e0, v2}
3811 $  cone(e0) = {v0, v1}
3812   If DMPlexStratify() is run on this mesh, it will give depths
3813 $  depth 0 = {v0, v1, v2}
3814 $  depth 1 = {e0, c0}
3815   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.
3816 
3817   DMPlexStratify() should be called after all calls to DMPlexSymmetrize()
3818 
3819   Level: beginner
3820 
3821 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexComputeCellTypes()
3822 @*/
3823 PetscErrorCode DMPlexStratify(DM dm)
3824 {
3825   DM_Plex       *mesh = (DM_Plex*) dm->data;
3826   DMLabel        label;
3827   PetscInt       pStart, pEnd, p;
3828   PetscInt       numRoots = 0, numLeaves = 0;
3829   PetscErrorCode ierr;
3830 
3831   PetscFunctionBegin;
3832   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3833   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
3834 
3835   /* Create depth label */
3836   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3837   ierr = DMCreateLabel(dm, "depth");CHKERRQ(ierr);
3838   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
3839 
3840   {
3841     /* Initialize roots and count leaves */
3842     PetscInt sMin = PETSC_MAX_INT;
3843     PetscInt sMax = PETSC_MIN_INT;
3844     PetscInt coneSize, supportSize;
3845 
3846     for (p = pStart; p < pEnd; ++p) {
3847       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
3848       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
3849       if (!coneSize && supportSize) {
3850         sMin = PetscMin(p, sMin);
3851         sMax = PetscMax(p, sMax);
3852         ++numRoots;
3853       } else if (!supportSize && coneSize) {
3854         ++numLeaves;
3855       } else if (!supportSize && !coneSize) {
3856         /* Isolated points */
3857         sMin = PetscMin(p, sMin);
3858         sMax = PetscMax(p, sMax);
3859       }
3860     }
3861     ierr = DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1);CHKERRQ(ierr);
3862   }
3863 
3864   if (numRoots + numLeaves == (pEnd - pStart)) {
3865     PetscInt sMin = PETSC_MAX_INT;
3866     PetscInt sMax = PETSC_MIN_INT;
3867     PetscInt coneSize, supportSize;
3868 
3869     for (p = pStart; p < pEnd; ++p) {
3870       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
3871       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
3872       if (!supportSize && coneSize) {
3873         sMin = PetscMin(p, sMin);
3874         sMax = PetscMax(p, sMax);
3875       }
3876     }
3877     ierr = DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1);CHKERRQ(ierr);
3878   } else {
3879     PetscInt level = 0;
3880     PetscInt qStart, qEnd, q;
3881 
3882     ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr);
3883     while (qEnd > qStart) {
3884       PetscInt sMin = PETSC_MAX_INT;
3885       PetscInt sMax = PETSC_MIN_INT;
3886 
3887       for (q = qStart; q < qEnd; ++q) {
3888         const PetscInt *support;
3889         PetscInt        supportSize, s;
3890 
3891         ierr = DMPlexGetSupportSize(dm, q, &supportSize);CHKERRQ(ierr);
3892         ierr = DMPlexGetSupport(dm, q, &support);CHKERRQ(ierr);
3893         for (s = 0; s < supportSize; ++s) {
3894           sMin = PetscMin(support[s], sMin);
3895           sMax = PetscMax(support[s], sMax);
3896         }
3897       }
3898       ierr = DMLabelGetNumValues(label, &level);CHKERRQ(ierr);
3899       ierr = DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1);CHKERRQ(ierr);
3900       ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr);
3901     }
3902   }
3903   { /* just in case there is an empty process */
3904     PetscInt numValues, maxValues = 0, v;
3905 
3906     ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
3907     ierr = MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
3908     for (v = numValues; v < maxValues; v++) {
3909       ierr = DMLabelAddStratum(label, v);CHKERRQ(ierr);
3910     }
3911   }
3912   ierr = PetscObjectStateGet((PetscObject) label, &mesh->depthState);CHKERRQ(ierr);
3913   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
3914   PetscFunctionReturn(0);
3915 }
3916 
3917 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
3918 {
3919   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
3920   PetscInt       dim, depth, pheight, coneSize;
3921   PetscErrorCode ierr;
3922 
3923   PetscFunctionBeginHot;
3924   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
3925   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3926   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
3927   pheight = depth - pdepth;
3928   if (depth <= 1) {
3929     switch (pdepth) {
3930       case 0: ct = DM_POLYTOPE_POINT;break;
3931       case 1:
3932         switch (coneSize) {
3933           case 2: ct = DM_POLYTOPE_SEGMENT;break;
3934           case 3: ct = DM_POLYTOPE_TRIANGLE;break;
3935           case 4:
3936           switch (dim) {
3937             case 2: ct = DM_POLYTOPE_QUADRILATERAL;break;
3938             case 3: ct = DM_POLYTOPE_TETRAHEDRON;break;
3939             default: break;
3940           }
3941           break;
3942         case 5: ct = DM_POLYTOPE_PYRAMID;break;
3943         case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break;
3944         case 8: ct = DM_POLYTOPE_HEXAHEDRON;break;
3945         default: break;
3946       }
3947     }
3948   } else {
3949     if (pdepth == 0) {
3950       ct = DM_POLYTOPE_POINT;
3951     } else if (pheight == 0) {
3952       switch (dim) {
3953         case 1:
3954           switch (coneSize) {
3955             case 2: ct = DM_POLYTOPE_SEGMENT;break;
3956             default: break;
3957           }
3958           break;
3959         case 2:
3960           switch (coneSize) {
3961             case 3: ct = DM_POLYTOPE_TRIANGLE;break;
3962             case 4: ct = DM_POLYTOPE_QUADRILATERAL;break;
3963             default: break;
3964           }
3965           break;
3966         case 3:
3967           switch (coneSize) {
3968             case 4: ct = DM_POLYTOPE_TETRAHEDRON;break;
3969             case 5:
3970             {
3971               const PetscInt *cone;
3972               PetscInt        faceConeSize;
3973 
3974               ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
3975               ierr = DMPlexGetConeSize(dm, cone[0], &faceConeSize);CHKERRQ(ierr);
3976               switch (faceConeSize) {
3977                 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break;
3978                 case 4: ct = DM_POLYTOPE_PYRAMID;break;
3979               }
3980             }
3981             break;
3982             case 6: ct = DM_POLYTOPE_HEXAHEDRON;break;
3983             default: break;
3984           }
3985           break;
3986         default: break;
3987       }
3988     } else if (pheight > 0) {
3989       switch (coneSize) {
3990         case 2: ct = DM_POLYTOPE_SEGMENT;break;
3991         case 3: ct = DM_POLYTOPE_TRIANGLE;break;
3992         case 4: ct = DM_POLYTOPE_QUADRILATERAL;break;
3993         default: break;
3994       }
3995     }
3996   }
3997   *pt = ct;
3998   PetscFunctionReturn(0);
3999 }
4000 
4001 /*@
4002   DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size.
4003 
4004   Collective on dm
4005 
4006   Input Parameter:
4007 . mesh - The DMPlex
4008 
4009   DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify()
4010 
4011   Level: developer
4012 
4013   Note: This function is normally called automatically by Plex when a cell type is requested. It creates an
4014   internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable
4015   automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype").
4016 
4017 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexStratify(), DMGetLabel(), DMCreateLabel()
4018 @*/
4019 PetscErrorCode DMPlexComputeCellTypes(DM dm)
4020 {
4021   DM_Plex       *mesh;
4022   DMLabel        ctLabel;
4023   PetscInt       pStart, pEnd, p;
4024   PetscErrorCode ierr;
4025 
4026   PetscFunctionBegin;
4027   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4028   mesh = (DM_Plex *) dm->data;
4029   ierr = DMCreateLabel(dm, "celltype");CHKERRQ(ierr);
4030   ierr = DMPlexGetCellTypeLabel(dm, &ctLabel);CHKERRQ(ierr);
4031   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
4032   for (p = pStart; p < pEnd; ++p) {
4033     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4034     PetscInt       pdepth;
4035 
4036     ierr = DMPlexGetPointDepth(dm, p, &pdepth);CHKERRQ(ierr);
4037     ierr = DMPlexComputeCellType_Internal(dm, p, pdepth, &ct);CHKERRQ(ierr);
4038     if (ct == DM_POLYTOPE_UNKNOWN) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %D is screwed up", p);
4039     ierr = DMLabelSetValue(ctLabel, p, ct);CHKERRQ(ierr);
4040   }
4041   ierr = PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState);CHKERRQ(ierr);
4042   ierr = PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view");CHKERRQ(ierr);
4043   PetscFunctionReturn(0);
4044 }
4045 
4046 /*@C
4047   DMPlexGetJoin - Get an array for the join of the set of points
4048 
4049   Not Collective
4050 
4051   Input Parameters:
4052 + dm - The DMPlex object
4053 . numPoints - The number of input points for the join
4054 - points - The input points
4055 
4056   Output Parameters:
4057 + numCoveredPoints - The number of points in the join
4058 - coveredPoints - The points in the join
4059 
4060   Level: intermediate
4061 
4062   Note: Currently, this is restricted to a single level join
4063 
4064   Fortran Notes:
4065   Since it returns an array, this routine is only available in Fortran 90, and you must
4066   include petsc.h90 in your code.
4067 
4068   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4069 
4070 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
4071 @*/
4072 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4073 {
4074   DM_Plex       *mesh = (DM_Plex*) dm->data;
4075   PetscInt      *join[2];
4076   PetscInt       joinSize, i = 0;
4077   PetscInt       dof, off, p, c, m;
4078   PetscErrorCode ierr;
4079 
4080   PetscFunctionBegin;
4081   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4082   PetscValidIntPointer(points, 3);
4083   PetscValidIntPointer(numCoveredPoints, 4);
4084   PetscValidPointer(coveredPoints, 5);
4085   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);CHKERRQ(ierr);
4086   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);CHKERRQ(ierr);
4087   /* Copy in support of first point */
4088   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
4089   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
4090   for (joinSize = 0; joinSize < dof; ++joinSize) {
4091     join[i][joinSize] = mesh->supports[off+joinSize];
4092   }
4093   /* Check each successive support */
4094   for (p = 1; p < numPoints; ++p) {
4095     PetscInt newJoinSize = 0;
4096 
4097     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
4098     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
4099     for (c = 0; c < dof; ++c) {
4100       const PetscInt point = mesh->supports[off+c];
4101 
4102       for (m = 0; m < joinSize; ++m) {
4103         if (point == join[i][m]) {
4104           join[1-i][newJoinSize++] = point;
4105           break;
4106         }
4107       }
4108     }
4109     joinSize = newJoinSize;
4110     i        = 1-i;
4111   }
4112   *numCoveredPoints = joinSize;
4113   *coveredPoints    = join[i];
4114   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);CHKERRQ(ierr);
4115   PetscFunctionReturn(0);
4116 }
4117 
4118 /*@C
4119   DMPlexRestoreJoin - Restore an array for the join of the set of points
4120 
4121   Not Collective
4122 
4123   Input Parameters:
4124 + dm - The DMPlex object
4125 . numPoints - The number of input points for the join
4126 - points - The input points
4127 
4128   Output Parameters:
4129 + numCoveredPoints - The number of points in the join
4130 - coveredPoints - The points in the join
4131 
4132   Fortran Notes:
4133   Since it returns an array, this routine is only available in Fortran 90, and you must
4134   include petsc.h90 in your code.
4135 
4136   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4137 
4138   Level: intermediate
4139 
4140 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
4141 @*/
4142 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4143 {
4144   PetscErrorCode ierr;
4145 
4146   PetscFunctionBegin;
4147   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4148   if (points) PetscValidIntPointer(points,3);
4149   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
4150   PetscValidPointer(coveredPoints, 5);
4151   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);CHKERRQ(ierr);
4152   if (numCoveredPoints) *numCoveredPoints = 0;
4153   PetscFunctionReturn(0);
4154 }
4155 
4156 /*@C
4157   DMPlexGetFullJoin - Get an array for the join of the set of points
4158 
4159   Not Collective
4160 
4161   Input Parameters:
4162 + dm - The DMPlex object
4163 . numPoints - The number of input points for the join
4164 - points - The input points
4165 
4166   Output Parameters:
4167 + numCoveredPoints - The number of points in the join
4168 - coveredPoints - The points in the join
4169 
4170   Fortran Notes:
4171   Since it returns an array, this routine is only available in Fortran 90, and you must
4172   include petsc.h90 in your code.
4173 
4174   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4175 
4176   Level: intermediate
4177 
4178 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
4179 @*/
4180 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4181 {
4182   DM_Plex       *mesh = (DM_Plex*) dm->data;
4183   PetscInt      *offsets, **closures;
4184   PetscInt      *join[2];
4185   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
4186   PetscInt       p, d, c, m, ms;
4187   PetscErrorCode ierr;
4188 
4189   PetscFunctionBegin;
4190   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4191   PetscValidIntPointer(points, 3);
4192   PetscValidIntPointer(numCoveredPoints, 4);
4193   PetscValidPointer(coveredPoints, 5);
4194 
4195   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4196   ierr    = PetscCalloc1(numPoints, &closures);CHKERRQ(ierr);
4197   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);CHKERRQ(ierr);
4198   ms      = mesh->maxSupportSize;
4199   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
4200   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);CHKERRQ(ierr);
4201   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);CHKERRQ(ierr);
4202 
4203   for (p = 0; p < numPoints; ++p) {
4204     PetscInt closureSize;
4205 
4206     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
4207 
4208     offsets[p*(depth+2)+0] = 0;
4209     for (d = 0; d < depth+1; ++d) {
4210       PetscInt pStart, pEnd, i;
4211 
4212       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
4213       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
4214         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
4215           offsets[p*(depth+2)+d+1] = i;
4216           break;
4217         }
4218       }
4219       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
4220     }
4221     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);
4222   }
4223   for (d = 0; d < depth+1; ++d) {
4224     PetscInt dof;
4225 
4226     /* Copy in support of first point */
4227     dof = offsets[d+1] - offsets[d];
4228     for (joinSize = 0; joinSize < dof; ++joinSize) {
4229       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
4230     }
4231     /* Check each successive cone */
4232     for (p = 1; p < numPoints && joinSize; ++p) {
4233       PetscInt newJoinSize = 0;
4234 
4235       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
4236       for (c = 0; c < dof; ++c) {
4237         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
4238 
4239         for (m = 0; m < joinSize; ++m) {
4240           if (point == join[i][m]) {
4241             join[1-i][newJoinSize++] = point;
4242             break;
4243           }
4244         }
4245       }
4246       joinSize = newJoinSize;
4247       i        = 1-i;
4248     }
4249     if (joinSize) break;
4250   }
4251   *numCoveredPoints = joinSize;
4252   *coveredPoints    = join[i];
4253   for (p = 0; p < numPoints; ++p) {
4254     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
4255   }
4256   ierr = PetscFree(closures);CHKERRQ(ierr);
4257   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);CHKERRQ(ierr);
4258   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);CHKERRQ(ierr);
4259   PetscFunctionReturn(0);
4260 }
4261 
4262 /*@C
4263   DMPlexGetMeet - Get an array for the meet of the set of points
4264 
4265   Not Collective
4266 
4267   Input Parameters:
4268 + dm - The DMPlex object
4269 . numPoints - The number of input points for the meet
4270 - points - The input points
4271 
4272   Output Parameters:
4273 + numCoveredPoints - The number of points in the meet
4274 - coveredPoints - The points in the meet
4275 
4276   Level: intermediate
4277 
4278   Note: Currently, this is restricted to a single level meet
4279 
4280   Fortran Notes:
4281   Since it returns an array, this routine is only available in Fortran 90, and you must
4282   include petsc.h90 in your code.
4283 
4284   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4285 
4286 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
4287 @*/
4288 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
4289 {
4290   DM_Plex       *mesh = (DM_Plex*) dm->data;
4291   PetscInt      *meet[2];
4292   PetscInt       meetSize, i = 0;
4293   PetscInt       dof, off, p, c, m;
4294   PetscErrorCode ierr;
4295 
4296   PetscFunctionBegin;
4297   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4298   PetscValidPointer(points, 3);
4299   PetscValidPointer(numCoveringPoints, 4);
4300   PetscValidPointer(coveringPoints, 5);
4301   ierr = DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);CHKERRQ(ierr);
4302   ierr = DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);CHKERRQ(ierr);
4303   /* Copy in cone of first point */
4304   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
4305   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
4306   for (meetSize = 0; meetSize < dof; ++meetSize) {
4307     meet[i][meetSize] = mesh->cones[off+meetSize];
4308   }
4309   /* Check each successive cone */
4310   for (p = 1; p < numPoints; ++p) {
4311     PetscInt newMeetSize = 0;
4312 
4313     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
4314     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
4315     for (c = 0; c < dof; ++c) {
4316       const PetscInt point = mesh->cones[off+c];
4317 
4318       for (m = 0; m < meetSize; ++m) {
4319         if (point == meet[i][m]) {
4320           meet[1-i][newMeetSize++] = point;
4321           break;
4322         }
4323       }
4324     }
4325     meetSize = newMeetSize;
4326     i        = 1-i;
4327   }
4328   *numCoveringPoints = meetSize;
4329   *coveringPoints    = meet[i];
4330   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);CHKERRQ(ierr);
4331   PetscFunctionReturn(0);
4332 }
4333 
4334 /*@C
4335   DMPlexRestoreMeet - Restore an array for the meet of the set of points
4336 
4337   Not Collective
4338 
4339   Input Parameters:
4340 + dm - The DMPlex object
4341 . numPoints - The number of input points for the meet
4342 - points - The input points
4343 
4344   Output Parameters:
4345 + numCoveredPoints - The number of points in the meet
4346 - coveredPoints - The points in the meet
4347 
4348   Level: intermediate
4349 
4350   Fortran Notes:
4351   Since it returns an array, this routine is only available in Fortran 90, and you must
4352   include petsc.h90 in your code.
4353 
4354   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4355 
4356 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
4357 @*/
4358 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4359 {
4360   PetscErrorCode ierr;
4361 
4362   PetscFunctionBegin;
4363   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4364   if (points) PetscValidIntPointer(points,3);
4365   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
4366   PetscValidPointer(coveredPoints,5);
4367   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);CHKERRQ(ierr);
4368   if (numCoveredPoints) *numCoveredPoints = 0;
4369   PetscFunctionReturn(0);
4370 }
4371 
4372 /*@C
4373   DMPlexGetFullMeet - Get an array for the meet of the set of points
4374 
4375   Not Collective
4376 
4377   Input Parameters:
4378 + dm - The DMPlex object
4379 . numPoints - The number of input points for the meet
4380 - points - The input points
4381 
4382   Output Parameters:
4383 + numCoveredPoints - The number of points in the meet
4384 - coveredPoints - The points in the meet
4385 
4386   Level: intermediate
4387 
4388   Fortran Notes:
4389   Since it returns an array, this routine is only available in Fortran 90, and you must
4390   include petsc.h90 in your code.
4391 
4392   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4393 
4394 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
4395 @*/
4396 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4397 {
4398   DM_Plex       *mesh = (DM_Plex*) dm->data;
4399   PetscInt      *offsets, **closures;
4400   PetscInt      *meet[2];
4401   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
4402   PetscInt       p, h, c, m, mc;
4403   PetscErrorCode ierr;
4404 
4405   PetscFunctionBegin;
4406   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4407   PetscValidPointer(points, 3);
4408   PetscValidPointer(numCoveredPoints, 4);
4409   PetscValidPointer(coveredPoints, 5);
4410 
4411   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
4412   ierr    = PetscMalloc1(numPoints, &closures);CHKERRQ(ierr);
4413   ierr    = DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);CHKERRQ(ierr);
4414   mc      = mesh->maxConeSize;
4415   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
4416   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);CHKERRQ(ierr);
4417   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);CHKERRQ(ierr);
4418 
4419   for (p = 0; p < numPoints; ++p) {
4420     PetscInt closureSize;
4421 
4422     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
4423 
4424     offsets[p*(height+2)+0] = 0;
4425     for (h = 0; h < height+1; ++h) {
4426       PetscInt pStart, pEnd, i;
4427 
4428       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
4429       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
4430         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
4431           offsets[p*(height+2)+h+1] = i;
4432           break;
4433         }
4434       }
4435       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
4436     }
4437     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);
4438   }
4439   for (h = 0; h < height+1; ++h) {
4440     PetscInt dof;
4441 
4442     /* Copy in cone of first point */
4443     dof = offsets[h+1] - offsets[h];
4444     for (meetSize = 0; meetSize < dof; ++meetSize) {
4445       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
4446     }
4447     /* Check each successive cone */
4448     for (p = 1; p < numPoints && meetSize; ++p) {
4449       PetscInt newMeetSize = 0;
4450 
4451       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
4452       for (c = 0; c < dof; ++c) {
4453         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
4454 
4455         for (m = 0; m < meetSize; ++m) {
4456           if (point == meet[i][m]) {
4457             meet[1-i][newMeetSize++] = point;
4458             break;
4459           }
4460         }
4461       }
4462       meetSize = newMeetSize;
4463       i        = 1-i;
4464     }
4465     if (meetSize) break;
4466   }
4467   *numCoveredPoints = meetSize;
4468   *coveredPoints    = meet[i];
4469   for (p = 0; p < numPoints; ++p) {
4470     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
4471   }
4472   ierr = PetscFree(closures);CHKERRQ(ierr);
4473   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);CHKERRQ(ierr);
4474   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);CHKERRQ(ierr);
4475   PetscFunctionReturn(0);
4476 }
4477 
4478 /*@C
4479   DMPlexEqual - Determine if two DMs have the same topology
4480 
4481   Not Collective
4482 
4483   Input Parameters:
4484 + dmA - A DMPlex object
4485 - dmB - A DMPlex object
4486 
4487   Output Parameters:
4488 . equal - PETSC_TRUE if the topologies are identical
4489 
4490   Level: intermediate
4491 
4492   Notes:
4493   We are not solving graph isomorphism, so we do not permutation.
4494 
4495 .seealso: DMPlexGetCone()
4496 @*/
4497 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
4498 {
4499   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;
4500   PetscErrorCode ierr;
4501 
4502   PetscFunctionBegin;
4503   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
4504   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
4505   PetscValidPointer(equal, 3);
4506 
4507   *equal = PETSC_FALSE;
4508   ierr = DMPlexGetDepth(dmA, &depth);CHKERRQ(ierr);
4509   ierr = DMPlexGetDepth(dmB, &depthB);CHKERRQ(ierr);
4510   if (depth != depthB) PetscFunctionReturn(0);
4511   ierr = DMPlexGetChart(dmA, &pStart,  &pEnd);CHKERRQ(ierr);
4512   ierr = DMPlexGetChart(dmB, &pStartB, &pEndB);CHKERRQ(ierr);
4513   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0);
4514   for (p = pStart; p < pEnd; ++p) {
4515     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
4516     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
4517 
4518     ierr = DMPlexGetConeSize(dmA, p, &coneSize);CHKERRQ(ierr);
4519     ierr = DMPlexGetCone(dmA, p, &cone);CHKERRQ(ierr);
4520     ierr = DMPlexGetConeOrientation(dmA, p, &ornt);CHKERRQ(ierr);
4521     ierr = DMPlexGetConeSize(dmB, p, &coneSizeB);CHKERRQ(ierr);
4522     ierr = DMPlexGetCone(dmB, p, &coneB);CHKERRQ(ierr);
4523     ierr = DMPlexGetConeOrientation(dmB, p, &orntB);CHKERRQ(ierr);
4524     if (coneSize != coneSizeB) PetscFunctionReturn(0);
4525     for (c = 0; c < coneSize; ++c) {
4526       if (cone[c] != coneB[c]) PetscFunctionReturn(0);
4527       if (ornt[c] != orntB[c]) PetscFunctionReturn(0);
4528     }
4529     ierr = DMPlexGetSupportSize(dmA, p, &supportSize);CHKERRQ(ierr);
4530     ierr = DMPlexGetSupport(dmA, p, &support);CHKERRQ(ierr);
4531     ierr = DMPlexGetSupportSize(dmB, p, &supportSizeB);CHKERRQ(ierr);
4532     ierr = DMPlexGetSupport(dmB, p, &supportB);CHKERRQ(ierr);
4533     if (supportSize != supportSizeB) PetscFunctionReturn(0);
4534     for (s = 0; s < supportSize; ++s) {
4535       if (support[s] != supportB[s]) PetscFunctionReturn(0);
4536     }
4537   }
4538   *equal = PETSC_TRUE;
4539   PetscFunctionReturn(0);
4540 }
4541 
4542 /*@C
4543   DMPlexGetNumFaceVertices - Returns the number of vertices on a face
4544 
4545   Not Collective
4546 
4547   Input Parameters:
4548 + dm         - The DMPlex
4549 . cellDim    - The cell dimension
4550 - numCorners - The number of vertices on a cell
4551 
4552   Output Parameters:
4553 . numFaceVertices - The number of vertices on a face
4554 
4555   Level: developer
4556 
4557   Notes:
4558   Of course this can only work for a restricted set of symmetric shapes
4559 
4560 .seealso: DMPlexGetCone()
4561 @*/
4562 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
4563 {
4564   MPI_Comm       comm;
4565   PetscErrorCode ierr;
4566 
4567   PetscFunctionBegin;
4568   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4569   PetscValidPointer(numFaceVertices,4);
4570   switch (cellDim) {
4571   case 0:
4572     *numFaceVertices = 0;
4573     break;
4574   case 1:
4575     *numFaceVertices = 1;
4576     break;
4577   case 2:
4578     switch (numCorners) {
4579     case 3: /* triangle */
4580       *numFaceVertices = 2; /* Edge has 2 vertices */
4581       break;
4582     case 4: /* quadrilateral */
4583       *numFaceVertices = 2; /* Edge has 2 vertices */
4584       break;
4585     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
4586       *numFaceVertices = 3; /* Edge has 3 vertices */
4587       break;
4588     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
4589       *numFaceVertices = 3; /* Edge has 3 vertices */
4590       break;
4591     default:
4592       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
4593     }
4594     break;
4595   case 3:
4596     switch (numCorners) {
4597     case 4: /* tetradehdron */
4598       *numFaceVertices = 3; /* Face has 3 vertices */
4599       break;
4600     case 6: /* tet cohesive cells */
4601       *numFaceVertices = 4; /* Face has 4 vertices */
4602       break;
4603     case 8: /* hexahedron */
4604       *numFaceVertices = 4; /* Face has 4 vertices */
4605       break;
4606     case 9: /* tet cohesive Lagrange cells */
4607       *numFaceVertices = 6; /* Face has 6 vertices */
4608       break;
4609     case 10: /* quadratic tetrahedron */
4610       *numFaceVertices = 6; /* Face has 6 vertices */
4611       break;
4612     case 12: /* hex cohesive Lagrange cells */
4613       *numFaceVertices = 6; /* Face has 6 vertices */
4614       break;
4615     case 18: /* quadratic tet cohesive Lagrange cells */
4616       *numFaceVertices = 6; /* Face has 6 vertices */
4617       break;
4618     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
4619       *numFaceVertices = 9; /* Face has 9 vertices */
4620       break;
4621     default:
4622       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
4623     }
4624     break;
4625   default:
4626     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
4627   }
4628   PetscFunctionReturn(0);
4629 }
4630 
4631 /*@
4632   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
4633 
4634   Not Collective
4635 
4636   Input Parameter:
4637 . dm    - The DMPlex object
4638 
4639   Output Parameter:
4640 . depthLabel - The DMLabel recording point depth
4641 
4642   Level: developer
4643 
4644 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum(), DMPlexGetPointDepth(),
4645 @*/
4646 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
4647 {
4648   PetscFunctionBegin;
4649   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4650   PetscValidPointer(depthLabel, 2);
4651   *depthLabel = dm->depthLabel;
4652   PetscFunctionReturn(0);
4653 }
4654 
4655 /*@
4656   DMPlexGetDepth - Get the depth of the DAG representing this mesh
4657 
4658   Not Collective
4659 
4660   Input Parameter:
4661 . dm    - The DMPlex object
4662 
4663   Output Parameter:
4664 . depth - The number of strata (breadth first levels) in the DAG
4665 
4666   Level: developer
4667 
4668   Notes:
4669   This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel().
4670   The point depth is described more in detail in DMPlexGetDepthStratum().
4671   An empty mesh gives -1.
4672 
4673 .seealso: DMPlexGetDepthLabel(), DMPlexGetDepthStratum(), DMPlexGetPointDepth(), DMPlexSymmetrize()
4674 @*/
4675 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
4676 {
4677   DMLabel        label;
4678   PetscInt       d = 0;
4679   PetscErrorCode ierr;
4680 
4681   PetscFunctionBegin;
4682   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4683   PetscValidPointer(depth, 2);
4684   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4685   if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);}
4686   *depth = d-1;
4687   PetscFunctionReturn(0);
4688 }
4689 
4690 /*@
4691   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
4692 
4693   Not Collective
4694 
4695   Input Parameters:
4696 + dm           - The DMPlex object
4697 - stratumValue - The requested depth
4698 
4699   Output Parameters:
4700 + start - The first point at this depth
4701 - end   - One beyond the last point at this depth
4702 
4703   Notes:
4704   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
4705   often "vertices".  If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next
4706   higher dimension, e.g., "edges".
4707 
4708   Level: developer
4709 
4710 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth(), DMPlexGetDepthLabel(), DMPlexGetPointDepth(), DMPlexSymmetrize(), DMPlexInterpolate()
4711 @*/
4712 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
4713 {
4714   DMLabel        label;
4715   PetscInt       pStart, pEnd;
4716   PetscErrorCode ierr;
4717 
4718   PetscFunctionBegin;
4719   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4720   if (start) {PetscValidPointer(start, 3); *start = 0;}
4721   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
4722   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
4723   if (pStart == pEnd) PetscFunctionReturn(0);
4724   if (stratumValue < 0) {
4725     if (start) *start = pStart;
4726     if (end)   *end   = pEnd;
4727     PetscFunctionReturn(0);
4728   }
4729   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4730   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
4731   ierr = DMLabelGetStratumBounds(label, stratumValue, start, end);CHKERRQ(ierr);
4732   PetscFunctionReturn(0);
4733 }
4734 
4735 /*@
4736   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
4737 
4738   Not Collective
4739 
4740   Input Parameters:
4741 + dm           - The DMPlex object
4742 - stratumValue - The requested height
4743 
4744   Output Parameters:
4745 + start - The first point at this height
4746 - end   - One beyond the last point at this height
4747 
4748   Notes:
4749   Height indexing is related to topological codimension.  Height stratum 0 contains the highest topological dimension
4750   points, often called "cells" or "elements".  If the mesh is "interpolated" (see DMPlexInterpolate()), then height
4751   stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
4752 
4753   Level: developer
4754 
4755 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth(), DMPlexGetPointHeight()
4756 @*/
4757 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
4758 {
4759   DMLabel        label;
4760   PetscInt       depth, pStart, pEnd;
4761   PetscErrorCode ierr;
4762 
4763   PetscFunctionBegin;
4764   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4765   if (start) {PetscValidPointer(start, 3); *start = 0;}
4766   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
4767   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
4768   if (pStart == pEnd) PetscFunctionReturn(0);
4769   if (stratumValue < 0) {
4770     if (start) *start = pStart;
4771     if (end)   *end   = pEnd;
4772     PetscFunctionReturn(0);
4773   }
4774   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4775   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
4776   ierr = DMLabelGetNumValues(label, &depth);CHKERRQ(ierr);
4777   ierr = DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);CHKERRQ(ierr);
4778   PetscFunctionReturn(0);
4779 }
4780 
4781 /*@
4782   DMPlexGetPointDepth - Get the depth of a given point
4783 
4784   Not Collective
4785 
4786   Input Parameters:
4787 + dm    - The DMPlex object
4788 - point - The point
4789 
4790   Output Parameter:
4791 . depth - The depth of the point
4792 
4793   Level: intermediate
4794 
4795 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexGetPointHeight()
4796 @*/
4797 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
4798 {
4799   PetscErrorCode ierr;
4800 
4801   PetscFunctionBegin;
4802   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4803   PetscValidIntPointer(depth, 3);
4804   ierr = DMLabelGetValue(dm->depthLabel, point, depth);CHKERRQ(ierr);
4805   PetscFunctionReturn(0);
4806 }
4807 
4808 /*@
4809   DMPlexGetPointHeight - Get the height of a given point
4810 
4811   Not Collective
4812 
4813   Input Parameters:
4814 + dm    - The DMPlex object
4815 - point - The point
4816 
4817   Output Parameter:
4818 . height - The height of the point
4819 
4820   Level: intermediate
4821 
4822 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexGetPointDepth()
4823 @*/
4824 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
4825 {
4826   PetscInt       n, pDepth;
4827   PetscErrorCode ierr;
4828 
4829   PetscFunctionBegin;
4830   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4831   PetscValidIntPointer(height, 3);
4832   ierr = DMLabelGetNumValues(dm->depthLabel, &n);CHKERRQ(ierr);
4833   ierr = DMLabelGetValue(dm->depthLabel, point, &pDepth);CHKERRQ(ierr);
4834   *height = n - 1 - pDepth;  /* DAG depth is n-1 */
4835   PetscFunctionReturn(0);
4836 }
4837 
4838 /*@
4839   DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell
4840 
4841   Not Collective
4842 
4843   Input Parameter:
4844 . dm - The DMPlex object
4845 
4846   Output Parameter:
4847 . celltypeLabel - The DMLabel recording cell polytope type
4848 
4849   Note: This function will trigger automatica computation of cell types. This can be disabled by calling
4850   DMCreateLabel(dm, "celltype") beforehand.
4851 
4852   Level: developer
4853 
4854 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMCreateLabel()
4855 @*/
4856 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
4857 {
4858   PetscErrorCode ierr;
4859 
4860   PetscFunctionBegin;
4861   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4862   PetscValidPointer(celltypeLabel, 2);
4863   if (!dm->celltypeLabel) {ierr = DMPlexComputeCellTypes(dm);CHKERRQ(ierr);}
4864   *celltypeLabel = dm->celltypeLabel;
4865   PetscFunctionReturn(0);
4866 }
4867 
4868 /*@
4869   DMPlexGetCellType - Get the polytope type of a given cell
4870 
4871   Not Collective
4872 
4873   Input Parameters:
4874 + dm   - The DMPlex object
4875 - cell - The cell
4876 
4877   Output Parameter:
4878 . celltype - The polytope type of the cell
4879 
4880   Level: intermediate
4881 
4882 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth()
4883 @*/
4884 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
4885 {
4886   DMLabel        label;
4887   PetscInt       ct;
4888   PetscErrorCode ierr;
4889 
4890   PetscFunctionBegin;
4891   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4892   PetscValidPointer(celltype, 3);
4893   ierr = DMPlexGetCellTypeLabel(dm, &label);CHKERRQ(ierr);
4894   ierr = DMLabelGetValue(label, cell, &ct);CHKERRQ(ierr);
4895   if (ct < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %D has not been assigned a cell type", cell);
4896   *celltype = (DMPolytopeType) ct;
4897   PetscFunctionReturn(0);
4898 }
4899 
4900 /*@
4901   DMPlexSetCellType - Set the polytope type of a given cell
4902 
4903   Not Collective
4904 
4905   Input Parameters:
4906 + dm   - The DMPlex object
4907 . cell - The cell
4908 - celltype - The polytope type of the cell
4909 
4910   Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function
4911   is executed. This function will override the computed type. However, if automatic classification will not succeed
4912   and a user wants to manually specify all types, the classification must be disabled by calling
4913   DMCreaateLabel(dm, "celltype") before getting or setting any cell types.
4914 
4915   Level: advanced
4916 
4917 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexComputeCellTypes(), DMCreateLabel()
4918 @*/
4919 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
4920 {
4921   DMLabel        label;
4922   PetscErrorCode ierr;
4923 
4924   PetscFunctionBegin;
4925   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4926   ierr = DMPlexGetCellTypeLabel(dm, &label);CHKERRQ(ierr);
4927   ierr = DMLabelSetValue(label, cell, celltype);CHKERRQ(ierr);
4928   PetscFunctionReturn(0);
4929 }
4930 
4931 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
4932 {
4933   PetscSection   section, s;
4934   Mat            m;
4935   PetscInt       maxHeight;
4936   PetscErrorCode ierr;
4937 
4938   PetscFunctionBegin;
4939   ierr = DMClone(dm, cdm);CHKERRQ(ierr);
4940   ierr = DMPlexGetMaxProjectionHeight(dm, &maxHeight);CHKERRQ(ierr);
4941   ierr = DMPlexSetMaxProjectionHeight(*cdm, maxHeight);CHKERRQ(ierr);
4942   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
4943   ierr = DMSetLocalSection(*cdm, section);CHKERRQ(ierr);
4944   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
4945   ierr = PetscSectionCreate(PETSC_COMM_SELF, &s);CHKERRQ(ierr);
4946   ierr = MatCreate(PETSC_COMM_SELF, &m);CHKERRQ(ierr);
4947   ierr = DMSetDefaultConstraints(*cdm, s, m);CHKERRQ(ierr);
4948   ierr = PetscSectionDestroy(&s);CHKERRQ(ierr);
4949   ierr = MatDestroy(&m);CHKERRQ(ierr);
4950 
4951   ierr = DMSetNumFields(*cdm, 1);CHKERRQ(ierr);
4952   ierr = DMCreateDS(*cdm);CHKERRQ(ierr);
4953   PetscFunctionReturn(0);
4954 }
4955 
4956 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
4957 {
4958   Vec            coordsLocal;
4959   DM             coordsDM;
4960   PetscErrorCode ierr;
4961 
4962   PetscFunctionBegin;
4963   *field = NULL;
4964   ierr = DMGetCoordinatesLocal(dm,&coordsLocal);CHKERRQ(ierr);
4965   ierr = DMGetCoordinateDM(dm,&coordsDM);CHKERRQ(ierr);
4966   if (coordsLocal && coordsDM) {
4967     ierr = DMFieldCreateDS(coordsDM, 0, coordsLocal, field);CHKERRQ(ierr);
4968   }
4969   PetscFunctionReturn(0);
4970 }
4971 
4972 /*@C
4973   DMPlexGetConeSection - Return a section which describes the layout of cone data
4974 
4975   Not Collective
4976 
4977   Input Parameters:
4978 . dm        - The DMPlex object
4979 
4980   Output Parameter:
4981 . section - The PetscSection object
4982 
4983   Level: developer
4984 
4985 .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
4986 @*/
4987 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
4988 {
4989   DM_Plex *mesh = (DM_Plex*) dm->data;
4990 
4991   PetscFunctionBegin;
4992   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4993   if (section) *section = mesh->coneSection;
4994   PetscFunctionReturn(0);
4995 }
4996 
4997 /*@C
4998   DMPlexGetSupportSection - Return a section which describes the layout of support data
4999 
5000   Not Collective
5001 
5002   Input Parameters:
5003 . dm        - The DMPlex object
5004 
5005   Output Parameter:
5006 . section - The PetscSection object
5007 
5008   Level: developer
5009 
5010 .seealso: DMPlexGetConeSection()
5011 @*/
5012 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
5013 {
5014   DM_Plex *mesh = (DM_Plex*) dm->data;
5015 
5016   PetscFunctionBegin;
5017   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5018   if (section) *section = mesh->supportSection;
5019   PetscFunctionReturn(0);
5020 }
5021 
5022 /*@C
5023   DMPlexGetCones - Return cone data
5024 
5025   Not Collective
5026 
5027   Input Parameters:
5028 . dm        - The DMPlex object
5029 
5030   Output Parameter:
5031 . cones - The cone for each point
5032 
5033   Level: developer
5034 
5035 .seealso: DMPlexGetConeSection()
5036 @*/
5037 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
5038 {
5039   DM_Plex *mesh = (DM_Plex*) dm->data;
5040 
5041   PetscFunctionBegin;
5042   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5043   if (cones) *cones = mesh->cones;
5044   PetscFunctionReturn(0);
5045 }
5046 
5047 /*@C
5048   DMPlexGetConeOrientations - Return cone orientation data
5049 
5050   Not Collective
5051 
5052   Input Parameters:
5053 . dm        - The DMPlex object
5054 
5055   Output Parameter:
5056 . coneOrientations - The array of cone orientations for all points
5057 
5058   Level: developer
5059 
5060   Notes:
5061   The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation().
5062 
5063   The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation().
5064 
5065 .seealso: DMPlexGetConeSection(), DMPlexGetConeOrientation()
5066 @*/
5067 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
5068 {
5069   DM_Plex *mesh = (DM_Plex*) dm->data;
5070 
5071   PetscFunctionBegin;
5072   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5073   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
5074   PetscFunctionReturn(0);
5075 }
5076 
5077 /******************************** FEM Support **********************************/
5078 
5079 /*
5080  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
5081  representing a line in the section.
5082 */
5083 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k)
5084 {
5085   PetscErrorCode ierr;
5086 
5087   PetscFunctionBeginHot;
5088   ierr = PetscSectionGetFieldComponents(section, field, Nc);CHKERRQ(ierr);
5089   if (line < 0) {
5090     *k = 0;
5091     *Nc = 0;
5092   } else if (vertexchart) {            /* If we only have a vertex chart, we must have degree k=1 */
5093     *k = 1;
5094   } else {                      /* Assume the full interpolated mesh is in the chart; lines in particular */
5095     /* An order k SEM disc has k-1 dofs on an edge */
5096     ierr = PetscSectionGetFieldDof(section, line, field, k);CHKERRQ(ierr);
5097     *k = *k / *Nc + 1;
5098   }
5099   PetscFunctionReturn(0);
5100 }
5101 
5102 /*@
5103 
5104   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
5105   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
5106   section provided (or the section of the DM).
5107 
5108   Input Parameters:
5109 + dm      - The DM
5110 . point   - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE
5111 - section - The PetscSection to reorder, or NULL for the default section
5112 
5113   Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
5114   degree of the basis.
5115 
5116   Example:
5117   A typical interpolated single-quad mesh might order points as
5118 .vb
5119   [c0, v1, v2, v3, v4, e5, e6, e7, e8]
5120 
5121   v4 -- e6 -- v3
5122   |           |
5123   e7    c0    e8
5124   |           |
5125   v1 -- e5 -- v2
5126 .ve
5127 
5128   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
5129   dofs in the order of points, e.g.,
5130 .vb
5131     c0 -> [0,1,2,3]
5132     v1 -> [4]
5133     ...
5134     e5 -> [8, 9]
5135 .ve
5136 
5137   which corresponds to the dofs
5138 .vb
5139     6   10  11  7
5140     13  2   3   15
5141     12  0   1   14
5142     4   8   9   5
5143 .ve
5144 
5145   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
5146 .vb
5147   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
5148 .ve
5149 
5150   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
5151 .vb
5152    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
5153 .ve
5154 
5155   Level: developer
5156 
5157 .seealso: DMGetLocalSection(), PetscSectionSetClosurePermutation(), DMSetGlobalSection()
5158 @*/
5159 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
5160 {
5161   DMLabel        label;
5162   PetscInt       dim, depth = -1, eStart = -1, Nf;
5163   PetscBool      vertexchart;
5164   PetscErrorCode ierr;
5165 
5166   PetscFunctionBegin;
5167   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5168   if (dim < 1) PetscFunctionReturn(0);
5169   if (point < 0) {
5170     PetscInt sStart,sEnd;
5171 
5172     ierr = DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd);CHKERRQ(ierr);
5173     point = sEnd-sStart ? sStart : point;
5174   }
5175   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
5176   if (point >= 0) { ierr = DMLabelGetValue(label, point, &depth);CHKERRQ(ierr); }
5177   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5178   if (depth == 1) {eStart = point;}
5179   else if  (depth == dim) {
5180     const PetscInt *cone;
5181 
5182     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
5183     if (dim == 2) eStart = cone[0];
5184     else if (dim == 3) {
5185       const PetscInt *cone2;
5186       ierr = DMPlexGetCone(dm, cone[0], &cone2);CHKERRQ(ierr);
5187       eStart = cone2[0];
5188     } 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);
5189   } 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);
5190   {                             /* Determine whether the chart covers all points or just vertices. */
5191     PetscInt pStart,pEnd,cStart,cEnd;
5192     ierr = DMPlexGetDepthStratum(dm,0,&pStart,&pEnd);CHKERRQ(ierr);
5193     ierr = PetscSectionGetChart(section,&cStart,&cEnd);CHKERRQ(ierr);
5194     if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Just vertices */
5195     else vertexchart = PETSC_FALSE;                                 /* Assume all interpolated points are in chart */
5196   }
5197   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
5198   for (PetscInt d=1; d<=dim; d++) {
5199     PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
5200     PetscInt *perm;
5201 
5202     for (f = 0; f < Nf; ++f) {
5203       ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
5204       size += PetscPowInt(k+1, d)*Nc;
5205     }
5206     ierr = PetscMalloc1(size, &perm);CHKERRQ(ierr);
5207     for (f = 0; f < Nf; ++f) {
5208       switch (d) {
5209       case 1:
5210         ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
5211         /*
5212          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
5213          We want              [ vtx0; edge of length k-1; vtx1 ]
5214          */
5215         for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset;
5216         for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset;
5217         for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset;
5218         foffset = offset;
5219         break;
5220       case 2:
5221         /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
5222         ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
5223         /* The SEM order is
5224 
5225          v_lb, {e_b}, v_rb,
5226          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
5227          v_lt, reverse {e_t}, v_rt
5228          */
5229         {
5230           const PetscInt of   = 0;
5231           const PetscInt oeb  = of   + PetscSqr(k-1);
5232           const PetscInt oer  = oeb  + (k-1);
5233           const PetscInt oet  = oer  + (k-1);
5234           const PetscInt oel  = oet  + (k-1);
5235           const PetscInt ovlb = oel  + (k-1);
5236           const PetscInt ovrb = ovlb + 1;
5237           const PetscInt ovrt = ovrb + 1;
5238           const PetscInt ovlt = ovrt + 1;
5239           PetscInt       o;
5240 
5241           /* bottom */
5242           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
5243           for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5244           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
5245           /* middle */
5246           for (i = 0; i < k-1; ++i) {
5247             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
5248             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;
5249             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
5250           }
5251           /* top */
5252           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
5253           for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5254           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
5255           foffset = offset;
5256         }
5257         break;
5258       case 3:
5259         /* The original hex closure is
5260 
5261          {c,
5262          f_b, f_t, f_f, f_b, f_r, f_l,
5263          e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
5264          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
5265          */
5266         ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
5267         /* The SEM order is
5268          Bottom Slice
5269          v_blf, {e^{(k-1)-n}_bf}, v_brf,
5270          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
5271          v_blb, {e_bb}, v_brb,
5272 
5273          Middle Slice (j)
5274          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
5275          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
5276          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
5277 
5278          Top Slice
5279          v_tlf, {e_tf}, v_trf,
5280          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
5281          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
5282          */
5283         {
5284           const PetscInt oc    = 0;
5285           const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
5286           const PetscInt oft   = ofb   + PetscSqr(k-1);
5287           const PetscInt off   = oft   + PetscSqr(k-1);
5288           const PetscInt ofk   = off   + PetscSqr(k-1);
5289           const PetscInt ofr   = ofk   + PetscSqr(k-1);
5290           const PetscInt ofl   = ofr   + PetscSqr(k-1);
5291           const PetscInt oebl  = ofl   + PetscSqr(k-1);
5292           const PetscInt oebb  = oebl  + (k-1);
5293           const PetscInt oebr  = oebb  + (k-1);
5294           const PetscInt oebf  = oebr  + (k-1);
5295           const PetscInt oetf  = oebf  + (k-1);
5296           const PetscInt oetr  = oetf  + (k-1);
5297           const PetscInt oetb  = oetr  + (k-1);
5298           const PetscInt oetl  = oetb  + (k-1);
5299           const PetscInt oerf  = oetl  + (k-1);
5300           const PetscInt oelf  = oerf  + (k-1);
5301           const PetscInt oelb  = oelf  + (k-1);
5302           const PetscInt oerb  = oelb  + (k-1);
5303           const PetscInt ovblf = oerb  + (k-1);
5304           const PetscInt ovblb = ovblf + 1;
5305           const PetscInt ovbrb = ovblb + 1;
5306           const PetscInt ovbrf = ovbrb + 1;
5307           const PetscInt ovtlf = ovbrf + 1;
5308           const PetscInt ovtrf = ovtlf + 1;
5309           const PetscInt ovtrb = ovtrf + 1;
5310           const PetscInt ovtlb = ovtrb + 1;
5311           PetscInt       o, n;
5312 
5313           /* Bottom Slice */
5314           /*   bottom */
5315           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
5316           for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5317           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
5318           /*   middle */
5319           for (i = 0; i < k-1; ++i) {
5320             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
5321             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;}
5322             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
5323           }
5324           /*   top */
5325           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
5326           for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5327           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
5328 
5329           /* Middle Slice */
5330           for (j = 0; j < k-1; ++j) {
5331             /*   bottom */
5332             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
5333             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;
5334             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
5335             /*   middle */
5336             for (i = 0; i < k-1; ++i) {
5337               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
5338               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;
5339               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
5340             }
5341             /*   top */
5342             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
5343             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;
5344             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
5345           }
5346 
5347           /* Top Slice */
5348           /*   bottom */
5349           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
5350           for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5351           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
5352           /*   middle */
5353           for (i = 0; i < k-1; ++i) {
5354             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
5355             for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
5356             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
5357           }
5358           /*   top */
5359           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
5360           for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5361           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
5362 
5363           foffset = offset;
5364         }
5365         break;
5366       default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", d);
5367       }
5368     }
5369     if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
5370     /* Check permutation */
5371     {
5372       PetscInt *check;
5373 
5374       ierr = PetscMalloc1(size, &check);CHKERRQ(ierr);
5375       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]);}
5376       for (i = 0; i < size; ++i) check[perm[i]] = i;
5377       for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
5378       ierr = PetscFree(check);CHKERRQ(ierr);
5379     }
5380     ierr = PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm);CHKERRQ(ierr);
5381   }
5382   PetscFunctionReturn(0);
5383 }
5384 
5385 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
5386 {
5387   PetscDS        prob;
5388   PetscInt       depth, Nf, h;
5389   DMLabel        label;
5390   PetscErrorCode ierr;
5391 
5392   PetscFunctionBeginHot;
5393   ierr = DMGetDS(dm, &prob);CHKERRQ(ierr);
5394   Nf      = prob->Nf;
5395   label   = dm->depthLabel;
5396   *dspace = NULL;
5397   if (field < Nf) {
5398     PetscObject disc = prob->disc[field];
5399 
5400     if (disc->classid == PETSCFE_CLASSID) {
5401       PetscDualSpace dsp;
5402 
5403       ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr);
5404       ierr = DMLabelGetNumValues(label,&depth);CHKERRQ(ierr);
5405       ierr = DMLabelGetValue(label,point,&h);CHKERRQ(ierr);
5406       h    = depth - 1 - h;
5407       if (h) {
5408         ierr = PetscDualSpaceGetHeightSubspace(dsp,h,dspace);CHKERRQ(ierr);
5409       } else {
5410         *dspace = dsp;
5411       }
5412     }
5413   }
5414   PetscFunctionReturn(0);
5415 }
5416 
5417 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5418 {
5419   PetscScalar    *array, *vArray;
5420   const PetscInt *cone, *coneO;
5421   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
5422   PetscErrorCode  ierr;
5423 
5424   PetscFunctionBeginHot;
5425   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5426   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
5427   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
5428   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
5429   if (!values || !*values) {
5430     if ((point >= pStart) && (point < pEnd)) {
5431       PetscInt dof;
5432 
5433       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5434       size += dof;
5435     }
5436     for (p = 0; p < numPoints; ++p) {
5437       const PetscInt cp = cone[p];
5438       PetscInt       dof;
5439 
5440       if ((cp < pStart) || (cp >= pEnd)) continue;
5441       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
5442       size += dof;
5443     }
5444     if (!values) {
5445       if (csize) *csize = size;
5446       PetscFunctionReturn(0);
5447     }
5448     ierr = DMGetWorkArray(dm, size, MPIU_SCALAR, &array);CHKERRQ(ierr);
5449   } else {
5450     array = *values;
5451   }
5452   size = 0;
5453   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
5454   if ((point >= pStart) && (point < pEnd)) {
5455     PetscInt     dof, off, d;
5456     PetscScalar *varr;
5457 
5458     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5459     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5460     varr = &vArray[off];
5461     for (d = 0; d < dof; ++d, ++offset) {
5462       array[offset] = varr[d];
5463     }
5464     size += dof;
5465   }
5466   for (p = 0; p < numPoints; ++p) {
5467     const PetscInt cp = cone[p];
5468     PetscInt       o  = coneO[p];
5469     PetscInt       dof, off, d;
5470     PetscScalar   *varr;
5471 
5472     if ((cp < pStart) || (cp >= pEnd)) continue;
5473     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
5474     ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
5475     varr = &vArray[off];
5476     if (o >= 0) {
5477       for (d = 0; d < dof; ++d, ++offset) {
5478         array[offset] = varr[d];
5479       }
5480     } else {
5481       for (d = dof-1; d >= 0; --d, ++offset) {
5482         array[offset] = varr[d];
5483       }
5484     }
5485     size += dof;
5486   }
5487   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
5488   if (!*values) {
5489     if (csize) *csize = size;
5490     *values = array;
5491   } else {
5492     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
5493     *csize = size;
5494   }
5495   PetscFunctionReturn(0);
5496 }
5497 
5498 /* Compress out points not in the section */
5499 PETSC_STATIC_INLINE PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
5500 {
5501   const PetscInt np = *numPoints;
5502   PetscInt       pStart, pEnd, p, q;
5503   PetscErrorCode ierr;
5504 
5505   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5506   for (p = 0, q = 0; p < np; ++p) {
5507     const PetscInt r = points[p*2];
5508     if ((r >= pStart) && (r < pEnd)) {
5509       points[q*2]   = r;
5510       points[q*2+1] = points[p*2+1];
5511       ++q;
5512     }
5513   }
5514   *numPoints = q;
5515   return 0;
5516 }
5517 
5518 /* Compressed closure does not apply closure permutation */
5519 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5520 {
5521   const PetscInt *cla = NULL;
5522   PetscInt       np, *pts = NULL;
5523   PetscErrorCode ierr;
5524 
5525   PetscFunctionBeginHot;
5526   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);CHKERRQ(ierr);
5527   if (*clPoints) {
5528     PetscInt dof, off;
5529 
5530     ierr = PetscSectionGetDof(*clSec, point, &dof);CHKERRQ(ierr);
5531     ierr = PetscSectionGetOffset(*clSec, point, &off);CHKERRQ(ierr);
5532     ierr = ISGetIndices(*clPoints, &cla);CHKERRQ(ierr);
5533     np   = dof/2;
5534     pts  = (PetscInt *) &cla[off];
5535   } else {
5536     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);CHKERRQ(ierr);
5537     ierr = CompressPoints_Private(section, &np, pts);CHKERRQ(ierr);
5538   }
5539   *numPoints = np;
5540   *points    = pts;
5541   *clp       = cla;
5542   PetscFunctionReturn(0);
5543 }
5544 
5545 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5546 {
5547   PetscErrorCode ierr;
5548 
5549   PetscFunctionBeginHot;
5550   if (!*clPoints) {
5551     ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);CHKERRQ(ierr);
5552   } else {
5553     ierr = ISRestoreIndices(*clPoints, clp);CHKERRQ(ierr);
5554   }
5555   *numPoints = 0;
5556   *points    = NULL;
5557   *clSec     = NULL;
5558   *clPoints  = NULL;
5559   *clp       = NULL;
5560   PetscFunctionReturn(0);
5561 }
5562 
5563 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[])
5564 {
5565   PetscInt          offset = 0, p;
5566   const PetscInt    **perms = NULL;
5567   const PetscScalar **flips = NULL;
5568   PetscErrorCode    ierr;
5569 
5570   PetscFunctionBeginHot;
5571   *size = 0;
5572   ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5573   for (p = 0; p < numPoints; p++) {
5574     const PetscInt    point = points[2*p];
5575     const PetscInt    *perm = perms ? perms[p] : NULL;
5576     const PetscScalar *flip = flips ? flips[p] : NULL;
5577     PetscInt          dof, off, d;
5578     const PetscScalar *varr;
5579 
5580     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5581     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5582     varr = &vArray[off];
5583     if (clperm) {
5584       if (perm) {
5585         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
5586       } else {
5587         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
5588       }
5589       if (flip) {
5590         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
5591       }
5592     } else {
5593       if (perm) {
5594         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
5595       } else {
5596         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
5597       }
5598       if (flip) {
5599         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
5600       }
5601     }
5602     offset += dof;
5603   }
5604   ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5605   *size = offset;
5606   PetscFunctionReturn(0);
5607 }
5608 
5609 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[])
5610 {
5611   PetscInt          offset = 0, f;
5612   PetscErrorCode    ierr;
5613 
5614   PetscFunctionBeginHot;
5615   *size = 0;
5616   for (f = 0; f < numFields; ++f) {
5617     PetscInt          p;
5618     const PetscInt    **perms = NULL;
5619     const PetscScalar **flips = NULL;
5620 
5621     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5622     for (p = 0; p < numPoints; p++) {
5623       const PetscInt    point = points[2*p];
5624       PetscInt          fdof, foff, b;
5625       const PetscScalar *varr;
5626       const PetscInt    *perm = perms ? perms[p] : NULL;
5627       const PetscScalar *flip = flips ? flips[p] : NULL;
5628 
5629       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5630       ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
5631       varr = &vArray[foff];
5632       if (clperm) {
5633         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
5634         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
5635         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
5636       } else {
5637         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
5638         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
5639         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
5640       }
5641       offset += fdof;
5642     }
5643     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5644   }
5645   *size = offset;
5646   PetscFunctionReturn(0);
5647 }
5648 
5649 /*@C
5650   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
5651 
5652   Not collective
5653 
5654   Input Parameters:
5655 + dm - The DM
5656 . section - The section describing the layout in v, or NULL to use the default section
5657 . v - The local vector
5658 - point - The point in the DM
5659 
5660   Input/Output Parameters:
5661 + csize  - The size of the input values array, or NULL; on output the number of values in the closure
5662 - values - An array to use for the values, or NULL to have it allocated automatically;
5663            if the user provided NULL, it is a borrowed array and should not be freed
5664 
5665 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
5666 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
5667 $ assembly function, and a user may already have allocated storage for this operation.
5668 $
5669 $ A typical use could be
5670 $
5671 $  values = NULL;
5672 $  ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
5673 $  for (cl = 0; cl < clSize; ++cl) {
5674 $    <Compute on closure>
5675 $  }
5676 $  ierr = DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
5677 $
5678 $ or
5679 $
5680 $  PetscMalloc1(clMaxSize, &values);
5681 $  for (p = pStart; p < pEnd; ++p) {
5682 $    clSize = clMaxSize;
5683 $    ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
5684 $    for (cl = 0; cl < clSize; ++cl) {
5685 $      <Compute on closure>
5686 $    }
5687 $  }
5688 $  PetscFree(values);
5689 
5690   Fortran Notes:
5691   Since it returns an array, this routine is only available in Fortran 90, and you must
5692   include petsc.h90 in your code.
5693 
5694   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5695 
5696   Level: intermediate
5697 
5698 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5699 @*/
5700 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5701 {
5702   PetscSection       clSection;
5703   IS                 clPoints;
5704   PetscInt          *points = NULL;
5705   const PetscInt    *clp, *perm;
5706   PetscInt           depth, numFields, numPoints, asize;
5707   PetscErrorCode     ierr;
5708 
5709   PetscFunctionBeginHot;
5710   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5711   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5712   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5713   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5714   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5715   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5716   if (depth == 1 && numFields < 2) {
5717     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
5718     PetscFunctionReturn(0);
5719   }
5720   /* Get points */
5721   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5722   /* Get sizes */
5723   asize = 0;
5724   for (PetscInt p = 0; p < numPoints*2; p += 2) {
5725     PetscInt dof;
5726     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5727     asize += dof;
5728   }
5729   if (values) {
5730     const PetscScalar *vArray;
5731     PetscInt          size;
5732 
5733     if (*values) {
5734       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);
5735     } else {ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, values);CHKERRQ(ierr);}
5736     ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm);CHKERRQ(ierr);
5737     ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr);
5738     /* Get values */
5739     if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values);CHKERRQ(ierr);}
5740     else               {ierr = DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values);CHKERRQ(ierr);}
5741     if (PetscUnlikely(asize != size)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %D does not match Vec closure size %D", asize, size);
5742     /* Cleanup array */
5743     ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr);
5744   }
5745   if (csize) *csize = asize;
5746   /* Cleanup points */
5747   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5748   PetscFunctionReturn(0);
5749 }
5750 
5751 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
5752 {
5753   DMLabel            depthLabel;
5754   PetscSection       clSection;
5755   IS                 clPoints;
5756   PetscScalar       *array;
5757   const PetscScalar *vArray;
5758   PetscInt          *points = NULL;
5759   const PetscInt    *clp, *perm = NULL;
5760   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;
5761   PetscErrorCode     ierr;
5762 
5763   PetscFunctionBeginHot;
5764   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5765   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5766   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5767   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5768   ierr = DMPlexGetDepth(dm, &mdepth);CHKERRQ(ierr);
5769   ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr);
5770   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5771   if (mdepth == 1 && numFields < 2) {
5772     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
5773     PetscFunctionReturn(0);
5774   }
5775   /* Get points */
5776   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5777   for (clsize=0,p=0; p<Np; p++) {
5778     PetscInt dof;
5779     ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr);
5780     clsize += dof;
5781   }
5782   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm);CHKERRQ(ierr);
5783   /* Filter points */
5784   for (p = 0; p < numPoints*2; p += 2) {
5785     PetscInt dep;
5786 
5787     ierr = DMLabelGetValue(depthLabel, points[p], &dep);CHKERRQ(ierr);
5788     if (dep != depth) continue;
5789     points[Np*2+0] = points[p];
5790     points[Np*2+1] = points[p+1];
5791     ++Np;
5792   }
5793   /* Get array */
5794   if (!values || !*values) {
5795     PetscInt asize = 0, dof;
5796 
5797     for (p = 0; p < Np*2; p += 2) {
5798       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5799       asize += dof;
5800     }
5801     if (!values) {
5802       ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5803       if (csize) *csize = asize;
5804       PetscFunctionReturn(0);
5805     }
5806     ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);CHKERRQ(ierr);
5807   } else {
5808     array = *values;
5809   }
5810   ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr);
5811   /* Get values */
5812   if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array);CHKERRQ(ierr);}
5813   else               {ierr = DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array);CHKERRQ(ierr);}
5814   /* Cleanup points */
5815   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5816   /* Cleanup array */
5817   ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr);
5818   if (!*values) {
5819     if (csize) *csize = size;
5820     *values = array;
5821   } else {
5822     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
5823     *csize = size;
5824   }
5825   PetscFunctionReturn(0);
5826 }
5827 
5828 /*@C
5829   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
5830 
5831   Not collective
5832 
5833   Input Parameters:
5834 + dm - The DM
5835 . section - The section describing the layout in v, or NULL to use the default section
5836 . v - The local vector
5837 . point - The point in the DM
5838 . csize - The number of values in the closure, or NULL
5839 - values - The array of values, which is a borrowed array and should not be freed
5840 
5841   Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()
5842 
5843   Fortran Notes:
5844   Since it returns an array, this routine is only available in Fortran 90, and you must
5845   include petsc.h90 in your code.
5846 
5847   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5848 
5849   Level: intermediate
5850 
5851 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5852 @*/
5853 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5854 {
5855   PetscInt       size = 0;
5856   PetscErrorCode ierr;
5857 
5858   PetscFunctionBegin;
5859   /* Should work without recalculating size */
5860   ierr = DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);CHKERRQ(ierr);
5861   *values = NULL;
5862   PetscFunctionReturn(0);
5863 }
5864 
5865 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
5866 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
5867 
5868 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[])
5869 {
5870   PetscInt        cdof;   /* The number of constraints on this point */
5871   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5872   PetscScalar    *a;
5873   PetscInt        off, cind = 0, k;
5874   PetscErrorCode  ierr;
5875 
5876   PetscFunctionBegin;
5877   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5878   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5879   a    = &array[off];
5880   if (!cdof || setBC) {
5881     if (clperm) {
5882       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
5883       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
5884     } else {
5885       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
5886       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
5887     }
5888   } else {
5889     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5890     if (clperm) {
5891       if (perm) {for (k = 0; k < dof; ++k) {
5892           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5893           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
5894         }
5895       } else {
5896         for (k = 0; k < dof; ++k) {
5897           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5898           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
5899         }
5900       }
5901     } else {
5902       if (perm) {
5903         for (k = 0; k < dof; ++k) {
5904           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5905           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
5906         }
5907       } else {
5908         for (k = 0; k < dof; ++k) {
5909           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5910           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
5911         }
5912       }
5913     }
5914   }
5915   PetscFunctionReturn(0);
5916 }
5917 
5918 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[])
5919 {
5920   PetscInt        cdof;   /* The number of constraints on this point */
5921   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5922   PetscScalar    *a;
5923   PetscInt        off, cind = 0, k;
5924   PetscErrorCode  ierr;
5925 
5926   PetscFunctionBegin;
5927   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5928   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5929   a    = &array[off];
5930   if (cdof) {
5931     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5932     if (clperm) {
5933       if (perm) {
5934         for (k = 0; k < dof; ++k) {
5935           if ((cind < cdof) && (k == cdofs[cind])) {
5936             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
5937             cind++;
5938           }
5939         }
5940       } else {
5941         for (k = 0; k < dof; ++k) {
5942           if ((cind < cdof) && (k == cdofs[cind])) {
5943             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
5944             cind++;
5945           }
5946         }
5947       }
5948     } else {
5949       if (perm) {
5950         for (k = 0; k < dof; ++k) {
5951           if ((cind < cdof) && (k == cdofs[cind])) {
5952             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
5953             cind++;
5954           }
5955         }
5956       } else {
5957         for (k = 0; k < dof; ++k) {
5958           if ((cind < cdof) && (k == cdofs[cind])) {
5959             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
5960             cind++;
5961           }
5962         }
5963       }
5964     }
5965   }
5966   PetscFunctionReturn(0);
5967 }
5968 
5969 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[])
5970 {
5971   PetscScalar    *a;
5972   PetscInt        fdof, foff, fcdof, foffset = *offset;
5973   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5974   PetscInt        cind = 0, b;
5975   PetscErrorCode  ierr;
5976 
5977   PetscFunctionBegin;
5978   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5979   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
5980   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
5981   a    = &array[foff];
5982   if (!fcdof || setBC) {
5983     if (clperm) {
5984       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
5985       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
5986     } else {
5987       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
5988       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
5989     }
5990   } else {
5991     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5992     if (clperm) {
5993       if (perm) {
5994         for (b = 0; b < fdof; b++) {
5995           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
5996           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
5997         }
5998       } else {
5999         for (b = 0; b < fdof; b++) {
6000           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6001           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
6002         }
6003       }
6004     } else {
6005       if (perm) {
6006         for (b = 0; b < fdof; b++) {
6007           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6008           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
6009         }
6010       } else {
6011         for (b = 0; b < fdof; b++) {
6012           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6013           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
6014         }
6015       }
6016     }
6017   }
6018   *offset += fdof;
6019   PetscFunctionReturn(0);
6020 }
6021 
6022 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[])
6023 {
6024   PetscScalar    *a;
6025   PetscInt        fdof, foff, fcdof, foffset = *offset;
6026   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6027   PetscInt        Nc, cind = 0, ncind = 0, b;
6028   PetscBool       ncSet, fcSet;
6029   PetscErrorCode  ierr;
6030 
6031   PetscFunctionBegin;
6032   ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
6033   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6034   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
6035   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
6036   a    = &array[foff];
6037   if (fcdof) {
6038     /* We just override fcdof and fcdofs with Ncc and comps */
6039     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6040     if (clperm) {
6041       if (perm) {
6042         if (comps) {
6043           for (b = 0; b < fdof; b++) {
6044             ncSet = fcSet = PETSC_FALSE;
6045             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6046             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6047             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
6048           }
6049         } else {
6050           for (b = 0; b < fdof; b++) {
6051             if ((cind < fcdof) && (b == fcdofs[cind])) {
6052               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
6053               ++cind;
6054             }
6055           }
6056         }
6057       } else {
6058         if (comps) {
6059           for (b = 0; b < fdof; b++) {
6060             ncSet = fcSet = PETSC_FALSE;
6061             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6062             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6063             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
6064           }
6065         } else {
6066           for (b = 0; b < fdof; b++) {
6067             if ((cind < fcdof) && (b == fcdofs[cind])) {
6068               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
6069               ++cind;
6070             }
6071           }
6072         }
6073       }
6074     } else {
6075       if (perm) {
6076         if (comps) {
6077           for (b = 0; b < fdof; b++) {
6078             ncSet = fcSet = PETSC_FALSE;
6079             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6080             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6081             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
6082           }
6083         } else {
6084           for (b = 0; b < fdof; b++) {
6085             if ((cind < fcdof) && (b == fcdofs[cind])) {
6086               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
6087               ++cind;
6088             }
6089           }
6090         }
6091       } else {
6092         if (comps) {
6093           for (b = 0; b < fdof; b++) {
6094             ncSet = fcSet = PETSC_FALSE;
6095             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6096             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6097             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
6098           }
6099         } else {
6100           for (b = 0; b < fdof; b++) {
6101             if ((cind < fcdof) && (b == fcdofs[cind])) {
6102               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
6103               ++cind;
6104             }
6105           }
6106         }
6107       }
6108     }
6109   }
6110   *offset += fdof;
6111   PetscFunctionReturn(0);
6112 }
6113 
6114 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6115 {
6116   PetscScalar    *array;
6117   const PetscInt *cone, *coneO;
6118   PetscInt        pStart, pEnd, p, numPoints, off, dof;
6119   PetscErrorCode  ierr;
6120 
6121   PetscFunctionBeginHot;
6122   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6123   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
6124   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
6125   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
6126   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6127   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
6128     const PetscInt cp = !p ? point : cone[p-1];
6129     const PetscInt o  = !p ? 0     : coneO[p-1];
6130 
6131     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
6132     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
6133     /* ADD_VALUES */
6134     {
6135       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6136       PetscScalar    *a;
6137       PetscInt        cdof, coff, cind = 0, k;
6138 
6139       ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
6140       ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
6141       a    = &array[coff];
6142       if (!cdof) {
6143         if (o >= 0) {
6144           for (k = 0; k < dof; ++k) {
6145             a[k] += values[off+k];
6146           }
6147         } else {
6148           for (k = 0; k < dof; ++k) {
6149             a[k] += values[off+dof-k-1];
6150           }
6151         }
6152       } else {
6153         ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
6154         if (o >= 0) {
6155           for (k = 0; k < dof; ++k) {
6156             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6157             a[k] += values[off+k];
6158           }
6159         } else {
6160           for (k = 0; k < dof; ++k) {
6161             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6162             a[k] += values[off+dof-k-1];
6163           }
6164         }
6165       }
6166     }
6167   }
6168   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6169   PetscFunctionReturn(0);
6170 }
6171 
6172 /*@C
6173   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
6174 
6175   Not collective
6176 
6177   Input Parameters:
6178 + dm - The DM
6179 . section - The section describing the layout in v, or NULL to use the default section
6180 . v - The local vector
6181 . point - The point in the DM
6182 . values - The array of values
6183 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
6184          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
6185 
6186   Fortran Notes:
6187   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
6188 
6189   Level: intermediate
6190 
6191 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
6192 @*/
6193 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6194 {
6195   PetscSection    clSection;
6196   IS              clPoints;
6197   PetscScalar    *array;
6198   PetscInt       *points = NULL;
6199   const PetscInt *clp, *clperm = NULL;
6200   PetscInt        depth, numFields, numPoints, p, clsize;
6201   PetscErrorCode  ierr;
6202 
6203   PetscFunctionBeginHot;
6204   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6205   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
6206   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6207   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6208   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6209   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6210   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
6211     ierr = DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);CHKERRQ(ierr);
6212     PetscFunctionReturn(0);
6213   }
6214   /* Get points */
6215   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6216   for (clsize=0,p=0; p<numPoints; p++) {
6217     PetscInt dof;
6218     ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr);
6219     clsize += dof;
6220   }
6221   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm);CHKERRQ(ierr);
6222   /* Get array */
6223   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6224   /* Get values */
6225   if (numFields > 0) {
6226     PetscInt offset = 0, f;
6227     for (f = 0; f < numFields; ++f) {
6228       const PetscInt    **perms = NULL;
6229       const PetscScalar **flips = NULL;
6230 
6231       ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6232       switch (mode) {
6233       case INSERT_VALUES:
6234         for (p = 0; p < numPoints; p++) {
6235           const PetscInt    point = points[2*p];
6236           const PetscInt    *perm = perms ? perms[p] : NULL;
6237           const PetscScalar *flip = flips ? flips[p] : NULL;
6238           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
6239         } break;
6240       case INSERT_ALL_VALUES:
6241         for (p = 0; p < numPoints; p++) {
6242           const PetscInt    point = points[2*p];
6243           const PetscInt    *perm = perms ? perms[p] : NULL;
6244           const PetscScalar *flip = flips ? flips[p] : NULL;
6245           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
6246         } break;
6247       case INSERT_BC_VALUES:
6248         for (p = 0; p < numPoints; p++) {
6249           const PetscInt    point = points[2*p];
6250           const PetscInt    *perm = perms ? perms[p] : NULL;
6251           const PetscScalar *flip = flips ? flips[p] : NULL;
6252           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
6253         } break;
6254       case ADD_VALUES:
6255         for (p = 0; p < numPoints; p++) {
6256           const PetscInt    point = points[2*p];
6257           const PetscInt    *perm = perms ? perms[p] : NULL;
6258           const PetscScalar *flip = flips ? flips[p] : NULL;
6259           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
6260         } break;
6261       case ADD_ALL_VALUES:
6262         for (p = 0; p < numPoints; p++) {
6263           const PetscInt    point = points[2*p];
6264           const PetscInt    *perm = perms ? perms[p] : NULL;
6265           const PetscScalar *flip = flips ? flips[p] : NULL;
6266           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
6267         } break;
6268       case ADD_BC_VALUES:
6269         for (p = 0; p < numPoints; p++) {
6270           const PetscInt    point = points[2*p];
6271           const PetscInt    *perm = perms ? perms[p] : NULL;
6272           const PetscScalar *flip = flips ? flips[p] : NULL;
6273           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
6274         } break;
6275       default:
6276         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6277       }
6278       ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6279     }
6280   } else {
6281     PetscInt dof, off;
6282     const PetscInt    **perms = NULL;
6283     const PetscScalar **flips = NULL;
6284 
6285     ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6286     switch (mode) {
6287     case INSERT_VALUES:
6288       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6289         const PetscInt    point = points[2*p];
6290         const PetscInt    *perm = perms ? perms[p] : NULL;
6291         const PetscScalar *flip = flips ? flips[p] : NULL;
6292         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6293         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
6294       } break;
6295     case INSERT_ALL_VALUES:
6296       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6297         const PetscInt    point = points[2*p];
6298         const PetscInt    *perm = perms ? perms[p] : NULL;
6299         const PetscScalar *flip = flips ? flips[p] : NULL;
6300         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6301         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
6302       } break;
6303     case INSERT_BC_VALUES:
6304       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6305         const PetscInt    point = points[2*p];
6306         const PetscInt    *perm = perms ? perms[p] : NULL;
6307         const PetscScalar *flip = flips ? flips[p] : NULL;
6308         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6309         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
6310       } break;
6311     case ADD_VALUES:
6312       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6313         const PetscInt    point = points[2*p];
6314         const PetscInt    *perm = perms ? perms[p] : NULL;
6315         const PetscScalar *flip = flips ? flips[p] : NULL;
6316         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6317         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
6318       } break;
6319     case ADD_ALL_VALUES:
6320       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6321         const PetscInt    point = points[2*p];
6322         const PetscInt    *perm = perms ? perms[p] : NULL;
6323         const PetscScalar *flip = flips ? flips[p] : NULL;
6324         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6325         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
6326       } break;
6327     case ADD_BC_VALUES:
6328       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6329         const PetscInt    point = points[2*p];
6330         const PetscInt    *perm = perms ? perms[p] : NULL;
6331         const PetscScalar *flip = flips ? flips[p] : NULL;
6332         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6333         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
6334       } break;
6335     default:
6336       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6337     }
6338     ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6339   }
6340   /* Cleanup points */
6341   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6342   /* Cleanup array */
6343   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6344   PetscFunctionReturn(0);
6345 }
6346 
6347 /* Check whether the given point is in the label. If not, update the offset to skip this point */
6348 PETSC_STATIC_INLINE PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset)
6349 {
6350   PetscFunctionBegin;
6351   if (label) {
6352     PetscInt       val, fdof;
6353     PetscErrorCode ierr;
6354 
6355     /* There is a problem with this:
6356          Suppose we have two label values, defining surfaces, interecting along a line in 3D. When we add cells to the label, the cells that
6357        touch both surfaces must pick a label value. Thus we miss setting values for the surface with that other value intersecting that cell.
6358        Thus I am only going to check val != -1, not val != labelId
6359     */
6360     ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
6361     if (val < 0) {
6362       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6363       *offset += fdof;
6364       PetscFunctionReturn(1);
6365     }
6366   }
6367   PetscFunctionReturn(0);
6368 }
6369 
6370 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
6371 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)
6372 {
6373   PetscSection      clSection;
6374   IS                clPoints;
6375   PetscScalar       *array;
6376   PetscInt          *points = NULL;
6377   const PetscInt    *clp;
6378   PetscInt          numFields, numPoints, p;
6379   PetscInt          offset = 0, f;
6380   PetscErrorCode    ierr;
6381 
6382   PetscFunctionBeginHot;
6383   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6384   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
6385   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6386   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6387   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6388   /* Get points */
6389   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6390   /* Get array */
6391   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6392   /* Get values */
6393   for (f = 0; f < numFields; ++f) {
6394     const PetscInt    **perms = NULL;
6395     const PetscScalar **flips = NULL;
6396 
6397     if (!fieldActive[f]) {
6398       for (p = 0; p < numPoints*2; p += 2) {
6399         PetscInt fdof;
6400         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6401         offset += fdof;
6402       }
6403       continue;
6404     }
6405     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6406     switch (mode) {
6407     case INSERT_VALUES:
6408       for (p = 0; p < numPoints; p++) {
6409         const PetscInt    point = points[2*p];
6410         const PetscInt    *perm = perms ? perms[p] : NULL;
6411         const PetscScalar *flip = flips ? flips[p] : NULL;
6412         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6413         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array);
6414       } break;
6415     case INSERT_ALL_VALUES:
6416       for (p = 0; p < numPoints; p++) {
6417         const PetscInt    point = points[2*p];
6418         const PetscInt    *perm = perms ? perms[p] : NULL;
6419         const PetscScalar *flip = flips ? flips[p] : NULL;
6420         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6421         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array);
6422       } break;
6423     case INSERT_BC_VALUES:
6424       for (p = 0; p < numPoints; p++) {
6425         const PetscInt    point = points[2*p];
6426         const PetscInt    *perm = perms ? perms[p] : NULL;
6427         const PetscScalar *flip = flips ? flips[p] : NULL;
6428         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6429         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array);
6430       } break;
6431     case ADD_VALUES:
6432       for (p = 0; p < numPoints; p++) {
6433         const PetscInt    point = points[2*p];
6434         const PetscInt    *perm = perms ? perms[p] : NULL;
6435         const PetscScalar *flip = flips ? flips[p] : NULL;
6436         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6437         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array);
6438       } break;
6439     case ADD_ALL_VALUES:
6440       for (p = 0; p < numPoints; p++) {
6441         const PetscInt    point = points[2*p];
6442         const PetscInt    *perm = perms ? perms[p] : NULL;
6443         const PetscScalar *flip = flips ? flips[p] : NULL;
6444         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6445         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array);
6446       } break;
6447     default:
6448       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6449     }
6450     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6451   }
6452   /* Cleanup points */
6453   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6454   /* Cleanup array */
6455   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6456   PetscFunctionReturn(0);
6457 }
6458 
6459 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
6460 {
6461   PetscMPIInt    rank;
6462   PetscInt       i, j;
6463   PetscErrorCode ierr;
6464 
6465   PetscFunctionBegin;
6466   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr);
6467   ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);CHKERRQ(ierr);
6468   for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);}
6469   for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);}
6470   numCIndices = numCIndices ? numCIndices : numRIndices;
6471   if (!values) PetscFunctionReturn(0);
6472   for (i = 0; i < numRIndices; i++) {
6473     ierr = PetscViewerASCIIPrintf(viewer, "[%d]", rank);CHKERRQ(ierr);
6474     for (j = 0; j < numCIndices; j++) {
6475 #if defined(PETSC_USE_COMPLEX)
6476       ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr);
6477 #else
6478       ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr);
6479 #endif
6480     }
6481     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
6482   }
6483   PetscFunctionReturn(0);
6484 }
6485 
6486 /*
6487   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
6488 
6489   Input Parameters:
6490 + section - The section for this data layout
6491 . islocal - Is the section (and thus indices being requested) local or global?
6492 . point   - The point contributing dofs with these indices
6493 . off     - The global offset of this point
6494 . loff    - The local offset of each field
6495 . setBC   - The flag determining whether to include indices of boundary values
6496 . perm    - A permutation of the dofs on this point, or NULL
6497 - indperm - A permutation of the entire indices array, or NULL
6498 
6499   Output Parameter:
6500 . indices - Indices for dofs on this point
6501 
6502   Level: developer
6503 
6504   Note: The indices could be local or global, depending on the value of 'off'.
6505 */
6506 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
6507 {
6508   PetscInt        dof;   /* The number of unknowns on this point */
6509   PetscInt        cdof;  /* The number of constraints on this point */
6510   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6511   PetscInt        cind = 0, k;
6512   PetscErrorCode  ierr;
6513 
6514   PetscFunctionBegin;
6515   if (!islocal && setBC) SETERRQ(PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC");
6516   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6517   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6518   if (!cdof || setBC) {
6519     for (k = 0; k < dof; ++k) {
6520       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
6521       const PetscInt ind    = indperm ? indperm[preind] : preind;
6522 
6523       indices[ind] = off + k;
6524     }
6525   } else {
6526     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6527     for (k = 0; k < dof; ++k) {
6528       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
6529       const PetscInt ind    = indperm ? indperm[preind] : preind;
6530 
6531       if ((cind < cdof) && (k == cdofs[cind])) {
6532         /* Insert check for returning constrained indices */
6533         indices[ind] = -(off+k+1);
6534         ++cind;
6535       } else {
6536         indices[ind] = off + k - (islocal ? 0 : cind);
6537       }
6538     }
6539   }
6540   *loff += dof;
6541   PetscFunctionReturn(0);
6542 }
6543 
6544 /*
6545  DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.
6546 
6547  Input Parameters:
6548 + section - a section (global or local)
6549 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global
6550 . point - point within section
6551 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
6552 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
6553 . setBC - identify constrained (boundary condition) points via involution.
6554 . perms - perms[f][permsoff][:] is a permutation of dofs within each field
6555 . permsoff - offset
6556 - indperm - index permutation
6557 
6558  Output Parameter:
6559 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
6560 . indices - array to hold indices (as defined by section) of each dof associated with point
6561 
6562  Notes:
6563  If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
6564  If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
6565  in the local vector.
6566 
6567  If section is global and setBC=false, the indices for constrained points are negative (and their value is not
6568  significant).  It is invalid to call with a global section and setBC=true.
6569 
6570  Developer Note:
6571  The section is only used for field layout, so islocal is technically a statement about the offset (off).  At some point
6572  in the future, global sections may have fields set, in which case we could pass the global section and obtain the
6573  offset could be obtained from the section instead of passing it explicitly as we do now.
6574 
6575  Example:
6576  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
6577  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
6578  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
6579  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.
6580 
6581  Level: developer
6582 */
6583 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[])
6584 {
6585   PetscInt       numFields, foff, f;
6586   PetscErrorCode ierr;
6587 
6588   PetscFunctionBegin;
6589   if (!islocal && setBC) SETERRQ(PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC");
6590   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6591   for (f = 0, foff = 0; f < numFields; ++f) {
6592     PetscInt        fdof, cfdof;
6593     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6594     PetscInt        cind = 0, b;
6595     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
6596 
6597     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6598     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
6599     if (!cfdof || setBC) {
6600       for (b = 0; b < fdof; ++b) {
6601         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6602         const PetscInt ind    = indperm ? indperm[preind] : preind;
6603 
6604         indices[ind] = off+foff+b;
6605       }
6606     } else {
6607       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6608       for (b = 0; b < fdof; ++b) {
6609         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6610         const PetscInt ind    = indperm ? indperm[preind] : preind;
6611 
6612         if ((cind < cfdof) && (b == fcdofs[cind])) {
6613           indices[ind] = -(off+foff+b+1);
6614           ++cind;
6615         } else {
6616           indices[ind] = off + foff + b - (islocal ? 0 : cind);
6617         }
6618       }
6619     }
6620     foff     += (setBC || islocal ? fdof : (fdof - cfdof));
6621     foffs[f] += fdof;
6622   }
6623   PetscFunctionReturn(0);
6624 }
6625 
6626 /*
6627   This version believes the globalSection offsets for each field, rather than just the point offset
6628 
6629  . foffs - The offset into 'indices' for each field, since it is segregated by field
6630 
6631  Notes:
6632  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
6633  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
6634 */
6635 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
6636 {
6637   PetscInt       numFields, foff, f;
6638   PetscErrorCode ierr;
6639 
6640   PetscFunctionBegin;
6641   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6642   for (f = 0; f < numFields; ++f) {
6643     PetscInt        fdof, cfdof;
6644     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6645     PetscInt        cind = 0, b;
6646     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
6647 
6648     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6649     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
6650     ierr = PetscSectionGetFieldOffset(globalSection, point, f, &foff);CHKERRQ(ierr);
6651     if (!cfdof) {
6652       for (b = 0; b < fdof; ++b) {
6653         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6654         const PetscInt ind    = indperm ? indperm[preind] : preind;
6655 
6656         indices[ind] = foff+b;
6657       }
6658     } else {
6659       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6660       for (b = 0; b < fdof; ++b) {
6661         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6662         const PetscInt ind    = indperm ? indperm[preind] : preind;
6663 
6664         if ((cind < cfdof) && (b == fcdofs[cind])) {
6665           indices[ind] = -(foff+b+1);
6666           ++cind;
6667         } else {
6668           indices[ind] = foff+b-cind;
6669         }
6670       }
6671     }
6672     foffs[f] += fdof;
6673   }
6674   PetscFunctionReturn(0);
6675 }
6676 
6677 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)
6678 {
6679   Mat             cMat;
6680   PetscSection    aSec, cSec;
6681   IS              aIS;
6682   PetscInt        aStart = -1, aEnd = -1;
6683   const PetscInt  *anchors;
6684   PetscInt        numFields, f, p, q, newP = 0;
6685   PetscInt        newNumPoints = 0, newNumIndices = 0;
6686   PetscInt        *newPoints, *indices, *newIndices;
6687   PetscInt        maxAnchor, maxDof;
6688   PetscInt        newOffsets[32];
6689   PetscInt        *pointMatOffsets[32];
6690   PetscInt        *newPointOffsets[32];
6691   PetscScalar     *pointMat[32];
6692   PetscScalar     *newValues=NULL,*tmpValues;
6693   PetscBool       anyConstrained = PETSC_FALSE;
6694   PetscErrorCode  ierr;
6695 
6696   PetscFunctionBegin;
6697   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6698   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6699   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6700 
6701   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
6702   /* if there are point-to-point constraints */
6703   if (aSec) {
6704     ierr = PetscArrayzero(newOffsets, 32);CHKERRQ(ierr);
6705     ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
6706     ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
6707     /* figure out how many points are going to be in the new element matrix
6708      * (we allow double counting, because it's all just going to be summed
6709      * into the global matrix anyway) */
6710     for (p = 0; p < 2*numPoints; p+=2) {
6711       PetscInt b    = points[p];
6712       PetscInt bDof = 0, bSecDof;
6713 
6714       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
6715       if (!bSecDof) {
6716         continue;
6717       }
6718       if (b >= aStart && b < aEnd) {
6719         ierr = PetscSectionGetDof(aSec,b,&bDof);CHKERRQ(ierr);
6720       }
6721       if (bDof) {
6722         /* this point is constrained */
6723         /* it is going to be replaced by its anchors */
6724         PetscInt bOff, q;
6725 
6726         anyConstrained = PETSC_TRUE;
6727         newNumPoints  += bDof;
6728         ierr = PetscSectionGetOffset(aSec,b,&bOff);CHKERRQ(ierr);
6729         for (q = 0; q < bDof; q++) {
6730           PetscInt a = anchors[bOff + q];
6731           PetscInt aDof;
6732 
6733           ierr           = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
6734           newNumIndices += aDof;
6735           for (f = 0; f < numFields; ++f) {
6736             PetscInt fDof;
6737 
6738             ierr             = PetscSectionGetFieldDof(section, a, f, &fDof);CHKERRQ(ierr);
6739             newOffsets[f+1] += fDof;
6740           }
6741         }
6742       }
6743       else {
6744         /* this point is not constrained */
6745         newNumPoints++;
6746         newNumIndices += bSecDof;
6747         for (f = 0; f < numFields; ++f) {
6748           PetscInt fDof;
6749 
6750           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
6751           newOffsets[f+1] += fDof;
6752         }
6753       }
6754     }
6755   }
6756   if (!anyConstrained) {
6757     if (outNumPoints)  *outNumPoints  = 0;
6758     if (outNumIndices) *outNumIndices = 0;
6759     if (outPoints)     *outPoints     = NULL;
6760     if (outValues)     *outValues     = NULL;
6761     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
6762     PetscFunctionReturn(0);
6763   }
6764 
6765   if (outNumPoints)  *outNumPoints  = newNumPoints;
6766   if (outNumIndices) *outNumIndices = newNumIndices;
6767 
6768   for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
6769 
6770   if (!outPoints && !outValues) {
6771     if (offsets) {
6772       for (f = 0; f <= numFields; f++) {
6773         offsets[f] = newOffsets[f];
6774       }
6775     }
6776     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
6777     PetscFunctionReturn(0);
6778   }
6779 
6780   if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
6781 
6782   ierr = DMGetDefaultConstraints(dm, &cSec, &cMat);CHKERRQ(ierr);
6783 
6784   /* workspaces */
6785   if (numFields) {
6786     for (f = 0; f < numFields; f++) {
6787       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
6788       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
6789     }
6790   }
6791   else {
6792     ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
6793     ierr = DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
6794   }
6795 
6796   /* get workspaces for the point-to-point matrices */
6797   if (numFields) {
6798     PetscInt totalOffset, totalMatOffset;
6799 
6800     for (p = 0; p < numPoints; p++) {
6801       PetscInt b    = points[2*p];
6802       PetscInt bDof = 0, bSecDof;
6803 
6804       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
6805       if (!bSecDof) {
6806         for (f = 0; f < numFields; f++) {
6807           newPointOffsets[f][p + 1] = 0;
6808           pointMatOffsets[f][p + 1] = 0;
6809         }
6810         continue;
6811       }
6812       if (b >= aStart && b < aEnd) {
6813         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6814       }
6815       if (bDof) {
6816         for (f = 0; f < numFields; f++) {
6817           PetscInt fDof, q, bOff, allFDof = 0;
6818 
6819           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
6820           ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
6821           for (q = 0; q < bDof; q++) {
6822             PetscInt a = anchors[bOff + q];
6823             PetscInt aFDof;
6824 
6825             ierr     = PetscSectionGetFieldDof(section, a, f, &aFDof);CHKERRQ(ierr);
6826             allFDof += aFDof;
6827           }
6828           newPointOffsets[f][p+1] = allFDof;
6829           pointMatOffsets[f][p+1] = fDof * allFDof;
6830         }
6831       }
6832       else {
6833         for (f = 0; f < numFields; f++) {
6834           PetscInt fDof;
6835 
6836           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
6837           newPointOffsets[f][p+1] = fDof;
6838           pointMatOffsets[f][p+1] = 0;
6839         }
6840       }
6841     }
6842     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
6843       newPointOffsets[f][0] = totalOffset;
6844       pointMatOffsets[f][0] = totalMatOffset;
6845       for (p = 0; p < numPoints; p++) {
6846         newPointOffsets[f][p+1] += newPointOffsets[f][p];
6847         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
6848       }
6849       totalOffset    = newPointOffsets[f][numPoints];
6850       totalMatOffset = pointMatOffsets[f][numPoints];
6851       ierr = DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
6852     }
6853   }
6854   else {
6855     for (p = 0; p < numPoints; p++) {
6856       PetscInt b    = points[2*p];
6857       PetscInt bDof = 0, bSecDof;
6858 
6859       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
6860       if (!bSecDof) {
6861         newPointOffsets[0][p + 1] = 0;
6862         pointMatOffsets[0][p + 1] = 0;
6863         continue;
6864       }
6865       if (b >= aStart && b < aEnd) {
6866         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6867       }
6868       if (bDof) {
6869         PetscInt bOff, q, allDof = 0;
6870 
6871         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
6872         for (q = 0; q < bDof; q++) {
6873           PetscInt a = anchors[bOff + q], aDof;
6874 
6875           ierr    = PetscSectionGetDof(section, a, &aDof);CHKERRQ(ierr);
6876           allDof += aDof;
6877         }
6878         newPointOffsets[0][p+1] = allDof;
6879         pointMatOffsets[0][p+1] = bSecDof * allDof;
6880       }
6881       else {
6882         newPointOffsets[0][p+1] = bSecDof;
6883         pointMatOffsets[0][p+1] = 0;
6884       }
6885     }
6886     newPointOffsets[0][0] = 0;
6887     pointMatOffsets[0][0] = 0;
6888     for (p = 0; p < numPoints; p++) {
6889       newPointOffsets[0][p+1] += newPointOffsets[0][p];
6890       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
6891     }
6892     ierr = DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
6893   }
6894 
6895   /* output arrays */
6896   ierr = DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
6897 
6898   /* get the point-to-point matrices; construct newPoints */
6899   ierr = PetscSectionGetMaxDof(aSec, &maxAnchor);CHKERRQ(ierr);
6900   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6901   ierr = DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
6902   ierr = DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
6903   if (numFields) {
6904     for (p = 0, newP = 0; p < numPoints; p++) {
6905       PetscInt b    = points[2*p];
6906       PetscInt o    = points[2*p+1];
6907       PetscInt bDof = 0, bSecDof;
6908 
6909       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
6910       if (!bSecDof) {
6911         continue;
6912       }
6913       if (b >= aStart && b < aEnd) {
6914         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6915       }
6916       if (bDof) {
6917         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
6918 
6919         fStart[0] = 0;
6920         fEnd[0]   = 0;
6921         for (f = 0; f < numFields; f++) {
6922           PetscInt fDof;
6923 
6924           ierr        = PetscSectionGetFieldDof(cSec, b, f, &fDof);CHKERRQ(ierr);
6925           fStart[f+1] = fStart[f] + fDof;
6926           fEnd[f+1]   = fStart[f+1];
6927         }
6928         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
6929         ierr = DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices);CHKERRQ(ierr);
6930 
6931         fAnchorStart[0] = 0;
6932         fAnchorEnd[0]   = 0;
6933         for (f = 0; f < numFields; f++) {
6934           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
6935 
6936           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
6937           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
6938         }
6939         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
6940         for (q = 0; q < bDof; q++) {
6941           PetscInt a = anchors[bOff + q], aOff;
6942 
6943           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
6944           newPoints[2*(newP + q)]     = a;
6945           newPoints[2*(newP + q) + 1] = 0;
6946           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
6947           ierr = DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices);CHKERRQ(ierr);
6948         }
6949         newP += bDof;
6950 
6951         if (outValues) {
6952           /* get the point-to-point submatrix */
6953           for (f = 0; f < numFields; f++) {
6954             ierr = MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);CHKERRQ(ierr);
6955           }
6956         }
6957       }
6958       else {
6959         newPoints[2 * newP]     = b;
6960         newPoints[2 * newP + 1] = o;
6961         newP++;
6962       }
6963     }
6964   } else {
6965     for (p = 0; p < numPoints; p++) {
6966       PetscInt b    = points[2*p];
6967       PetscInt o    = points[2*p+1];
6968       PetscInt bDof = 0, bSecDof;
6969 
6970       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
6971       if (!bSecDof) {
6972         continue;
6973       }
6974       if (b >= aStart && b < aEnd) {
6975         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6976       }
6977       if (bDof) {
6978         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
6979 
6980         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
6981         ierr = DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices);CHKERRQ(ierr);
6982 
6983         ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr);
6984         for (q = 0; q < bDof; q++) {
6985           PetscInt a = anchors[bOff + q], aOff;
6986 
6987           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
6988 
6989           newPoints[2*(newP + q)]     = a;
6990           newPoints[2*(newP + q) + 1] = 0;
6991           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
6992           ierr = DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices);CHKERRQ(ierr);
6993         }
6994         newP += bDof;
6995 
6996         /* get the point-to-point submatrix */
6997         if (outValues) {
6998           ierr = MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);CHKERRQ(ierr);
6999         }
7000       }
7001       else {
7002         newPoints[2 * newP]     = b;
7003         newPoints[2 * newP + 1] = o;
7004         newP++;
7005       }
7006     }
7007   }
7008 
7009   if (outValues) {
7010     ierr = DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
7011     ierr = PetscArrayzero(tmpValues,newNumIndices*numIndices);CHKERRQ(ierr);
7012     /* multiply constraints on the right */
7013     if (numFields) {
7014       for (f = 0; f < numFields; f++) {
7015         PetscInt oldOff = offsets[f];
7016 
7017         for (p = 0; p < numPoints; p++) {
7018           PetscInt cStart = newPointOffsets[f][p];
7019           PetscInt b      = points[2 * p];
7020           PetscInt c, r, k;
7021           PetscInt dof;
7022 
7023           ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
7024           if (!dof) {
7025             continue;
7026           }
7027           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7028             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
7029             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
7030 
7031             for (r = 0; r < numIndices; r++) {
7032               for (c = 0; c < nCols; c++) {
7033                 for (k = 0; k < dof; k++) {
7034                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
7035                 }
7036               }
7037             }
7038           }
7039           else {
7040             /* copy this column as is */
7041             for (r = 0; r < numIndices; r++) {
7042               for (c = 0; c < dof; c++) {
7043                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7044               }
7045             }
7046           }
7047           oldOff += dof;
7048         }
7049       }
7050     }
7051     else {
7052       PetscInt oldOff = 0;
7053       for (p = 0; p < numPoints; p++) {
7054         PetscInt cStart = newPointOffsets[0][p];
7055         PetscInt b      = points[2 * p];
7056         PetscInt c, r, k;
7057         PetscInt dof;
7058 
7059         ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
7060         if (!dof) {
7061           continue;
7062         }
7063         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7064           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
7065           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
7066 
7067           for (r = 0; r < numIndices; r++) {
7068             for (c = 0; c < nCols; c++) {
7069               for (k = 0; k < dof; k++) {
7070                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
7071               }
7072             }
7073           }
7074         }
7075         else {
7076           /* copy this column as is */
7077           for (r = 0; r < numIndices; r++) {
7078             for (c = 0; c < dof; c++) {
7079               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7080             }
7081           }
7082         }
7083         oldOff += dof;
7084       }
7085     }
7086 
7087     if (multiplyLeft) {
7088       ierr = DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr);
7089       ierr = PetscArrayzero(newValues,newNumIndices*newNumIndices);CHKERRQ(ierr);
7090       /* multiply constraints transpose on the left */
7091       if (numFields) {
7092         for (f = 0; f < numFields; f++) {
7093           PetscInt oldOff = offsets[f];
7094 
7095           for (p = 0; p < numPoints; p++) {
7096             PetscInt rStart = newPointOffsets[f][p];
7097             PetscInt b      = points[2 * p];
7098             PetscInt c, r, k;
7099             PetscInt dof;
7100 
7101             ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
7102             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7103               PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
7104               const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
7105 
7106               for (r = 0; r < nRows; r++) {
7107                 for (c = 0; c < newNumIndices; c++) {
7108                   for (k = 0; k < dof; k++) {
7109                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7110                   }
7111                 }
7112               }
7113             }
7114             else {
7115               /* copy this row as is */
7116               for (r = 0; r < dof; r++) {
7117                 for (c = 0; c < newNumIndices; c++) {
7118                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7119                 }
7120               }
7121             }
7122             oldOff += dof;
7123           }
7124         }
7125       }
7126       else {
7127         PetscInt oldOff = 0;
7128 
7129         for (p = 0; p < numPoints; p++) {
7130           PetscInt rStart = newPointOffsets[0][p];
7131           PetscInt b      = points[2 * p];
7132           PetscInt c, r, k;
7133           PetscInt dof;
7134 
7135           ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
7136           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7137             PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
7138             const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
7139 
7140             for (r = 0; r < nRows; r++) {
7141               for (c = 0; c < newNumIndices; c++) {
7142                 for (k = 0; k < dof; k++) {
7143                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7144                 }
7145               }
7146             }
7147           }
7148           else {
7149             /* copy this row as is */
7150             for (r = 0; r < dof; r++) {
7151               for (c = 0; c < newNumIndices; c++) {
7152                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7153               }
7154             }
7155           }
7156           oldOff += dof;
7157         }
7158       }
7159 
7160       ierr = DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
7161     }
7162     else {
7163       newValues = tmpValues;
7164     }
7165   }
7166 
7167   /* clean up */
7168   ierr = DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
7169   ierr = DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
7170 
7171   if (numFields) {
7172     for (f = 0; f < numFields; f++) {
7173       ierr = DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
7174       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
7175       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
7176     }
7177   }
7178   else {
7179     ierr = DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
7180     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
7181     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
7182   }
7183   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
7184 
7185   /* output */
7186   if (outPoints) {
7187     *outPoints = newPoints;
7188   }
7189   else {
7190     ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
7191   }
7192   if (outValues) {
7193     *outValues = newValues;
7194   }
7195   for (f = 0; f <= numFields; f++) {
7196     offsets[f] = newOffsets[f];
7197   }
7198   PetscFunctionReturn(0);
7199 }
7200 
7201 /*@C
7202   DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.
7203 
7204   Not collective
7205 
7206   Input Parameters:
7207 + dm         - The DM
7208 . section    - The PetscSection describing the points (a local section)
7209 . idxSection - The PetscSection from which to obtain indices (may be local or global)
7210 . point      - The point defining the closure
7211 - useClPerm  - Use the closure point permutation if available
7212 
7213   Output Parameters:
7214 + numIndices - The number of dof indices in the closure of point with the input sections
7215 . indices    - The dof indices
7216 . outOffsets - Array to write the field offsets into, or NULL
7217 - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
7218 
7219   Notes:
7220   Must call DMPlexRestoreClosureIndices() to free allocated memory
7221 
7222   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
7223   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
7224   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
7225   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
7226   indices (with the above semantics) are implied.
7227 
7228   Level: advanced
7229 
7230 .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection()
7231 @*/
7232 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm,
7233                                        PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7234 {
7235   /* Closure ordering */
7236   PetscSection        clSection;
7237   IS                  clPoints;
7238   const PetscInt     *clp;
7239   PetscInt           *points;
7240   const PetscInt     *clperm = NULL;
7241   /* Dof permutation and sign flips */
7242   const PetscInt    **perms[32] = {NULL};
7243   const PetscScalar **flips[32] = {NULL};
7244   PetscScalar        *valCopy   = NULL;
7245   /* Hanging node constraints */
7246   PetscInt           *pointsC = NULL;
7247   PetscScalar        *valuesC = NULL;
7248   PetscInt            NclC, NiC;
7249 
7250   PetscInt           *idx;
7251   PetscInt            Nf, Ncl, Ni = 0, offsets[32], p, f;
7252   PetscBool           isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
7253   PetscErrorCode      ierr;
7254 
7255   PetscFunctionBeginHot;
7256   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7257   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7258   PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3);
7259   if (numIndices) PetscValidPointer(numIndices, 6);
7260   if (indices)    PetscValidPointer(indices, 7);
7261   if (outOffsets) PetscValidPointer(outOffsets, 8);
7262   if (values)     PetscValidPointer(values, 9);
7263   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
7264   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
7265   ierr = PetscArrayzero(offsets, 32);CHKERRQ(ierr);
7266   /* 1) Get points in closure */
7267   ierr = DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr);
7268   if (useClPerm) {
7269     PetscInt depth, clsize;
7270     ierr = DMPlexGetPointDepth(dm, point, &depth);CHKERRQ(ierr);
7271     for (clsize=0,p=0; p<Ncl; p++) {
7272       PetscInt dof;
7273       ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr);
7274       clsize += dof;
7275     }
7276     ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm);CHKERRQ(ierr);
7277   }
7278   /* 2) Get number of indices on these points and field offsets from section */
7279   for (p = 0; p < Ncl*2; p += 2) {
7280     PetscInt dof, fdof;
7281 
7282     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7283     for (f = 0; f < Nf; ++f) {
7284       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7285       offsets[f+1] += fdof;
7286     }
7287     Ni += dof;
7288   }
7289   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
7290   if (Nf && offsets[Nf] != Ni) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Ni);
7291   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
7292   for (f = 0; f < PetscMax(1, Nf); ++f) {
7293     if (Nf) {ierr = PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7294     else    {ierr = PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7295     /* may need to apply sign changes to the element matrix */
7296     if (values && flips[f]) {
7297       PetscInt foffset = offsets[f];
7298 
7299       for (p = 0; p < Ncl; ++p) {
7300         PetscInt           pnt  = points[2*p], fdof;
7301         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
7302 
7303         if (!Nf) {ierr = PetscSectionGetDof(section, pnt, &fdof);CHKERRQ(ierr);}
7304         else     {ierr = PetscSectionGetFieldDof(section, pnt, f, &fdof);CHKERRQ(ierr);}
7305         if (flip) {
7306           PetscInt i, j, k;
7307 
7308           if (!valCopy) {
7309             ierr = DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy);CHKERRQ(ierr);
7310             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
7311             *values = valCopy;
7312           }
7313           for (i = 0; i < fdof; ++i) {
7314             PetscScalar fval = flip[i];
7315 
7316             for (k = 0; k < Ni; ++k) {
7317               valCopy[Ni * (foffset + i) + k] *= fval;
7318               valCopy[Ni * k + (foffset + i)] *= fval;
7319             }
7320           }
7321         }
7322         foffset += fdof;
7323       }
7324     }
7325   }
7326   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
7327   ierr = DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE);CHKERRQ(ierr);
7328   if (NclC) {
7329     if (valCopy) {ierr = DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy);CHKERRQ(ierr);}
7330     for (f = 0; f < PetscMax(1, Nf); ++f) {
7331       if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7332       else    {ierr = PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7333     }
7334     for (f = 0; f < PetscMax(1, Nf); ++f) {
7335       if (Nf) {ierr = PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]);CHKERRQ(ierr);}
7336       else    {ierr = PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]);CHKERRQ(ierr);}
7337     }
7338     ierr = DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr);
7339     Ncl     = NclC;
7340     Ni      = NiC;
7341     points  = pointsC;
7342     if (values) *values = valuesC;
7343   }
7344   /* 5) Calculate indices */
7345   ierr = DMGetWorkArray(dm, Ni, MPIU_INT, &idx);CHKERRQ(ierr);
7346   if (Nf) {
7347     PetscInt  idxOff;
7348     PetscBool useFieldOffsets;
7349 
7350     if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];}
7351     ierr = PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets);CHKERRQ(ierr);
7352     if (useFieldOffsets) {
7353       for (p = 0; p < Ncl; ++p) {
7354         const PetscInt pnt = points[p*2];
7355 
7356         ierr = DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx);CHKERRQ(ierr);
7357       }
7358     } else {
7359       for (p = 0; p < Ncl; ++p) {
7360         const PetscInt pnt = points[p*2];
7361 
7362         ierr = PetscSectionGetOffset(idxSection, pnt, &idxOff);CHKERRQ(ierr);
7363         /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
7364          * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
7365          * global section. */
7366         ierr = DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx);CHKERRQ(ierr);
7367       }
7368     }
7369   } else {
7370     PetscInt off = 0, idxOff;
7371 
7372     for (p = 0; p < Ncl; ++p) {
7373       const PetscInt  pnt  = points[p*2];
7374       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
7375 
7376       ierr = PetscSectionGetOffset(idxSection, pnt, &idxOff);CHKERRQ(ierr);
7377       /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
7378        * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
7379       ierr = DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx);CHKERRQ(ierr);
7380     }
7381   }
7382   /* 6) Cleanup */
7383   for (f = 0; f < PetscMax(1, Nf); ++f) {
7384     if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7385     else    {ierr = PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7386   }
7387   if (NclC) {
7388     ierr = DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC);CHKERRQ(ierr);
7389   } else {
7390     ierr = DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr);
7391   }
7392 
7393   if (numIndices) *numIndices = Ni;
7394   if (indices)    *indices    = idx;
7395   PetscFunctionReturn(0);
7396 }
7397 
7398 /*@C
7399   DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.
7400 
7401   Not collective
7402 
7403   Input Parameters:
7404 + dm         - The DM
7405 . section    - The PetscSection describing the points (a local section)
7406 . idxSection - The PetscSection from which to obtain indices (may be local or global)
7407 . point      - The point defining the closure
7408 - useClPerm  - Use the closure point permutation if available
7409 
7410   Output Parameters:
7411 + numIndices - The number of dof indices in the closure of point with the input sections
7412 . indices    - The dof indices
7413 . outOffsets - Array to write the field offsets into, or NULL
7414 - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
7415 
7416   Notes:
7417   If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values).
7418 
7419   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
7420   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
7421   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
7422   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
7423   indices (with the above semantics) are implied.
7424 
7425   Level: advanced
7426 
7427 .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection()
7428 @*/
7429 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm,
7430                                            PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7431 {
7432   PetscErrorCode ierr;
7433 
7434   PetscFunctionBegin;
7435   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7436   PetscValidPointer(indices, 7);
7437   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, indices);CHKERRQ(ierr);
7438   PetscFunctionReturn(0);
7439 }
7440 
7441 /*@C
7442   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
7443 
7444   Not collective
7445 
7446   Input Parameters:
7447 + dm - The DM
7448 . section - The section describing the layout in v, or NULL to use the default section
7449 . globalSection - The section describing the layout in v, or NULL to use the default global section
7450 . A - The matrix
7451 . point - The point in the DM
7452 . values - The array of values
7453 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7454 
7455   Fortran Notes:
7456   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
7457 
7458   Level: intermediate
7459 
7460 .seealso DMPlexMatSetClosureGeneral(), DMPlexVecGetClosure(), DMPlexVecSetClosure()
7461 @*/
7462 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7463 {
7464   DM_Plex           *mesh = (DM_Plex*) dm->data;
7465   PetscInt          *indices;
7466   PetscInt           numIndices;
7467   const PetscScalar *valuesOrig = values;
7468   PetscErrorCode     ierr;
7469 
7470   PetscFunctionBegin;
7471   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7472   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
7473   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7474   if (!globalSection) {ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
7475   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
7476   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
7477 
7478   ierr = DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7479 
7480   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);}
7481   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7482   if (ierr) {
7483     PetscMPIInt    rank;
7484     PetscErrorCode ierr2;
7485 
7486     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2);
7487     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7488     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
7489     ierr2 = DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr2);
7490     if (values != valuesOrig) {ierr2 = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values);CHKERRQ(ierr2);}
7491     CHKERRQ(ierr);
7492   }
7493   if (mesh->printFEM > 1) {
7494     PetscInt i;
7495     ierr = PetscPrintf(PETSC_COMM_SELF, "  Indices:");CHKERRQ(ierr);
7496     for (i = 0; i < numIndices; ++i) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);CHKERRQ(ierr);}
7497     ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
7498   }
7499 
7500   ierr = DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7501   if (values != valuesOrig) {ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values);CHKERRQ(ierr);}
7502   PetscFunctionReturn(0);
7503 }
7504 
7505 /*@C
7506   DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section
7507 
7508   Not collective
7509 
7510   Input Parameters:
7511 + dmRow - The DM for the row fields
7512 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow
7513 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow
7514 . dmCol - The DM for the column fields
7515 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol
7516 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol
7517 . A - The matrix
7518 . point - The point in the DMs
7519 . values - The array of values
7520 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7521 
7522   Level: intermediate
7523 
7524 .seealso DMPlexMatSetClosure(), DMPlexVecGetClosure(), DMPlexVecSetClosure()
7525 @*/
7526 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7527 {
7528   DM_Plex           *mesh = (DM_Plex*) dmRow->data;
7529   PetscInt          *indicesRow, *indicesCol;
7530   PetscInt           numIndicesRow, numIndicesCol;
7531   const PetscScalar *valuesOrig = values;
7532   PetscErrorCode     ierr;
7533 
7534   PetscFunctionBegin;
7535   PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1);
7536   if (!sectionRow) {ierr = DMGetLocalSection(dmRow, &sectionRow);CHKERRQ(ierr);}
7537   PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2);
7538   if (!globalSectionRow) {ierr = DMGetGlobalSection(dmRow, &globalSectionRow);CHKERRQ(ierr);}
7539   PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3);
7540   PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4);
7541   if (!sectionCol) {ierr = DMGetLocalSection(dmCol, &sectionCol);CHKERRQ(ierr);}
7542   PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5);
7543   if (!globalSectionCol) {ierr = DMGetGlobalSection(dmCol, &globalSectionCol);CHKERRQ(ierr);}
7544   PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6);
7545   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
7546 
7547   ierr = DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7548   ierr = DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7549 
7550   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values);CHKERRQ(ierr);}
7551   ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode);
7552   if (ierr) {
7553     PetscMPIInt    rank;
7554     PetscErrorCode ierr2;
7555 
7556     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2);
7557     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7558     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values);CHKERRQ(ierr2);
7559     ierr2 = DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr2);
7560     ierr2 = DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr2);
7561     if (values != valuesOrig) {ierr2 = DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values);CHKERRQ(ierr2);}
7562     CHKERRQ(ierr);
7563   }
7564 
7565   ierr = DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7566   ierr = DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7567   if (values != valuesOrig) {ierr = DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values);CHKERRQ(ierr);}
7568   PetscFunctionReturn(0);
7569 }
7570 
7571 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7572 {
7573   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
7574   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
7575   PetscInt       *cpoints = NULL;
7576   PetscInt       *findices, *cindices;
7577   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7578   PetscInt        foffsets[32], coffsets[32];
7579   DMPolytopeType  ct;
7580   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
7581   PetscErrorCode  ierr;
7582 
7583   PetscFunctionBegin;
7584   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
7585   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
7586   if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);}
7587   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
7588   if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);}
7589   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
7590   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
7591   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
7592   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
7593   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
7594   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
7595   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
7596   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7597   ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr);
7598   ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr);
7599   /* Column indices */
7600   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7601   maxFPoints = numCPoints;
7602   /* Compress out points not in the section */
7603   /*   TODO: Squeeze out points with 0 dof as well */
7604   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
7605   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
7606     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
7607       cpoints[q*2]   = cpoints[p];
7608       cpoints[q*2+1] = cpoints[p+1];
7609       ++q;
7610     }
7611   }
7612   numCPoints = q;
7613   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
7614     PetscInt fdof;
7615 
7616     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
7617     if (!dof) continue;
7618     for (f = 0; f < numFields; ++f) {
7619       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
7620       coffsets[f+1] += fdof;
7621     }
7622     numCIndices += dof;
7623   }
7624   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
7625   /* Row indices */
7626   ierr = DMPlexGetCellType(dmc, point, &ct);CHKERRQ(ierr);
7627   {
7628     DMPlexTransform tr;
7629     DMPolytopeType *rct;
7630     PetscInt       *rsize, *rcone, *rornt, Nt;
7631 
7632     ierr = DMPlexTransformCreate(PETSC_COMM_SELF, &tr);CHKERRQ(ierr);
7633     ierr = DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR);CHKERRQ(ierr);
7634     ierr = DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt);CHKERRQ(ierr);
7635     numSubcells = rsize[Nt-1];
7636     ierr = DMPlexTransformDestroy(&tr);CHKERRQ(ierr);
7637   }
7638   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7639   for (r = 0, q = 0; r < numSubcells; ++r) {
7640     /* TODO Map from coarse to fine cells */
7641     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7642     /* Compress out points not in the section */
7643     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
7644     for (p = 0; p < numFPoints*2; p += 2) {
7645       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
7646         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
7647         if (!dof) continue;
7648         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
7649         if (s < q) continue;
7650         ftotpoints[q*2]   = fpoints[p];
7651         ftotpoints[q*2+1] = fpoints[p+1];
7652         ++q;
7653       }
7654     }
7655     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7656   }
7657   numFPoints = q;
7658   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
7659     PetscInt fdof;
7660 
7661     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
7662     if (!dof) continue;
7663     for (f = 0; f < numFields; ++f) {
7664       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
7665       foffsets[f+1] += fdof;
7666     }
7667     numFIndices += dof;
7668   }
7669   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
7670 
7671   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
7672   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
7673   ierr = DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
7674   ierr = DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
7675   if (numFields) {
7676     const PetscInt **permsF[32] = {NULL};
7677     const PetscInt **permsC[32] = {NULL};
7678 
7679     for (f = 0; f < numFields; f++) {
7680       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7681       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7682     }
7683     for (p = 0; p < numFPoints; p++) {
7684       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7685       ierr = DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr);
7686     }
7687     for (p = 0; p < numCPoints; p++) {
7688       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7689       ierr = DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr);
7690     }
7691     for (f = 0; f < numFields; f++) {
7692       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7693       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7694     }
7695   } else {
7696     const PetscInt **permsF = NULL;
7697     const PetscInt **permsC = NULL;
7698 
7699     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7700     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7701     for (p = 0, off = 0; p < numFPoints; p++) {
7702       const PetscInt *perm = permsF ? permsF[p] : NULL;
7703 
7704       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7705       ierr = DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr);
7706     }
7707     for (p = 0, off = 0; p < numCPoints; p++) {
7708       const PetscInt *perm = permsC ? permsC[p] : NULL;
7709 
7710       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7711       ierr = DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr);
7712     }
7713     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7714     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7715   }
7716   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);}
7717   /* TODO: flips */
7718   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
7719   if (ierr) {
7720     PetscMPIInt    rank;
7721     PetscErrorCode ierr2;
7722 
7723     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2);
7724     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7725     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
7726     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
7727     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
7728     CHKERRQ(ierr);
7729   }
7730   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7731   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7732   ierr = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
7733   ierr = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
7734   PetscFunctionReturn(0);
7735 }
7736 
7737 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
7738 {
7739   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
7740   PetscInt      *cpoints = NULL;
7741   PetscInt       foffsets[32], coffsets[32];
7742   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7743   DMPolytopeType ct;
7744   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
7745   PetscErrorCode ierr;
7746 
7747   PetscFunctionBegin;
7748   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
7749   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
7750   if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);}
7751   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
7752   if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);}
7753   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
7754   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
7755   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
7756   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
7757   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
7758   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
7759   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7760   ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr);
7761   ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr);
7762   /* Column indices */
7763   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7764   maxFPoints = numCPoints;
7765   /* Compress out points not in the section */
7766   /*   TODO: Squeeze out points with 0 dof as well */
7767   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
7768   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
7769     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
7770       cpoints[q*2]   = cpoints[p];
7771       cpoints[q*2+1] = cpoints[p+1];
7772       ++q;
7773     }
7774   }
7775   numCPoints = q;
7776   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
7777     PetscInt fdof;
7778 
7779     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
7780     if (!dof) continue;
7781     for (f = 0; f < numFields; ++f) {
7782       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
7783       coffsets[f+1] += fdof;
7784     }
7785     numCIndices += dof;
7786   }
7787   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
7788   /* Row indices */
7789   ierr = DMPlexGetCellType(dmc, point, &ct);CHKERRQ(ierr);
7790   {
7791     DMPlexTransform tr;
7792     DMPolytopeType *rct;
7793     PetscInt       *rsize, *rcone, *rornt, Nt;
7794 
7795     ierr = DMPlexTransformCreate(PETSC_COMM_SELF, &tr);CHKERRQ(ierr);
7796     ierr = DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR);CHKERRQ(ierr);
7797     ierr = DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt);CHKERRQ(ierr);
7798     numSubcells = rsize[Nt-1];
7799     ierr = DMPlexTransformDestroy(&tr);CHKERRQ(ierr);
7800   }
7801   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7802   for (r = 0, q = 0; r < numSubcells; ++r) {
7803     /* TODO Map from coarse to fine cells */
7804     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7805     /* Compress out points not in the section */
7806     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
7807     for (p = 0; p < numFPoints*2; p += 2) {
7808       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
7809         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
7810         if (!dof) continue;
7811         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
7812         if (s < q) continue;
7813         ftotpoints[q*2]   = fpoints[p];
7814         ftotpoints[q*2+1] = fpoints[p+1];
7815         ++q;
7816       }
7817     }
7818     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7819   }
7820   numFPoints = q;
7821   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
7822     PetscInt fdof;
7823 
7824     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
7825     if (!dof) continue;
7826     for (f = 0; f < numFields; ++f) {
7827       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
7828       foffsets[f+1] += fdof;
7829     }
7830     numFIndices += dof;
7831   }
7832   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
7833 
7834   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
7835   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
7836   if (numFields) {
7837     const PetscInt **permsF[32] = {NULL};
7838     const PetscInt **permsC[32] = {NULL};
7839 
7840     for (f = 0; f < numFields; f++) {
7841       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7842       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7843     }
7844     for (p = 0; p < numFPoints; p++) {
7845       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7846       ierr = DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr);
7847     }
7848     for (p = 0; p < numCPoints; p++) {
7849       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7850       ierr = DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr);
7851     }
7852     for (f = 0; f < numFields; f++) {
7853       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7854       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7855     }
7856   } else {
7857     const PetscInt **permsF = NULL;
7858     const PetscInt **permsC = NULL;
7859 
7860     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7861     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7862     for (p = 0, off = 0; p < numFPoints; p++) {
7863       const PetscInt *perm = permsF ? permsF[p] : NULL;
7864 
7865       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7866       ierr = DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr);
7867     }
7868     for (p = 0, off = 0; p < numCPoints; p++) {
7869       const PetscInt *perm = permsC ? permsC[p] : NULL;
7870 
7871       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7872       ierr = DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr);
7873     }
7874     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7875     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7876   }
7877   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7878   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7879   PetscFunctionReturn(0);
7880 }
7881 
7882 /*@C
7883   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
7884 
7885   Input Parameter:
7886 . dm   - The DMPlex object
7887 
7888   Output Parameter:
7889 . cellHeight - The height of a cell
7890 
7891   Level: developer
7892 
7893 .seealso DMPlexSetVTKCellHeight()
7894 @*/
7895 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
7896 {
7897   DM_Plex *mesh = (DM_Plex*) dm->data;
7898 
7899   PetscFunctionBegin;
7900   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7901   PetscValidPointer(cellHeight, 2);
7902   *cellHeight = mesh->vtkCellHeight;
7903   PetscFunctionReturn(0);
7904 }
7905 
7906 /*@C
7907   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
7908 
7909   Input Parameters:
7910 + dm   - The DMPlex object
7911 - cellHeight - The height of a cell
7912 
7913   Level: developer
7914 
7915 .seealso DMPlexGetVTKCellHeight()
7916 @*/
7917 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
7918 {
7919   DM_Plex *mesh = (DM_Plex*) dm->data;
7920 
7921   PetscFunctionBegin;
7922   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7923   mesh->vtkCellHeight = cellHeight;
7924   PetscFunctionReturn(0);
7925 }
7926 
7927 /*@
7928   DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions
7929 
7930   Input Parameter:
7931 . dm - The DMPlex object
7932 
7933   Output Parameters:
7934 + gcStart - The first ghost cell, or NULL
7935 - gcEnd   - The upper bound on ghost cells, or NULL
7936 
7937   Level: advanced
7938 
7939 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum()
7940 @*/
7941 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd)
7942 {
7943   DMLabel        ctLabel;
7944   PetscErrorCode ierr;
7945 
7946   PetscFunctionBegin;
7947   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7948   ierr = DMPlexGetCellTypeLabel(dm, &ctLabel);CHKERRQ(ierr);
7949   ierr = DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd);CHKERRQ(ierr);
7950   PetscFunctionReturn(0);
7951 }
7952 
7953 /* We can easily have a form that takes an IS instead */
7954 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
7955 {
7956   PetscSection   section, globalSection;
7957   PetscInt      *numbers, p;
7958   PetscErrorCode ierr;
7959 
7960   PetscFunctionBegin;
7961   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
7962   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
7963   for (p = pStart; p < pEnd; ++p) {
7964     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
7965   }
7966   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
7967   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
7968   ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr);
7969   for (p = pStart; p < pEnd; ++p) {
7970     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
7971     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
7972     else                       numbers[p-pStart] += shift;
7973   }
7974   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
7975   if (globalSize) {
7976     PetscLayout layout;
7977     ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr);
7978     ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr);
7979     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
7980   }
7981   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
7982   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
7983   PetscFunctionReturn(0);
7984 }
7985 
7986 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
7987 {
7988   PetscInt       cellHeight, cStart, cEnd;
7989   PetscErrorCode ierr;
7990 
7991   PetscFunctionBegin;
7992   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
7993   if (includeHybrid) {ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);}
7994   else               {ierr = DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);}
7995   ierr = DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);CHKERRQ(ierr);
7996   PetscFunctionReturn(0);
7997 }
7998 
7999 /*@
8000   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
8001 
8002   Input Parameter:
8003 . dm   - The DMPlex object
8004 
8005   Output Parameter:
8006 . globalCellNumbers - Global cell numbers for all cells on this process
8007 
8008   Level: developer
8009 
8010 .seealso DMPlexGetVertexNumbering()
8011 @*/
8012 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
8013 {
8014   DM_Plex       *mesh = (DM_Plex*) dm->data;
8015   PetscErrorCode ierr;
8016 
8017   PetscFunctionBegin;
8018   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8019   if (!mesh->globalCellNumbers) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);CHKERRQ(ierr);}
8020   *globalCellNumbers = mesh->globalCellNumbers;
8021   PetscFunctionReturn(0);
8022 }
8023 
8024 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
8025 {
8026   PetscInt       vStart, vEnd;
8027   PetscErrorCode ierr;
8028 
8029   PetscFunctionBegin;
8030   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8031   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8032   ierr = DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);CHKERRQ(ierr);
8033   PetscFunctionReturn(0);
8034 }
8035 
8036 /*@
8037   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
8038 
8039   Input Parameter:
8040 . dm   - The DMPlex object
8041 
8042   Output Parameter:
8043 . globalVertexNumbers - Global vertex numbers for all vertices on this process
8044 
8045   Level: developer
8046 
8047 .seealso DMPlexGetCellNumbering()
8048 @*/
8049 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
8050 {
8051   DM_Plex       *mesh = (DM_Plex*) dm->data;
8052   PetscErrorCode ierr;
8053 
8054   PetscFunctionBegin;
8055   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8056   if (!mesh->globalVertexNumbers) {ierr = DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);CHKERRQ(ierr);}
8057   *globalVertexNumbers = mesh->globalVertexNumbers;
8058   PetscFunctionReturn(0);
8059 }
8060 
8061 /*@
8062   DMPlexCreatePointNumbering - Create a global numbering for all points on this process
8063 
8064   Input Parameter:
8065 . dm   - The DMPlex object
8066 
8067   Output Parameter:
8068 . globalPointNumbers - Global numbers for all points on this process
8069 
8070   Level: developer
8071 
8072 .seealso DMPlexGetCellNumbering()
8073 @*/
8074 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
8075 {
8076   IS             nums[4];
8077   PetscInt       depths[4], gdepths[4], starts[4];
8078   PetscInt       depth, d, shift = 0;
8079   PetscErrorCode ierr;
8080 
8081   PetscFunctionBegin;
8082   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8083   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8084   /* For unstratified meshes use dim instead of depth */
8085   if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);}
8086   for (d = 0; d <= depth; ++d) {
8087     PetscInt end;
8088 
8089     depths[d] = depth-d;
8090     ierr = DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);CHKERRQ(ierr);
8091     if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
8092   }
8093   ierr = PetscSortIntWithArray(depth+1, starts, depths);CHKERRQ(ierr);
8094   ierr = MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRMPI(ierr);
8095   for (d = 0; d <= depth; ++d) {
8096     if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
8097   }
8098   for (d = 0; d <= depth; ++d) {
8099     PetscInt pStart, pEnd, gsize;
8100 
8101     ierr = DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);CHKERRQ(ierr);
8102     ierr = DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr);
8103     shift += gsize;
8104   }
8105   ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);CHKERRQ(ierr);
8106   for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);}
8107   PetscFunctionReturn(0);
8108 }
8109 
8110 /*@
8111   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
8112 
8113   Input Parameter:
8114 . dm - The DMPlex object
8115 
8116   Output Parameter:
8117 . ranks - The rank field
8118 
8119   Options Database Keys:
8120 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
8121 
8122   Level: intermediate
8123 
8124 .seealso: DMView()
8125 @*/
8126 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
8127 {
8128   DM             rdm;
8129   PetscFE        fe;
8130   PetscScalar   *r;
8131   PetscMPIInt    rank;
8132   DMPolytopeType ct;
8133   PetscInt       dim, cStart, cEnd, c;
8134   PetscBool      simplex;
8135   PetscErrorCode ierr;
8136 
8137   PetscFunctionBeginUser;
8138   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8139   PetscValidPointer(ranks, 2);
8140   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRMPI(ierr);
8141   ierr = DMClone(dm, &rdm);CHKERRQ(ierr);
8142   ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr);
8143   ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8144   ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr);
8145   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
8146   ierr = PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe);CHKERRQ(ierr);
8147   ierr = PetscObjectSetName((PetscObject) fe, "rank");CHKERRQ(ierr);
8148   ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
8149   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
8150   ierr = DMCreateDS(rdm);CHKERRQ(ierr);
8151   ierr = DMCreateGlobalVector(rdm, ranks);CHKERRQ(ierr);
8152   ierr = PetscObjectSetName((PetscObject) *ranks, "partition");CHKERRQ(ierr);
8153   ierr = VecGetArray(*ranks, &r);CHKERRQ(ierr);
8154   for (c = cStart; c < cEnd; ++c) {
8155     PetscScalar *lr;
8156 
8157     ierr = DMPlexPointGlobalRef(rdm, c, r, &lr);CHKERRQ(ierr);
8158     if (lr) *lr = rank;
8159   }
8160   ierr = VecRestoreArray(*ranks, &r);CHKERRQ(ierr);
8161   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
8162   PetscFunctionReturn(0);
8163 }
8164 
8165 /*@
8166   DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
8167 
8168   Input Parameters:
8169 + dm    - The DMPlex
8170 - label - The DMLabel
8171 
8172   Output Parameter:
8173 . val - The label value field
8174 
8175   Options Database Keys:
8176 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer
8177 
8178   Level: intermediate
8179 
8180 .seealso: DMView()
8181 @*/
8182 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
8183 {
8184   DM             rdm;
8185   PetscFE        fe;
8186   PetscScalar   *v;
8187   PetscInt       dim, cStart, cEnd, c;
8188   PetscErrorCode ierr;
8189 
8190   PetscFunctionBeginUser;
8191   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8192   PetscValidPointer(label, 2);
8193   PetscValidPointer(val, 3);
8194   ierr = DMClone(dm, &rdm);CHKERRQ(ierr);
8195   ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr);
8196   ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);CHKERRQ(ierr);
8197   ierr = PetscObjectSetName((PetscObject) fe, "label_value");CHKERRQ(ierr);
8198   ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
8199   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
8200   ierr = DMCreateDS(rdm);CHKERRQ(ierr);
8201   ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8202   ierr = DMCreateGlobalVector(rdm, val);CHKERRQ(ierr);
8203   ierr = PetscObjectSetName((PetscObject) *val, "label_value");CHKERRQ(ierr);
8204   ierr = VecGetArray(*val, &v);CHKERRQ(ierr);
8205   for (c = cStart; c < cEnd; ++c) {
8206     PetscScalar *lv;
8207     PetscInt     cval;
8208 
8209     ierr = DMPlexPointGlobalRef(rdm, c, v, &lv);CHKERRQ(ierr);
8210     ierr = DMLabelGetValue(label, c, &cval);CHKERRQ(ierr);
8211     *lv = cval;
8212   }
8213   ierr = VecRestoreArray(*val, &v);CHKERRQ(ierr);
8214   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
8215   PetscFunctionReturn(0);
8216 }
8217 
8218 /*@
8219   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
8220 
8221   Input Parameter:
8222 . dm - The DMPlex object
8223 
8224   Notes:
8225   This is a useful diagnostic when creating meshes programmatically.
8226 
8227   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8228 
8229   Level: developer
8230 
8231 .seealso: DMCreate(), DMSetFromOptions()
8232 @*/
8233 PetscErrorCode DMPlexCheckSymmetry(DM dm)
8234 {
8235   PetscSection    coneSection, supportSection;
8236   const PetscInt *cone, *support;
8237   PetscInt        coneSize, c, supportSize, s;
8238   PetscInt        pStart, pEnd, p, pp, csize, ssize;
8239   PetscBool       storagecheck = PETSC_TRUE;
8240   PetscErrorCode  ierr;
8241 
8242   PetscFunctionBegin;
8243   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8244   ierr = DMViewFromOptions(dm, NULL, "-sym_dm_view");CHKERRQ(ierr);
8245   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
8246   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
8247   /* Check that point p is found in the support of its cone points, and vice versa */
8248   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
8249   for (p = pStart; p < pEnd; ++p) {
8250     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
8251     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
8252     for (c = 0; c < coneSize; ++c) {
8253       PetscBool dup = PETSC_FALSE;
8254       PetscInt  d;
8255       for (d = c-1; d >= 0; --d) {
8256         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
8257       }
8258       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
8259       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
8260       for (s = 0; s < supportSize; ++s) {
8261         if (support[s] == p) break;
8262       }
8263       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
8264         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);CHKERRQ(ierr);
8265         for (s = 0; s < coneSize; ++s) {
8266           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);CHKERRQ(ierr);
8267         }
8268         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8269         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);CHKERRQ(ierr);
8270         for (s = 0; s < supportSize; ++s) {
8271           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);CHKERRQ(ierr);
8272         }
8273         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8274         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
8275         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
8276       }
8277     }
8278     ierr = DMPlexGetTreeParent(dm, p, &pp, NULL);CHKERRQ(ierr);
8279     if (p != pp) { storagecheck = PETSC_FALSE; continue; }
8280     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
8281     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
8282     for (s = 0; s < supportSize; ++s) {
8283       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
8284       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8285       for (c = 0; c < coneSize; ++c) {
8286         ierr = DMPlexGetTreeParent(dm, cone[c], &pp, NULL);CHKERRQ(ierr);
8287         if (cone[c] != pp) { c = 0; break; }
8288         if (cone[c] == p) break;
8289       }
8290       if (c >= coneSize) {
8291         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);CHKERRQ(ierr);
8292         for (c = 0; c < supportSize; ++c) {
8293           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);CHKERRQ(ierr);
8294         }
8295         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8296         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);CHKERRQ(ierr);
8297         for (c = 0; c < coneSize; ++c) {
8298           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);CHKERRQ(ierr);
8299         }
8300         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8301         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
8302       }
8303     }
8304   }
8305   if (storagecheck) {
8306     ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
8307     ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
8308     if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
8309   }
8310   PetscFunctionReturn(0);
8311 }
8312 
8313 /*
8314   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.
8315 */
8316 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit)
8317 {
8318   DMPolytopeType  cct;
8319   PetscInt        ptpoints[4];
8320   const PetscInt *cone, *ccone, *ptcone;
8321   PetscInt        coneSize, cp, cconeSize, ccp, npt = 0, pt;
8322   PetscErrorCode  ierr;
8323 
8324   PetscFunctionBegin;
8325   *unsplit = 0;
8326   switch (ct) {
8327     case DM_POLYTOPE_POINT_PRISM_TENSOR:
8328       ptpoints[npt++] = c;
8329       break;
8330     case DM_POLYTOPE_SEG_PRISM_TENSOR:
8331       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8332       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8333       for (cp = 0; cp < coneSize; ++cp) {
8334         ierr = DMPlexGetCellType(dm, cone[cp], &cct);CHKERRQ(ierr);
8335         if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp];
8336       }
8337       break;
8338     case DM_POLYTOPE_TRI_PRISM_TENSOR:
8339     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8340       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8341       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8342       for (cp = 0; cp < coneSize; ++cp) {
8343         ierr = DMPlexGetCone(dm, cone[cp], &ccone);CHKERRQ(ierr);
8344         ierr = DMPlexGetConeSize(dm, cone[cp], &cconeSize);CHKERRQ(ierr);
8345         for (ccp = 0; ccp < cconeSize; ++ccp) {
8346           ierr = DMPlexGetCellType(dm, ccone[ccp], &cct);CHKERRQ(ierr);
8347           if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) {
8348             PetscInt p;
8349             for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break;
8350             if (p == npt) ptpoints[npt++] = ccone[ccp];
8351           }
8352         }
8353       }
8354       break;
8355     default: break;
8356   }
8357   for (pt = 0; pt < npt; ++pt) {
8358     ierr = DMPlexGetCone(dm, ptpoints[pt], &ptcone);CHKERRQ(ierr);
8359     if (ptcone[0] == ptcone[1]) ++(*unsplit);
8360   }
8361   PetscFunctionReturn(0);
8362 }
8363 
8364 /*@
8365   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
8366 
8367   Input Parameters:
8368 + dm - The DMPlex object
8369 - cellHeight - Normally 0
8370 
8371   Notes:
8372   This is a useful diagnostic when creating meshes programmatically.
8373   Currently applicable only to homogeneous simplex or tensor meshes.
8374 
8375   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8376 
8377   Level: developer
8378 
8379 .seealso: DMCreate(), DMSetFromOptions()
8380 @*/
8381 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
8382 {
8383   DMPlexInterpolatedFlag interp;
8384   DMPolytopeType         ct;
8385   PetscInt               vStart, vEnd, cStart, cEnd, c;
8386   PetscErrorCode         ierr;
8387 
8388   PetscFunctionBegin;
8389   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8390   ierr = DMPlexIsInterpolated(dm, &interp);CHKERRQ(ierr);
8391   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8392   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8393   for (c = cStart; c < cEnd; ++c) {
8394     PetscInt *closure = NULL;
8395     PetscInt  coneSize, closureSize, cl, Nv = 0;
8396 
8397     ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
8398     if ((PetscInt) ct < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has no cell type", c);
8399     if (ct == DM_POLYTOPE_UNKNOWN) continue;
8400     if (interp == DMPLEX_INTERPOLATED_FULL) {
8401       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8402       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));
8403     }
8404     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8405     for (cl = 0; cl < closureSize*2; cl += 2) {
8406       const PetscInt p = closure[cl];
8407       if ((p >= vStart) && (p < vEnd)) ++Nv;
8408     }
8409     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8410     /* Special Case: Tensor faces with identified vertices */
8411     if (Nv < DMPolytopeTypeGetNumVertices(ct)) {
8412       PetscInt unsplit;
8413 
8414       ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr);
8415       if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue;
8416     }
8417     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));
8418   }
8419   PetscFunctionReturn(0);
8420 }
8421 
8422 /*@
8423   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
8424 
8425   Not Collective
8426 
8427   Input Parameters:
8428 + dm - The DMPlex object
8429 - cellHeight - Normally 0
8430 
8431   Notes:
8432   This is a useful diagnostic when creating meshes programmatically.
8433   This routine is only relevant for meshes that are fully interpolated across all ranks.
8434   It will error out if a partially interpolated mesh is given on some rank.
8435   It will do nothing for locally uninterpolated mesh (as there is nothing to check).
8436 
8437   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8438 
8439   Level: developer
8440 
8441 .seealso: DMCreate(), DMPlexGetVTKCellHeight(), DMSetFromOptions()
8442 @*/
8443 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
8444 {
8445   PetscInt       dim, depth, vStart, vEnd, cStart, cEnd, c, h;
8446   PetscErrorCode ierr;
8447   DMPlexInterpolatedFlag interpEnum;
8448 
8449   PetscFunctionBegin;
8450   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8451   ierr = DMPlexIsInterpolated(dm, &interpEnum);CHKERRQ(ierr);
8452   if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0);
8453   if (interpEnum == DMPLEX_INTERPOLATED_PARTIAL) {
8454     PetscMPIInt rank;
8455     MPI_Comm    comm;
8456 
8457     ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
8458     ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
8459     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Mesh is only partially interpolated on rank %d, this is currently not supported", rank);
8460   }
8461 
8462   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8463   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8464   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8465   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
8466     ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr);
8467     for (c = cStart; c < cEnd; ++c) {
8468       const PetscInt      *cone, *ornt, *faceSizes, *faces;
8469       const DMPolytopeType *faceTypes;
8470       DMPolytopeType        ct;
8471       PetscInt              numFaces, coneSize, f;
8472       PetscInt             *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit;
8473 
8474       ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
8475       ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr);
8476       if (unsplit) continue;
8477       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8478       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8479       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
8480       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8481       for (cl = 0; cl < closureSize*2; cl += 2) {
8482         const PetscInt p = closure[cl];
8483         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
8484       }
8485       ierr = DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces);CHKERRQ(ierr);
8486       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);
8487       for (f = 0; f < numFaces; ++f) {
8488         DMPolytopeType fct;
8489         PetscInt       *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
8490 
8491         ierr = DMPlexGetCellType(dm, cone[f], &fct);CHKERRQ(ierr);
8492         ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
8493         for (cl = 0; cl < fclosureSize*2; cl += 2) {
8494           const PetscInt p = fclosure[cl];
8495           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
8496         }
8497         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]);
8498         for (v = 0; v < fnumCorners; ++v) {
8499           if (fclosure[v] != faces[fOff+v]) {
8500             PetscInt v1;
8501 
8502             ierr = PetscPrintf(PETSC_COMM_SELF, "face closure:");CHKERRQ(ierr);
8503             for (v1 = 0; v1 < fnumCorners; ++v1) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", fclosure[v1]);CHKERRQ(ierr);}
8504             ierr = PetscPrintf(PETSC_COMM_SELF, "\ncell face:");CHKERRQ(ierr);
8505             for (v1 = 0; v1 < fnumCorners; ++v1) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", faces[fOff+v1]);CHKERRQ(ierr);}
8506             ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8507             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]);
8508           }
8509         }
8510         ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
8511         fOff += faceSizes[f];
8512       }
8513       ierr = DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces);CHKERRQ(ierr);
8514       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8515     }
8516   }
8517   PetscFunctionReturn(0);
8518 }
8519 
8520 /*@
8521   DMPlexCheckGeometry - Check the geometry of mesh cells
8522 
8523   Input Parameter:
8524 . dm - The DMPlex object
8525 
8526   Notes:
8527   This is a useful diagnostic when creating meshes programmatically.
8528 
8529   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8530 
8531   Level: developer
8532 
8533 .seealso: DMCreate(), DMSetFromOptions()
8534 @*/
8535 PetscErrorCode DMPlexCheckGeometry(DM dm)
8536 {
8537   Vec            coordinates;
8538   PetscReal      detJ, J[9], refVol = 1.0;
8539   PetscReal      vol;
8540   PetscBool      periodic;
8541   PetscInt       dim, depth, dE, d, cStart, cEnd, c;
8542   PetscErrorCode ierr;
8543 
8544   PetscFunctionBegin;
8545   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8546   ierr = DMGetCoordinateDim(dm, &dE);CHKERRQ(ierr);
8547   if (dim != dE) PetscFunctionReturn(0);
8548   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8549   ierr = DMGetPeriodicity(dm, &periodic, NULL, NULL, NULL);CHKERRQ(ierr);
8550   for (d = 0; d < dim; ++d) refVol *= 2.0;
8551   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8552   /* Make sure local coordinates are created, because that step is collective */
8553   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8554   for (c = cStart; c < cEnd; ++c) {
8555     DMPolytopeType ct;
8556     PetscInt       unsplit;
8557     PetscBool      ignoreZeroVol = PETSC_FALSE;
8558 
8559     ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
8560     switch (ct) {
8561       case DM_POLYTOPE_SEG_PRISM_TENSOR:
8562       case DM_POLYTOPE_TRI_PRISM_TENSOR:
8563       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8564         ignoreZeroVol = PETSC_TRUE; break;
8565       default: break;
8566     }
8567     switch (ct) {
8568       case DM_POLYTOPE_TRI_PRISM:
8569       case DM_POLYTOPE_TRI_PRISM_TENSOR:
8570       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8571       case DM_POLYTOPE_PYRAMID:
8572         continue;
8573       default: break;
8574     }
8575     ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr);
8576     if (unsplit) continue;
8577     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);CHKERRQ(ierr);
8578     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);
8579     ierr = PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);CHKERRQ(ierr);
8580     if (depth > 1 && !periodic) {
8581       ierr = DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);CHKERRQ(ierr);
8582       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);
8583       ierr = PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);CHKERRQ(ierr);
8584     }
8585   }
8586   PetscFunctionReturn(0);
8587 }
8588 
8589 /*@
8590   DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex.
8591 
8592   Input Parameters:
8593 . dm - The DMPlex object
8594 
8595   Notes:
8596   This is mainly intended for debugging/testing purposes.
8597   It currently checks only meshes with no partition overlapping.
8598 
8599   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8600 
8601   Level: developer
8602 
8603 .seealso: DMGetPointSF(), DMSetFromOptions()
8604 @*/
8605 PetscErrorCode DMPlexCheckPointSF(DM dm)
8606 {
8607   PetscSF         pointSF;
8608   PetscInt        cellHeight, cStart, cEnd, l, nleaves, nroots, overlap;
8609   const PetscInt *locals, *rootdegree;
8610   PetscBool       distributed;
8611   PetscErrorCode  ierr;
8612 
8613   PetscFunctionBegin;
8614   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8615   ierr = DMGetPointSF(dm, &pointSF);CHKERRQ(ierr);
8616   ierr = DMPlexIsDistributed(dm, &distributed);CHKERRQ(ierr);
8617   if (!distributed) PetscFunctionReturn(0);
8618   ierr = DMPlexGetOverlap(dm, &overlap);CHKERRQ(ierr);
8619   if (overlap) {
8620     ierr = PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping");CHKERRQ(ierr);
8621     PetscFunctionReturn(0);
8622   }
8623   if (!pointSF) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but does not have PointSF attached");
8624   ierr = PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, NULL);CHKERRQ(ierr);
8625   if (nroots < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set");
8626   ierr = PetscSFComputeDegreeBegin(pointSF, &rootdegree);CHKERRQ(ierr);
8627   ierr = PetscSFComputeDegreeEnd(pointSF, &rootdegree);CHKERRQ(ierr);
8628 
8629   /* 1) check there are no faces in 2D, cells in 3D, in interface */
8630   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8631   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8632   for (l = 0; l < nleaves; ++l) {
8633     const PetscInt point = locals[l];
8634 
8635     if (point >= cStart && point < cEnd) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D which is a cell", point);
8636   }
8637 
8638   /* 2) if some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
8639   for (l = 0; l < nleaves; ++l) {
8640     const PetscInt  point = locals[l];
8641     const PetscInt *cone;
8642     PetscInt        coneSize, c, idx;
8643 
8644     ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
8645     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
8646     for (c = 0; c < coneSize; ++c) {
8647       if (!rootdegree[cone[c]]) {
8648         ierr = PetscFindInt(cone[c], nleaves, locals, &idx);CHKERRQ(ierr);
8649         if (idx < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D but not %D from its cone", point, cone[c]);
8650       }
8651     }
8652   }
8653   PetscFunctionReturn(0);
8654 }
8655 
8656 PetscErrorCode DMPlexCheckAll_Internal(DM dm, PetscInt cellHeight)
8657 {
8658   PetscErrorCode ierr;
8659 
8660   PetscFunctionBegin;
8661   ierr = DMPlexCheckSymmetry(dm);CHKERRQ(ierr);
8662   ierr = DMPlexCheckSkeleton(dm, cellHeight);CHKERRQ(ierr);
8663   ierr = DMPlexCheckFaces(dm, cellHeight);CHKERRQ(ierr);
8664   ierr = DMPlexCheckGeometry(dm);CHKERRQ(ierr);
8665   ierr = DMPlexCheckPointSF(dm);CHKERRQ(ierr);
8666   ierr = DMPlexCheckInterfaceCones(dm);CHKERRQ(ierr);
8667   PetscFunctionReturn(0);
8668 }
8669 
8670 typedef struct cell_stats
8671 {
8672   PetscReal min, max, sum, squaresum;
8673   PetscInt  count;
8674 } cell_stats_t;
8675 
8676 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
8677 {
8678   PetscInt i, N = *len;
8679 
8680   for (i = 0; i < N; i++) {
8681     cell_stats_t *A = (cell_stats_t *) a;
8682     cell_stats_t *B = (cell_stats_t *) b;
8683 
8684     B->min = PetscMin(A->min,B->min);
8685     B->max = PetscMax(A->max,B->max);
8686     B->sum += A->sum;
8687     B->squaresum += A->squaresum;
8688     B->count += A->count;
8689   }
8690 }
8691 
8692 /*@
8693   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
8694 
8695   Collective on dm
8696 
8697   Input Parameters:
8698 + dm        - The DMPlex object
8699 . output    - If true, statistics will be displayed on stdout
8700 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output
8701 
8702   Notes:
8703   This is mainly intended for debugging/testing purposes.
8704 
8705   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8706 
8707   Level: developer
8708 
8709 .seealso: DMSetFromOptions(), DMPlexComputeOrthogonalQuality()
8710 @*/
8711 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
8712 {
8713   DM             dmCoarse;
8714   cell_stats_t   stats, globalStats;
8715   MPI_Comm       comm = PetscObjectComm((PetscObject)dm);
8716   PetscReal      *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
8717   PetscReal      limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
8718   PetscInt       cdim, cStart, cEnd, c, eStart, eEnd, count = 0;
8719   PetscMPIInt    rank,size;
8720   PetscErrorCode ierr;
8721 
8722   PetscFunctionBegin;
8723   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8724   stats.min   = PETSC_MAX_REAL;
8725   stats.max   = PETSC_MIN_REAL;
8726   stats.sum   = stats.squaresum = 0.;
8727   stats.count = 0;
8728 
8729   ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr);
8730   ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
8731   ierr = DMGetCoordinateDim(dm,&cdim);CHKERRQ(ierr);
8732   ierr = PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ);CHKERRQ(ierr);
8733   ierr = DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd);CHKERRQ(ierr);
8734   ierr = DMPlexGetDepthStratum(dm,1,&eStart,&eEnd);CHKERRQ(ierr);
8735   for (c = cStart; c < cEnd; c++) {
8736     PetscInt  i;
8737     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
8738 
8739     ierr = DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);CHKERRQ(ierr);
8740     if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
8741     for (i = 0; i < PetscSqr(cdim); ++i) {
8742       frobJ    += J[i] * J[i];
8743       frobInvJ += invJ[i] * invJ[i];
8744     }
8745     cond2 = frobJ * frobInvJ;
8746     cond  = PetscSqrtReal(cond2);
8747 
8748     stats.min        = PetscMin(stats.min,cond);
8749     stats.max        = PetscMax(stats.max,cond);
8750     stats.sum       += cond;
8751     stats.squaresum += cond2;
8752     stats.count++;
8753     if (output && cond > limit) {
8754       PetscSection coordSection;
8755       Vec          coordsLocal;
8756       PetscScalar *coords = NULL;
8757       PetscInt     Nv, d, clSize, cl, *closure = NULL;
8758 
8759       ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8760       ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8761       ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr);
8762       ierr = PetscSynchronizedPrintf(comm, "[%d] Cell %D cond %g\n", rank, c, (double) cond);CHKERRQ(ierr);
8763       for (i = 0; i < Nv/cdim; ++i) {
8764         ierr = PetscSynchronizedPrintf(comm, "  Vertex %D: (", i);CHKERRQ(ierr);
8765         for (d = 0; d < cdim; ++d) {
8766           if (d > 0) {ierr = PetscSynchronizedPrintf(comm, ", ");CHKERRQ(ierr);}
8767           ierr = PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]));CHKERRQ(ierr);
8768         }
8769         ierr = PetscSynchronizedPrintf(comm, ")\n");CHKERRQ(ierr);
8770       }
8771       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
8772       for (cl = 0; cl < clSize*2; cl += 2) {
8773         const PetscInt edge = closure[cl];
8774 
8775         if ((edge >= eStart) && (edge < eEnd)) {
8776           PetscReal len;
8777 
8778           ierr = DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL);CHKERRQ(ierr);
8779           ierr = PetscSynchronizedPrintf(comm, "  Edge %D: length %g\n", edge, (double) len);CHKERRQ(ierr);
8780         }
8781       }
8782       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
8783       ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr);
8784     }
8785   }
8786   if (output) {ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);}
8787 
8788   if (size > 1) {
8789     PetscMPIInt   blockLengths[2] = {4,1};
8790     MPI_Aint      blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
8791     MPI_Datatype  blockTypes[2]   = {MPIU_REAL,MPIU_INT}, statType;
8792     MPI_Op        statReduce;
8793 
8794     ierr = MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);CHKERRMPI(ierr);
8795     ierr = MPI_Type_commit(&statType);CHKERRMPI(ierr);
8796     ierr = MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);CHKERRMPI(ierr);
8797     ierr = MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);CHKERRMPI(ierr);
8798     ierr = MPI_Op_free(&statReduce);CHKERRMPI(ierr);
8799     ierr = MPI_Type_free(&statType);CHKERRMPI(ierr);
8800   } else {
8801     ierr = PetscArraycpy(&globalStats,&stats,1);CHKERRQ(ierr);
8802   }
8803   if (rank == 0) {
8804     count = globalStats.count;
8805     min   = globalStats.min;
8806     max   = globalStats.max;
8807     mean  = globalStats.sum / globalStats.count;
8808     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
8809   }
8810 
8811   if (output) {
8812     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);
8813   }
8814   ierr = PetscFree2(J,invJ);CHKERRQ(ierr);
8815 
8816   ierr = DMGetCoarseDM(dm,&dmCoarse);CHKERRQ(ierr);
8817   if (dmCoarse) {
8818     PetscBool isplex;
8819 
8820     ierr = PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);CHKERRQ(ierr);
8821     if (isplex) {
8822       ierr = DMPlexCheckCellShape(dmCoarse,output,condLimit);CHKERRQ(ierr);
8823     }
8824   }
8825   PetscFunctionReturn(0);
8826 }
8827 
8828 /*@
8829   DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with
8830   orthogonal quality below given tolerance.
8831 
8832   Collective on dm
8833 
8834   Input Parameters:
8835 + dm   - The DMPlex object
8836 . fv   - Optional PetscFV object for pre-computed cell/face centroid information
8837 - atol - [0, 1] Absolute tolerance for tagging cells.
8838 
8839   Output Parameters:
8840 + OrthQual      - Vec containing orthogonal quality per cell
8841 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE
8842 
8843   Options Database Keys:
8844 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is
8845 supported.
8846 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector.
8847 
8848   Notes:
8849   Orthogonal quality is given by the following formula:
8850 
8851   \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]
8852 
8853   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
8854   is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the
8855   current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by
8856   calculating the cosine of the angle between these vectors.
8857 
8858   Orthogonal quality ranges from 1 (best) to 0 (worst).
8859 
8860   This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for
8861   pre-computed FVM cell data, but if it is not passed in then this data will be computed.
8862 
8863   Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance.
8864 
8865   Level: intermediate
8866 
8867 .seealso: DMPlexCheckCellShape(), DMCreateLabel()
8868 @*/
8869 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel)
8870 {
8871   PetscInt                nc, cellHeight, cStart, cEnd, cell, cellIter = 0;
8872   PetscInt                *idx;
8873   PetscScalar             *oqVals;
8874   const PetscScalar       *cellGeomArr, *faceGeomArr;
8875   PetscReal               *ci, *fi, *Ai;
8876   MPI_Comm                comm;
8877   Vec                     cellgeom, facegeom;
8878   DM                      dmFace, dmCell;
8879   IS                      glob;
8880   ISLocalToGlobalMapping  ltog;
8881   PetscViewer             vwr;
8882   PetscErrorCode          ierr;
8883 
8884   PetscFunctionBegin;
8885   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8886   if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);}
8887   PetscValidPointer(OrthQual, 4);
8888   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);
8889   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
8890   ierr = DMGetDimension(dm, &nc);CHKERRQ(ierr);
8891   if (nc < 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %D)", nc);
8892   {
8893     DMPlexInterpolatedFlag interpFlag;
8894 
8895     ierr = DMPlexIsInterpolated(dm, &interpFlag);CHKERRQ(ierr);
8896     if (interpFlag != DMPLEX_INTERPOLATED_FULL) {
8897       PetscMPIInt rank;
8898 
8899       ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
8900       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank);
8901     }
8902   }
8903   if (OrthQualLabel) {
8904     PetscValidPointer(OrthQualLabel, 5);
8905     ierr = DMCreateLabel(dm, "Orthogonal_Quality");CHKERRQ(ierr);
8906     ierr = DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel);CHKERRQ(ierr);
8907   } else {*OrthQualLabel = NULL;}
8908   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8909   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8910   ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob);CHKERRQ(ierr);
8911   ierr = ISLocalToGlobalMappingCreateIS(glob, &ltog);CHKERRQ(ierr);
8912   ierr = ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH);CHKERRQ(ierr);
8913   ierr = VecCreate(comm, OrthQual);CHKERRQ(ierr);
8914   ierr = VecSetType(*OrthQual, VECSTANDARD);CHKERRQ(ierr);
8915   ierr = VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE);CHKERRQ(ierr);
8916   ierr = VecSetLocalToGlobalMapping(*OrthQual, ltog);CHKERRQ(ierr);
8917   ierr = VecSetUp(*OrthQual);CHKERRQ(ierr);
8918   ierr = ISDestroy(&glob);CHKERRQ(ierr);
8919   ierr = ISLocalToGlobalMappingDestroy(&ltog);CHKERRQ(ierr);
8920   ierr = DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL);CHKERRQ(ierr);
8921   ierr = VecGetArrayRead(cellgeom, &cellGeomArr);CHKERRQ(ierr);
8922   ierr = VecGetArrayRead(facegeom, &faceGeomArr);CHKERRQ(ierr);
8923   ierr = VecGetDM(cellgeom, &dmCell);CHKERRQ(ierr);
8924   ierr = VecGetDM(facegeom, &dmFace);CHKERRQ(ierr);
8925   ierr = PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai);CHKERRQ(ierr);
8926   for (cell = cStart; cell < cEnd; cellIter++,cell++) {
8927     PetscInt           cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE;
8928     PetscInt           cellarr[2], *adj = NULL;
8929     PetscScalar        *cArr, *fArr;
8930     PetscReal          minvalc = 1.0, minvalf = 1.0;
8931     PetscFVCellGeom    *cg;
8932 
8933     idx[cellIter] = cell-cStart;
8934     cellarr[0] = cell;
8935     /* Make indexing into cellGeom easier */
8936     ierr = DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg);CHKERRQ(ierr);
8937     ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj);CHKERRQ(ierr);
8938     /* Technically 1 too big, but easier than fiddling with empty adjacency array */
8939     ierr = PetscCalloc2(adjSize, &cArr, adjSize, &fArr);CHKERRQ(ierr);
8940     for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) {
8941       PetscInt         i;
8942       const PetscInt   neigh = adj[cellneigh];
8943       PetscReal        normci = 0, normfi = 0, normai = 0;
8944       PetscFVCellGeom  *cgneigh;
8945       PetscFVFaceGeom  *fg;
8946 
8947       /* Don't count ourselves in the neighbor list */
8948       if (neigh == cell) continue;
8949       ierr = DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh);CHKERRQ(ierr);
8950       cellarr[1] = neigh;
8951       {
8952         PetscInt       numcovpts;
8953         const PetscInt *covpts;
8954 
8955         ierr = DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts);CHKERRQ(ierr);
8956         ierr = DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg);CHKERRQ(ierr);
8957         ierr = DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts);CHKERRQ(ierr);
8958       }
8959 
8960       /* Compute c_i, f_i and their norms */
8961       for (i = 0; i < nc; i++) {
8962         ci[i] = cgneigh->centroid[i] - cg->centroid[i];
8963         fi[i] = fg->centroid[i] - cg->centroid[i];
8964         Ai[i] = fg->normal[i];
8965         normci += PetscPowReal(ci[i], 2);
8966         normfi += PetscPowReal(fi[i], 2);
8967         normai += PetscPowReal(Ai[i], 2);
8968       }
8969       normci = PetscSqrtReal(normci);
8970       normfi = PetscSqrtReal(normfi);
8971       normai = PetscSqrtReal(normai);
8972 
8973       /* Normalize and compute for each face-cell-normal pair */
8974       for (i = 0; i < nc; i++) {
8975         ci[i] = ci[i]/normci;
8976         fi[i] = fi[i]/normfi;
8977         Ai[i] = Ai[i]/normai;
8978         /* PetscAbs because I don't know if normals are guaranteed to point out */
8979         cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]);
8980         fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]);
8981       }
8982       if (PetscRealPart(cArr[cellneighiter]) < minvalc) {
8983         minvalc = PetscRealPart(cArr[cellneighiter]);
8984       }
8985       if (PetscRealPart(fArr[cellneighiter]) < minvalf) {
8986         minvalf = PetscRealPart(fArr[cellneighiter]);
8987       }
8988     }
8989     ierr = PetscFree(adj);CHKERRQ(ierr);
8990     ierr = PetscFree2(cArr, fArr);CHKERRQ(ierr);
8991     /* Defer to cell if they're equal */
8992     oqVals[cellIter] = PetscMin(minvalf, minvalc);
8993     if (OrthQualLabel) {
8994       if (PetscRealPart(oqVals[cellIter]) <= atol) {ierr = DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE);CHKERRQ(ierr);}
8995     }
8996   }
8997   ierr = VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES);CHKERRQ(ierr);
8998   ierr = VecAssemblyBegin(*OrthQual);CHKERRQ(ierr);
8999   ierr = VecAssemblyEnd(*OrthQual);CHKERRQ(ierr);
9000   ierr = VecRestoreArrayRead(cellgeom, &cellGeomArr);CHKERRQ(ierr);
9001   ierr = VecRestoreArrayRead(facegeom, &faceGeomArr);CHKERRQ(ierr);
9002   ierr = PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL);CHKERRQ(ierr);
9003   if (OrthQualLabel) {
9004     if (vwr) {ierr = DMLabelView(*OrthQualLabel, vwr);CHKERRQ(ierr);}
9005   }
9006   ierr = PetscFree5(idx, oqVals, ci, fi, Ai);CHKERRQ(ierr);
9007   ierr = PetscViewerDestroy(&vwr);CHKERRQ(ierr);
9008   ierr = VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view");CHKERRQ(ierr);
9009   PetscFunctionReturn(0);
9010 }
9011 
9012 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect
9013  * interpolator construction */
9014 static PetscErrorCode DMGetFullDM(DM dm, DM *odm)
9015 {
9016   PetscSection   section, newSection, gsection;
9017   PetscSF        sf;
9018   PetscBool      hasConstraints, ghasConstraints;
9019   PetscErrorCode ierr;
9020 
9021   PetscFunctionBegin;
9022   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9023   PetscValidPointer(odm,2);
9024   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
9025   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
9026   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRMPI(ierr);
9027   if (!ghasConstraints) {
9028     ierr = PetscObjectReference((PetscObject)dm);CHKERRQ(ierr);
9029     *odm = dm;
9030     PetscFunctionReturn(0);
9031   }
9032   ierr = DMClone(dm, odm);CHKERRQ(ierr);
9033   ierr = DMCopyFields(dm, *odm);CHKERRQ(ierr);
9034   ierr = DMGetLocalSection(*odm, &newSection);CHKERRQ(ierr);
9035   ierr = DMGetPointSF(*odm, &sf);CHKERRQ(ierr);
9036   ierr = PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
9037   ierr = DMSetGlobalSection(*odm, gsection);CHKERRQ(ierr);
9038   ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
9039   PetscFunctionReturn(0);
9040 }
9041 
9042 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift)
9043 {
9044   DM             dmco, dmfo;
9045   Mat            interpo;
9046   Vec            rscale;
9047   Vec            cglobalo, clocal;
9048   Vec            fglobal, fglobalo, flocal;
9049   PetscBool      regular;
9050   PetscErrorCode ierr;
9051 
9052   PetscFunctionBegin;
9053   ierr = DMGetFullDM(dmc, &dmco);CHKERRQ(ierr);
9054   ierr = DMGetFullDM(dmf, &dmfo);CHKERRQ(ierr);
9055   ierr = DMSetCoarseDM(dmfo, dmco);CHKERRQ(ierr);
9056   ierr = DMPlexGetRegularRefinement(dmf, &regular);CHKERRQ(ierr);
9057   ierr = DMPlexSetRegularRefinement(dmfo, regular);CHKERRQ(ierr);
9058   ierr = DMCreateInterpolation(dmco, dmfo, &interpo, &rscale);CHKERRQ(ierr);
9059   ierr = DMCreateGlobalVector(dmco, &cglobalo);CHKERRQ(ierr);
9060   ierr = DMCreateLocalVector(dmc, &clocal);CHKERRQ(ierr);
9061   ierr = VecSet(cglobalo, 0.);CHKERRQ(ierr);
9062   ierr = VecSet(clocal, 0.);CHKERRQ(ierr);
9063   ierr = DMCreateGlobalVector(dmf, &fglobal);CHKERRQ(ierr);
9064   ierr = DMCreateGlobalVector(dmfo, &fglobalo);CHKERRQ(ierr);
9065   ierr = DMCreateLocalVector(dmf, &flocal);CHKERRQ(ierr);
9066   ierr = VecSet(fglobal, 0.);CHKERRQ(ierr);
9067   ierr = VecSet(fglobalo, 0.);CHKERRQ(ierr);
9068   ierr = VecSet(flocal, 0.);CHKERRQ(ierr);
9069   ierr = DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL);CHKERRQ(ierr);
9070   ierr = DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo);CHKERRQ(ierr);
9071   ierr = DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo);CHKERRQ(ierr);
9072   ierr = MatMult(interpo, cglobalo, fglobalo);CHKERRQ(ierr);
9073   ierr = DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal);CHKERRQ(ierr);
9074   ierr = DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal);CHKERRQ(ierr);
9075   ierr = DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal);CHKERRQ(ierr);
9076   ierr = DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal);CHKERRQ(ierr);
9077   *shift = fglobal;
9078   ierr = VecDestroy(&flocal);CHKERRQ(ierr);
9079   ierr = VecDestroy(&fglobalo);CHKERRQ(ierr);
9080   ierr = VecDestroy(&clocal);CHKERRQ(ierr);
9081   ierr = VecDestroy(&cglobalo);CHKERRQ(ierr);
9082   ierr = VecDestroy(&rscale);CHKERRQ(ierr);
9083   ierr = MatDestroy(&interpo);CHKERRQ(ierr);
9084   ierr = DMDestroy(&dmfo);CHKERRQ(ierr);
9085   ierr = DMDestroy(&dmco);CHKERRQ(ierr);
9086   PetscFunctionReturn(0);
9087 }
9088 
9089 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
9090 {
9091   PetscObject    shifto;
9092   Vec            shift;
9093 
9094   PetscErrorCode ierr;
9095 
9096   PetscFunctionBegin;
9097   if (!interp) {
9098     Vec rscale;
9099 
9100     ierr = DMCreateInterpolation(coarse, fine, &interp, &rscale);CHKERRQ(ierr);
9101     ierr = VecDestroy(&rscale);CHKERRQ(ierr);
9102   } else {
9103     ierr = PetscObjectReference((PetscObject)interp);CHKERRQ(ierr);
9104   }
9105   ierr = PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto);CHKERRQ(ierr);
9106   if (!shifto) {
9107     ierr = DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift);CHKERRQ(ierr);
9108     ierr = PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift);CHKERRQ(ierr);
9109     shifto = (PetscObject) shift;
9110     ierr = VecDestroy(&shift);CHKERRQ(ierr);
9111   }
9112   shift = (Vec) shifto;
9113   ierr = MatInterpolate(interp, coarseSol, fineSol);CHKERRQ(ierr);
9114   ierr = VecAXPY(fineSol, 1.0, shift);CHKERRQ(ierr);
9115   ierr = MatDestroy(&interp);CHKERRQ(ierr);
9116   PetscFunctionReturn(0);
9117 }
9118 
9119 /* Pointwise interpolation
9120      Just code FEM for now
9121      u^f = I u^c
9122      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
9123      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
9124      I_{ij} = psi^f_i phi^c_j
9125 */
9126 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
9127 {
9128   PetscSection   gsc, gsf;
9129   PetscInt       m, n;
9130   void          *ctx;
9131   DM             cdm;
9132   PetscBool      regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE;
9133   PetscErrorCode ierr;
9134 
9135   PetscFunctionBegin;
9136   ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
9137   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
9138   ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
9139   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
9140 
9141   ierr = PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);CHKERRQ(ierr);
9142   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr);
9143   ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
9144   ierr = MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);CHKERRQ(ierr);
9145   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
9146 
9147   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
9148   ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
9149   if (!isRefined || (regular && cdm == dmCoarse)) {ierr = DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx);CHKERRQ(ierr);}
9150   else                                            {ierr = DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
9151   ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr);
9152   if (scaling) {
9153     /* Use naive scaling */
9154     ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr);
9155   }
9156   PetscFunctionReturn(0);
9157 }
9158 
9159 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
9160 {
9161   PetscErrorCode ierr;
9162   VecScatter     ctx;
9163 
9164   PetscFunctionBegin;
9165   ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);CHKERRQ(ierr);
9166   ierr = MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);CHKERRQ(ierr);
9167   ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr);
9168   PetscFunctionReturn(0);
9169 }
9170 
9171 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux,
9172                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
9173                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
9174                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
9175 {
9176   g0[0] = 1.0;
9177 }
9178 
9179 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
9180 {
9181   PetscSection   gsc, gsf;
9182   PetscInt       m, n;
9183   void          *ctx;
9184   DM             cdm;
9185   PetscBool      regular;
9186   PetscErrorCode ierr;
9187 
9188   PetscFunctionBegin;
9189   if (dmFine == dmCoarse) {
9190     DM       dmc;
9191     PetscDS  ds;
9192     Vec      u;
9193     IS       cellIS;
9194     PetscFormKey key;
9195     PetscInt depth;
9196 
9197     ierr = DMClone(dmFine, &dmc);CHKERRQ(ierr);
9198     ierr = DMCopyDisc(dmFine, dmc);CHKERRQ(ierr);
9199     ierr = DMGetDS(dmc, &ds);CHKERRQ(ierr);
9200     ierr = PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL);CHKERRQ(ierr);
9201     ierr = DMCreateMatrix(dmc, mass);CHKERRQ(ierr);
9202     ierr = DMGetGlobalVector(dmc, &u);CHKERRQ(ierr);
9203     ierr = DMPlexGetDepth(dmc, &depth);CHKERRQ(ierr);
9204     ierr = DMGetStratumIS(dmc, "depth", depth, &cellIS);CHKERRQ(ierr);
9205     ierr = MatZeroEntries(*mass);CHKERRQ(ierr);
9206     key.label = NULL;
9207     key.value = 0;
9208     key.field = 0;
9209     key.part  = 0;
9210     ierr = DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL);CHKERRQ(ierr);
9211     ierr = ISDestroy(&cellIS);CHKERRQ(ierr);
9212     ierr = DMRestoreGlobalVector(dmc, &u);CHKERRQ(ierr);
9213     ierr = DMDestroy(&dmc);CHKERRQ(ierr);
9214   } else {
9215     ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
9216     ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
9217     ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
9218     ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
9219 
9220     ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);CHKERRQ(ierr);
9221     ierr = MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
9222     ierr = MatSetType(*mass, dmCoarse->mattype);CHKERRQ(ierr);
9223     ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
9224 
9225     ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
9226     ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
9227     if (regular && cdm == dmCoarse) {ierr = DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
9228     else                            {ierr = DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
9229   }
9230   ierr = MatViewFromOptions(*mass, NULL, "-mass_mat_view");CHKERRQ(ierr);
9231   PetscFunctionReturn(0);
9232 }
9233 
9234 /*@
9235   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
9236 
9237   Input Parameter:
9238 . dm - The DMPlex object
9239 
9240   Output Parameter:
9241 . regular - The flag
9242 
9243   Level: intermediate
9244 
9245 .seealso: DMPlexSetRegularRefinement()
9246 @*/
9247 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
9248 {
9249   PetscFunctionBegin;
9250   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9251   PetscValidPointer(regular, 2);
9252   *regular = ((DM_Plex *) dm->data)->regularRefinement;
9253   PetscFunctionReturn(0);
9254 }
9255 
9256 /*@
9257   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
9258 
9259   Input Parameters:
9260 + dm - The DMPlex object
9261 - regular - The flag
9262 
9263   Level: intermediate
9264 
9265 .seealso: DMPlexGetRegularRefinement()
9266 @*/
9267 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
9268 {
9269   PetscFunctionBegin;
9270   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9271   ((DM_Plex *) dm->data)->regularRefinement = regular;
9272   PetscFunctionReturn(0);
9273 }
9274 
9275 /* anchors */
9276 /*@
9277   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
9278   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
9279 
9280   not collective
9281 
9282   Input Parameter:
9283 . dm - The DMPlex object
9284 
9285   Output Parameters:
9286 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
9287 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
9288 
9289   Level: intermediate
9290 
9291 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
9292 @*/
9293 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
9294 {
9295   DM_Plex *plex = (DM_Plex *)dm->data;
9296   PetscErrorCode ierr;
9297 
9298   PetscFunctionBegin;
9299   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9300   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);}
9301   if (anchorSection) *anchorSection = plex->anchorSection;
9302   if (anchorIS) *anchorIS = plex->anchorIS;
9303   PetscFunctionReturn(0);
9304 }
9305 
9306 /*@
9307   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
9308   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
9309   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
9310 
9311   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
9312   DMGetConstraints() and filling in the entries in the constraint matrix.
9313 
9314   collective on dm
9315 
9316   Input Parameters:
9317 + dm - The DMPlex object
9318 . 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).
9319 - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
9320 
9321   The reference counts of anchorSection and anchorIS are incremented.
9322 
9323   Level: intermediate
9324 
9325 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
9326 @*/
9327 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
9328 {
9329   DM_Plex        *plex = (DM_Plex *)dm->data;
9330   PetscMPIInt    result;
9331   PetscErrorCode ierr;
9332 
9333   PetscFunctionBegin;
9334   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9335   if (anchorSection) {
9336     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
9337     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRMPI(ierr);
9338     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
9339   }
9340   if (anchorIS) {
9341     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
9342     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRMPI(ierr);
9343     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
9344   }
9345 
9346   ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr);
9347   ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr);
9348   plex->anchorSection = anchorSection;
9349 
9350   ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr);
9351   ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr);
9352   plex->anchorIS = anchorIS;
9353 
9354   if (PetscUnlikelyDebug(anchorIS && anchorSection)) {
9355     PetscInt size, a, pStart, pEnd;
9356     const PetscInt *anchors;
9357 
9358     ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
9359     ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr);
9360     ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr);
9361     for (a = 0; a < size; a++) {
9362       PetscInt p;
9363 
9364       p = anchors[a];
9365       if (p >= pStart && p < pEnd) {
9366         PetscInt dof;
9367 
9368         ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
9369         if (dof) {
9370           PetscErrorCode ierr2;
9371 
9372           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
9373           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
9374         }
9375       }
9376     }
9377     ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr);
9378   }
9379   /* reset the generic constraints */
9380   ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr);
9381   PetscFunctionReturn(0);
9382 }
9383 
9384 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
9385 {
9386   PetscSection anchorSection;
9387   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
9388   PetscErrorCode ierr;
9389 
9390   PetscFunctionBegin;
9391   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9392   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
9393   ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr);
9394   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
9395   if (numFields) {
9396     PetscInt f;
9397     ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr);
9398 
9399     for (f = 0; f < numFields; f++) {
9400       PetscInt numComp;
9401 
9402       ierr = PetscSectionGetFieldComponents(section,f,&numComp);CHKERRQ(ierr);
9403       ierr = PetscSectionSetFieldComponents(*cSec,f,numComp);CHKERRQ(ierr);
9404     }
9405   }
9406   ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
9407   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
9408   pStart = PetscMax(pStart,sStart);
9409   pEnd   = PetscMin(pEnd,sEnd);
9410   pEnd   = PetscMax(pStart,pEnd);
9411   ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr);
9412   for (p = pStart; p < pEnd; p++) {
9413     ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
9414     if (dof) {
9415       ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
9416       ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr);
9417       for (f = 0; f < numFields; f++) {
9418         ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
9419         ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr);
9420       }
9421     }
9422   }
9423   ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr);
9424   ierr = PetscObjectSetName((PetscObject) *cSec, "Constraint Section");CHKERRQ(ierr);
9425   PetscFunctionReturn(0);
9426 }
9427 
9428 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
9429 {
9430   PetscSection   aSec;
9431   PetscInt       pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
9432   const PetscInt *anchors;
9433   PetscInt       numFields, f;
9434   IS             aIS;
9435   PetscErrorCode ierr;
9436   MatType        mtype;
9437   PetscBool      iscuda,iskokkos;
9438 
9439   PetscFunctionBegin;
9440   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9441   ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr);
9442   ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr);
9443   ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr);
9444   ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr);
9445   ierr = PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda);CHKERRQ(ierr);
9446   if (!iscuda) { ierr = PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda);CHKERRQ(ierr); }
9447   ierr = PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos);CHKERRQ(ierr);
9448   if (!iskokkos) { ierr = PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos);CHKERRQ(ierr); }
9449   if (iscuda) mtype = MATSEQAIJCUSPARSE;
9450   else if (iskokkos) mtype = MATSEQAIJKOKKOS;
9451   else mtype = MATSEQAIJ;
9452   ierr = MatSetType(*cMat,mtype);CHKERRQ(ierr);
9453   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
9454   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
9455   /* cSec will be a subset of aSec and section */
9456   ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
9457   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
9458   ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr);
9459   i[0] = 0;
9460   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
9461   for (p = pStart; p < pEnd; p++) {
9462     PetscInt rDof, rOff, r;
9463 
9464     ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
9465     if (!rDof) continue;
9466     ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
9467     if (numFields) {
9468       for (f = 0; f < numFields; f++) {
9469         annz = 0;
9470         for (r = 0; r < rDof; r++) {
9471           a = anchors[rOff + r];
9472           if (a < sStart || a >= sEnd) continue;
9473           ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
9474           annz += aDof;
9475         }
9476         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
9477         ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr);
9478         for (q = 0; q < dof; q++) {
9479           i[off + q + 1] = i[off + q] + annz;
9480         }
9481       }
9482     }
9483     else {
9484       annz = 0;
9485       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
9486       for (q = 0; q < dof; q++) {
9487         a = anchors[rOff + q];
9488         if (a < sStart || a >= sEnd) continue;
9489         ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
9490         annz += aDof;
9491       }
9492       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
9493       ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr);
9494       for (q = 0; q < dof; q++) {
9495         i[off + q + 1] = i[off + q] + annz;
9496       }
9497     }
9498   }
9499   nnz = i[m];
9500   ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr);
9501   offset = 0;
9502   for (p = pStart; p < pEnd; p++) {
9503     if (numFields) {
9504       for (f = 0; f < numFields; f++) {
9505         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
9506         for (q = 0; q < dof; q++) {
9507           PetscInt rDof, rOff, r;
9508           ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
9509           ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
9510           for (r = 0; r < rDof; r++) {
9511             PetscInt s;
9512 
9513             a = anchors[rOff + r];
9514             if (a < sStart || a >= sEnd) continue;
9515             ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
9516             ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr);
9517             for (s = 0; s < aDof; s++) {
9518               j[offset++] = aOff + s;
9519             }
9520           }
9521         }
9522       }
9523     }
9524     else {
9525       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
9526       for (q = 0; q < dof; q++) {
9527         PetscInt rDof, rOff, r;
9528         ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
9529         ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
9530         for (r = 0; r < rDof; r++) {
9531           PetscInt s;
9532 
9533           a = anchors[rOff + r];
9534           if (a < sStart || a >= sEnd) continue;
9535           ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
9536           ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr);
9537           for (s = 0; s < aDof; s++) {
9538             j[offset++] = aOff + s;
9539           }
9540         }
9541       }
9542     }
9543   }
9544   ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr);
9545   ierr = PetscFree(i);CHKERRQ(ierr);
9546   ierr = PetscFree(j);CHKERRQ(ierr);
9547   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
9548   PetscFunctionReturn(0);
9549 }
9550 
9551 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
9552 {
9553   DM_Plex        *plex = (DM_Plex *)dm->data;
9554   PetscSection   anchorSection, section, cSec;
9555   Mat            cMat;
9556   PetscErrorCode ierr;
9557 
9558   PetscFunctionBegin;
9559   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9560   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
9561   if (anchorSection) {
9562     PetscInt Nf;
9563 
9564     ierr = DMGetLocalSection(dm,&section);CHKERRQ(ierr);
9565     ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr);
9566     ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr);
9567     ierr = DMGetNumFields(dm,&Nf);CHKERRQ(ierr);
9568     if (Nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);}
9569     ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr);
9570     ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr);
9571     ierr = MatDestroy(&cMat);CHKERRQ(ierr);
9572   }
9573   PetscFunctionReturn(0);
9574 }
9575 
9576 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
9577 {
9578   IS             subis;
9579   PetscSection   section, subsection;
9580   PetscErrorCode ierr;
9581 
9582   PetscFunctionBegin;
9583   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
9584   if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
9585   if (!subdm)   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
9586   /* Create subdomain */
9587   ierr = DMPlexFilter(dm, label, value, subdm);CHKERRQ(ierr);
9588   /* Create submodel */
9589   ierr = DMPlexGetSubpointIS(*subdm, &subis);CHKERRQ(ierr);
9590   ierr = PetscSectionCreateSubmeshSection(section, subis, &subsection);CHKERRQ(ierr);
9591   ierr = DMSetLocalSection(*subdm, subsection);CHKERRQ(ierr);
9592   ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
9593   ierr = DMCopyDisc(dm, *subdm);CHKERRQ(ierr);
9594   /* Create map from submodel to global model */
9595   if (is) {
9596     PetscSection    sectionGlobal, subsectionGlobal;
9597     IS              spIS;
9598     const PetscInt *spmap;
9599     PetscInt       *subIndices;
9600     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
9601     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
9602 
9603     ierr = DMPlexGetSubpointIS(*subdm, &spIS);CHKERRQ(ierr);
9604     ierr = ISGetIndices(spIS, &spmap);CHKERRQ(ierr);
9605     ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
9606     ierr = DMGetGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
9607     ierr = DMGetGlobalSection(*subdm, &subsectionGlobal);CHKERRQ(ierr);
9608     ierr = PetscSectionGetChart(subsection, &pStart, &pEnd);CHKERRQ(ierr);
9609     for (p = pStart; p < pEnd; ++p) {
9610       PetscInt gdof, pSubSize  = 0;
9611 
9612       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
9613       if (gdof > 0) {
9614         for (f = 0; f < Nf; ++f) {
9615           PetscInt fdof, fcdof;
9616 
9617           ierr     = PetscSectionGetFieldDof(subsection, p, f, &fdof);CHKERRQ(ierr);
9618           ierr     = PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);CHKERRQ(ierr);
9619           pSubSize += fdof-fcdof;
9620         }
9621         subSize += pSubSize;
9622         if (pSubSize) {
9623           if (bs < 0) {
9624             bs = pSubSize;
9625           } else if (bs != pSubSize) {
9626             /* Layout does not admit a pointwise block size */
9627             bs = 1;
9628           }
9629         }
9630       }
9631     }
9632     /* Must have same blocksize on all procs (some might have no points) */
9633     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
9634     ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr);
9635     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
9636     else                            {bs = bsMinMax[0];}
9637     ierr = PetscMalloc1(subSize, &subIndices);CHKERRQ(ierr);
9638     for (p = pStart; p < pEnd; ++p) {
9639       PetscInt gdof, goff;
9640 
9641       ierr = PetscSectionGetDof(subsectionGlobal, p, &gdof);CHKERRQ(ierr);
9642       if (gdof > 0) {
9643         const PetscInt point = spmap[p];
9644 
9645         ierr = PetscSectionGetOffset(sectionGlobal, point, &goff);CHKERRQ(ierr);
9646         for (f = 0; f < Nf; ++f) {
9647           PetscInt fdof, fcdof, fc, f2, poff = 0;
9648 
9649           /* Can get rid of this loop by storing field information in the global section */
9650           for (f2 = 0; f2 < f; ++f2) {
9651             ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
9652             ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
9653             poff += fdof-fcdof;
9654           }
9655           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
9656           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
9657           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
9658             subIndices[subOff] = goff+poff+fc;
9659           }
9660         }
9661       }
9662     }
9663     ierr = ISRestoreIndices(spIS, &spmap);CHKERRQ(ierr);
9664     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);
9665     if (bs > 1) {
9666       /* We need to check that the block size does not come from non-contiguous fields */
9667       PetscInt i, j, set = 1;
9668       for (i = 0; i < subSize; i += bs) {
9669         for (j = 0; j < bs; ++j) {
9670           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
9671         }
9672       }
9673       if (set) {ierr = ISSetBlockSize(*is, bs);CHKERRQ(ierr);}
9674     }
9675     /* Attach nullspace */
9676     for (f = 0; f < Nf; ++f) {
9677       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
9678       if ((*subdm)->nullspaceConstructors[f]) break;
9679     }
9680     if (f < Nf) {
9681       MatNullSpace nullSpace;
9682       ierr = (*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace);CHKERRQ(ierr);
9683 
9684       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
9685       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
9686     }
9687   }
9688   PetscFunctionReturn(0);
9689 }
9690 
9691 /*@
9692   DMPlexMonitorThroughput - Report the cell throughput of FE integration
9693 
9694   Input Parameter:
9695 - dm - The DM
9696 
9697   Level: developer
9698 
9699   Options Database Keys:
9700 . -dm_plex_monitor_throughput - Activate the monitor
9701 
9702 .seealso: DMSetFromOptions(), DMPlexCreate()
9703 @*/
9704 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy)
9705 {
9706 #if defined(PETSC_USE_LOG)
9707   PetscStageLog      stageLog;
9708   PetscLogEvent      event;
9709   PetscLogStage      stage;
9710   PetscEventPerfInfo eventInfo;
9711   PetscReal          cellRate, flopRate;
9712   PetscInt           cStart, cEnd, Nf, N;
9713   const char        *name;
9714   PetscErrorCode     ierr;
9715 #endif
9716 
9717   PetscFunctionBegin;
9718   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9719 #if defined(PETSC_USE_LOG)
9720   ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
9721   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9722   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
9723   ierr = PetscLogGetStageLog(&stageLog);CHKERRQ(ierr);
9724   ierr = PetscStageLogGetCurrent(stageLog, &stage);CHKERRQ(ierr);
9725   ierr = PetscLogEventGetId("DMPlexResidualFE", &event);CHKERRQ(ierr);
9726   ierr = PetscLogEventGetPerfInfo(stage, event, &eventInfo);CHKERRQ(ierr);
9727   N        = (cEnd - cStart)*Nf*eventInfo.count;
9728   flopRate = eventInfo.flops/eventInfo.time;
9729   cellRate = N/eventInfo.time;
9730   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);
9731 #else
9732   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log.");
9733 #endif
9734   PetscFunctionReturn(0);
9735 }
9736