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