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