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