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