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