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