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