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