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