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