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