xref: /petsc/src/dm/impls/plex/plex.c (revision c9ad657ee665028d2ed9861512a1c779b61e2acc)
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 #include <petscdmplextransform.h>
10 
11 /* Logging support */
12 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;
13 
14 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
15 
16 /*@
17   DMPlexIsSimplex - Is the first cell in this mesh a simplex?
18 
19   Input Parameter:
20 . dm      - The DMPlex object
21 
22   Output Parameter:
23 . simplex - Flag checking for a simplex
24 
25   Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
26   If the mesh has no cells, this returns PETSC_FALSE.
27 
28   Level: intermediate
29 
30 .seealso DMPlexGetSimplexOrBoxCells(), DMPlexGetCellType(), DMPlexGetHeightStratum(), DMPolytopeTypeGetNumVertices()
31 @*/
32 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex)
33 {
34   DMPolytopeType ct;
35   PetscInt       cStart, cEnd;
36   PetscErrorCode ierr;
37 
38   PetscFunctionBegin;
39   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
40   if (cEnd <= cStart) {*simplex = PETSC_FALSE; PetscFunctionReturn(0);}
41   ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr);
42   *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
43   PetscFunctionReturn(0);
44 }
45 
46 /*@
47   DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells
48 
49   Input Parameters:
50 + dm     - The DMPlex object
51 - height - The cell height in the Plex, 0 is the default
52 
53   Output Parameters:
54 + cStart - The first "normal" cell
55 - cEnd   - The upper bound on "normal"" cells
56 
57   Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
58 
59   Level: developer
60 
61 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum()
62 @*/
63 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd)
64 {
65   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
66   PetscInt       cS, cE, c;
67   PetscErrorCode ierr;
68 
69   PetscFunctionBegin;
70   ierr = DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE);CHKERRQ(ierr);
71   for (c = cS; c < cE; ++c) {
72     DMPolytopeType cct;
73 
74     ierr = DMPlexGetCellType(dm, c, &cct);CHKERRQ(ierr);
75     if ((PetscInt) cct < 0) break;
76     switch (cct) {
77       case DM_POLYTOPE_POINT:
78       case DM_POLYTOPE_SEGMENT:
79       case DM_POLYTOPE_TRIANGLE:
80       case DM_POLYTOPE_QUADRILATERAL:
81       case DM_POLYTOPE_TETRAHEDRON:
82       case DM_POLYTOPE_HEXAHEDRON:
83         ct = cct;
84         break;
85       default: break;
86     }
87     if (ct != DM_POLYTOPE_UNKNOWN) break;
88   }
89   if (ct != DM_POLYTOPE_UNKNOWN) {
90     DMLabel ctLabel;
91 
92     ierr = DMPlexGetCellTypeLabel(dm, &ctLabel);CHKERRQ(ierr);
93     ierr = DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE);CHKERRQ(ierr);
94   }
95   if (cStart) *cStart = cS;
96   if (cEnd)   *cEnd   = cE;
97   PetscFunctionReturn(0);
98 }
99 
100 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
101 {
102   PetscInt       cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd;
103   PetscInt       vcdof[2] = {0,0}, globalvcdof[2];
104   PetscErrorCode ierr;
105 
106   PetscFunctionBegin;
107   *ft  = PETSC_VTK_INVALID;
108   ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
109   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
110   ierr = DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
111   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
112   if (field >= 0) {
113     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]);CHKERRQ(ierr);}
114     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]);CHKERRQ(ierr);}
115   } else {
116     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vcdof[0]);CHKERRQ(ierr);}
117     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &vcdof[1]);CHKERRQ(ierr);}
118   }
119   ierr = MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
120   if (globalvcdof[0]) {
121     *sStart = vStart;
122     *sEnd   = vEnd;
123     if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
124     else                        *ft = PETSC_VTK_POINT_FIELD;
125   } else if (globalvcdof[1]) {
126     *sStart = cStart;
127     *sEnd   = cEnd;
128     if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
129     else                        *ft = PETSC_VTK_CELL_FIELD;
130   } else {
131     if (field >= 0) {
132       const char *fieldname;
133 
134       ierr = PetscSectionGetFieldName(section, field, &fieldname);CHKERRQ(ierr);
135       ierr = PetscInfo2((PetscObject) dm, "Could not classify VTK output type of section field %D \"%s\"\n", field, fieldname);CHKERRQ(ierr);
136     } else {
137       ierr = PetscInfo((PetscObject) dm, "Could not classify VTK output type of section\"%s\"\n");CHKERRQ(ierr);
138     }
139   }
140   PetscFunctionReturn(0);
141 }
142 
143 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
144 {
145   DM                 dm;
146   PetscSection       s;
147   PetscDraw          draw, popup;
148   DM                 cdm;
149   PetscSection       coordSection;
150   Vec                coordinates;
151   const PetscScalar *coords, *array;
152   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
153   PetscReal          vbound[2], time;
154   PetscBool          isnull, flg;
155   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
156   const char        *name;
157   char               title[PETSC_MAX_PATH_LEN];
158   PetscErrorCode     ierr;
159 
160   PetscFunctionBegin;
161   ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr);
162   ierr = PetscDrawIsNull(draw, &isnull);CHKERRQ(ierr);
163   if (isnull) PetscFunctionReturn(0);
164 
165   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
166   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
167   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D. Use PETSCVIEWERGLVIS", dim);
168   ierr = DMGetLocalSection(dm, &s);CHKERRQ(ierr);
169   ierr = PetscSectionGetNumFields(s, &Nf);CHKERRQ(ierr);
170   ierr = DMGetCoarsenLevel(dm, &level);CHKERRQ(ierr);
171   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
172   ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr);
173   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
174   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
175   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
176 
177   ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
178   ierr = DMGetOutputSequenceNumber(dm, &step, &time);CHKERRQ(ierr);
179 
180   ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr);
181   ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr);
182   for (c = 0; c < N; c += dim) {
183     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
184     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
185   }
186   ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr);
187   ierr = PetscDrawClear(draw);CHKERRQ(ierr);
188 
189   /* Could implement something like DMDASelectFields() */
190   for (f = 0; f < Nf; ++f) {
191     DM   fdm = dm;
192     Vec  fv  = v;
193     IS   fis;
194     char prefix[PETSC_MAX_PATH_LEN];
195     const char *fname;
196 
197     ierr = PetscSectionGetFieldComponents(s, f, &Nc);CHKERRQ(ierr);
198     ierr = PetscSectionGetFieldName(s, f, &fname);CHKERRQ(ierr);
199 
200     if (v->hdr.prefix) {ierr = PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix));CHKERRQ(ierr);}
201     else               {prefix[0] = '\0';}
202     if (Nf > 1) {
203       ierr = DMCreateSubDM(dm, 1, &f, &fis, &fdm);CHKERRQ(ierr);
204       ierr = VecGetSubVector(v, fis, &fv);CHKERRQ(ierr);
205       ierr = PetscStrlcat(prefix, fname,sizeof(prefix));CHKERRQ(ierr);
206       ierr = PetscStrlcat(prefix, "_",sizeof(prefix));CHKERRQ(ierr);
207     }
208     for (comp = 0; comp < Nc; ++comp, ++w) {
209       PetscInt nmax = 2;
210 
211       ierr = PetscViewerDrawGetDraw(viewer, w, &draw);CHKERRQ(ierr);
212       if (Nc > 1) {ierr = PetscSNPrintf(title, sizeof(title), "%s:%s_%D Step: %D Time: %.4g", name, fname, comp, step, time);CHKERRQ(ierr);}
213       else        {ierr = PetscSNPrintf(title, sizeof(title), "%s:%s Step: %D Time: %.4g", name, fname, step, time);CHKERRQ(ierr);}
214       ierr = PetscDrawSetTitle(draw, title);CHKERRQ(ierr);
215 
216       /* TODO Get max and min only for this component */
217       ierr = PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);CHKERRQ(ierr);
218       if (!flg) {
219         ierr = VecMin(fv, NULL, &vbound[0]);CHKERRQ(ierr);
220         ierr = VecMax(fv, NULL, &vbound[1]);CHKERRQ(ierr);
221         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
222       }
223       ierr = PetscDrawGetPopup(draw, &popup);CHKERRQ(ierr);
224       ierr = PetscDrawScalePopup(popup, vbound[0], vbound[1]);CHKERRQ(ierr);
225       ierr = PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);CHKERRQ(ierr);
226 
227       ierr = VecGetArrayRead(fv, &array);CHKERRQ(ierr);
228       for (c = cStart; c < cEnd; ++c) {
229         PetscScalar *coords = NULL, *a = NULL;
230         PetscInt     numCoords, color[4] = {-1,-1,-1,-1};
231 
232         ierr = DMPlexPointLocalRead(fdm, c, array, &a);CHKERRQ(ierr);
233         if (a) {
234           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
235           color[1] = color[2] = color[3] = color[0];
236         } else {
237           PetscScalar *vals = NULL;
238           PetscInt     numVals, va;
239 
240           ierr = DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);CHKERRQ(ierr);
241           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);
242           switch (numVals/Nc) {
243           case 3: /* P1 Triangle */
244           case 4: /* P1 Quadrangle */
245             for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]);
246             break;
247           case 6: /* P2 Triangle */
248           case 8: /* P2 Quadrangle */
249             for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]);
250             break;
251           default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc);
252           }
253           ierr = DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);CHKERRQ(ierr);
254         }
255         ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr);
256         switch (numCoords) {
257         case 6:
258         case 12: /* Localized triangle */
259           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);
260           break;
261         case 8:
262         case 16: /* Localized quadrilateral */
263           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);
264           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);
265           break;
266         default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
267         }
268         ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr);
269       }
270       ierr = VecRestoreArrayRead(fv, &array);CHKERRQ(ierr);
271       ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
272       ierr = PetscDrawPause(draw);CHKERRQ(ierr);
273       ierr = PetscDrawSave(draw);CHKERRQ(ierr);
274     }
275     if (Nf > 1) {
276       ierr = VecRestoreSubVector(v, fis, &fv);CHKERRQ(ierr);
277       ierr = ISDestroy(&fis);CHKERRQ(ierr);
278       ierr = DMDestroy(&fdm);CHKERRQ(ierr);
279     }
280   }
281   PetscFunctionReturn(0);
282 }
283 
284 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
285 {
286   DM                      dm;
287   Vec                     locv;
288   const char              *name;
289   PetscSection            section;
290   PetscInt                pStart, pEnd;
291   PetscInt                numFields;
292   PetscViewerVTKFieldType ft;
293   PetscErrorCode          ierr;
294 
295   PetscFunctionBegin;
296   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
297   ierr = DMCreateLocalVector(dm, &locv);CHKERRQ(ierr); /* VTK viewer requires exclusive ownership of the vector */
298   ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
299   ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
300   ierr = VecCopy(v, locv);CHKERRQ(ierr);
301   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
302   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
303   if (!numFields) {
304     ierr = DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);CHKERRQ(ierr);
305     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv);CHKERRQ(ierr);
306   } else {
307     PetscInt f;
308 
309     for (f = 0; f < numFields; f++) {
310       ierr = DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft);CHKERRQ(ierr);
311       if (ft == PETSC_VTK_INVALID) continue;
312       ierr = PetscObjectReference((PetscObject)locv);CHKERRQ(ierr);
313       ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv);CHKERRQ(ierr);
314     }
315     ierr = VecDestroy(&locv);CHKERRQ(ierr);
316   }
317   PetscFunctionReturn(0);
318 }
319 
320 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
321 {
322   DM             dm;
323   PetscBool      isvtk, ishdf5, isdraw, isglvis;
324   PetscErrorCode ierr;
325 
326   PetscFunctionBegin;
327   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
328   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
329   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);CHKERRQ(ierr);
330   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);CHKERRQ(ierr);
331   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);CHKERRQ(ierr);
332   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);CHKERRQ(ierr);
333   if (isvtk || ishdf5 || isdraw || isglvis) {
334     PetscInt    i,numFields;
335     PetscObject fe;
336     PetscBool   fem = PETSC_FALSE;
337     Vec         locv = v;
338     const char  *name;
339     PetscInt    step;
340     PetscReal   time;
341 
342     ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr);
343     for (i=0; i<numFields; i++) {
344       ierr = DMGetField(dm, i, NULL, &fe);CHKERRQ(ierr);
345       if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; }
346     }
347     if (fem) {
348       PetscObject isZero;
349 
350       ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
351       ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
352       ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
353       ierr = PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero);CHKERRQ(ierr);
354       ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero);CHKERRQ(ierr);
355       ierr = VecCopy(v, locv);CHKERRQ(ierr);
356       ierr = DMGetOutputSequenceNumber(dm, NULL, &time);CHKERRQ(ierr);
357       ierr = DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);CHKERRQ(ierr);
358     }
359     if (isvtk) {
360       ierr = VecView_Plex_Local_VTK(locv, viewer);CHKERRQ(ierr);
361     } else if (ishdf5) {
362 #if defined(PETSC_HAVE_HDF5)
363       ierr = VecView_Plex_Local_HDF5_Internal(locv, viewer);CHKERRQ(ierr);
364 #else
365       SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
366 #endif
367     } else if (isdraw) {
368       ierr = VecView_Plex_Local_Draw(locv, viewer);CHKERRQ(ierr);
369     } else if (isglvis) {
370       ierr = DMGetOutputSequenceNumber(dm, &step, NULL);CHKERRQ(ierr);
371       ierr = PetscViewerGLVisSetSnapId(viewer, step);CHKERRQ(ierr);
372       ierr = VecView_GLVis(locv, viewer);CHKERRQ(ierr);
373     }
374     if (fem) {
375       ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL);CHKERRQ(ierr);
376       ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
377     }
378   } else {
379     PetscBool isseq;
380 
381     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
382     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
383     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
384   }
385   PetscFunctionReturn(0);
386 }
387 
388 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
389 {
390   DM             dm;
391   PetscBool      isvtk, ishdf5, isdraw, isglvis, isexodusii;
392   PetscErrorCode ierr;
393 
394   PetscFunctionBegin;
395   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
396   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
397   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,      &isvtk);CHKERRQ(ierr);
398   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5);CHKERRQ(ierr);
399   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,     &isdraw);CHKERRQ(ierr);
400   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS,    &isglvis);CHKERRQ(ierr);
401   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii);CHKERRQ(ierr);
402   if (isvtk || isdraw || isglvis) {
403     Vec         locv;
404     PetscObject isZero;
405     const char *name;
406 
407     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
408     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
409     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
410     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
411     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
412     ierr = PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero);CHKERRQ(ierr);
413     ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero);CHKERRQ(ierr);
414     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
415     ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL);CHKERRQ(ierr);
416     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
417   } else if (ishdf5) {
418 #if defined(PETSC_HAVE_HDF5)
419     ierr = VecView_Plex_HDF5_Internal(v, viewer);CHKERRQ(ierr);
420 #else
421     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
422 #endif
423   } else if (isexodusii) {
424 #if defined(PETSC_HAVE_EXODUSII)
425     ierr = VecView_PlexExodusII_Internal(v, viewer);CHKERRQ(ierr);
426 #else
427     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
428 #endif
429   } else {
430     PetscBool isseq;
431 
432     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
433     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
434     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
435   }
436   PetscFunctionReturn(0);
437 }
438 
439 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
440 {
441   DM                dm;
442   MPI_Comm          comm;
443   PetscViewerFormat format;
444   Vec               v;
445   PetscBool         isvtk, ishdf5;
446   PetscErrorCode    ierr;
447 
448   PetscFunctionBegin;
449   ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr);
450   ierr = PetscObjectGetComm((PetscObject) originalv, &comm);CHKERRQ(ierr);
451   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
452   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
453   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
454   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);CHKERRQ(ierr);
455   if (format == PETSC_VIEWER_NATIVE) {
456     /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
457     /* this need a better fix */
458     if (dm->useNatural) {
459       if (dm->sfNatural) {
460         const char *vecname;
461         PetscInt    n, nroots;
462 
463         ierr = VecGetLocalSize(originalv, &n);CHKERRQ(ierr);
464         ierr = PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
465         if (n == nroots) {
466           ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr);
467           ierr = DMPlexGlobalToNaturalBegin(dm, originalv, v);CHKERRQ(ierr);
468           ierr = DMPlexGlobalToNaturalEnd(dm, originalv, v);CHKERRQ(ierr);
469           ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr);
470           ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr);
471         } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
472       } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
473     } else v = originalv;
474   } else v = originalv;
475 
476   if (ishdf5) {
477 #if defined(PETSC_HAVE_HDF5)
478     ierr = VecView_Plex_HDF5_Native_Internal(v, viewer);CHKERRQ(ierr);
479 #else
480     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
481 #endif
482   } else if (isvtk) {
483     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
484   } else {
485     PetscBool isseq;
486 
487     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
488     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
489     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
490   }
491   if (v != originalv) {ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr);}
492   PetscFunctionReturn(0);
493 }
494 
495 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
496 {
497   DM             dm;
498   PetscBool      ishdf5;
499   PetscErrorCode ierr;
500 
501   PetscFunctionBegin;
502   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
503   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
504   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
505   if (ishdf5) {
506     DM          dmBC;
507     Vec         gv;
508     const char *name;
509 
510     ierr = DMGetOutputDM(dm, &dmBC);CHKERRQ(ierr);
511     ierr = DMGetGlobalVector(dmBC, &gv);CHKERRQ(ierr);
512     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
513     ierr = PetscObjectSetName((PetscObject) gv, name);CHKERRQ(ierr);
514     ierr = VecLoad_Default(gv, viewer);CHKERRQ(ierr);
515     ierr = DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr);
516     ierr = DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr);
517     ierr = DMRestoreGlobalVector(dmBC, &gv);CHKERRQ(ierr);
518   } else {
519     ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr);
520   }
521   PetscFunctionReturn(0);
522 }
523 
524 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
525 {
526   DM             dm;
527   PetscBool      ishdf5,isexodusii;
528   PetscErrorCode ierr;
529 
530   PetscFunctionBegin;
531   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
532   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
533   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5);CHKERRQ(ierr);
534   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii);CHKERRQ(ierr);
535   if (ishdf5) {
536 #if defined(PETSC_HAVE_HDF5)
537     ierr = VecLoad_Plex_HDF5_Internal(v, viewer);CHKERRQ(ierr);
538 #else
539     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
540 #endif
541   } else if (isexodusii) {
542 #if defined(PETSC_HAVE_EXODUSII)
543     ierr = VecLoad_PlexExodusII_Internal(v, viewer);CHKERRQ(ierr);
544 #else
545     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
546 #endif
547   } else {
548     ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr);
549   }
550   PetscFunctionReturn(0);
551 }
552 
553 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
554 {
555   DM                dm;
556   PetscViewerFormat format;
557   PetscBool         ishdf5;
558   PetscErrorCode    ierr;
559 
560   PetscFunctionBegin;
561   ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr);
562   if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
563   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
564   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
565   if (format == PETSC_VIEWER_NATIVE) {
566     if (dm->useNatural) {
567       if (dm->sfNatural) {
568         if (ishdf5) {
569 #if defined(PETSC_HAVE_HDF5)
570           Vec         v;
571           const char *vecname;
572 
573           ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr);
574           ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr);
575           ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr);
576           ierr = VecLoad_Plex_HDF5_Native_Internal(v, viewer);CHKERRQ(ierr);
577           ierr = DMPlexNaturalToGlobalBegin(dm, v, originalv);CHKERRQ(ierr);
578           ierr = DMPlexNaturalToGlobalEnd(dm, v, originalv);CHKERRQ(ierr);
579           ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr);
580 #else
581           SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
582 #endif
583         } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
584       }
585     } else {
586       ierr = VecLoad_Default(originalv, viewer);CHKERRQ(ierr);
587     }
588   }
589   PetscFunctionReturn(0);
590 }
591 
592 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
593 {
594   PetscSection       coordSection;
595   Vec                coordinates;
596   DMLabel            depthLabel, celltypeLabel;
597   const char        *name[4];
598   const PetscScalar *a;
599   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
600   PetscErrorCode     ierr;
601 
602   PetscFunctionBegin;
603   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
604   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
605   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
606   ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr);
607   ierr = DMPlexGetCellTypeLabel(dm, &celltypeLabel);CHKERRQ(ierr);
608   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
609   ierr = PetscSectionGetChart(coordSection, &pStart, &pEnd);CHKERRQ(ierr);
610   ierr = VecGetArrayRead(coordinates, &a);CHKERRQ(ierr);
611   name[0]     = "vertex";
612   name[1]     = "edge";
613   name[dim-1] = "face";
614   name[dim]   = "cell";
615   for (c = cStart; c < cEnd; ++c) {
616     PetscInt *closure = NULL;
617     PetscInt  closureSize, cl, ct;
618 
619     ierr = DMLabelGetValue(celltypeLabel, c, &ct);CHKERRQ(ierr);
620     ierr = PetscViewerASCIIPrintf(viewer, "Geometry for cell %D polytope type %s:\n", c, DMPolytopeTypes[ct]);CHKERRQ(ierr);
621     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
622     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
623     for (cl = 0; cl < closureSize*2; cl += 2) {
624       PetscInt point = closure[cl], depth, dof, off, d, p;
625 
626       if ((point < pStart) || (point >= pEnd)) continue;
627       ierr = PetscSectionGetDof(coordSection, point, &dof);CHKERRQ(ierr);
628       if (!dof) continue;
629       ierr = DMLabelGetValue(depthLabel, point, &depth);CHKERRQ(ierr);
630       ierr = PetscSectionGetOffset(coordSection, point, &off);CHKERRQ(ierr);
631       ierr = PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);CHKERRQ(ierr);
632       for (p = 0; p < dof/dim; ++p) {
633         ierr = PetscViewerASCIIPrintf(viewer, " (");CHKERRQ(ierr);
634         for (d = 0; d < dim; ++d) {
635           if (d > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
636           ierr = PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]));CHKERRQ(ierr);
637         }
638         ierr = PetscViewerASCIIPrintf(viewer, ")");CHKERRQ(ierr);
639       }
640       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
641     }
642     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
643     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
644   }
645   ierr = VecRestoreArrayRead(coordinates, &a);CHKERRQ(ierr);
646   PetscFunctionReturn(0);
647 }
648 
649 typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem;
650 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL};
651 
652 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[])
653 {
654   PetscInt       i;
655   PetscErrorCode ierr;
656 
657   PetscFunctionBegin;
658   if (dim > 3) {
659     for (i = 0; i < dim; ++i) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i]));CHKERRQ(ierr);}
660   } else {
661     PetscReal coords[3], trcoords[3];
662 
663     for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]);
664     switch (cs) {
665       case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break;
666       case CS_POLAR:
667         if (dim != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %D", dim);
668         trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
669         trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
670         break;
671       case CS_CYLINDRICAL:
672         if (dim != 3) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %D", dim);
673         trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
674         trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
675         trcoords[2] = coords[2];
676         break;
677       case CS_SPHERICAL:
678         if (dim != 3) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %D", dim);
679         trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2]));
680         trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]);
681         trcoords[2] = PetscAtan2Real(coords[1], coords[0]);
682         break;
683     }
684     for (i = 0; i < dim; ++i) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i]);CHKERRQ(ierr);}
685   }
686   PetscFunctionReturn(0);
687 }
688 
689 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
690 {
691   DM_Plex          *mesh = (DM_Plex*) dm->data;
692   DM                cdm;
693   PetscSection      coordSection;
694   Vec               coordinates;
695   PetscViewerFormat format;
696   PetscErrorCode    ierr;
697 
698   PetscFunctionBegin;
699   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
700   ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr);
701   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
702   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
703   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
704     const char *name;
705     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
706     PetscInt    pStart, pEnd, p, numLabels, l;
707     PetscMPIInt rank, size;
708 
709     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRMPI(ierr);
710     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRMPI(ierr);
711     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
712     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
713     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
714     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
715     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
716     if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
717     else      {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
718     if (cellHeight) {ierr = PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);CHKERRQ(ierr);}
719     ierr = PetscViewerASCIIPrintf(viewer, "Supports:\n", name);CHKERRQ(ierr);
720     ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
721     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %D\n", rank, maxSupportSize);CHKERRQ(ierr);
722     for (p = pStart; p < pEnd; ++p) {
723       PetscInt dof, off, s;
724 
725       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
726       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
727       for (s = off; s < off+dof; ++s) {
728         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
729       }
730     }
731     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
732     ierr = PetscViewerASCIIPrintf(viewer, "Cones:\n", name);CHKERRQ(ierr);
733     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %D\n", rank, maxConeSize);CHKERRQ(ierr);
734     for (p = pStart; p < pEnd; ++p) {
735       PetscInt dof, off, c;
736 
737       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
738       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
739       for (c = off; c < off+dof; ++c) {
740         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
741       }
742     }
743     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
744     ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
745     if (coordSection && coordinates) {
746       CoordSystem        cs = CS_CARTESIAN;
747       const PetscScalar *array;
748       PetscInt           Nf, Nc, pStart, pEnd, p;
749       PetscMPIInt        rank;
750       const char        *name;
751 
752       ierr = PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL);CHKERRQ(ierr);
753       ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank);CHKERRMPI(ierr);
754       ierr = PetscSectionGetNumFields(coordSection, &Nf);CHKERRQ(ierr);
755       if (Nf != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %D", Nf);
756       ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
757       ierr = PetscSectionGetChart(coordSection, &pStart, &pEnd);CHKERRQ(ierr);
758       ierr = PetscObjectGetName((PetscObject) coordinates, &name);CHKERRQ(ierr);
759       ierr = PetscViewerASCIIPrintf(viewer, "%s with %D fields\n", name, Nf);CHKERRQ(ierr);
760       ierr = PetscViewerASCIIPrintf(viewer, "  field 0 with %D components\n", Nc);CHKERRQ(ierr);
761       if (cs != CS_CARTESIAN) {ierr = PetscViewerASCIIPrintf(viewer, "  output coordinate system: %s\n", CoordSystems[cs]);CHKERRQ(ierr);}
762 
763       ierr = VecGetArrayRead(coordinates, &array);CHKERRQ(ierr);
764       ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
765       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank);CHKERRQ(ierr);
766       for (p = pStart; p < pEnd; ++p) {
767         PetscInt dof, off;
768 
769         ierr = PetscSectionGetDof(coordSection, p, &dof);CHKERRQ(ierr);
770         ierr = PetscSectionGetOffset(coordSection, p, &off);CHKERRQ(ierr);
771         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "  (%4D) dim %2D offset %3D", p, dof, off);CHKERRQ(ierr);
772         ierr = DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off]);CHKERRQ(ierr);
773         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\n");CHKERRQ(ierr);
774       }
775       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
776       ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
777       ierr = VecRestoreArrayRead(coordinates, &array);CHKERRQ(ierr);
778     }
779     ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
780     if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);}
781     for (l = 0; l < numLabels; ++l) {
782       DMLabel     label;
783       PetscBool   isdepth;
784       const char *name;
785 
786       ierr = DMGetLabelName(dm, l, &name);CHKERRQ(ierr);
787       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
788       if (isdepth) continue;
789       ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
790       ierr = DMLabelView(label, viewer);CHKERRQ(ierr);
791     }
792     if (size > 1) {
793       PetscSF sf;
794 
795       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
796       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
797     }
798     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
799   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
800     const char  *name, *color;
801     const char  *defcolors[3]  = {"gray", "orange", "green"};
802     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
803     char         lname[PETSC_MAX_PATH_LEN];
804     PetscReal    scale         = 2.0;
805     PetscReal    tikzscale     = 1.0;
806     PetscBool    useNumbers    = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE;
807     double       tcoords[3];
808     PetscScalar *coords;
809     PetscInt     numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n;
810     PetscMPIInt  rank, size;
811     char         **names, **colors, **lcolors;
812     PetscBool    flg, lflg;
813     PetscBT      wp = NULL;
814     PetscInt     pEnd, pStart;
815 
816     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
817     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
818     ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
819     numLabels  = PetscMax(numLabels, 10);
820     numColors  = 10;
821     numLColors = 10;
822     ierr = PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);CHKERRQ(ierr);
823     ierr = PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);CHKERRQ(ierr);
824     ierr = PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL);CHKERRQ(ierr);
825     ierr = PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);CHKERRQ(ierr);
826     for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers;
827     for (d = 0; d < 4; ++d) drawColors[d]  = PETSC_TRUE;
828     n = 4;
829     ierr = PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg);CHKERRQ(ierr);
830     if (flg && n != dim+1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %D != %D dim+1", n, dim+1);
831     ierr = PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg);CHKERRQ(ierr);
832     if (flg && n != dim+1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %D != %D dim+1", n, dim+1);
833     ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);CHKERRQ(ierr);
834     if (!useLabels) numLabels = 0;
835     ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);CHKERRQ(ierr);
836     if (!useColors) {
837       numColors = 3;
838       for (c = 0; c < numColors; ++c) {ierr = PetscStrallocpy(defcolors[c], &colors[c]);CHKERRQ(ierr);}
839     }
840     ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);CHKERRQ(ierr);
841     if (!useColors) {
842       numLColors = 4;
843       for (c = 0; c < numLColors; ++c) {ierr = PetscStrallocpy(deflcolors[c], &lcolors[c]);CHKERRQ(ierr);}
844     }
845     ierr = PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg);CHKERRQ(ierr);
846     plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3);
847     ierr = PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg);CHKERRQ(ierr);
848     if (flg && plotEdges && depth < dim) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated");
849     if (depth < dim) plotEdges = PETSC_FALSE;
850     ierr = PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL);CHKERRQ(ierr);
851 
852     /* filter points with labelvalue != labeldefaultvalue */
853     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
854     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
855     ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
856     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
857     if (lflg) {
858       DMLabel lbl;
859 
860       ierr = DMGetLabel(dm, lname, &lbl);CHKERRQ(ierr);
861       if (lbl) {
862         PetscInt val, defval;
863 
864         ierr = DMLabelGetDefaultValue(lbl, &defval);CHKERRQ(ierr);
865         ierr = PetscBTCreate(pEnd-pStart, &wp);CHKERRQ(ierr);
866         for (c = pStart;  c < pEnd; c++) {
867           PetscInt *closure = NULL;
868           PetscInt  closureSize;
869 
870           ierr = DMLabelGetValue(lbl, c, &val);CHKERRQ(ierr);
871           if (val == defval) continue;
872 
873           ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
874           for (p = 0; p < closureSize*2; p += 2) {
875             ierr = PetscBTSet(wp, closure[p] - pStart);CHKERRQ(ierr);
876           }
877           ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
878         }
879       }
880     }
881 
882     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRMPI(ierr);
883     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRMPI(ierr);
884     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
885     ierr = PetscViewerASCIIPrintf(viewer, "\
886 \\documentclass[tikz]{standalone}\n\n\
887 \\usepackage{pgflibraryshapes}\n\
888 \\usetikzlibrary{backgrounds}\n\
889 \\usetikzlibrary{arrows}\n\
890 \\begin{document}\n");CHKERRQ(ierr);
891     if (size > 1) {
892       ierr = PetscViewerASCIIPrintf(viewer, "%s for process ", name);CHKERRQ(ierr);
893       for (p = 0; p < size; ++p) {
894         if (p > 0 && p == size-1) {
895           ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
896         } else if (p > 0) {
897           ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
898         }
899         ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
900       }
901       ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n");CHKERRQ(ierr);
902     }
903     if (drawHasse) {
904       PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart));
905 
906       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%D}\n", vStart);CHKERRQ(ierr);
907       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%D}\n", vEnd-1);CHKERRQ(ierr);
908       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%D}\n", vEnd-vStart);CHKERRQ(ierr);
909       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.);CHKERRQ(ierr);
910       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%D}\n", eStart);CHKERRQ(ierr);
911       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%D}\n", eEnd-1);CHKERRQ(ierr);
912       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.);CHKERRQ(ierr);
913       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%D}\n", eEnd-eStart);CHKERRQ(ierr);
914       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%D}\n", cStart);CHKERRQ(ierr);
915       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%D}\n", cEnd-1);CHKERRQ(ierr);
916       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%D}\n", cEnd-cStart);CHKERRQ(ierr);
917       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.);CHKERRQ(ierr);
918     }
919     ierr = PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale);CHKERRQ(ierr);
920 
921     /* Plot vertices */
922     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
923     ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
924     for (v = vStart; v < vEnd; ++v) {
925       PetscInt  off, dof, d;
926       PetscBool isLabeled = PETSC_FALSE;
927 
928       if (wp && !PetscBTLookup(wp,v - pStart)) continue;
929       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
930       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
931       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");CHKERRQ(ierr);
932       if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
933       for (d = 0; d < dof; ++d) {
934         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
935         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
936       }
937       /* Rotate coordinates since PGF makes z point out of the page instead of up */
938       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
939       for (d = 0; d < dof; ++d) {
940         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
941         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d]);CHKERRQ(ierr);
942       }
943       if (drawHasse) color = colors[0%numColors];
944       else           color = colors[rank%numColors];
945       for (l = 0; l < numLabels; ++l) {
946         PetscInt val;
947         ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr);
948         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
949       }
950       if (drawNumbers[0]) {
951         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);CHKERRQ(ierr);
952       } else if (drawColors[0]) {
953         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);CHKERRQ(ierr);
954       } else {
955         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [] {};\n", v, rank);CHKERRQ(ierr);
956       }
957     }
958     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
959     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
960     /* Plot edges */
961     if (plotEdges) {
962       ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
963       ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
964       for (e = eStart; e < eEnd; ++e) {
965         const PetscInt *cone;
966         PetscInt        coneSize, offA, offB, dof, d;
967 
968         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
969         ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
970         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
971         ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
972         ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
973         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
974         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
975         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
976         for (d = 0; d < dof; ++d) {
977           tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
978           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
979         }
980         /* Rotate coordinates since PGF makes z point out of the page instead of up */
981         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
982         for (d = 0; d < dof; ++d) {
983           if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
984           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);CHKERRQ(ierr);
985         }
986         if (drawHasse) color = colors[1%numColors];
987         else           color = colors[rank%numColors];
988         for (l = 0; l < numLabels; ++l) {
989           PetscInt val;
990           ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr);
991           if (val >= 0) {color = lcolors[l%numLColors]; break;}
992         }
993         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);CHKERRQ(ierr);
994       }
995       ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
996       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
997       ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
998     }
999     /* Plot cells */
1000     if (dim == 3 || !drawNumbers[1]) {
1001       for (e = eStart; e < eEnd; ++e) {
1002         const PetscInt *cone;
1003 
1004         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
1005         color = colors[rank%numColors];
1006         for (l = 0; l < numLabels; ++l) {
1007           PetscInt val;
1008           ierr = DMGetLabelValue(dm, names[l], e, &val);CHKERRQ(ierr);
1009           if (val >= 0) {color = lcolors[l%numLColors]; break;}
1010         }
1011         ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
1012         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);CHKERRQ(ierr);
1013       }
1014     } else {
1015        DMPolytopeType ct;
1016 
1017       /* Drawing a 2D polygon */
1018       for (c = cStart; c < cEnd; ++c) {
1019         if (wp && !PetscBTLookup(wp, c - pStart)) continue;
1020         ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
1021         if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR ||
1022             ct == DM_POLYTOPE_TRI_PRISM_TENSOR ||
1023             ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
1024           const PetscInt *cone;
1025           PetscInt        coneSize, e;
1026 
1027           ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1028           ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
1029           for (e = 0; e < coneSize; ++e) {
1030             const PetscInt *econe;
1031 
1032             ierr = DMPlexGetCone(dm, cone[e], &econe);CHKERRQ(ierr);
1033             ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d) -- (%D_%d);\n", colors[rank%numColors], econe[0], rank, cone[e], rank, econe[1], rank);CHKERRQ(ierr);
1034           }
1035         } else {
1036           PetscInt *closure = NULL;
1037           PetscInt  closureSize, Nv = 0, v;
1038 
1039           ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1040           for (p = 0; p < closureSize*2; p += 2) {
1041             const PetscInt point = closure[p];
1042 
1043             if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point;
1044           }
1045           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
1046           for (v = 0; v <= Nv; ++v) {
1047             const PetscInt vertex = closure[v%Nv];
1048 
1049             if (v > 0) {
1050               if (plotEdges) {
1051                 const PetscInt *edge;
1052                 PetscInt        endpoints[2], ne;
1053 
1054                 endpoints[0] = closure[v-1]; endpoints[1] = vertex;
1055                 ierr = DMPlexGetJoin(dm, 2, endpoints, &ne, &edge);CHKERRQ(ierr);
1056                 if (ne != 1) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %D, %D", endpoints[0], endpoints[1]);
1057                 ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d) -- ", edge[0], rank);CHKERRQ(ierr);
1058                 ierr = DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge);CHKERRQ(ierr);
1059               } else {
1060                 ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);
1061               }
1062             }
1063             ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", vertex, rank);CHKERRQ(ierr);
1064           }
1065           ierr = PetscViewerASCIISynchronizedPrintf(viewer, ";\n");CHKERRQ(ierr);
1066           ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1067         }
1068       }
1069     }
1070     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
1071     for (c = cStart; c < cEnd; ++c) {
1072       double    ccoords[3] = {0.0, 0.0, 0.0};
1073       PetscBool isLabeled  = PETSC_FALSE;
1074       PetscInt *closure    = NULL;
1075       PetscInt  closureSize, dof, d, n = 0;
1076 
1077       if (wp && !PetscBTLookup(wp,c - pStart)) continue;
1078       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1079       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");CHKERRQ(ierr);
1080       for (p = 0; p < closureSize*2; p += 2) {
1081         const PetscInt point = closure[p];
1082         PetscInt       off;
1083 
1084         if ((point < vStart) || (point >= vEnd)) continue;
1085         ierr = PetscSectionGetDof(coordSection, point, &dof);CHKERRQ(ierr);
1086         ierr = PetscSectionGetOffset(coordSection, point, &off);CHKERRQ(ierr);
1087         for (d = 0; d < dof; ++d) {
1088           tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
1089           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1090         }
1091         /* Rotate coordinates since PGF makes z point out of the page instead of up */
1092         if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
1093         for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];}
1094         ++n;
1095       }
1096       for (d = 0; d < dof; ++d) {ccoords[d] /= n;}
1097       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1098       for (d = 0; d < dof; ++d) {
1099         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
1100         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d]);CHKERRQ(ierr);
1101       }
1102       if (drawHasse) color = colors[depth%numColors];
1103       else           color = colors[rank%numColors];
1104       for (l = 0; l < numLabels; ++l) {
1105         PetscInt val;
1106         ierr = DMGetLabelValue(dm, names[l], c, &val);CHKERRQ(ierr);
1107         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
1108       }
1109       if (drawNumbers[dim]) {
1110         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", c, rank, color, c);CHKERRQ(ierr);
1111       } else if (drawColors[dim]) {
1112         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color);CHKERRQ(ierr);
1113       } else {
1114         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [] {};\n", c, rank);CHKERRQ(ierr);
1115       }
1116     }
1117     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
1118     if (drawHasse) {
1119       color = colors[depth%numColors];
1120       ierr = PetscViewerASCIIPrintf(viewer, "%% Cells\n");CHKERRQ(ierr);
1121       ierr = PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n");CHKERRQ(ierr);
1122       ierr = PetscViewerASCIIPrintf(viewer, "{\n");CHKERRQ(ierr);
1123       ierr = PetscViewerASCIIPrintf(viewer, "  \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color);CHKERRQ(ierr);
1124       ierr = PetscViewerASCIIPrintf(viewer, "}\n");CHKERRQ(ierr);
1125 
1126       color = colors[1%numColors];
1127       ierr = PetscViewerASCIIPrintf(viewer, "%% Edges\n");CHKERRQ(ierr);
1128       ierr = PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n");CHKERRQ(ierr);
1129       ierr = PetscViewerASCIIPrintf(viewer, "{\n");CHKERRQ(ierr);
1130       ierr = PetscViewerASCIIPrintf(viewer, "  \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color);CHKERRQ(ierr);
1131       ierr = PetscViewerASCIIPrintf(viewer, "}\n");CHKERRQ(ierr);
1132 
1133       color = colors[0%numColors];
1134       ierr = PetscViewerASCIIPrintf(viewer, "%% Vertices\n");CHKERRQ(ierr);
1135       ierr = PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n");CHKERRQ(ierr);
1136       ierr = PetscViewerASCIIPrintf(viewer, "{\n");CHKERRQ(ierr);
1137       ierr = PetscViewerASCIIPrintf(viewer, "  \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color);CHKERRQ(ierr);
1138       ierr = PetscViewerASCIIPrintf(viewer, "}\n");CHKERRQ(ierr);
1139 
1140       for (p = pStart; p < pEnd; ++p) {
1141         const PetscInt *cone;
1142         PetscInt        coneSize, cp;
1143 
1144         ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1145         ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1146         for (cp = 0; cp < coneSize; ++cp) {
1147           ierr = PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%D_%d) -- (%D_%d);\n", cone[cp], rank, p, rank);CHKERRQ(ierr);
1148         }
1149       }
1150     }
1151     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
1152     ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
1153     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");CHKERRQ(ierr);
1154     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
1155     for (l = 0; l < numLabels;  ++l) {ierr = PetscFree(names[l]);CHKERRQ(ierr);}
1156     for (c = 0; c < numColors;  ++c) {ierr = PetscFree(colors[c]);CHKERRQ(ierr);}
1157     for (c = 0; c < numLColors; ++c) {ierr = PetscFree(lcolors[c]);CHKERRQ(ierr);}
1158     ierr = PetscFree3(names, colors, lcolors);CHKERRQ(ierr);
1159     ierr = PetscBTDestroy(&wp);CHKERRQ(ierr);
1160   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
1161     Vec                    cown,acown;
1162     VecScatter             sct;
1163     ISLocalToGlobalMapping g2l;
1164     IS                     gid,acis;
1165     MPI_Comm               comm,ncomm = MPI_COMM_NULL;
1166     MPI_Group              ggroup,ngroup;
1167     PetscScalar            *array,nid;
1168     const PetscInt         *idxs;
1169     PetscInt               *idxs2,*start,*adjacency,*work;
1170     PetscInt64             lm[3],gm[3];
1171     PetscInt               i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight;
1172     PetscMPIInt            d1,d2,rank;
1173 
1174     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1175     ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
1176 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1177     ierr = MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm);CHKERRMPI(ierr);
1178 #endif
1179     if (ncomm != MPI_COMM_NULL) {
1180       ierr = MPI_Comm_group(comm,&ggroup);CHKERRMPI(ierr);
1181       ierr = MPI_Comm_group(ncomm,&ngroup);CHKERRMPI(ierr);
1182       d1   = 0;
1183       ierr = MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2);CHKERRMPI(ierr);
1184       nid  = d2;
1185       ierr = MPI_Group_free(&ggroup);CHKERRMPI(ierr);
1186       ierr = MPI_Group_free(&ngroup);CHKERRMPI(ierr);
1187       ierr = MPI_Comm_free(&ncomm);CHKERRMPI(ierr);
1188     } else nid = 0.0;
1189 
1190     /* Get connectivity */
1191     ierr = DMPlexGetVTKCellHeight(dm,&cellHeight);CHKERRQ(ierr);
1192     ierr = DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid);CHKERRQ(ierr);
1193 
1194     /* filter overlapped local cells */
1195     ierr = DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd);CHKERRQ(ierr);
1196     ierr = ISGetIndices(gid,&idxs);CHKERRQ(ierr);
1197     ierr = ISGetLocalSize(gid,&cum);CHKERRQ(ierr);
1198     ierr = PetscMalloc1(cum,&idxs2);CHKERRQ(ierr);
1199     for (c = cStart, cum = 0; c < cEnd; c++) {
1200       if (idxs[c-cStart] < 0) continue;
1201       idxs2[cum++] = idxs[c-cStart];
1202     }
1203     ierr = ISRestoreIndices(gid,&idxs);CHKERRQ(ierr);
1204     if (numVertices != cum) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %D != %D",numVertices,cum);
1205     ierr = ISDestroy(&gid);CHKERRQ(ierr);
1206     ierr = ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid);CHKERRQ(ierr);
1207 
1208     /* support for node-aware cell locality */
1209     ierr = ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis);CHKERRQ(ierr);
1210     ierr = VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown);CHKERRQ(ierr);
1211     ierr = VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown);CHKERRQ(ierr);
1212     ierr = VecGetArray(cown,&array);CHKERRQ(ierr);
1213     for (c = 0; c < numVertices; c++) array[c] = nid;
1214     ierr = VecRestoreArray(cown,&array);CHKERRQ(ierr);
1215     ierr = VecScatterCreate(cown,acis,acown,NULL,&sct);CHKERRQ(ierr);
1216     ierr = VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1217     ierr = VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1218     ierr = ISDestroy(&acis);CHKERRQ(ierr);
1219     ierr = VecScatterDestroy(&sct);CHKERRQ(ierr);
1220     ierr = VecDestroy(&cown);CHKERRQ(ierr);
1221 
1222     /* compute edgeCut */
1223     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]);
1224     ierr = PetscMalloc1(cum,&work);CHKERRQ(ierr);
1225     ierr = ISLocalToGlobalMappingCreateIS(gid,&g2l);CHKERRQ(ierr);
1226     ierr = ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH);CHKERRQ(ierr);
1227     ierr = ISDestroy(&gid);CHKERRQ(ierr);
1228     ierr = VecGetArray(acown,&array);CHKERRQ(ierr);
1229     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
1230       PetscInt totl;
1231 
1232       totl = start[c+1]-start[c];
1233       ierr = ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work);CHKERRQ(ierr);
1234       for (i = 0; i < totl; i++) {
1235         if (work[i] < 0) {
1236           ect  += 1;
1237           ectn += (array[i + start[c]] != nid) ? 0 : 1;
1238         }
1239       }
1240     }
1241     ierr  = PetscFree(work);CHKERRQ(ierr);
1242     ierr  = VecRestoreArray(acown,&array);CHKERRQ(ierr);
1243     lm[0] = numVertices > 0 ?  numVertices : PETSC_MAX_INT;
1244     lm[1] = -numVertices;
1245     ierr  = MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm);CHKERRMPI(ierr);
1246     ierr  = PetscViewerASCIIPrintf(viewer,"  Cell balance: %.2f (max %D, min %D",-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0]);CHKERRQ(ierr);
1247     lm[0] = ect; /* edgeCut */
1248     lm[1] = ectn; /* node-aware edgeCut */
1249     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
1250     ierr  = MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm);CHKERRMPI(ierr);
1251     ierr  = PetscViewerASCIIPrintf(viewer,", empty %D)\n",(PetscInt)gm[2]);CHKERRQ(ierr);
1252 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1253     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);
1254 #else
1255     ierr  = PetscViewerASCIIPrintf(viewer,"  Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0);CHKERRQ(ierr);
1256 #endif
1257     ierr  = ISLocalToGlobalMappingDestroy(&g2l);CHKERRQ(ierr);
1258     ierr  = PetscFree(start);CHKERRQ(ierr);
1259     ierr  = PetscFree(adjacency);CHKERRQ(ierr);
1260     ierr  = VecDestroy(&acown);CHKERRQ(ierr);
1261   } else {
1262     const char    *name;
1263     PetscInt      *sizes, *hybsizes, *ghostsizes;
1264     PetscInt       locDepth, depth, cellHeight, dim, d;
1265     PetscInt       pStart, pEnd, p, gcStart, gcEnd, gcNum;
1266     PetscInt       numLabels, l;
1267     DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN;
1268     MPI_Comm       comm;
1269     PetscMPIInt    size, rank;
1270 
1271     ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
1272     ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr);
1273     ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
1274     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1275     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
1276     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
1277     if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
1278     else      {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
1279     if (cellHeight) {ierr = PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);CHKERRQ(ierr);}
1280     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
1281     ierr = MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRMPI(ierr);
1282     ierr = DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd);CHKERRQ(ierr);
1283     gcNum = gcEnd - gcStart;
1284     ierr = PetscCalloc3(size,&sizes,size,&hybsizes,size,&ghostsizes);CHKERRQ(ierr);
1285     for (d = 0; d <= depth; d++) {
1286       PetscInt Nc[2] = {0, 0}, ict;
1287 
1288       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
1289       if (pStart < pEnd) {ierr = DMPlexGetCellType(dm, pStart, &ct0);CHKERRQ(ierr);}
1290       ict  = ct0;
1291       ierr = MPI_Bcast(&ict, 1, MPIU_INT, 0, comm);CHKERRMPI(ierr);
1292       ct0  = (DMPolytopeType) ict;
1293       for (p = pStart; p < pEnd; ++p) {
1294         DMPolytopeType ct;
1295 
1296         ierr = DMPlexGetCellType(dm, p, &ct);CHKERRQ(ierr);
1297         if (ct == ct0) ++Nc[0];
1298         else           ++Nc[1];
1299       }
1300       ierr = MPI_Gather(&Nc[0], 1, MPIU_INT, sizes,    1, MPIU_INT, 0, comm);CHKERRMPI(ierr);
1301       ierr = MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRMPI(ierr);
1302       if (d == depth) {ierr = MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm);CHKERRMPI(ierr);}
1303       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", (depth == 1) && d ? dim : d);CHKERRQ(ierr);
1304       for (p = 0; p < size; ++p) {
1305         if (rank == 0) {
1306           ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]+hybsizes[p]);CHKERRQ(ierr);
1307           if (hybsizes[p]   > 0) {ierr = PetscViewerASCIIPrintf(viewer, " (%D)", hybsizes[p]);CHKERRQ(ierr);}
1308           if (ghostsizes[p] > 0) {ierr = PetscViewerASCIIPrintf(viewer, " [%D]", ghostsizes[p]);CHKERRQ(ierr);}
1309         }
1310       }
1311       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
1312     }
1313     ierr = PetscFree3(sizes,hybsizes,ghostsizes);CHKERRQ(ierr);
1314     {
1315       const PetscReal      *maxCell;
1316       const PetscReal      *L;
1317       const DMBoundaryType *bd;
1318       PetscBool             per, localized;
1319 
1320       ierr = DMGetPeriodicity(dm, &per, &maxCell, &L, &bd);CHKERRQ(ierr);
1321       ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
1322       if (per) {
1323         ierr = PetscViewerASCIIPrintf(viewer, "Periodic mesh (");CHKERRQ(ierr);
1324         ierr = PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);CHKERRQ(ierr);
1325         for (d = 0; d < dim; ++d) {
1326           if (bd && d > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
1327           if (bd)    {ierr = PetscViewerASCIIPrintf(viewer, "%s", DMBoundaryTypes[bd[d]]);CHKERRQ(ierr);}
1328         }
1329         ierr = PetscViewerASCIIPrintf(viewer, ") coordinates %s\n", localized ? "localized" : "not localized");CHKERRQ(ierr);
1330         ierr = PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);CHKERRQ(ierr);
1331       }
1332     }
1333     ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
1334     if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);}
1335     for (l = 0; l < numLabels; ++l) {
1336       DMLabel         label;
1337       const char     *name;
1338       IS              valueIS;
1339       const PetscInt *values;
1340       PetscInt        numValues, v;
1341 
1342       ierr = DMGetLabelName(dm, l, &name);CHKERRQ(ierr);
1343       ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
1344       ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
1345       ierr = PetscViewerASCIIPrintf(viewer, "  %s: %D strata with value/size (", name, numValues);CHKERRQ(ierr);
1346       ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
1347       ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
1348       ierr = PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);CHKERRQ(ierr);
1349       for (v = 0; v < numValues; ++v) {
1350         PetscInt size;
1351 
1352         ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr);
1353         if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
1354         ierr = PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);CHKERRQ(ierr);
1355       }
1356       ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr);
1357       ierr = PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);CHKERRQ(ierr);
1358       ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
1359       ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
1360     }
1361     {
1362       char    **labelNames;
1363       PetscInt  Nl = numLabels;
1364       PetscBool flg;
1365 
1366       ierr = PetscMalloc1(Nl, &labelNames);CHKERRQ(ierr);
1367       ierr = PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg);CHKERRQ(ierr);
1368       for (l = 0; l < Nl; ++l) {
1369         DMLabel label;
1370 
1371         ierr = DMHasLabel(dm, labelNames[l], &flg);CHKERRQ(ierr);
1372         if (flg) {
1373           ierr = DMGetLabel(dm, labelNames[l], &label);CHKERRQ(ierr);
1374           ierr = DMLabelView(label, viewer);CHKERRQ(ierr);
1375         }
1376         ierr = PetscFree(labelNames[l]);CHKERRQ(ierr);
1377       }
1378       ierr = PetscFree(labelNames);CHKERRQ(ierr);
1379     }
1380     /* If no fields are specified, people do not want to see adjacency */
1381     if (dm->Nf) {
1382       PetscInt f;
1383 
1384       for (f = 0; f < dm->Nf; ++f) {
1385         const char *name;
1386 
1387         ierr = PetscObjectGetName(dm->fields[f].disc, &name);CHKERRQ(ierr);
1388         if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Field %s:\n", name);CHKERRQ(ierr);}
1389         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1390         if (dm->fields[f].label) {ierr = DMLabelView(dm->fields[f].label, viewer);CHKERRQ(ierr);}
1391         if (dm->fields[f].adjacency[0]) {
1392           if (dm->fields[f].adjacency[1]) {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n");CHKERRQ(ierr);}
1393           else                            {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FVM\n");CHKERRQ(ierr);}
1394         } else {
1395           if (dm->fields[f].adjacency[1]) {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FEM\n");CHKERRQ(ierr);}
1396           else                            {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n");CHKERRQ(ierr);}
1397         }
1398         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1399       }
1400     }
1401     ierr = DMGetCoarseDM(dm, &cdm);CHKERRQ(ierr);
1402     if (cdm) {
1403       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1404       ierr = DMPlexView_Ascii(cdm, viewer);CHKERRQ(ierr);
1405       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1406     }
1407   }
1408   PetscFunctionReturn(0);
1409 }
1410 
1411 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[])
1412 {
1413   DMPolytopeType ct;
1414   PetscMPIInt    rank;
1415   PetscInt       cdim;
1416   PetscErrorCode ierr;
1417 
1418   PetscFunctionBegin;
1419   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRMPI(ierr);
1420   ierr = DMPlexGetCellType(dm, cell, &ct);CHKERRQ(ierr);
1421   ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
1422   switch (ct) {
1423   case DM_POLYTOPE_SEGMENT:
1424   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1425     switch (cdim) {
1426     case 1:
1427     {
1428       const PetscReal y  = 0.5;  /* TODO Put it in the middle of the viewport */
1429       const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */
1430 
1431       ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), y,    PetscRealPart(coords[1]), y,    PETSC_DRAW_BLACK);CHKERRQ(ierr);
1432       ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), y+dy, PetscRealPart(coords[0]), y-dy, PETSC_DRAW_BLACK);CHKERRQ(ierr);
1433       ierr = PetscDrawLine(draw, PetscRealPart(coords[1]), y+dy, PetscRealPart(coords[1]), y-dy, PETSC_DRAW_BLACK);CHKERRQ(ierr);
1434     }
1435     break;
1436     case 2:
1437     {
1438       const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1]));
1439       const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0]));
1440       const PetscReal l  = 0.1/PetscSqrtReal(dx*dx + dy*dy);
1441 
1442       ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1443       ierr = PetscDrawLine(draw, PetscRealPart(coords[0])+l*dx, PetscRealPart(coords[1])+l*dy, PetscRealPart(coords[0])-l*dx, PetscRealPart(coords[1])-l*dy, PETSC_DRAW_BLACK);CHKERRQ(ierr);
1444       ierr = PetscDrawLine(draw, PetscRealPart(coords[2])+l*dx, PetscRealPart(coords[3])+l*dy, PetscRealPart(coords[2])-l*dx, PetscRealPart(coords[3])-l*dy, PETSC_DRAW_BLACK);CHKERRQ(ierr);
1445     }
1446     break;
1447     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %D", cdim);
1448     }
1449     break;
1450   case DM_POLYTOPE_TRIANGLE:
1451     ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1452                              PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1453                              PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1454                              PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr);
1455     ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1456     ierr = PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1457     ierr = PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1458     break;
1459   case DM_POLYTOPE_QUADRILATERAL:
1460     ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1461                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1462                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1463                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr);
1464     ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]),
1465                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1466                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1467                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr);
1468     ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1469     ierr = PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1470     ierr = PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1471     ierr = PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1472     break;
1473   default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1474   }
1475   PetscFunctionReturn(0);
1476 }
1477 
1478 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1479 {
1480   DMPolytopeType ct;
1481   PetscReal      centroid[2] = {0., 0.};
1482   PetscMPIInt    rank;
1483   PetscInt       fillColor, v, e, d;
1484   PetscErrorCode ierr;
1485 
1486   PetscFunctionBegin;
1487   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRMPI(ierr);
1488   ierr = DMPlexGetCellType(dm, cell, &ct);CHKERRQ(ierr);
1489   fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2;
1490   switch (ct) {
1491   case DM_POLYTOPE_TRIANGLE:
1492     {
1493       PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.};
1494 
1495       for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;}
1496       for (e = 0; e < 3; ++e) {
1497         refCoords[0] = refVertices[e*2+0];
1498         refCoords[1] = refVertices[e*2+1];
1499         for (d = 1; d <= edgeDiv; ++d) {
1500           refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv;
1501           refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv;
1502         }
1503         ierr = DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords);CHKERRQ(ierr);
1504         for (d = 0; d < edgeDiv; ++d) {
1505           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);
1506           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);
1507         }
1508       }
1509     }
1510     break;
1511   default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1512   }
1513   PetscFunctionReturn(0);
1514 }
1515 
1516 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1517 {
1518   PetscDraw          draw;
1519   DM                 cdm;
1520   PetscSection       coordSection;
1521   Vec                coordinates;
1522   const PetscScalar *coords;
1523   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
1524   PetscReal         *refCoords, *edgeCoords;
1525   PetscBool          isnull, drawAffine = PETSC_TRUE;
1526   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4;
1527   PetscErrorCode     ierr;
1528 
1529   PetscFunctionBegin;
1530   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
1531   if (dim > 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
1532   ierr = PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL);CHKERRQ(ierr);
1533   if (!drawAffine) {ierr = PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords);CHKERRQ(ierr);}
1534   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
1535   ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr);
1536   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
1537   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1538   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1539 
1540   ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr);
1541   ierr = PetscDrawIsNull(draw, &isnull);CHKERRQ(ierr);
1542   if (isnull) PetscFunctionReturn(0);
1543   ierr = PetscDrawSetTitle(draw, "Mesh");CHKERRQ(ierr);
1544 
1545   ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr);
1546   ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr);
1547   for (c = 0; c < N; c += dim) {
1548     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
1549     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1550   }
1551   ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr);
1552   ierr = MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
1553   ierr = MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
1554   ierr = PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);CHKERRQ(ierr);
1555   ierr = PetscDrawClear(draw);CHKERRQ(ierr);
1556 
1557   for (c = cStart; c < cEnd; ++c) {
1558     PetscScalar *coords = NULL;
1559     PetscInt     numCoords;
1560 
1561     ierr = DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords);CHKERRQ(ierr);
1562     if (drawAffine) {
1563       ierr = DMPlexDrawCell(dm, draw, c, coords);CHKERRQ(ierr);
1564     } else {
1565       ierr = DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords);CHKERRQ(ierr);
1566     }
1567     ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr);
1568   }
1569   if (!drawAffine) {ierr = PetscFree2(refCoords, edgeCoords);CHKERRQ(ierr);}
1570   ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
1571   ierr = PetscDrawPause(draw);CHKERRQ(ierr);
1572   ierr = PetscDrawSave(draw);CHKERRQ(ierr);
1573   PetscFunctionReturn(0);
1574 }
1575 
1576 #if defined(PETSC_HAVE_EXODUSII)
1577 #include <exodusII.h>
1578 #include <petscviewerexodusii.h>
1579 #endif
1580 
1581 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1582 {
1583   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus;
1584   char           name[PETSC_MAX_PATH_LEN];
1585   PetscErrorCode ierr;
1586 
1587   PetscFunctionBegin;
1588   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1589   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1590   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII,    &iascii);CHKERRQ(ierr);
1591   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,      &isvtk);CHKERRQ(ierr);
1592   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5);CHKERRQ(ierr);
1593   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,     &isdraw);CHKERRQ(ierr);
1594   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS,    &isglvis);CHKERRQ(ierr);
1595   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus);CHKERRQ(ierr);
1596   if (iascii) {
1597     PetscViewerFormat format;
1598     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1599     if (format == PETSC_VIEWER_ASCII_GLVIS) {
1600       ierr = DMPlexView_GLVis(dm, viewer);CHKERRQ(ierr);
1601     } else {
1602       ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
1603     }
1604   } else if (ishdf5) {
1605 #if defined(PETSC_HAVE_HDF5)
1606     ierr = DMPlexView_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
1607 #else
1608     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1609 #endif
1610   } else if (isvtk) {
1611     ierr = DMPlexVTKWriteAll((PetscObject) dm,viewer);CHKERRQ(ierr);
1612   } else if (isdraw) {
1613     ierr = DMPlexView_Draw(dm, viewer);CHKERRQ(ierr);
1614   } else if (isglvis) {
1615     ierr = DMPlexView_GLVis(dm, viewer);CHKERRQ(ierr);
1616 #if defined(PETSC_HAVE_EXODUSII)
1617   } else if (isexodus) {
1618 /*
1619       exodusII requires that all sets be part of exactly one cell set.
1620       If the dm does not have a "Cell Sets" label defined, we create one
1621       with ID 1, containig all cells.
1622       Note that if the Cell Sets label is defined but does not cover all cells,
1623       we may still have a problem. This should probably be checked here or in the viewer;
1624     */
1625     PetscInt numCS;
1626     ierr = DMGetLabelSize(dm,"Cell Sets",&numCS);CHKERRQ(ierr);
1627     if (!numCS) {
1628       PetscInt cStart, cEnd, c;
1629       ierr = DMCreateLabel(dm, "Cell Sets");CHKERRQ(ierr);
1630       ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1631       for (c = cStart; c < cEnd; ++c) {ierr = DMSetLabelValue(dm, "Cell Sets", c, 1);CHKERRQ(ierr);}
1632     }
1633     ierr = DMView_PlexExodusII(dm, viewer);CHKERRQ(ierr);
1634 #endif
1635   } else {
1636     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1637   }
1638   /* Optionally view the partition */
1639   ierr = PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);CHKERRQ(ierr);
1640   if (flg) {
1641     Vec ranks;
1642     ierr = DMPlexCreateRankField(dm, &ranks);CHKERRQ(ierr);
1643     ierr = VecView(ranks, viewer);CHKERRQ(ierr);
1644     ierr = VecDestroy(&ranks);CHKERRQ(ierr);
1645   }
1646   /* Optionally view a label */
1647   ierr = PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg);CHKERRQ(ierr);
1648   if (flg) {
1649     DMLabel label;
1650     Vec     val;
1651 
1652     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
1653     if (!label) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
1654     ierr = DMPlexCreateLabelField(dm, label, &val);CHKERRQ(ierr);
1655     ierr = VecView(val, viewer);CHKERRQ(ierr);
1656     ierr = VecDestroy(&val);CHKERRQ(ierr);
1657   }
1658   PetscFunctionReturn(0);
1659 }
1660 
1661 /*@
1662   DMPlexTopologyView - Saves a DMPlex topology into a file
1663 
1664   Collective on DM
1665 
1666   Input Parameters:
1667 + dm     - The DM whose topology is to be saved
1668 - viewer - The PetscViewer for saving
1669 
1670   Level: advanced
1671 
1672 .seealso: DMView(), DMPlexCoordinatesView(), DMPlexLabelsView(), DMPlexTopologyLoad()
1673 @*/
1674 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
1675 {
1676   PetscBool      ishdf5;
1677   PetscErrorCode ierr;
1678 
1679   PetscFunctionBegin;
1680   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1681   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1682   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1683   if (ishdf5) {
1684 #if defined(PETSC_HAVE_HDF5)
1685     PetscViewerFormat format;
1686     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1687     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1688       IS globalPointNumbering;
1689 
1690       ierr = DMPlexCreatePointNumbering(dm, &globalPointNumbering);CHKERRQ(ierr);
1691       ierr = DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer);CHKERRQ(ierr);
1692       ierr = ISDestroy(&globalPointNumbering);CHKERRQ(ierr);
1693     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
1694 #else
1695     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1696 #endif
1697   }
1698   PetscFunctionReturn(0);
1699 }
1700 
1701 /*@
1702   DMPlexCoordinatesView - Saves DMPlex coordinates into a file
1703 
1704   Collective on DM
1705 
1706   Input Parameters:
1707 + dm     - The DM whose coordinates are to be saved
1708 - viewer - The PetscViewer for saving
1709 
1710   Level: advanced
1711 
1712 .seealso: DMView(), DMPlexTopologyView(), DMPlexLabelsView(), DMPlexCoordinatesLoad()
1713 @*/
1714 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
1715 {
1716   PetscBool      ishdf5;
1717   PetscErrorCode ierr;
1718 
1719   PetscFunctionBegin;
1720   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1721   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1722   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1723   if (ishdf5) {
1724 #if defined(PETSC_HAVE_HDF5)
1725     PetscViewerFormat format;
1726     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1727     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1728       ierr = DMPlexCoordinatesView_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
1729     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1730 #else
1731     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1732 #endif
1733   }
1734   PetscFunctionReturn(0);
1735 }
1736 
1737 /*@
1738   DMPlexLabelsView - Saves DMPlex labels into a file
1739 
1740   Collective on DM
1741 
1742   Input Parameters:
1743 + dm     - The DM whose labels are to be saved
1744 - viewer - The PetscViewer for saving
1745 
1746   Level: advanced
1747 
1748 .seealso: DMView(), DMPlexTopologyView(), DMPlexCoordinatesView(), DMPlexLabelsLoad()
1749 @*/
1750 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
1751 {
1752   PetscBool      ishdf5;
1753   PetscErrorCode ierr;
1754 
1755   PetscFunctionBegin;
1756   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1757   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1758   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1759   if (ishdf5) {
1760 #if defined(PETSC_HAVE_HDF5)
1761     IS                globalPointNumbering;
1762     PetscViewerFormat format;
1763 
1764     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1765     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1766       ierr = DMPlexCreatePointNumbering(dm, &globalPointNumbering);CHKERRQ(ierr);
1767       ierr = DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer);CHKERRQ(ierr);
1768       ierr = ISDestroy(&globalPointNumbering);CHKERRQ(ierr);
1769     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1770 #else
1771     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1772 #endif
1773   }
1774   PetscFunctionReturn(0);
1775 }
1776 
1777 /*@
1778   DMPlexSectionView - Saves a section associated with a DMPlex
1779 
1780   Collective on DM
1781 
1782   Input Parameters:
1783 + dm         - The DM that contains the topology on which the section to be saved is defined
1784 . viewer     - The PetscViewer for saving
1785 - sectiondm  - The DM that contains the section to be saved
1786 
1787   Level: advanced
1788 
1789   Notes:
1790   This function is a wrapper around PetscSectionView(); in addition to the raw section, it saves information that associates the section points to the topology (dm) points. When the topology (dm) and the section are later loaded with DMPlexTopologyLoad() and DMPlexSectionLoad(), respectively, this information is used to match section points with topology points.
1791 
1792   In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
1793 
1794 .seealso: DMView(), DMPlexTopologyView(), DMPlexCoordinatesView(), DMPlexLabelsView(), DMPlexGlobalVectorView(), DMPlexLocalVectorView(), PetscSectionView(), DMPlexSectionLoad()
1795 @*/
1796 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
1797 {
1798   PetscBool      ishdf5;
1799   PetscErrorCode ierr;
1800 
1801   PetscFunctionBegin;
1802   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1803   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1804   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
1805   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
1806   if (ishdf5) {
1807 #if defined(PETSC_HAVE_HDF5)
1808     ierr = DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm);CHKERRQ(ierr);
1809 #else
1810     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1811 #endif
1812   }
1813   PetscFunctionReturn(0);
1814 }
1815 
1816 /*@
1817   DMPlexGlobalVectorView - Saves a global vector
1818 
1819   Collective on DM
1820 
1821   Input Parameters:
1822 + dm        - The DM that represents the topology
1823 . viewer    - The PetscViewer to save data with
1824 . sectiondm - The DM that contains the global section on which vec is defined
1825 - vec       - The global vector to be saved
1826 
1827   Level: advanced
1828 
1829   Notes:
1830   In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
1831 
1832   Typical calling sequence
1833 $       DMCreate(PETSC_COMM_WORLD, &dm);
1834 $       DMSetType(dm, DMPLEX);
1835 $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
1836 $       DMClone(dm, &sectiondm);
1837 $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
1838 $       PetscSectionCreate(PETSC_COMM_WORLD, &section);
1839 $       DMPlexGetChart(sectiondm, &pStart, &pEnd);
1840 $       PetscSectionSetChart(section, pStart, pEnd);
1841 $       PetscSectionSetUp(section);
1842 $       DMSetLocalSection(sectiondm, section);
1843 $       PetscSectionDestroy(&section);
1844 $       DMGetGlobalVector(sectiondm, &vec);
1845 $       PetscObjectSetName((PetscObject)vec, "vec_name");
1846 $       DMPlexTopologyView(dm, viewer);
1847 $       DMPlexSectionView(dm, viewer, sectiondm);
1848 $       DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
1849 $       DMRestoreGlobalVector(sectiondm, &vec);
1850 $       DMDestroy(&sectiondm);
1851 $       DMDestroy(&dm);
1852 
1853 .seealso: DMPlexTopologyView(), DMPlexSectionView(), DMPlexLocalVectorView(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad()
1854 @*/
1855 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
1856 {
1857   PetscBool       ishdf5;
1858   PetscErrorCode  ierr;
1859 
1860   PetscFunctionBegin;
1861   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1862   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1863   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
1864   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
1865   /* Check consistency */
1866   {
1867     PetscSection  section;
1868     PetscBool     includesConstraints;
1869     PetscInt      m, m1;
1870 
1871     ierr = VecGetLocalSize(vec, &m1);CHKERRQ(ierr);
1872     ierr = DMGetGlobalSection(sectiondm, &section);CHKERRQ(ierr);
1873     ierr = PetscSectionGetIncludesConstraints(section, &includesConstraints);CHKERRQ(ierr);
1874     if (includesConstraints) {ierr = PetscSectionGetStorageSize(section, &m);CHKERRQ(ierr);}
1875     else {ierr = PetscSectionGetConstrainedStorageSize(section, &m);CHKERRQ(ierr);}
1876     if (m1 != m) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%D) != global section storage size (%D)", m1, m);
1877   }
1878   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1879   if (ishdf5) {
1880 #if defined(PETSC_HAVE_HDF5)
1881     ierr = DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec);CHKERRQ(ierr);
1882 #else
1883     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1884 #endif
1885   }
1886   PetscFunctionReturn(0);
1887 }
1888 
1889 /*@
1890   DMPlexLocalVectorView - Saves a local vector
1891 
1892   Collective on DM
1893 
1894   Input Parameters:
1895 + dm        - The DM that represents the topology
1896 . viewer    - The PetscViewer to save data with
1897 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm
1898 - vec       - The local vector to be saved
1899 
1900   Level: advanced
1901 
1902   Notes:
1903   In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
1904 
1905   Typical calling sequence
1906 $       DMCreate(PETSC_COMM_WORLD, &dm);
1907 $       DMSetType(dm, DMPLEX);
1908 $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
1909 $       DMClone(dm, &sectiondm);
1910 $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
1911 $       PetscSectionCreate(PETSC_COMM_WORLD, &section);
1912 $       DMPlexGetChart(sectiondm, &pStart, &pEnd);
1913 $       PetscSectionSetChart(section, pStart, pEnd);
1914 $       PetscSectionSetUp(section);
1915 $       DMSetLocalSection(sectiondm, section);
1916 $       DMGetLocalVector(sectiondm, &vec);
1917 $       PetscObjectSetName((PetscObject)vec, "vec_name");
1918 $       DMPlexTopologyView(dm, viewer);
1919 $       DMPlexSectionView(dm, viewer, sectiondm);
1920 $       DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
1921 $       DMRestoreLocalVector(sectiondm, &vec);
1922 $       DMDestroy(&sectiondm);
1923 $       DMDestroy(&dm);
1924 
1925 .seealso: DMPlexTopologyView(), DMPlexSectionView(), DMPlexGlobalVectorView(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad()
1926 @*/
1927 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
1928 {
1929   PetscBool       ishdf5;
1930   PetscErrorCode  ierr;
1931 
1932   PetscFunctionBegin;
1933   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1934   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1935   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
1936   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
1937   /* Check consistency */
1938   {
1939     PetscSection  section;
1940     PetscBool     includesConstraints;
1941     PetscInt      m, m1;
1942 
1943     ierr = VecGetLocalSize(vec, &m1);CHKERRQ(ierr);
1944     ierr = DMGetLocalSection(sectiondm, &section);CHKERRQ(ierr);
1945     ierr = PetscSectionGetIncludesConstraints(section, &includesConstraints);CHKERRQ(ierr);
1946     if (includesConstraints) {ierr = PetscSectionGetStorageSize(section, &m);CHKERRQ(ierr);}
1947     else {ierr = PetscSectionGetConstrainedStorageSize(section, &m);CHKERRQ(ierr);}
1948     if (m1 != m) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%D) != local section storage size (%D)", m1, m);
1949   }
1950   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1951   if (ishdf5) {
1952 #if defined(PETSC_HAVE_HDF5)
1953     ierr = DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec);CHKERRQ(ierr);
1954 #else
1955     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1956 #endif
1957   }
1958   PetscFunctionReturn(0);
1959 }
1960 
1961 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1962 {
1963   PetscBool      ishdf5;
1964   PetscErrorCode ierr;
1965 
1966   PetscFunctionBegin;
1967   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1968   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1969   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);CHKERRQ(ierr);
1970   if (ishdf5) {
1971 #if defined(PETSC_HAVE_HDF5)
1972     PetscViewerFormat format;
1973     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1974     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
1975       ierr = DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);CHKERRQ(ierr);
1976     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1977       ierr = DMPlexLoad_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
1978     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1979     PetscFunctionReturn(0);
1980 #else
1981     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1982 #endif
1983   } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
1984 }
1985 
1986 /*@
1987   DMPlexTopologyLoad - Loads a topology into a DMPlex
1988 
1989   Collective on DM
1990 
1991   Input Parameters:
1992 + dm     - The DM into which the topology is loaded
1993 - viewer - The PetscViewer for the saved topology
1994 
1995   Output Parameters:
1996 . globalToLocalPointSF - 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
1997 
1998   Level: advanced
1999 
2000 .seealso: DMLoad(), DMPlexCoordinatesLoad(), DMPlexLabelsLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat()
2001 @*/
2002 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
2003 {
2004   PetscBool      ishdf5;
2005   PetscErrorCode ierr;
2006 
2007   PetscFunctionBegin;
2008   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2009   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2010   if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3);
2011   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
2012   if (ishdf5) {
2013 #if defined(PETSC_HAVE_HDF5)
2014     PetscViewerFormat format;
2015     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
2016     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2017       ierr = DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF);CHKERRQ(ierr);
2018     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2019 #else
2020     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2021 #endif
2022   }
2023   PetscFunctionReturn(0);
2024 }
2025 
2026 /*@
2027   DMPlexCoordinatesLoad - Loads coordinates into a DMPlex
2028 
2029   Collective on DM
2030 
2031   Input Parameters:
2032 + dm     - The DM into which the coordinates are loaded
2033 . viewer - The PetscViewer for the saved coordinates
2034 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
2035 
2036   Level: advanced
2037 
2038 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexLabelsLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat()
2039 @*/
2040 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2041 {
2042   PetscBool      ishdf5;
2043   PetscErrorCode ierr;
2044 
2045   PetscFunctionBegin;
2046   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2047   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2048   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
2049   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
2050   if (ishdf5) {
2051 #if defined(PETSC_HAVE_HDF5)
2052     PetscViewerFormat format;
2053     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
2054     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2055       ierr = DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF);CHKERRQ(ierr);
2056     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2057 #else
2058     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2059 #endif
2060   }
2061   PetscFunctionReturn(0);
2062 }
2063 
2064 /*@
2065   DMPlexLabelsLoad - Loads labels into a DMPlex
2066 
2067   Collective on DM
2068 
2069   Input Parameters:
2070 + dm     - The DM into which the labels are loaded
2071 - viewer - The PetscViewer for the saved labels
2072 
2073   Level: advanced
2074 
2075 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexCoordinatesLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat()
2076 @*/
2077 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer)
2078 {
2079   PetscBool      ishdf5;
2080   PetscErrorCode ierr;
2081 
2082   PetscFunctionBegin;
2083   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2084   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2085   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
2086   if (ishdf5) {
2087 #if defined(PETSC_HAVE_HDF5)
2088     PetscViewerFormat format;
2089 
2090     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
2091     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2092       ierr = DMPlexLabelsLoad_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
2093     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2094 #else
2095     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2096 #endif
2097   }
2098   PetscFunctionReturn(0);
2099 }
2100 
2101 /*@
2102   DMPlexSectionLoad - Loads section into a DMPlex
2103 
2104   Collective on DM
2105 
2106   Input Parameters:
2107 + dm          - The DM that represents the topology
2108 . viewer      - The PetscViewer that represents the on-disk section (sectionA)
2109 . sectiondm   - The DM into which the on-disk section (sectionA) is migrated
2110 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
2111 
2112   Output Parameters
2113 + globalDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a global Vec associated with the sectiondm's global section (NULL if not needed)
2114 - localDofSF  - The SF that migrates any on-disk Vec data associated with sectionA into a local Vec associated with the sectiondm's local section (NULL if not needed)
2115 
2116   Level: advanced
2117 
2118   Notes:
2119   This function is a wrapper around PetscSectionLoad(); it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in dm. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points.
2120 
2121   In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
2122 
2123   The output parameter, globalDofSF (localDofSF), can later be used with DMPlexGlobalVectorLoad() (DMPlexLocalVectorLoad()) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section.
2124 
2125   Example using 2 processes:
2126 $  NX (number of points on dm): 4
2127 $  sectionA                   : the on-disk section
2128 $  vecA                       : a vector associated with sectionA
2129 $  sectionB                   : sectiondm's local section constructed in this function
2130 $  vecB (local)               : a vector associated with sectiondm's local section
2131 $  vecB (global)              : a vector associated with sectiondm's global section
2132 $
2133 $                                     rank 0    rank 1
2134 $  vecA (global)                  : [.0 .4 .1 | .2 .3]        <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
2135 $  sectionA->atlasOff             :       0 2 | 1             <- loaded in PetscSectionLoad()
2136 $  sectionA->atlasDof             :       1 3 | 1             <- loaded in PetscSectionLoad()
2137 $  sectionA's global point numbers:       0 2 | 3             <- loaded in DMPlexSectionLoad()
2138 $  [0, NX)                        :       0 1 | 2 3           <- conceptual partition used in globalToLocalPointSF
2139 $  sectionB's global point numbers:     0 1 3 | 3 2           <- associated with [0, NX) by globalToLocalPointSF
2140 $  sectionB->atlasDof             :     1 0 1 | 1 3
2141 $  sectionB->atlasOff (no perm)   :     0 1 1 | 0 1
2142 $  vecB (local)                   :   [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
2143 $  vecB (global)                  :    [.0 .4 | .1 .2 .3]     <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
2144 $
2145 $  where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.
2146 
2147 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexCoordinatesLoad(), DMPlexLabelsLoad(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad(), PetscSectionLoad(), DMPlexSectionView()
2148 @*/
2149 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF)
2150 {
2151   PetscBool      ishdf5;
2152   PetscErrorCode ierr;
2153 
2154   PetscFunctionBegin;
2155   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2156   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2157   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2158   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4);
2159   if (globalDofSF) PetscValidPointer(globalDofSF, 5);
2160   if (localDofSF) PetscValidPointer(localDofSF, 6);
2161   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
2162   if (ishdf5) {
2163 #if defined(PETSC_HAVE_HDF5)
2164     ierr = DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF);CHKERRQ(ierr);
2165 #else
2166     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2167 #endif
2168   }
2169   PetscFunctionReturn(0);
2170 }
2171 
2172 /*@
2173   DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector
2174 
2175   Collective on DM
2176 
2177   Input Parameters:
2178 + dm        - The DM that represents the topology
2179 . viewer    - The PetscViewer that represents the on-disk vector data
2180 . sectiondm - The DM that contains the global section on which vec is defined
2181 . sf        - The SF that migrates the on-disk vector data into vec
2182 - vec       - The global vector to set values of
2183 
2184   Level: advanced
2185 
2186   Notes:
2187   In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
2188 
2189   Typical calling sequence
2190 $       DMCreate(PETSC_COMM_WORLD, &dm);
2191 $       DMSetType(dm, DMPLEX);
2192 $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
2193 $       DMPlexTopologyLoad(dm, viewer, &sfX);
2194 $       DMClone(dm, &sectiondm);
2195 $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2196 $       DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL);
2197 $       DMGetGlobalVector(sectiondm, &vec);
2198 $       PetscObjectSetName((PetscObject)vec, "vec_name");
2199 $       DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec);
2200 $       DMRestoreGlobalVector(sectiondm, &vec);
2201 $       PetscSFDestroy(&gsf);
2202 $       PetscSFDestroy(&sfX);
2203 $       DMDestroy(&sectiondm);
2204 $       DMDestroy(&dm);
2205 
2206 .seealso: DMPlexTopologyLoad(), DMPlexSectionLoad(), DMPlexLocalVectorLoad(), DMPlexGlobalVectorView(), DMPlexLocalVectorView()
2207 @*/
2208 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2209 {
2210   PetscBool       ishdf5;
2211   PetscErrorCode  ierr;
2212 
2213   PetscFunctionBegin;
2214   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2215   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2216   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2217   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
2218   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
2219   /* Check consistency */
2220   {
2221     PetscSection  section;
2222     PetscBool     includesConstraints;
2223     PetscInt      m, m1;
2224 
2225     ierr = VecGetLocalSize(vec, &m1);CHKERRQ(ierr);
2226     ierr = DMGetGlobalSection(sectiondm, &section);CHKERRQ(ierr);
2227     ierr = PetscSectionGetIncludesConstraints(section, &includesConstraints);CHKERRQ(ierr);
2228     if (includesConstraints) {ierr = PetscSectionGetStorageSize(section, &m);CHKERRQ(ierr);}
2229     else {ierr = PetscSectionGetConstrainedStorageSize(section, &m);CHKERRQ(ierr);}
2230     if (m1 != m) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%D) != global section storage size (%D)", m1, m);
2231   }
2232   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
2233   if (ishdf5) {
2234 #if defined(PETSC_HAVE_HDF5)
2235     ierr = DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec);CHKERRQ(ierr);
2236 #else
2237     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2238 #endif
2239   }
2240   PetscFunctionReturn(0);
2241 }
2242 
2243 /*@
2244   DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector
2245 
2246   Collective on DM
2247 
2248   Input Parameters:
2249 + dm        - The DM that represents the topology
2250 . viewer    - The PetscViewer that represents the on-disk vector data
2251 . sectiondm - The DM that contains the local section on which vec is defined
2252 . sf        - The SF that migrates the on-disk vector data into vec
2253 - vec       - The local vector to set values of
2254 
2255   Level: advanced
2256 
2257   Notes:
2258   In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
2259 
2260   Typical calling sequence
2261 $       DMCreate(PETSC_COMM_WORLD, &dm);
2262 $       DMSetType(dm, DMPLEX);
2263 $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
2264 $       DMPlexTopologyLoad(dm, viewer, &sfX);
2265 $       DMClone(dm, &sectiondm);
2266 $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2267 $       DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf);
2268 $       DMGetLocalVector(sectiondm, &vec);
2269 $       PetscObjectSetName((PetscObject)vec, "vec_name");
2270 $       DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec);
2271 $       DMRestoreLocalVector(sectiondm, &vec);
2272 $       PetscSFDestroy(&lsf);
2273 $       PetscSFDestroy(&sfX);
2274 $       DMDestroy(&sectiondm);
2275 $       DMDestroy(&dm);
2276 
2277 .seealso: DMPlexTopologyLoad(), DMPlexSectionLoad(), DMPlexGlobalVectorLoad(), DMPlexGlobalVectorView(), DMPlexLocalVectorView()
2278 @*/
2279 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2280 {
2281   PetscBool       ishdf5;
2282   PetscErrorCode  ierr;
2283 
2284   PetscFunctionBegin;
2285   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2286   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2287   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2288   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
2289   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
2290   /* Check consistency */
2291   {
2292     PetscSection  section;
2293     PetscBool     includesConstraints;
2294     PetscInt      m, m1;
2295 
2296     ierr = VecGetLocalSize(vec, &m1);CHKERRQ(ierr);
2297     ierr = DMGetLocalSection(sectiondm, &section);CHKERRQ(ierr);
2298     ierr = PetscSectionGetIncludesConstraints(section, &includesConstraints);CHKERRQ(ierr);
2299     if (includesConstraints) {ierr = PetscSectionGetStorageSize(section, &m);CHKERRQ(ierr);}
2300     else {ierr = PetscSectionGetConstrainedStorageSize(section, &m);CHKERRQ(ierr);}
2301     if (m1 != m) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%D) != local section storage size (%D)", m1, m);
2302   }
2303   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
2304   if (ishdf5) {
2305 #if defined(PETSC_HAVE_HDF5)
2306     ierr = DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec);CHKERRQ(ierr);
2307 #else
2308     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2309 #endif
2310   }
2311   PetscFunctionReturn(0);
2312 }
2313 
2314 PetscErrorCode DMDestroy_Plex(DM dm)
2315 {
2316   DM_Plex       *mesh = (DM_Plex*) dm->data;
2317   PetscErrorCode ierr;
2318 
2319   PetscFunctionBegin;
2320   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);CHKERRQ(ierr);
2321   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);CHKERRQ(ierr);
2322   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL);CHKERRQ(ierr);
2323   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL);CHKERRQ(ierr);
2324   if (--mesh->refct > 0) PetscFunctionReturn(0);
2325   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
2326   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
2327   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
2328   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
2329   ierr = PetscSectionDestroy(&mesh->subdomainSection);CHKERRQ(ierr);
2330   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
2331   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
2332   ierr = PetscFree(mesh->tetgenOpts);CHKERRQ(ierr);
2333   ierr = PetscFree(mesh->triangleOpts);CHKERRQ(ierr);
2334   ierr = PetscFree(mesh->transformType);CHKERRQ(ierr);
2335   ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr);
2336   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
2337   ierr = ISDestroy(&mesh->subpointIS);CHKERRQ(ierr);
2338   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
2339   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
2340   ierr = PetscSectionDestroy(&mesh->anchorSection);CHKERRQ(ierr);
2341   ierr = ISDestroy(&mesh->anchorIS);CHKERRQ(ierr);
2342   ierr = PetscSectionDestroy(&mesh->parentSection);CHKERRQ(ierr);
2343   ierr = PetscFree(mesh->parents);CHKERRQ(ierr);
2344   ierr = PetscFree(mesh->childIDs);CHKERRQ(ierr);
2345   ierr = PetscSectionDestroy(&mesh->childSection);CHKERRQ(ierr);
2346   ierr = PetscFree(mesh->children);CHKERRQ(ierr);
2347   ierr = DMDestroy(&mesh->referenceTree);CHKERRQ(ierr);
2348   ierr = PetscGridHashDestroy(&mesh->lbox);CHKERRQ(ierr);
2349   ierr = PetscFree(mesh->neighbors);CHKERRQ(ierr);
2350   if (mesh->metricCtx) { ierr = PetscFree(mesh->metricCtx);CHKERRQ(ierr); }
2351   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
2352   ierr = PetscFree(mesh);CHKERRQ(ierr);
2353   PetscFunctionReturn(0);
2354 }
2355 
2356 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
2357 {
2358   PetscSection           sectionGlobal;
2359   PetscInt               bs = -1, mbs;
2360   PetscInt               localSize;
2361   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
2362   PetscErrorCode         ierr;
2363   MatType                mtype;
2364   ISLocalToGlobalMapping ltog;
2365 
2366   PetscFunctionBegin;
2367   ierr = MatInitializePackage();CHKERRQ(ierr);
2368   mtype = dm->mattype;
2369   ierr = DMGetGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
2370   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
2371   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
2372   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
2373   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
2374   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
2375   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
2376   ierr = MatGetBlockSize(*J, &mbs);CHKERRQ(ierr);
2377   if (mbs > 1) bs = mbs;
2378   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
2379   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
2380   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
2381   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
2382   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
2383   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
2384   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
2385   ierr = PetscStrcmp(mtype, MATIS, &isMatIS);CHKERRQ(ierr);
2386   if (!isShell) {
2387     PetscSection subSection;
2388     PetscBool    fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
2389     PetscInt    *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize;
2390     PetscInt     pStart, pEnd, p, dof, cdof;
2391 
2392     /* Set localtoglobalmapping on the matrix for MatSetValuesLocal() to work (it also creates the local matrices in case of MATIS) */
2393     if (isMatIS) { /* need a different l2g map than the one computed by DMGetLocalToGlobalMapping */
2394       PetscSection section;
2395       PetscInt     size;
2396 
2397       ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
2398       ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
2399       ierr = PetscMalloc1(size,&ltogidx);CHKERRQ(ierr);
2400       ierr = DMPlexGetSubdomainSection(dm, &subSection);CHKERRQ(ierr);
2401     } else {
2402       ierr = DMGetLocalToGlobalMapping(dm,&ltog);CHKERRQ(ierr);
2403     }
2404     ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
2405     for (p = pStart, lsize = 0; p < pEnd; ++p) {
2406       PetscInt bdof;
2407 
2408       ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
2409       ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
2410       dof  = dof < 0 ? -(dof+1) : dof;
2411       bdof = cdof && (dof-cdof) ? 1 : dof;
2412       if (dof) {
2413         if (bs < 0)          {bs = bdof;}
2414         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
2415       }
2416       if (isMatIS) {
2417         PetscInt loff,c,off;
2418         ierr = PetscSectionGetOffset(subSection, p, &loff);CHKERRQ(ierr);
2419         ierr = PetscSectionGetOffset(sectionGlobal, p, &off);CHKERRQ(ierr);
2420         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
2421       }
2422     }
2423     /* Must have same blocksize on all procs (some might have no points) */
2424     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
2425     ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr);
2426     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
2427     else                            {bs = bsMinMax[0];}
2428     bs = PetscMax(1,bs);
2429     if (isMatIS) { /* Must reduce indices by blocksize */
2430       PetscInt l;
2431 
2432       lsize = lsize/bs;
2433       if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] = ltogidx[l*bs]/bs;
2434       ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);CHKERRQ(ierr);
2435     }
2436     ierr = MatSetLocalToGlobalMapping(*J,ltog,ltog);CHKERRQ(ierr);
2437     if (isMatIS) {
2438       ierr = ISLocalToGlobalMappingDestroy(&ltog);CHKERRQ(ierr);
2439     }
2440     ierr = PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);CHKERRQ(ierr);
2441     ierr = DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
2442     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
2443   }
2444   ierr = MatSetDM(*J, dm);CHKERRQ(ierr);
2445   PetscFunctionReturn(0);
2446 }
2447 
2448 /*@
2449   DMPlexGetSubdomainSection - Returns the section associated with the subdomain
2450 
2451   Not collective
2452 
2453   Input Parameter:
2454 . mesh - The DMPlex
2455 
2456   Output Parameters:
2457 . subsection - The subdomain section
2458 
2459   Level: developer
2460 
2461 .seealso:
2462 @*/
2463 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
2464 {
2465   DM_Plex       *mesh = (DM_Plex*) dm->data;
2466   PetscErrorCode ierr;
2467 
2468   PetscFunctionBegin;
2469   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2470   if (!mesh->subdomainSection) {
2471     PetscSection section;
2472     PetscSF      sf;
2473 
2474     ierr = PetscSFCreate(PETSC_COMM_SELF,&sf);CHKERRQ(ierr);
2475     ierr = DMGetLocalSection(dm,&section);CHKERRQ(ierr);
2476     ierr = PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);CHKERRQ(ierr);
2477     ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
2478   }
2479   *subsection = mesh->subdomainSection;
2480   PetscFunctionReturn(0);
2481 }
2482 
2483 /*@
2484   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
2485 
2486   Not collective
2487 
2488   Input Parameter:
2489 . mesh - The DMPlex
2490 
2491   Output Parameters:
2492 + pStart - The first mesh point
2493 - pEnd   - The upper bound for mesh points
2494 
2495   Level: beginner
2496 
2497 .seealso: DMPlexCreate(), DMPlexSetChart()
2498 @*/
2499 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
2500 {
2501   DM_Plex       *mesh = (DM_Plex*) dm->data;
2502   PetscErrorCode ierr;
2503 
2504   PetscFunctionBegin;
2505   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2506   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
2507   PetscFunctionReturn(0);
2508 }
2509 
2510 /*@
2511   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
2512 
2513   Not collective
2514 
2515   Input Parameters:
2516 + mesh - The DMPlex
2517 . pStart - The first mesh point
2518 - pEnd   - The upper bound for mesh points
2519 
2520   Output Parameters:
2521 
2522   Level: beginner
2523 
2524 .seealso: DMPlexCreate(), DMPlexGetChart()
2525 @*/
2526 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
2527 {
2528   DM_Plex       *mesh = (DM_Plex*) dm->data;
2529   PetscErrorCode ierr;
2530 
2531   PetscFunctionBegin;
2532   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2533   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
2534   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
2535   PetscFunctionReturn(0);
2536 }
2537 
2538 /*@
2539   DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
2540 
2541   Not collective
2542 
2543   Input Parameters:
2544 + mesh - The DMPlex
2545 - p - The point, which must lie in the chart set with DMPlexSetChart()
2546 
2547   Output Parameter:
2548 . size - The cone size for point p
2549 
2550   Level: beginner
2551 
2552 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2553 @*/
2554 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
2555 {
2556   DM_Plex       *mesh = (DM_Plex*) dm->data;
2557   PetscErrorCode ierr;
2558 
2559   PetscFunctionBegin;
2560   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2561   PetscValidPointer(size, 3);
2562   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
2563   PetscFunctionReturn(0);
2564 }
2565 
2566 /*@
2567   DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
2568 
2569   Not collective
2570 
2571   Input Parameters:
2572 + mesh - The DMPlex
2573 . p - The point, which must lie in the chart set with DMPlexSetChart()
2574 - size - The cone size for point p
2575 
2576   Output Parameter:
2577 
2578   Note:
2579   This should be called after DMPlexSetChart().
2580 
2581   Level: beginner
2582 
2583 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
2584 @*/
2585 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
2586 {
2587   DM_Plex       *mesh = (DM_Plex*) dm->data;
2588   PetscErrorCode ierr;
2589 
2590   PetscFunctionBegin;
2591   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2592   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
2593 
2594   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
2595   PetscFunctionReturn(0);
2596 }
2597 
2598 /*@
2599   DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG
2600 
2601   Not collective
2602 
2603   Input Parameters:
2604 + mesh - The DMPlex
2605 . p - The point, which must lie in the chart set with DMPlexSetChart()
2606 - size - The additional cone size for point p
2607 
2608   Output Parameter:
2609 
2610   Note:
2611   This should be called after DMPlexSetChart().
2612 
2613   Level: beginner
2614 
2615 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
2616 @*/
2617 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
2618 {
2619   DM_Plex       *mesh = (DM_Plex*) dm->data;
2620   PetscInt       csize;
2621   PetscErrorCode ierr;
2622 
2623   PetscFunctionBegin;
2624   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2625   ierr = PetscSectionAddDof(mesh->coneSection, p, size);CHKERRQ(ierr);
2626   ierr = PetscSectionGetDof(mesh->coneSection, p, &csize);CHKERRQ(ierr);
2627 
2628   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
2629   PetscFunctionReturn(0);
2630 }
2631 
2632 /*@C
2633   DMPlexGetCone - Return the points on the in-edges for this point in the DAG
2634 
2635   Not collective
2636 
2637   Input Parameters:
2638 + dm - The DMPlex
2639 - p - The point, which must lie in the chart set with DMPlexSetChart()
2640 
2641   Output Parameter:
2642 . cone - An array of points which are on the in-edges for point p
2643 
2644   Level: beginner
2645 
2646   Fortran Notes:
2647   Since it returns an array, this routine is only available in Fortran 90, and you must
2648   include petsc.h90 in your code.
2649   You must also call DMPlexRestoreCone() after you finish using the returned array.
2650   DMPlexRestoreCone() is not needed/available in C.
2651 
2652 .seealso: DMPlexGetConeSize(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart()
2653 @*/
2654 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
2655 {
2656   DM_Plex       *mesh = (DM_Plex*) dm->data;
2657   PetscInt       off;
2658   PetscErrorCode ierr;
2659 
2660   PetscFunctionBegin;
2661   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2662   PetscValidPointer(cone, 3);
2663   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2664   *cone = &mesh->cones[off];
2665   PetscFunctionReturn(0);
2666 }
2667 
2668 /*@C
2669   DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
2670 
2671   Not collective
2672 
2673   Input Parameters:
2674 + dm - The DMPlex
2675 - p - The IS of points, which must lie in the chart set with DMPlexSetChart()
2676 
2677   Output Parameters:
2678 + pConesSection - PetscSection describing the layout of pCones
2679 - pCones - An array of points which are on the in-edges for the point set p
2680 
2681   Level: intermediate
2682 
2683 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart()
2684 @*/
2685 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
2686 {
2687   PetscSection        cs, newcs;
2688   PetscInt            *cones;
2689   PetscInt            *newarr=NULL;
2690   PetscInt            n;
2691   PetscErrorCode      ierr;
2692 
2693   PetscFunctionBegin;
2694   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
2695   ierr = DMPlexGetConeSection(dm, &cs);CHKERRQ(ierr);
2696   ierr = PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL);CHKERRQ(ierr);
2697   if (pConesSection) *pConesSection = newcs;
2698   if (pCones) {
2699     ierr = PetscSectionGetStorageSize(newcs, &n);CHKERRQ(ierr);
2700     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones);CHKERRQ(ierr);
2701   }
2702   PetscFunctionReturn(0);
2703 }
2704 
2705 /*@
2706   DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.
2707 
2708   Not collective
2709 
2710   Input Parameters:
2711 + dm - The DMPlex
2712 - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2713 
2714   Output Parameter:
2715 . expandedPoints - An array of vertices recursively expanded from input points
2716 
2717   Level: advanced
2718 
2719   Notes:
2720   Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections.
2721   There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate.
2722 
2723 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexRestoreConeRecursive(), DMPlexGetDepth()
2724 @*/
2725 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
2726 {
2727   IS                  *expandedPointsAll;
2728   PetscInt            depth;
2729   PetscErrorCode      ierr;
2730 
2731   PetscFunctionBegin;
2732   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2733   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
2734   PetscValidPointer(expandedPoints, 3);
2735   ierr = DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);CHKERRQ(ierr);
2736   *expandedPoints = expandedPointsAll[0];
2737   ierr = PetscObjectReference((PetscObject)expandedPointsAll[0]);CHKERRQ(ierr);
2738   ierr = DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);CHKERRQ(ierr);
2739   PetscFunctionReturn(0);
2740 }
2741 
2742 /*@
2743   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).
2744 
2745   Not collective
2746 
2747   Input Parameters:
2748 + dm - The DMPlex
2749 - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2750 
2751   Output Parameters:
2752 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
2753 . expandedPoints - (optional) An array of index sets with recursively expanded cones
2754 - sections - (optional) An array of sections which describe mappings from points to their cone points
2755 
2756   Level: advanced
2757 
2758   Notes:
2759   Like DMPlexGetConeTuple() but recursive.
2760 
2761   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.
2762   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.
2763 
2764   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:
2765   (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d];
2766   (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d].
2767 
2768 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexRestoreConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth()
2769 @*/
2770 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
2771 {
2772   const PetscInt      *arr0=NULL, *cone=NULL;
2773   PetscInt            *arr=NULL, *newarr=NULL;
2774   PetscInt            d, depth_, i, n, newn, cn, co, start, end;
2775   IS                  *expandedPoints_;
2776   PetscSection        *sections_;
2777   PetscErrorCode      ierr;
2778 
2779   PetscFunctionBegin;
2780   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2781   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
2782   if (depth) PetscValidIntPointer(depth, 3);
2783   if (expandedPoints) PetscValidPointer(expandedPoints, 4);
2784   if (sections) PetscValidPointer(sections, 5);
2785   ierr = ISGetLocalSize(points, &n);CHKERRQ(ierr);
2786   ierr = ISGetIndices(points, &arr0);CHKERRQ(ierr);
2787   ierr = DMPlexGetDepth(dm, &depth_);CHKERRQ(ierr);
2788   ierr = PetscCalloc1(depth_, &expandedPoints_);CHKERRQ(ierr);
2789   ierr = PetscCalloc1(depth_, &sections_);CHKERRQ(ierr);
2790   arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */
2791   for (d=depth_-1; d>=0; d--) {
2792     ierr = PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]);CHKERRQ(ierr);
2793     ierr = PetscSectionSetChart(sections_[d], 0, n);CHKERRQ(ierr);
2794     for (i=0; i<n; i++) {
2795       ierr = DMPlexGetDepthStratum(dm, d+1, &start, &end);CHKERRQ(ierr);
2796       if (arr[i] >= start && arr[i] < end) {
2797         ierr = DMPlexGetConeSize(dm, arr[i], &cn);CHKERRQ(ierr);
2798         ierr = PetscSectionSetDof(sections_[d], i, cn);CHKERRQ(ierr);
2799       } else {
2800         ierr = PetscSectionSetDof(sections_[d], i, 1);CHKERRQ(ierr);
2801       }
2802     }
2803     ierr = PetscSectionSetUp(sections_[d]);CHKERRQ(ierr);
2804     ierr = PetscSectionGetStorageSize(sections_[d], &newn);CHKERRQ(ierr);
2805     ierr = PetscMalloc1(newn, &newarr);CHKERRQ(ierr);
2806     for (i=0; i<n; i++) {
2807       ierr = PetscSectionGetDof(sections_[d], i, &cn);CHKERRQ(ierr);
2808       ierr = PetscSectionGetOffset(sections_[d], i, &co);CHKERRQ(ierr);
2809       if (cn > 1) {
2810         ierr = DMPlexGetCone(dm, arr[i], &cone);CHKERRQ(ierr);
2811         ierr = PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt));CHKERRQ(ierr);
2812       } else {
2813         newarr[co] = arr[i];
2814       }
2815     }
2816     ierr = ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]);CHKERRQ(ierr);
2817     arr = newarr;
2818     n = newn;
2819   }
2820   ierr = ISRestoreIndices(points, &arr0);CHKERRQ(ierr);
2821   *depth = depth_;
2822   if (expandedPoints) *expandedPoints = expandedPoints_;
2823   else {
2824     for (d=0; d<depth_; d++) {ierr = ISDestroy(&expandedPoints_[d]);CHKERRQ(ierr);}
2825     ierr = PetscFree(expandedPoints_);CHKERRQ(ierr);
2826   }
2827   if (sections) *sections = sections_;
2828   else {
2829     for (d=0; d<depth_; d++) {ierr = PetscSectionDestroy(&sections_[d]);CHKERRQ(ierr);}
2830     ierr = PetscFree(sections_);CHKERRQ(ierr);
2831   }
2832   PetscFunctionReturn(0);
2833 }
2834 
2835 /*@
2836   DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive
2837 
2838   Not collective
2839 
2840   Input Parameters:
2841 + dm - The DMPlex
2842 - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2843 
2844   Output Parameters:
2845 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
2846 . expandedPoints - (optional) An array of recursively expanded cones
2847 - sections - (optional) An array of sections which describe mappings from points to their cone points
2848 
2849   Level: advanced
2850 
2851   Notes:
2852   See DMPlexGetConeRecursive() for details.
2853 
2854 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth()
2855 @*/
2856 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
2857 {
2858   PetscInt            d, depth_;
2859   PetscErrorCode      ierr;
2860 
2861   PetscFunctionBegin;
2862   ierr = DMPlexGetDepth(dm, &depth_);CHKERRQ(ierr);
2863   if (depth && *depth != depth_) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
2864   if (depth) *depth = 0;
2865   if (expandedPoints) {
2866     for (d=0; d<depth_; d++) {ierr = ISDestroy(&((*expandedPoints)[d]));CHKERRQ(ierr);}
2867     ierr = PetscFree(*expandedPoints);CHKERRQ(ierr);
2868   }
2869   if (sections)  {
2870     for (d=0; d<depth_; d++) {ierr = PetscSectionDestroy(&((*sections)[d]));CHKERRQ(ierr);}
2871     ierr = PetscFree(*sections);CHKERRQ(ierr);
2872   }
2873   PetscFunctionReturn(0);
2874 }
2875 
2876 /*@
2877   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
2878 
2879   Not collective
2880 
2881   Input Parameters:
2882 + mesh - The DMPlex
2883 . p - The point, which must lie in the chart set with DMPlexSetChart()
2884 - cone - An array of points which are on the in-edges for point p
2885 
2886   Output Parameter:
2887 
2888   Note:
2889   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
2890 
2891   Level: beginner
2892 
2893 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
2894 @*/
2895 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
2896 {
2897   DM_Plex       *mesh = (DM_Plex*) dm->data;
2898   PetscInt       pStart, pEnd;
2899   PetscInt       dof, off, c;
2900   PetscErrorCode ierr;
2901 
2902   PetscFunctionBegin;
2903   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2904   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2905   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
2906   if (dof) PetscValidPointer(cone, 3);
2907   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2908   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);
2909   for (c = 0; c < dof; ++c) {
2910     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);
2911     mesh->cones[off+c] = cone[c];
2912   }
2913   PetscFunctionReturn(0);
2914 }
2915 
2916 /*@C
2917   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
2918 
2919   Not collective
2920 
2921   Input Parameters:
2922 + mesh - The DMPlex
2923 - p - The point, which must lie in the chart set with DMPlexSetChart()
2924 
2925   Output Parameter:
2926 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
2927                     integer giving the prescription for cone traversal.
2928 
2929   Level: beginner
2930 
2931   Notes:
2932   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
2933   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
2934   of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv()
2935   with the identity.
2936 
2937   Fortran Notes:
2938   Since it returns an array, this routine is only available in Fortran 90, and you must
2939   include petsc.h90 in your code.
2940   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
2941   DMPlexRestoreConeOrientation() is not needed/available in C.
2942 
2943 .seealso: DMPolytopeTypeComposeOrientation(), DMPolytopeTypeComposeOrientationInv(), DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
2944 @*/
2945 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
2946 {
2947   DM_Plex       *mesh = (DM_Plex*) dm->data;
2948   PetscInt       off;
2949   PetscErrorCode ierr;
2950 
2951   PetscFunctionBegin;
2952   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2953   if (PetscDefined(USE_DEBUG)) {
2954     PetscInt dof;
2955     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
2956     if (dof) PetscValidPointer(coneOrientation, 3);
2957   }
2958   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2959 
2960   *coneOrientation = &mesh->coneOrientations[off];
2961   PetscFunctionReturn(0);
2962 }
2963 
2964 /*@
2965   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
2966 
2967   Not collective
2968 
2969   Input Parameters:
2970 + mesh - The DMPlex
2971 . p - The point, which must lie in the chart set with DMPlexSetChart()
2972 - coneOrientation - An array of orientations
2973   Output Parameter:
2974 
2975   Notes:
2976   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
2977 
2978   The meaning of coneOrientation is detailed in DMPlexGetConeOrientation().
2979 
2980   Level: beginner
2981 
2982 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2983 @*/
2984 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
2985 {
2986   DM_Plex       *mesh = (DM_Plex*) dm->data;
2987   PetscInt       pStart, pEnd;
2988   PetscInt       dof, off, c;
2989   PetscErrorCode ierr;
2990 
2991   PetscFunctionBegin;
2992   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2993   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2994   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
2995   if (dof) PetscValidPointer(coneOrientation, 3);
2996   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2997   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);
2998   for (c = 0; c < dof; ++c) {
2999     PetscInt cdof, o = coneOrientation[c];
3000 
3001     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
3002     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);
3003     mesh->coneOrientations[off+c] = o;
3004   }
3005   PetscFunctionReturn(0);
3006 }
3007 
3008 /*@
3009   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
3010 
3011   Not collective
3012 
3013   Input Parameters:
3014 + mesh - The DMPlex
3015 . p - The point, which must lie in the chart set with DMPlexSetChart()
3016 . conePos - The local index in the cone where the point should be put
3017 - conePoint - The mesh point to insert
3018 
3019   Level: beginner
3020 
3021 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
3022 @*/
3023 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
3024 {
3025   DM_Plex       *mesh = (DM_Plex*) dm->data;
3026   PetscInt       pStart, pEnd;
3027   PetscInt       dof, off;
3028   PetscErrorCode ierr;
3029 
3030   PetscFunctionBegin;
3031   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3032   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3033   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);
3034   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);
3035   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
3036   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
3037   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);
3038   mesh->cones[off+conePos] = conePoint;
3039   PetscFunctionReturn(0);
3040 }
3041 
3042 /*@
3043   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
3044 
3045   Not collective
3046 
3047   Input Parameters:
3048 + mesh - The DMPlex
3049 . p - The point, which must lie in the chart set with DMPlexSetChart()
3050 . conePos - The local index in the cone where the point should be put
3051 - coneOrientation - The point orientation to insert
3052 
3053   Level: beginner
3054 
3055   Notes:
3056   The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation().
3057 
3058 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
3059 @*/
3060 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
3061 {
3062   DM_Plex       *mesh = (DM_Plex*) dm->data;
3063   PetscInt       pStart, pEnd;
3064   PetscInt       dof, off;
3065   PetscErrorCode ierr;
3066 
3067   PetscFunctionBegin;
3068   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3069   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3070   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);
3071   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
3072   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
3073   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);
3074   mesh->coneOrientations[off+conePos] = coneOrientation;
3075   PetscFunctionReturn(0);
3076 }
3077 
3078 /*@
3079   DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
3080 
3081   Not collective
3082 
3083   Input Parameters:
3084 + mesh - The DMPlex
3085 - p - The point, which must lie in the chart set with DMPlexSetChart()
3086 
3087   Output Parameter:
3088 . size - The support size for point p
3089 
3090   Level: beginner
3091 
3092 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
3093 @*/
3094 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
3095 {
3096   DM_Plex       *mesh = (DM_Plex*) dm->data;
3097   PetscErrorCode ierr;
3098 
3099   PetscFunctionBegin;
3100   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3101   PetscValidPointer(size, 3);
3102   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
3103   PetscFunctionReturn(0);
3104 }
3105 
3106 /*@
3107   DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
3108 
3109   Not collective
3110 
3111   Input Parameters:
3112 + mesh - The DMPlex
3113 . p - The point, which must lie in the chart set with DMPlexSetChart()
3114 - size - The support size for point p
3115 
3116   Output Parameter:
3117 
3118   Note:
3119   This should be called after DMPlexSetChart().
3120 
3121   Level: beginner
3122 
3123 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
3124 @*/
3125 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
3126 {
3127   DM_Plex       *mesh = (DM_Plex*) dm->data;
3128   PetscErrorCode ierr;
3129 
3130   PetscFunctionBegin;
3131   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3132   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
3133 
3134   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
3135   PetscFunctionReturn(0);
3136 }
3137 
3138 /*@C
3139   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
3140 
3141   Not collective
3142 
3143   Input Parameters:
3144 + mesh - The DMPlex
3145 - p - The point, which must lie in the chart set with DMPlexSetChart()
3146 
3147   Output Parameter:
3148 . support - An array of points which are on the out-edges for point p
3149 
3150   Level: beginner
3151 
3152   Fortran Notes:
3153   Since it returns an array, this routine is only available in Fortran 90, and you must
3154   include petsc.h90 in your code.
3155   You must also call DMPlexRestoreSupport() after you finish using the returned array.
3156   DMPlexRestoreSupport() is not needed/available in C.
3157 
3158 .seealso: DMPlexGetSupportSize(), DMPlexSetSupport(), DMPlexGetCone(), DMPlexSetChart()
3159 @*/
3160 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
3161 {
3162   DM_Plex       *mesh = (DM_Plex*) dm->data;
3163   PetscInt       off;
3164   PetscErrorCode ierr;
3165 
3166   PetscFunctionBegin;
3167   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3168   PetscValidPointer(support, 3);
3169   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
3170   *support = &mesh->supports[off];
3171   PetscFunctionReturn(0);
3172 }
3173 
3174 /*@
3175   DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers
3176 
3177   Not collective
3178 
3179   Input Parameters:
3180 + mesh - The DMPlex
3181 . p - The point, which must lie in the chart set with DMPlexSetChart()
3182 - support - An array of points which are on the out-edges for point p
3183 
3184   Output Parameter:
3185 
3186   Note:
3187   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
3188 
3189   Level: beginner
3190 
3191 .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
3192 @*/
3193 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
3194 {
3195   DM_Plex       *mesh = (DM_Plex*) dm->data;
3196   PetscInt       pStart, pEnd;
3197   PetscInt       dof, off, c;
3198   PetscErrorCode ierr;
3199 
3200   PetscFunctionBegin;
3201   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3202   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
3203   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
3204   if (dof) PetscValidPointer(support, 3);
3205   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
3206   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);
3207   for (c = 0; c < dof; ++c) {
3208     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);
3209     mesh->supports[off+c] = support[c];
3210   }
3211   PetscFunctionReturn(0);
3212 }
3213 
3214 /*@
3215   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
3216 
3217   Not collective
3218 
3219   Input Parameters:
3220 + mesh - The DMPlex
3221 . p - The point, which must lie in the chart set with DMPlexSetChart()
3222 . supportPos - The local index in the cone where the point should be put
3223 - supportPoint - The mesh point to insert
3224 
3225   Level: beginner
3226 
3227 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
3228 @*/
3229 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
3230 {
3231   DM_Plex       *mesh = (DM_Plex*) dm->data;
3232   PetscInt       pStart, pEnd;
3233   PetscInt       dof, off;
3234   PetscErrorCode ierr;
3235 
3236   PetscFunctionBegin;
3237   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3238   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
3239   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
3240   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
3241   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);
3242   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);
3243   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);
3244   mesh->supports[off+supportPos] = supportPoint;
3245   PetscFunctionReturn(0);
3246 }
3247 
3248 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */
3249 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o)
3250 {
3251   switch (ct) {
3252     case DM_POLYTOPE_SEGMENT:
3253       if (o == -1) return -2;
3254       break;
3255     case DM_POLYTOPE_TRIANGLE:
3256       if (o == -3) return -1;
3257       if (o == -2) return -3;
3258       if (o == -1) return -2;
3259       break;
3260     case DM_POLYTOPE_QUADRILATERAL:
3261       if (o == -4) return -2;
3262       if (o == -3) return -1;
3263       if (o == -2) return -4;
3264       if (o == -1) return -3;
3265       break;
3266     default: return o;
3267   }
3268   return o;
3269 }
3270 
3271 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */
3272 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o)
3273 {
3274   switch (ct) {
3275     case DM_POLYTOPE_SEGMENT:
3276       if ((o == -2) || (o == 1)) return -1;
3277       if (o == -1) return 0;
3278       break;
3279     case DM_POLYTOPE_TRIANGLE:
3280       if (o == -3) return -2;
3281       if (o == -2) return -1;
3282       if (o == -1) return -3;
3283       break;
3284     case DM_POLYTOPE_QUADRILATERAL:
3285       if (o == -4) return -2;
3286       if (o == -3) return -1;
3287       if (o == -2) return -4;
3288       if (o == -1) return -3;
3289       break;
3290     default: return o;
3291   }
3292   return o;
3293 }
3294 
3295 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */
3296 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm)
3297 {
3298   PetscInt       pStart, pEnd, p;
3299   PetscErrorCode ierr;
3300 
3301   PetscFunctionBegin;
3302   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3303   for (p = pStart; p < pEnd; ++p) {
3304     const PetscInt *cone, *ornt;
3305     PetscInt        coneSize, c;
3306 
3307     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
3308     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
3309     ierr = DMPlexGetConeOrientation(dm, p, &ornt);CHKERRQ(ierr);
3310     for (c = 0; c < coneSize; ++c) {
3311       DMPolytopeType ct;
3312       const PetscInt o = ornt[c];
3313 
3314       ierr = DMPlexGetCellType(dm, cone[c], &ct);CHKERRQ(ierr);
3315       switch (ct) {
3316         case DM_POLYTOPE_SEGMENT:
3317           if ((o == -2) || (o == 1)) {ierr = DMPlexInsertConeOrientation(dm, p, c, -1);CHKERRQ(ierr);}
3318           if (o == -1) {ierr = DMPlexInsertConeOrientation(dm, p, c, 0);CHKERRQ(ierr);}
3319           break;
3320         case DM_POLYTOPE_TRIANGLE:
3321           if (o == -3) {ierr = DMPlexInsertConeOrientation(dm, p, c, -2);CHKERRQ(ierr);}
3322           if (o == -2) {ierr = DMPlexInsertConeOrientation(dm, p, c, -1);CHKERRQ(ierr);}
3323           if (o == -1) {ierr = DMPlexInsertConeOrientation(dm, p, c, -3);CHKERRQ(ierr);}
3324           break;
3325         case DM_POLYTOPE_QUADRILATERAL:
3326           if (o == -4) {ierr = DMPlexInsertConeOrientation(dm, p, c, -2);CHKERRQ(ierr);}
3327           if (o == -3) {ierr = DMPlexInsertConeOrientation(dm, p, c, -1);CHKERRQ(ierr);}
3328           if (o == -2) {ierr = DMPlexInsertConeOrientation(dm, p, c, -4);CHKERRQ(ierr);}
3329           if (o == -1) {ierr = DMPlexInsertConeOrientation(dm, p, c, -3);CHKERRQ(ierr);}
3330           break;
3331         default: break;
3332       }
3333     }
3334   }
3335   PetscFunctionReturn(0);
3336 }
3337 
3338 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3339 {
3340   DMPolytopeType  ct = DM_POLYTOPE_UNKNOWN;
3341   PetscInt       *closure;
3342   const PetscInt *tmp = NULL, *tmpO = NULL;
3343   PetscInt        off = 0, tmpSize, t;
3344   PetscErrorCode  ierr;
3345 
3346   PetscFunctionBeginHot;
3347   if (ornt) {
3348     ierr = DMPlexGetCellType(dm, p, &ct);CHKERRQ(ierr);
3349     if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3350   }
3351   if (*points) {
3352     closure = *points;
3353   } else {
3354     PetscInt maxConeSize, maxSupportSize;
3355     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3356     ierr = DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure);CHKERRQ(ierr);
3357   }
3358   if (useCone) {
3359     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
3360     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
3361     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
3362   } else {
3363     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
3364     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
3365   }
3366   if (ct == DM_POLYTOPE_UNKNOWN) {
3367     closure[off++] = p;
3368     closure[off++] = 0;
3369     for (t = 0; t < tmpSize; ++t) {
3370       closure[off++] = tmp[t];
3371       closure[off++] = tmpO ? tmpO[t] : 0;
3372     }
3373   } else {
3374     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt);CHKERRQ(ierr);
3375 
3376     /* We assume that cells with a valid type have faces with a valid type */
3377     closure[off++] = p;
3378     closure[off++] = ornt;
3379     for (t = 0; t < tmpSize; ++t) {
3380       DMPolytopeType ft;
3381 
3382       ierr = DMPlexGetCellType(dm, tmp[t], &ft);CHKERRQ(ierr);
3383       closure[off++] = tmp[arr[t]];
3384       closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0;
3385     }
3386   }
3387   if (numPoints) *numPoints = tmpSize+1;
3388   if (points)    *points    = closure;
3389   PetscFunctionReturn(0);
3390 }
3391 
3392 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */
3393 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points)
3394 {
3395   const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
3396   const PetscInt *cone, *ornt;
3397   PetscInt       *pts,  *closure = NULL;
3398   DMPolytopeType  ft;
3399   PetscInt        maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize;
3400   PetscInt        dim, coneSize, c, d, clSize, cl;
3401   PetscErrorCode  ierr;
3402 
3403   PetscFunctionBeginHot;
3404   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
3405   ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
3406   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
3407   ierr = DMPlexGetConeOrientation(dm, point, &ornt);CHKERRQ(ierr);
3408   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3409   coneSeries    = (maxConeSize    > 1) ? ((PetscPowInt(maxConeSize,    dim+1)-1)/(maxConeSize-1))    : dim+1;
3410   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1;
3411   maxSize       = PetscMax(coneSeries, supportSeries);
3412   if (*points) {pts  = *points;}
3413   else         {ierr = DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts);CHKERRQ(ierr);}
3414   c    = 0;
3415   pts[c++] = point;
3416   pts[c++] = o;
3417   ierr = DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft);CHKERRQ(ierr);
3418   ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure);CHKERRQ(ierr);
3419   for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];}
3420   ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure);CHKERRQ(ierr);
3421   for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];}
3422   ierr = DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure);CHKERRQ(ierr);
3423   for (d = 2; d < coneSize; ++d) {
3424     ierr = DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft);CHKERRQ(ierr);
3425     pts[c++] = cone[arr[d*2+0]];
3426     pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]);
3427   }
3428   if (dim >= 3) {
3429     for (d = 2; d < coneSize; ++d) {
3430       const PetscInt  fpoint = cone[arr[d*2+0]];
3431       const PetscInt *fcone, *fornt;
3432       PetscInt        fconeSize, fc, i;
3433 
3434       ierr = DMPlexGetCellType(dm, fpoint, &ft);CHKERRQ(ierr);
3435       const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]));
3436       ierr = DMPlexGetConeSize(dm, fpoint, &fconeSize);CHKERRQ(ierr);
3437       ierr = DMPlexGetCone(dm, fpoint, &fcone);CHKERRQ(ierr);
3438       ierr = DMPlexGetConeOrientation(dm, fpoint, &fornt);CHKERRQ(ierr);
3439       for (fc = 0; fc < fconeSize; ++fc) {
3440         const PetscInt cp = fcone[farr[fc*2+0]];
3441         const PetscInt co = farr[fc*2+1];
3442 
3443         for (i = 0; i < c; i += 2) if (pts[i] == cp) break;
3444         if (i == c) {
3445           ierr = DMPlexGetCellType(dm, cp, &ft);CHKERRQ(ierr);
3446           pts[c++] = cp;
3447           pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]);
3448         }
3449       }
3450     }
3451   }
3452   *numPoints = c/2;
3453   *points    = pts;
3454   PetscFunctionReturn(0);
3455 }
3456 
3457 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3458 {
3459   DMPolytopeType ct;
3460   PetscInt      *closure, *fifo;
3461   PetscInt       closureSize = 0, fifoStart = 0, fifoSize = 0;
3462   PetscInt       maxConeSize, maxSupportSize, coneSeries, supportSeries;
3463   PetscInt       depth, maxSize;
3464   PetscErrorCode ierr;
3465 
3466   PetscFunctionBeginHot;
3467   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3468   if (depth == 1) {
3469     ierr = DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points);CHKERRQ(ierr);
3470     PetscFunctionReturn(0);
3471   }
3472   ierr = DMPlexGetCellType(dm, p, &ct);CHKERRQ(ierr);
3473   if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3474   if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
3475     ierr = DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points);CHKERRQ(ierr);
3476     PetscFunctionReturn(0);
3477   }
3478   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3479   coneSeries    = (maxConeSize    > 1) ? ((PetscPowInt(maxConeSize,    depth+1)-1)/(maxConeSize-1))    : depth+1;
3480   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1;
3481   maxSize       = PetscMax(coneSeries, supportSeries);
3482   ierr = DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo);CHKERRQ(ierr);
3483   if (*points) {closure = *points;}
3484   else         {ierr = DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure);CHKERRQ(ierr);}
3485   closure[closureSize++] = p;
3486   closure[closureSize++] = ornt;
3487   fifo[fifoSize++]       = p;
3488   fifo[fifoSize++]       = ornt;
3489   fifo[fifoSize++]       = ct;
3490   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
3491   while (fifoSize - fifoStart) {
3492     const PetscInt       q    = fifo[fifoStart++];
3493     const PetscInt       o    = fifo[fifoStart++];
3494     const DMPolytopeType qt   = (DMPolytopeType) fifo[fifoStart++];
3495     const PetscInt      *qarr = DMPolytopeTypeGetArrangment(qt, o);
3496     const PetscInt      *tmp, *tmpO;
3497     PetscInt             tmpSize, t;
3498 
3499     if (PetscDefined(USE_DEBUG)) {
3500       PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2;
3501       if (o && (o >= nO || o < -nO)) SETERRQ5(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %D not in [%D,%D) for %s %D", o, -nO, nO, DMPolytopeTypes[qt], q);
3502     }
3503     if (useCone) {
3504       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
3505       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
3506       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
3507     } else {
3508       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
3509       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
3510       tmpO = NULL;
3511     }
3512     for (t = 0; t < tmpSize; ++t) {
3513       const PetscInt ip = useCone && qarr ? qarr[t*2]   : t;
3514       const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0;
3515       const PetscInt cp = tmp[ip];
3516       ierr = DMPlexGetCellType(dm, cp, &ct);CHKERRQ(ierr);
3517       const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0;
3518       PetscInt       c;
3519 
3520       /* Check for duplicate */
3521       for (c = 0; c < closureSize; c += 2) {
3522         if (closure[c] == cp) break;
3523       }
3524       if (c == closureSize) {
3525         closure[closureSize++] = cp;
3526         closure[closureSize++] = co;
3527         fifo[fifoSize++]       = cp;
3528         fifo[fifoSize++]       = co;
3529         fifo[fifoSize++]       = ct;
3530       }
3531     }
3532   }
3533   ierr = DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo);CHKERRQ(ierr);
3534   if (numPoints) *numPoints = closureSize/2;
3535   if (points)    *points    = closure;
3536   PetscFunctionReturn(0);
3537 }
3538 
3539 /*@C
3540   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
3541 
3542   Not collective
3543 
3544   Input Parameters:
3545 + dm      - The DMPlex
3546 . p       - The mesh point
3547 - useCone - PETSC_TRUE for the closure, otherwise return the star
3548 
3549   Input/Output Parameter:
3550 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...];
3551            if NULL on input, internal storage will be returned, otherwise the provided array is used
3552 
3553   Output Parameter:
3554 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints
3555 
3556   Note:
3557   If using internal storage (points is NULL on input), each call overwrites the last output.
3558 
3559   Fortran Notes:
3560   Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code.
3561 
3562   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3563 
3564   Level: beginner
3565 
3566 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
3567 @*/
3568 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3569 {
3570   PetscErrorCode ierr;
3571 
3572   PetscFunctionBeginHot;
3573   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3574   if (numPoints) PetscValidIntPointer(numPoints, 4);
3575   if (points)    PetscValidPointer(points, 5);
3576   ierr = DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points);CHKERRQ(ierr);
3577   PetscFunctionReturn(0);
3578 }
3579 
3580 /*@C
3581   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
3582 
3583   Not collective
3584 
3585   Input Parameters:
3586 + dm        - The DMPlex
3587 . p         - The mesh point
3588 . useCone   - PETSC_TRUE for the closure, otherwise return the star
3589 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints
3590 - points    - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
3591 
3592   Note:
3593   If not using internal storage (points is not NULL on input), this call is unnecessary
3594 
3595   Fortran Notes:
3596   Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code.
3597 
3598   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3599 
3600   Level: beginner
3601 
3602 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
3603 @*/
3604 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3605 {
3606   PetscErrorCode ierr;
3607 
3608   PetscFunctionBeginHot;
3609   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3610   if (numPoints) *numPoints = 0;
3611   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, points);CHKERRQ(ierr);
3612   PetscFunctionReturn(0);
3613 }
3614 
3615 /*@
3616   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
3617 
3618   Not collective
3619 
3620   Input Parameter:
3621 . mesh - The DMPlex
3622 
3623   Output Parameters:
3624 + maxConeSize - The maximum number of in-edges
3625 - maxSupportSize - The maximum number of out-edges
3626 
3627   Level: beginner
3628 
3629 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
3630 @*/
3631 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
3632 {
3633   DM_Plex *mesh = (DM_Plex*) dm->data;
3634 
3635   PetscFunctionBegin;
3636   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3637   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
3638   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
3639   PetscFunctionReturn(0);
3640 }
3641 
3642 PetscErrorCode DMSetUp_Plex(DM dm)
3643 {
3644   DM_Plex       *mesh = (DM_Plex*) dm->data;
3645   PetscInt       size;
3646   PetscErrorCode ierr;
3647 
3648   PetscFunctionBegin;
3649   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3650   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
3651   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
3652   ierr = PetscMalloc1(size, &mesh->cones);CHKERRQ(ierr);
3653   ierr = PetscCalloc1(size, &mesh->coneOrientations);CHKERRQ(ierr);
3654   ierr = PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt));CHKERRQ(ierr);
3655   if (mesh->maxSupportSize) {
3656     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
3657     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
3658     ierr = PetscMalloc1(size, &mesh->supports);CHKERRQ(ierr);
3659     ierr = PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt));CHKERRQ(ierr);
3660   }
3661   PetscFunctionReturn(0);
3662 }
3663 
3664 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
3665 {
3666   PetscErrorCode ierr;
3667 
3668   PetscFunctionBegin;
3669   if (subdm) {ierr = DMClone(dm, subdm);CHKERRQ(ierr);}
3670   ierr = DMCreateSectionSubDM(dm, numFields, fields, is, subdm);CHKERRQ(ierr);
3671   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
3672   if (dm->useNatural && dm->sfMigration) {
3673     PetscSF        sfMigrationInv,sfNatural;
3674     PetscSection   section, sectionSeq;
3675 
3676     (*subdm)->sfMigration = dm->sfMigration;
3677     ierr = PetscObjectReference((PetscObject) dm->sfMigration);CHKERRQ(ierr);
3678     ierr = DMGetLocalSection((*subdm), &section);CHKERRQ(ierr);
3679     ierr = PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);CHKERRQ(ierr);
3680     ierr = PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq);CHKERRQ(ierr);
3681     ierr = PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);CHKERRQ(ierr);
3682 
3683     ierr = DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);CHKERRQ(ierr);
3684     (*subdm)->sfNatural = sfNatural;
3685     ierr = PetscSectionDestroy(&sectionSeq);CHKERRQ(ierr);
3686     ierr = PetscSFDestroy(&sfMigrationInv);CHKERRQ(ierr);
3687   }
3688   PetscFunctionReturn(0);
3689 }
3690 
3691 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
3692 {
3693   PetscErrorCode ierr;
3694   PetscInt       i = 0;
3695 
3696   PetscFunctionBegin;
3697   ierr = DMClone(dms[0], superdm);CHKERRQ(ierr);
3698   ierr = DMCreateSectionSuperDM(dms, len, is, superdm);CHKERRQ(ierr);
3699   (*superdm)->useNatural = PETSC_FALSE;
3700   for (i = 0; i < len; i++) {
3701     if (dms[i]->useNatural && dms[i]->sfMigration) {
3702       PetscSF        sfMigrationInv,sfNatural;
3703       PetscSection   section, sectionSeq;
3704 
3705       (*superdm)->sfMigration = dms[i]->sfMigration;
3706       ierr = PetscObjectReference((PetscObject) dms[i]->sfMigration);CHKERRQ(ierr);
3707       (*superdm)->useNatural = PETSC_TRUE;
3708       ierr = DMGetLocalSection((*superdm), &section);CHKERRQ(ierr);
3709       ierr = PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);CHKERRQ(ierr);
3710       ierr = PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq);CHKERRQ(ierr);
3711       ierr = PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);CHKERRQ(ierr);
3712 
3713       ierr = DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);CHKERRQ(ierr);
3714       (*superdm)->sfNatural = sfNatural;
3715       ierr = PetscSectionDestroy(&sectionSeq);CHKERRQ(ierr);
3716       ierr = PetscSFDestroy(&sfMigrationInv);CHKERRQ(ierr);
3717       break;
3718     }
3719   }
3720   PetscFunctionReturn(0);
3721 }
3722 
3723 /*@
3724   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
3725 
3726   Not collective
3727 
3728   Input Parameter:
3729 . mesh - The DMPlex
3730 
3731   Output Parameter:
3732 
3733   Note:
3734   This should be called after all calls to DMPlexSetCone()
3735 
3736   Level: beginner
3737 
3738 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
3739 @*/
3740 PetscErrorCode DMPlexSymmetrize(DM dm)
3741 {
3742   DM_Plex       *mesh = (DM_Plex*) dm->data;
3743   PetscInt      *offsets;
3744   PetscInt       supportSize;
3745   PetscInt       pStart, pEnd, p;
3746   PetscErrorCode ierr;
3747 
3748   PetscFunctionBegin;
3749   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3750   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
3751   ierr = PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0);CHKERRQ(ierr);
3752   /* Calculate support sizes */
3753   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3754   for (p = pStart; p < pEnd; ++p) {
3755     PetscInt dof, off, c;
3756 
3757     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
3758     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
3759     for (c = off; c < off+dof; ++c) {
3760       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
3761     }
3762   }
3763   for (p = pStart; p < pEnd; ++p) {
3764     PetscInt dof;
3765 
3766     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
3767 
3768     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
3769   }
3770   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
3771   /* Calculate supports */
3772   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
3773   ierr = PetscMalloc1(supportSize, &mesh->supports);CHKERRQ(ierr);
3774   ierr = PetscCalloc1(pEnd - pStart, &offsets);CHKERRQ(ierr);
3775   for (p = pStart; p < pEnd; ++p) {
3776     PetscInt dof, off, c;
3777 
3778     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
3779     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
3780     for (c = off; c < off+dof; ++c) {
3781       const PetscInt q = mesh->cones[c];
3782       PetscInt       offS;
3783 
3784       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
3785 
3786       mesh->supports[offS+offsets[q]] = p;
3787       ++offsets[q];
3788     }
3789   }
3790   ierr = PetscFree(offsets);CHKERRQ(ierr);
3791   ierr = PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0);CHKERRQ(ierr);
3792   PetscFunctionReturn(0);
3793 }
3794 
3795 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
3796 {
3797   IS             stratumIS;
3798   PetscErrorCode ierr;
3799 
3800   PetscFunctionBegin;
3801   if (pStart >= pEnd) PetscFunctionReturn(0);
3802   if (PetscDefined(USE_DEBUG)) {
3803     PetscInt  qStart, qEnd, numLevels, level;
3804     PetscBool overlap = PETSC_FALSE;
3805     ierr = DMLabelGetNumValues(label, &numLevels);CHKERRQ(ierr);
3806     for (level = 0; level < numLevels; level++) {
3807       ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr);
3808       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;}
3809     }
3810     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);
3811   }
3812   ierr = ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS);CHKERRQ(ierr);
3813   ierr = DMLabelSetStratumIS(label, depth, stratumIS);CHKERRQ(ierr);
3814   ierr = ISDestroy(&stratumIS);CHKERRQ(ierr);
3815   PetscFunctionReturn(0);
3816 }
3817 
3818 /*@
3819   DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
3820   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
3821   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
3822   the DAG.
3823 
3824   Collective on dm
3825 
3826   Input Parameter:
3827 . mesh - The DMPlex
3828 
3829   Output Parameter:
3830 
3831   Notes:
3832   Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
3833   meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on
3834   until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
3835   manually via DMGetLabel().  The height is defined implicitly by height = maxDimension - depth, and can be accessed
3836   via DMPlexGetHeightStratum().  For example, cells have height 0 and faces have height 1.
3837 
3838   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
3839   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
3840   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
3841   to interpolate only that one (e0), so that
3842 $  cone(c0) = {e0, v2}
3843 $  cone(e0) = {v0, v1}
3844   If DMPlexStratify() is run on this mesh, it will give depths
3845 $  depth 0 = {v0, v1, v2}
3846 $  depth 1 = {e0, c0}
3847   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.
3848 
3849   DMPlexStratify() should be called after all calls to DMPlexSymmetrize()
3850 
3851   Level: beginner
3852 
3853 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexComputeCellTypes()
3854 @*/
3855 PetscErrorCode DMPlexStratify(DM dm)
3856 {
3857   DM_Plex       *mesh = (DM_Plex*) dm->data;
3858   DMLabel        label;
3859   PetscInt       pStart, pEnd, p;
3860   PetscInt       numRoots = 0, numLeaves = 0;
3861   PetscErrorCode ierr;
3862 
3863   PetscFunctionBegin;
3864   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3865   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
3866 
3867   /* Create depth label */
3868   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3869   ierr = DMCreateLabel(dm, "depth");CHKERRQ(ierr);
3870   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
3871 
3872   {
3873     /* Initialize roots and count leaves */
3874     PetscInt sMin = PETSC_MAX_INT;
3875     PetscInt sMax = PETSC_MIN_INT;
3876     PetscInt coneSize, supportSize;
3877 
3878     for (p = pStart; p < pEnd; ++p) {
3879       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
3880       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
3881       if (!coneSize && supportSize) {
3882         sMin = PetscMin(p, sMin);
3883         sMax = PetscMax(p, sMax);
3884         ++numRoots;
3885       } else if (!supportSize && coneSize) {
3886         ++numLeaves;
3887       } else if (!supportSize && !coneSize) {
3888         /* Isolated points */
3889         sMin = PetscMin(p, sMin);
3890         sMax = PetscMax(p, sMax);
3891       }
3892     }
3893     ierr = DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1);CHKERRQ(ierr);
3894   }
3895 
3896   if (numRoots + numLeaves == (pEnd - pStart)) {
3897     PetscInt sMin = PETSC_MAX_INT;
3898     PetscInt sMax = PETSC_MIN_INT;
3899     PetscInt coneSize, supportSize;
3900 
3901     for (p = pStart; p < pEnd; ++p) {
3902       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
3903       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
3904       if (!supportSize && coneSize) {
3905         sMin = PetscMin(p, sMin);
3906         sMax = PetscMax(p, sMax);
3907       }
3908     }
3909     ierr = DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1);CHKERRQ(ierr);
3910   } else {
3911     PetscInt level = 0;
3912     PetscInt qStart, qEnd, q;
3913 
3914     ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr);
3915     while (qEnd > qStart) {
3916       PetscInt sMin = PETSC_MAX_INT;
3917       PetscInt sMax = PETSC_MIN_INT;
3918 
3919       for (q = qStart; q < qEnd; ++q) {
3920         const PetscInt *support;
3921         PetscInt        supportSize, s;
3922 
3923         ierr = DMPlexGetSupportSize(dm, q, &supportSize);CHKERRQ(ierr);
3924         ierr = DMPlexGetSupport(dm, q, &support);CHKERRQ(ierr);
3925         for (s = 0; s < supportSize; ++s) {
3926           sMin = PetscMin(support[s], sMin);
3927           sMax = PetscMax(support[s], sMax);
3928         }
3929       }
3930       ierr = DMLabelGetNumValues(label, &level);CHKERRQ(ierr);
3931       ierr = DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1);CHKERRQ(ierr);
3932       ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr);
3933     }
3934   }
3935   { /* just in case there is an empty process */
3936     PetscInt numValues, maxValues = 0, v;
3937 
3938     ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
3939     ierr = MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
3940     for (v = numValues; v < maxValues; v++) {
3941       ierr = DMLabelAddStratum(label, v);CHKERRQ(ierr);
3942     }
3943   }
3944   ierr = PetscObjectStateGet((PetscObject) label, &mesh->depthState);CHKERRQ(ierr);
3945   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
3946   PetscFunctionReturn(0);
3947 }
3948 
3949 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
3950 {
3951   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
3952   PetscInt       dim, depth, pheight, coneSize;
3953   PetscErrorCode ierr;
3954 
3955   PetscFunctionBeginHot;
3956   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
3957   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3958   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
3959   pheight = depth - pdepth;
3960   if (depth <= 1) {
3961     switch (pdepth) {
3962       case 0: ct = DM_POLYTOPE_POINT;break;
3963       case 1:
3964         switch (coneSize) {
3965           case 2: ct = DM_POLYTOPE_SEGMENT;break;
3966           case 3: ct = DM_POLYTOPE_TRIANGLE;break;
3967           case 4:
3968           switch (dim) {
3969             case 2: ct = DM_POLYTOPE_QUADRILATERAL;break;
3970             case 3: ct = DM_POLYTOPE_TETRAHEDRON;break;
3971             default: break;
3972           }
3973           break;
3974         case 5: ct = DM_POLYTOPE_PYRAMID;break;
3975         case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break;
3976         case 8: ct = DM_POLYTOPE_HEXAHEDRON;break;
3977         default: break;
3978       }
3979     }
3980   } else {
3981     if (pdepth == 0) {
3982       ct = DM_POLYTOPE_POINT;
3983     } else if (pheight == 0) {
3984       switch (dim) {
3985         case 1:
3986           switch (coneSize) {
3987             case 2: ct = DM_POLYTOPE_SEGMENT;break;
3988             default: break;
3989           }
3990           break;
3991         case 2:
3992           switch (coneSize) {
3993             case 3: ct = DM_POLYTOPE_TRIANGLE;break;
3994             case 4: ct = DM_POLYTOPE_QUADRILATERAL;break;
3995             default: break;
3996           }
3997           break;
3998         case 3:
3999           switch (coneSize) {
4000             case 4: ct = DM_POLYTOPE_TETRAHEDRON;break;
4001             case 5:
4002             {
4003               const PetscInt *cone;
4004               PetscInt        faceConeSize;
4005 
4006               ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
4007               ierr = DMPlexGetConeSize(dm, cone[0], &faceConeSize);CHKERRQ(ierr);
4008               switch (faceConeSize) {
4009                 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break;
4010                 case 4: ct = DM_POLYTOPE_PYRAMID;break;
4011               }
4012             }
4013             break;
4014             case 6: ct = DM_POLYTOPE_HEXAHEDRON;break;
4015             default: break;
4016           }
4017           break;
4018         default: break;
4019       }
4020     } else if (pheight > 0) {
4021       switch (coneSize) {
4022         case 2: ct = DM_POLYTOPE_SEGMENT;break;
4023         case 3: ct = DM_POLYTOPE_TRIANGLE;break;
4024         case 4: ct = DM_POLYTOPE_QUADRILATERAL;break;
4025         default: break;
4026       }
4027     }
4028   }
4029   *pt = ct;
4030   PetscFunctionReturn(0);
4031 }
4032 
4033 /*@
4034   DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size.
4035 
4036   Collective on dm
4037 
4038   Input Parameter:
4039 . mesh - The DMPlex
4040 
4041   DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify()
4042 
4043   Level: developer
4044 
4045   Note: This function is normally called automatically by Plex when a cell type is requested. It creates an
4046   internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable
4047   automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype").
4048 
4049 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexStratify(), DMGetLabel(), DMCreateLabel()
4050 @*/
4051 PetscErrorCode DMPlexComputeCellTypes(DM dm)
4052 {
4053   DM_Plex       *mesh;
4054   DMLabel        ctLabel;
4055   PetscInt       pStart, pEnd, p;
4056   PetscErrorCode ierr;
4057 
4058   PetscFunctionBegin;
4059   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4060   mesh = (DM_Plex *) dm->data;
4061   ierr = DMCreateLabel(dm, "celltype");CHKERRQ(ierr);
4062   ierr = DMPlexGetCellTypeLabel(dm, &ctLabel);CHKERRQ(ierr);
4063   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
4064   for (p = pStart; p < pEnd; ++p) {
4065     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4066     PetscInt       pdepth;
4067 
4068     ierr = DMPlexGetPointDepth(dm, p, &pdepth);CHKERRQ(ierr);
4069     ierr = DMPlexComputeCellType_Internal(dm, p, pdepth, &ct);CHKERRQ(ierr);
4070     if (ct == DM_POLYTOPE_UNKNOWN) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %D is screwed up", p);
4071     ierr = DMLabelSetValue(ctLabel, p, ct);CHKERRQ(ierr);
4072   }
4073   ierr = PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState);CHKERRQ(ierr);
4074   ierr = PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view");CHKERRQ(ierr);
4075   PetscFunctionReturn(0);
4076 }
4077 
4078 /*@C
4079   DMPlexGetJoin - Get an array for the join of the set of points
4080 
4081   Not Collective
4082 
4083   Input Parameters:
4084 + dm - The DMPlex object
4085 . numPoints - The number of input points for the join
4086 - points - The input points
4087 
4088   Output Parameters:
4089 + numCoveredPoints - The number of points in the join
4090 - coveredPoints - The points in the join
4091 
4092   Level: intermediate
4093 
4094   Note: Currently, this is restricted to a single level join
4095 
4096   Fortran Notes:
4097   Since it returns an array, this routine is only available in Fortran 90, and you must
4098   include petsc.h90 in your code.
4099 
4100   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4101 
4102 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
4103 @*/
4104 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4105 {
4106   DM_Plex       *mesh = (DM_Plex*) dm->data;
4107   PetscInt      *join[2];
4108   PetscInt       joinSize, i = 0;
4109   PetscInt       dof, off, p, c, m;
4110   PetscErrorCode ierr;
4111 
4112   PetscFunctionBegin;
4113   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4114   PetscValidIntPointer(points, 3);
4115   PetscValidIntPointer(numCoveredPoints, 4);
4116   PetscValidPointer(coveredPoints, 5);
4117   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);CHKERRQ(ierr);
4118   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);CHKERRQ(ierr);
4119   /* Copy in support of first point */
4120   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
4121   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
4122   for (joinSize = 0; joinSize < dof; ++joinSize) {
4123     join[i][joinSize] = mesh->supports[off+joinSize];
4124   }
4125   /* Check each successive support */
4126   for (p = 1; p < numPoints; ++p) {
4127     PetscInt newJoinSize = 0;
4128 
4129     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
4130     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
4131     for (c = 0; c < dof; ++c) {
4132       const PetscInt point = mesh->supports[off+c];
4133 
4134       for (m = 0; m < joinSize; ++m) {
4135         if (point == join[i][m]) {
4136           join[1-i][newJoinSize++] = point;
4137           break;
4138         }
4139       }
4140     }
4141     joinSize = newJoinSize;
4142     i        = 1-i;
4143   }
4144   *numCoveredPoints = joinSize;
4145   *coveredPoints    = join[i];
4146   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);CHKERRQ(ierr);
4147   PetscFunctionReturn(0);
4148 }
4149 
4150 /*@C
4151   DMPlexRestoreJoin - Restore an array for the join of the set of points
4152 
4153   Not Collective
4154 
4155   Input Parameters:
4156 + dm - The DMPlex object
4157 . numPoints - The number of input points for the join
4158 - points - The input points
4159 
4160   Output Parameters:
4161 + numCoveredPoints - The number of points in the join
4162 - coveredPoints - The points in the join
4163 
4164   Fortran Notes:
4165   Since it returns an array, this routine is only available in Fortran 90, and you must
4166   include petsc.h90 in your code.
4167 
4168   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4169 
4170   Level: intermediate
4171 
4172 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
4173 @*/
4174 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4175 {
4176   PetscErrorCode ierr;
4177 
4178   PetscFunctionBegin;
4179   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4180   if (points) PetscValidIntPointer(points,3);
4181   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
4182   PetscValidPointer(coveredPoints, 5);
4183   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);CHKERRQ(ierr);
4184   if (numCoveredPoints) *numCoveredPoints = 0;
4185   PetscFunctionReturn(0);
4186 }
4187 
4188 /*@C
4189   DMPlexGetFullJoin - Get an array for the join of the set of points
4190 
4191   Not Collective
4192 
4193   Input Parameters:
4194 + dm - The DMPlex object
4195 . numPoints - The number of input points for the join
4196 - points - The input points
4197 
4198   Output Parameters:
4199 + numCoveredPoints - The number of points in the join
4200 - coveredPoints - The points in the join
4201 
4202   Fortran Notes:
4203   Since it returns an array, this routine is only available in Fortran 90, and you must
4204   include petsc.h90 in your code.
4205 
4206   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4207 
4208   Level: intermediate
4209 
4210 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
4211 @*/
4212 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4213 {
4214   DM_Plex       *mesh = (DM_Plex*) dm->data;
4215   PetscInt      *offsets, **closures;
4216   PetscInt      *join[2];
4217   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
4218   PetscInt       p, d, c, m, ms;
4219   PetscErrorCode ierr;
4220 
4221   PetscFunctionBegin;
4222   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4223   PetscValidIntPointer(points, 3);
4224   PetscValidIntPointer(numCoveredPoints, 4);
4225   PetscValidPointer(coveredPoints, 5);
4226 
4227   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4228   ierr    = PetscCalloc1(numPoints, &closures);CHKERRQ(ierr);
4229   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);CHKERRQ(ierr);
4230   ms      = mesh->maxSupportSize;
4231   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
4232   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);CHKERRQ(ierr);
4233   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);CHKERRQ(ierr);
4234 
4235   for (p = 0; p < numPoints; ++p) {
4236     PetscInt closureSize;
4237 
4238     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
4239 
4240     offsets[p*(depth+2)+0] = 0;
4241     for (d = 0; d < depth+1; ++d) {
4242       PetscInt pStart, pEnd, i;
4243 
4244       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
4245       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
4246         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
4247           offsets[p*(depth+2)+d+1] = i;
4248           break;
4249         }
4250       }
4251       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
4252     }
4253     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);
4254   }
4255   for (d = 0; d < depth+1; ++d) {
4256     PetscInt dof;
4257 
4258     /* Copy in support of first point */
4259     dof = offsets[d+1] - offsets[d];
4260     for (joinSize = 0; joinSize < dof; ++joinSize) {
4261       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
4262     }
4263     /* Check each successive cone */
4264     for (p = 1; p < numPoints && joinSize; ++p) {
4265       PetscInt newJoinSize = 0;
4266 
4267       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
4268       for (c = 0; c < dof; ++c) {
4269         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
4270 
4271         for (m = 0; m < joinSize; ++m) {
4272           if (point == join[i][m]) {
4273             join[1-i][newJoinSize++] = point;
4274             break;
4275           }
4276         }
4277       }
4278       joinSize = newJoinSize;
4279       i        = 1-i;
4280     }
4281     if (joinSize) break;
4282   }
4283   *numCoveredPoints = joinSize;
4284   *coveredPoints    = join[i];
4285   for (p = 0; p < numPoints; ++p) {
4286     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
4287   }
4288   ierr = PetscFree(closures);CHKERRQ(ierr);
4289   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);CHKERRQ(ierr);
4290   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);CHKERRQ(ierr);
4291   PetscFunctionReturn(0);
4292 }
4293 
4294 /*@C
4295   DMPlexGetMeet - Get an array for the meet of the set of points
4296 
4297   Not Collective
4298 
4299   Input Parameters:
4300 + dm - The DMPlex object
4301 . numPoints - The number of input points for the meet
4302 - points - The input points
4303 
4304   Output Parameters:
4305 + numCoveredPoints - The number of points in the meet
4306 - coveredPoints - The points in the meet
4307 
4308   Level: intermediate
4309 
4310   Note: Currently, this is restricted to a single level meet
4311 
4312   Fortran Notes:
4313   Since it returns an array, this routine is only available in Fortran 90, and you must
4314   include petsc.h90 in your code.
4315 
4316   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4317 
4318 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
4319 @*/
4320 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
4321 {
4322   DM_Plex       *mesh = (DM_Plex*) dm->data;
4323   PetscInt      *meet[2];
4324   PetscInt       meetSize, i = 0;
4325   PetscInt       dof, off, p, c, m;
4326   PetscErrorCode ierr;
4327 
4328   PetscFunctionBegin;
4329   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4330   PetscValidPointer(points, 3);
4331   PetscValidPointer(numCoveringPoints, 4);
4332   PetscValidPointer(coveringPoints, 5);
4333   ierr = DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);CHKERRQ(ierr);
4334   ierr = DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);CHKERRQ(ierr);
4335   /* Copy in cone of first point */
4336   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
4337   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
4338   for (meetSize = 0; meetSize < dof; ++meetSize) {
4339     meet[i][meetSize] = mesh->cones[off+meetSize];
4340   }
4341   /* Check each successive cone */
4342   for (p = 1; p < numPoints; ++p) {
4343     PetscInt newMeetSize = 0;
4344 
4345     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
4346     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
4347     for (c = 0; c < dof; ++c) {
4348       const PetscInt point = mesh->cones[off+c];
4349 
4350       for (m = 0; m < meetSize; ++m) {
4351         if (point == meet[i][m]) {
4352           meet[1-i][newMeetSize++] = point;
4353           break;
4354         }
4355       }
4356     }
4357     meetSize = newMeetSize;
4358     i        = 1-i;
4359   }
4360   *numCoveringPoints = meetSize;
4361   *coveringPoints    = meet[i];
4362   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);CHKERRQ(ierr);
4363   PetscFunctionReturn(0);
4364 }
4365 
4366 /*@C
4367   DMPlexRestoreMeet - Restore an array for the meet of the set of points
4368 
4369   Not Collective
4370 
4371   Input Parameters:
4372 + dm - The DMPlex object
4373 . numPoints - The number of input points for the meet
4374 - points - The input points
4375 
4376   Output Parameters:
4377 + numCoveredPoints - The number of points in the meet
4378 - coveredPoints - The points in the meet
4379 
4380   Level: intermediate
4381 
4382   Fortran Notes:
4383   Since it returns an array, this routine is only available in Fortran 90, and you must
4384   include petsc.h90 in your code.
4385 
4386   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4387 
4388 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
4389 @*/
4390 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4391 {
4392   PetscErrorCode ierr;
4393 
4394   PetscFunctionBegin;
4395   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4396   if (points) PetscValidIntPointer(points,3);
4397   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
4398   PetscValidPointer(coveredPoints,5);
4399   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);CHKERRQ(ierr);
4400   if (numCoveredPoints) *numCoveredPoints = 0;
4401   PetscFunctionReturn(0);
4402 }
4403 
4404 /*@C
4405   DMPlexGetFullMeet - Get an array for the meet of the set of points
4406 
4407   Not Collective
4408 
4409   Input Parameters:
4410 + dm - The DMPlex object
4411 . numPoints - The number of input points for the meet
4412 - points - The input points
4413 
4414   Output Parameters:
4415 + numCoveredPoints - The number of points in the meet
4416 - coveredPoints - The points in the meet
4417 
4418   Level: intermediate
4419 
4420   Fortran Notes:
4421   Since it returns an array, this routine is only available in Fortran 90, and you must
4422   include petsc.h90 in your code.
4423 
4424   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4425 
4426 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
4427 @*/
4428 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4429 {
4430   DM_Plex       *mesh = (DM_Plex*) dm->data;
4431   PetscInt      *offsets, **closures;
4432   PetscInt      *meet[2];
4433   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
4434   PetscInt       p, h, c, m, mc;
4435   PetscErrorCode ierr;
4436 
4437   PetscFunctionBegin;
4438   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4439   PetscValidPointer(points, 3);
4440   PetscValidPointer(numCoveredPoints, 4);
4441   PetscValidPointer(coveredPoints, 5);
4442 
4443   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
4444   ierr    = PetscMalloc1(numPoints, &closures);CHKERRQ(ierr);
4445   ierr    = DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);CHKERRQ(ierr);
4446   mc      = mesh->maxConeSize;
4447   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
4448   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);CHKERRQ(ierr);
4449   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);CHKERRQ(ierr);
4450 
4451   for (p = 0; p < numPoints; ++p) {
4452     PetscInt closureSize;
4453 
4454     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
4455 
4456     offsets[p*(height+2)+0] = 0;
4457     for (h = 0; h < height+1; ++h) {
4458       PetscInt pStart, pEnd, i;
4459 
4460       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
4461       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
4462         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
4463           offsets[p*(height+2)+h+1] = i;
4464           break;
4465         }
4466       }
4467       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
4468     }
4469     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);
4470   }
4471   for (h = 0; h < height+1; ++h) {
4472     PetscInt dof;
4473 
4474     /* Copy in cone of first point */
4475     dof = offsets[h+1] - offsets[h];
4476     for (meetSize = 0; meetSize < dof; ++meetSize) {
4477       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
4478     }
4479     /* Check each successive cone */
4480     for (p = 1; p < numPoints && meetSize; ++p) {
4481       PetscInt newMeetSize = 0;
4482 
4483       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
4484       for (c = 0; c < dof; ++c) {
4485         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
4486 
4487         for (m = 0; m < meetSize; ++m) {
4488           if (point == meet[i][m]) {
4489             meet[1-i][newMeetSize++] = point;
4490             break;
4491           }
4492         }
4493       }
4494       meetSize = newMeetSize;
4495       i        = 1-i;
4496     }
4497     if (meetSize) break;
4498   }
4499   *numCoveredPoints = meetSize;
4500   *coveredPoints    = meet[i];
4501   for (p = 0; p < numPoints; ++p) {
4502     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
4503   }
4504   ierr = PetscFree(closures);CHKERRQ(ierr);
4505   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);CHKERRQ(ierr);
4506   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);CHKERRQ(ierr);
4507   PetscFunctionReturn(0);
4508 }
4509 
4510 /*@C
4511   DMPlexEqual - Determine if two DMs have the same topology
4512 
4513   Not Collective
4514 
4515   Input Parameters:
4516 + dmA - A DMPlex object
4517 - dmB - A DMPlex object
4518 
4519   Output Parameters:
4520 . equal - PETSC_TRUE if the topologies are identical
4521 
4522   Level: intermediate
4523 
4524   Notes:
4525   We are not solving graph isomorphism, so we do not permutation.
4526 
4527 .seealso: DMPlexGetCone()
4528 @*/
4529 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
4530 {
4531   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;
4532   PetscErrorCode ierr;
4533 
4534   PetscFunctionBegin;
4535   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
4536   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
4537   PetscValidPointer(equal, 3);
4538 
4539   *equal = PETSC_FALSE;
4540   ierr = DMPlexGetDepth(dmA, &depth);CHKERRQ(ierr);
4541   ierr = DMPlexGetDepth(dmB, &depthB);CHKERRQ(ierr);
4542   if (depth != depthB) PetscFunctionReturn(0);
4543   ierr = DMPlexGetChart(dmA, &pStart,  &pEnd);CHKERRQ(ierr);
4544   ierr = DMPlexGetChart(dmB, &pStartB, &pEndB);CHKERRQ(ierr);
4545   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0);
4546   for (p = pStart; p < pEnd; ++p) {
4547     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
4548     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
4549 
4550     ierr = DMPlexGetConeSize(dmA, p, &coneSize);CHKERRQ(ierr);
4551     ierr = DMPlexGetCone(dmA, p, &cone);CHKERRQ(ierr);
4552     ierr = DMPlexGetConeOrientation(dmA, p, &ornt);CHKERRQ(ierr);
4553     ierr = DMPlexGetConeSize(dmB, p, &coneSizeB);CHKERRQ(ierr);
4554     ierr = DMPlexGetCone(dmB, p, &coneB);CHKERRQ(ierr);
4555     ierr = DMPlexGetConeOrientation(dmB, p, &orntB);CHKERRQ(ierr);
4556     if (coneSize != coneSizeB) PetscFunctionReturn(0);
4557     for (c = 0; c < coneSize; ++c) {
4558       if (cone[c] != coneB[c]) PetscFunctionReturn(0);
4559       if (ornt[c] != orntB[c]) PetscFunctionReturn(0);
4560     }
4561     ierr = DMPlexGetSupportSize(dmA, p, &supportSize);CHKERRQ(ierr);
4562     ierr = DMPlexGetSupport(dmA, p, &support);CHKERRQ(ierr);
4563     ierr = DMPlexGetSupportSize(dmB, p, &supportSizeB);CHKERRQ(ierr);
4564     ierr = DMPlexGetSupport(dmB, p, &supportB);CHKERRQ(ierr);
4565     if (supportSize != supportSizeB) PetscFunctionReturn(0);
4566     for (s = 0; s < supportSize; ++s) {
4567       if (support[s] != supportB[s]) PetscFunctionReturn(0);
4568     }
4569   }
4570   *equal = PETSC_TRUE;
4571   PetscFunctionReturn(0);
4572 }
4573 
4574 /*@C
4575   DMPlexGetNumFaceVertices - Returns the number of vertices on a face
4576 
4577   Not Collective
4578 
4579   Input Parameters:
4580 + dm         - The DMPlex
4581 . cellDim    - The cell dimension
4582 - numCorners - The number of vertices on a cell
4583 
4584   Output Parameters:
4585 . numFaceVertices - The number of vertices on a face
4586 
4587   Level: developer
4588 
4589   Notes:
4590   Of course this can only work for a restricted set of symmetric shapes
4591 
4592 .seealso: DMPlexGetCone()
4593 @*/
4594 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
4595 {
4596   MPI_Comm       comm;
4597   PetscErrorCode ierr;
4598 
4599   PetscFunctionBegin;
4600   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4601   PetscValidPointer(numFaceVertices,4);
4602   switch (cellDim) {
4603   case 0:
4604     *numFaceVertices = 0;
4605     break;
4606   case 1:
4607     *numFaceVertices = 1;
4608     break;
4609   case 2:
4610     switch (numCorners) {
4611     case 3: /* triangle */
4612       *numFaceVertices = 2; /* Edge has 2 vertices */
4613       break;
4614     case 4: /* quadrilateral */
4615       *numFaceVertices = 2; /* Edge has 2 vertices */
4616       break;
4617     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
4618       *numFaceVertices = 3; /* Edge has 3 vertices */
4619       break;
4620     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
4621       *numFaceVertices = 3; /* Edge has 3 vertices */
4622       break;
4623     default:
4624       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
4625     }
4626     break;
4627   case 3:
4628     switch (numCorners) {
4629     case 4: /* tetradehdron */
4630       *numFaceVertices = 3; /* Face has 3 vertices */
4631       break;
4632     case 6: /* tet cohesive cells */
4633       *numFaceVertices = 4; /* Face has 4 vertices */
4634       break;
4635     case 8: /* hexahedron */
4636       *numFaceVertices = 4; /* Face has 4 vertices */
4637       break;
4638     case 9: /* tet cohesive Lagrange cells */
4639       *numFaceVertices = 6; /* Face has 6 vertices */
4640       break;
4641     case 10: /* quadratic tetrahedron */
4642       *numFaceVertices = 6; /* Face has 6 vertices */
4643       break;
4644     case 12: /* hex cohesive Lagrange cells */
4645       *numFaceVertices = 6; /* Face has 6 vertices */
4646       break;
4647     case 18: /* quadratic tet cohesive Lagrange cells */
4648       *numFaceVertices = 6; /* Face has 6 vertices */
4649       break;
4650     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
4651       *numFaceVertices = 9; /* Face has 9 vertices */
4652       break;
4653     default:
4654       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
4655     }
4656     break;
4657   default:
4658     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
4659   }
4660   PetscFunctionReturn(0);
4661 }
4662 
4663 /*@
4664   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
4665 
4666   Not Collective
4667 
4668   Input Parameter:
4669 . dm    - The DMPlex object
4670 
4671   Output Parameter:
4672 . depthLabel - The DMLabel recording point depth
4673 
4674   Level: developer
4675 
4676 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum(), DMPlexGetPointDepth(),
4677 @*/
4678 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
4679 {
4680   PetscFunctionBegin;
4681   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4682   PetscValidPointer(depthLabel, 2);
4683   *depthLabel = dm->depthLabel;
4684   PetscFunctionReturn(0);
4685 }
4686 
4687 /*@
4688   DMPlexGetDepth - Get the depth of the DAG representing this mesh
4689 
4690   Not Collective
4691 
4692   Input Parameter:
4693 . dm    - The DMPlex object
4694 
4695   Output Parameter:
4696 . depth - The number of strata (breadth first levels) in the DAG
4697 
4698   Level: developer
4699 
4700   Notes:
4701   This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel().
4702   The point depth is described more in detail in DMPlexGetDepthStratum().
4703   An empty mesh gives -1.
4704 
4705 .seealso: DMPlexGetDepthLabel(), DMPlexGetDepthStratum(), DMPlexGetPointDepth(), DMPlexSymmetrize()
4706 @*/
4707 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
4708 {
4709   DMLabel        label;
4710   PetscInt       d = 0;
4711   PetscErrorCode ierr;
4712 
4713   PetscFunctionBegin;
4714   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4715   PetscValidPointer(depth, 2);
4716   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4717   if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);}
4718   *depth = d-1;
4719   PetscFunctionReturn(0);
4720 }
4721 
4722 /*@
4723   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
4724 
4725   Not Collective
4726 
4727   Input Parameters:
4728 + dm           - The DMPlex object
4729 - stratumValue - The requested depth
4730 
4731   Output Parameters:
4732 + start - The first point at this depth
4733 - end   - One beyond the last point at this depth
4734 
4735   Notes:
4736   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
4737   often "vertices".  If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next
4738   higher dimension, e.g., "edges".
4739 
4740   Level: developer
4741 
4742 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth(), DMPlexGetDepthLabel(), DMPlexGetPointDepth(), DMPlexSymmetrize(), DMPlexInterpolate()
4743 @*/
4744 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
4745 {
4746   DMLabel        label;
4747   PetscInt       pStart, pEnd;
4748   PetscErrorCode ierr;
4749 
4750   PetscFunctionBegin;
4751   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4752   if (start) {PetscValidPointer(start, 3); *start = 0;}
4753   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
4754   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
4755   if (pStart == pEnd) PetscFunctionReturn(0);
4756   if (stratumValue < 0) {
4757     if (start) *start = pStart;
4758     if (end)   *end   = pEnd;
4759     PetscFunctionReturn(0);
4760   }
4761   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4762   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
4763   ierr = DMLabelGetStratumBounds(label, stratumValue, start, end);CHKERRQ(ierr);
4764   PetscFunctionReturn(0);
4765 }
4766 
4767 /*@
4768   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
4769 
4770   Not Collective
4771 
4772   Input Parameters:
4773 + dm           - The DMPlex object
4774 - stratumValue - The requested height
4775 
4776   Output Parameters:
4777 + start - The first point at this height
4778 - end   - One beyond the last point at this height
4779 
4780   Notes:
4781   Height indexing is related to topological codimension.  Height stratum 0 contains the highest topological dimension
4782   points, often called "cells" or "elements".  If the mesh is "interpolated" (see DMPlexInterpolate()), then height
4783   stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
4784 
4785   Level: developer
4786 
4787 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth(), DMPlexGetPointHeight()
4788 @*/
4789 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
4790 {
4791   DMLabel        label;
4792   PetscInt       depth, pStart, pEnd;
4793   PetscErrorCode ierr;
4794 
4795   PetscFunctionBegin;
4796   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4797   if (start) {PetscValidPointer(start, 3); *start = 0;}
4798   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
4799   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
4800   if (pStart == pEnd) PetscFunctionReturn(0);
4801   if (stratumValue < 0) {
4802     if (start) *start = pStart;
4803     if (end)   *end   = pEnd;
4804     PetscFunctionReturn(0);
4805   }
4806   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4807   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
4808   ierr = DMLabelGetNumValues(label, &depth);CHKERRQ(ierr);
4809   ierr = DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);CHKERRQ(ierr);
4810   PetscFunctionReturn(0);
4811 }
4812 
4813 /*@
4814   DMPlexGetPointDepth - Get the depth of a given point
4815 
4816   Not Collective
4817 
4818   Input Parameters:
4819 + dm    - The DMPlex object
4820 - point - The point
4821 
4822   Output Parameter:
4823 . depth - The depth of the point
4824 
4825   Level: intermediate
4826 
4827 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexGetPointHeight()
4828 @*/
4829 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
4830 {
4831   PetscErrorCode ierr;
4832 
4833   PetscFunctionBegin;
4834   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4835   PetscValidIntPointer(depth, 3);
4836   ierr = DMLabelGetValue(dm->depthLabel, point, depth);CHKERRQ(ierr);
4837   PetscFunctionReturn(0);
4838 }
4839 
4840 /*@
4841   DMPlexGetPointHeight - Get the height of a given point
4842 
4843   Not Collective
4844 
4845   Input Parameters:
4846 + dm    - The DMPlex object
4847 - point - The point
4848 
4849   Output Parameter:
4850 . height - The height of the point
4851 
4852   Level: intermediate
4853 
4854 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexGetPointDepth()
4855 @*/
4856 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
4857 {
4858   PetscInt       n, pDepth;
4859   PetscErrorCode ierr;
4860 
4861   PetscFunctionBegin;
4862   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4863   PetscValidIntPointer(height, 3);
4864   ierr = DMLabelGetNumValues(dm->depthLabel, &n);CHKERRQ(ierr);
4865   ierr = DMLabelGetValue(dm->depthLabel, point, &pDepth);CHKERRQ(ierr);
4866   *height = n - 1 - pDepth;  /* DAG depth is n-1 */
4867   PetscFunctionReturn(0);
4868 }
4869 
4870 /*@
4871   DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell
4872 
4873   Not Collective
4874 
4875   Input Parameter:
4876 . dm - The DMPlex object
4877 
4878   Output Parameter:
4879 . celltypeLabel - The DMLabel recording cell polytope type
4880 
4881   Note: This function will trigger automatica computation of cell types. This can be disabled by calling
4882   DMCreateLabel(dm, "celltype") beforehand.
4883 
4884   Level: developer
4885 
4886 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMCreateLabel()
4887 @*/
4888 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
4889 {
4890   PetscErrorCode ierr;
4891 
4892   PetscFunctionBegin;
4893   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4894   PetscValidPointer(celltypeLabel, 2);
4895   if (!dm->celltypeLabel) {ierr = DMPlexComputeCellTypes(dm);CHKERRQ(ierr);}
4896   *celltypeLabel = dm->celltypeLabel;
4897   PetscFunctionReturn(0);
4898 }
4899 
4900 /*@
4901   DMPlexGetCellType - Get the polytope type of a given cell
4902 
4903   Not Collective
4904 
4905   Input Parameters:
4906 + dm   - The DMPlex object
4907 - cell - The cell
4908 
4909   Output Parameter:
4910 . celltype - The polytope type of the cell
4911 
4912   Level: intermediate
4913 
4914 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth()
4915 @*/
4916 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
4917 {
4918   DMLabel        label;
4919   PetscInt       ct;
4920   PetscErrorCode ierr;
4921 
4922   PetscFunctionBegin;
4923   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4924   PetscValidPointer(celltype, 3);
4925   ierr = DMPlexGetCellTypeLabel(dm, &label);CHKERRQ(ierr);
4926   ierr = DMLabelGetValue(label, cell, &ct);CHKERRQ(ierr);
4927   if (ct < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %D has not been assigned a cell type", cell);
4928   *celltype = (DMPolytopeType) ct;
4929   PetscFunctionReturn(0);
4930 }
4931 
4932 /*@
4933   DMPlexSetCellType - Set the polytope type of a given cell
4934 
4935   Not Collective
4936 
4937   Input Parameters:
4938 + dm   - The DMPlex object
4939 . cell - The cell
4940 - celltype - The polytope type of the cell
4941 
4942   Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function
4943   is executed. This function will override the computed type. However, if automatic classification will not succeed
4944   and a user wants to manually specify all types, the classification must be disabled by calling
4945   DMCreaateLabel(dm, "celltype") before getting or setting any cell types.
4946 
4947   Level: advanced
4948 
4949 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexComputeCellTypes(), DMCreateLabel()
4950 @*/
4951 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
4952 {
4953   DMLabel        label;
4954   PetscErrorCode ierr;
4955 
4956   PetscFunctionBegin;
4957   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4958   ierr = DMPlexGetCellTypeLabel(dm, &label);CHKERRQ(ierr);
4959   ierr = DMLabelSetValue(label, cell, celltype);CHKERRQ(ierr);
4960   PetscFunctionReturn(0);
4961 }
4962 
4963 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
4964 {
4965   PetscSection   section, s;
4966   Mat            m;
4967   PetscInt       maxHeight;
4968   PetscErrorCode ierr;
4969 
4970   PetscFunctionBegin;
4971   ierr = DMClone(dm, cdm);CHKERRQ(ierr);
4972   ierr = DMPlexGetMaxProjectionHeight(dm, &maxHeight);CHKERRQ(ierr);
4973   ierr = DMPlexSetMaxProjectionHeight(*cdm, maxHeight);CHKERRQ(ierr);
4974   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
4975   ierr = DMSetLocalSection(*cdm, section);CHKERRQ(ierr);
4976   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
4977   ierr = PetscSectionCreate(PETSC_COMM_SELF, &s);CHKERRQ(ierr);
4978   ierr = MatCreate(PETSC_COMM_SELF, &m);CHKERRQ(ierr);
4979   ierr = DMSetDefaultConstraints(*cdm, s, m);CHKERRQ(ierr);
4980   ierr = PetscSectionDestroy(&s);CHKERRQ(ierr);
4981   ierr = MatDestroy(&m);CHKERRQ(ierr);
4982 
4983   ierr = DMSetNumFields(*cdm, 1);CHKERRQ(ierr);
4984   ierr = DMCreateDS(*cdm);CHKERRQ(ierr);
4985   PetscFunctionReturn(0);
4986 }
4987 
4988 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
4989 {
4990   Vec            coordsLocal;
4991   DM             coordsDM;
4992   PetscErrorCode ierr;
4993 
4994   PetscFunctionBegin;
4995   *field = NULL;
4996   ierr = DMGetCoordinatesLocal(dm,&coordsLocal);CHKERRQ(ierr);
4997   ierr = DMGetCoordinateDM(dm,&coordsDM);CHKERRQ(ierr);
4998   if (coordsLocal && coordsDM) {
4999     ierr = DMFieldCreateDS(coordsDM, 0, coordsLocal, field);CHKERRQ(ierr);
5000   }
5001   PetscFunctionReturn(0);
5002 }
5003 
5004 /*@C
5005   DMPlexGetConeSection - Return a section which describes the layout of cone data
5006 
5007   Not Collective
5008 
5009   Input Parameters:
5010 . dm        - The DMPlex object
5011 
5012   Output Parameter:
5013 . section - The PetscSection object
5014 
5015   Level: developer
5016 
5017 .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
5018 @*/
5019 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
5020 {
5021   DM_Plex *mesh = (DM_Plex*) dm->data;
5022 
5023   PetscFunctionBegin;
5024   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5025   if (section) *section = mesh->coneSection;
5026   PetscFunctionReturn(0);
5027 }
5028 
5029 /*@C
5030   DMPlexGetSupportSection - Return a section which describes the layout of support data
5031 
5032   Not Collective
5033 
5034   Input Parameters:
5035 . dm        - The DMPlex object
5036 
5037   Output Parameter:
5038 . section - The PetscSection object
5039 
5040   Level: developer
5041 
5042 .seealso: DMPlexGetConeSection()
5043 @*/
5044 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
5045 {
5046   DM_Plex *mesh = (DM_Plex*) dm->data;
5047 
5048   PetscFunctionBegin;
5049   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5050   if (section) *section = mesh->supportSection;
5051   PetscFunctionReturn(0);
5052 }
5053 
5054 /*@C
5055   DMPlexGetCones - Return cone data
5056 
5057   Not Collective
5058 
5059   Input Parameters:
5060 . dm        - The DMPlex object
5061 
5062   Output Parameter:
5063 . cones - The cone for each point
5064 
5065   Level: developer
5066 
5067 .seealso: DMPlexGetConeSection()
5068 @*/
5069 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
5070 {
5071   DM_Plex *mesh = (DM_Plex*) dm->data;
5072 
5073   PetscFunctionBegin;
5074   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5075   if (cones) *cones = mesh->cones;
5076   PetscFunctionReturn(0);
5077 }
5078 
5079 /*@C
5080   DMPlexGetConeOrientations - Return cone orientation data
5081 
5082   Not Collective
5083 
5084   Input Parameters:
5085 . dm        - The DMPlex object
5086 
5087   Output Parameter:
5088 . coneOrientations - The array of cone orientations for all points
5089 
5090   Level: developer
5091 
5092   Notes:
5093   The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation().
5094 
5095   The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation().
5096 
5097 .seealso: DMPlexGetConeSection(), DMPlexGetConeOrientation()
5098 @*/
5099 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
5100 {
5101   DM_Plex *mesh = (DM_Plex*) dm->data;
5102 
5103   PetscFunctionBegin;
5104   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5105   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
5106   PetscFunctionReturn(0);
5107 }
5108 
5109 /******************************** FEM Support **********************************/
5110 
5111 /*
5112  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
5113  representing a line in the section.
5114 */
5115 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k)
5116 {
5117   PetscErrorCode ierr;
5118 
5119   PetscFunctionBeginHot;
5120   ierr = PetscSectionGetFieldComponents(section, field, Nc);CHKERRQ(ierr);
5121   if (line < 0) {
5122     *k = 0;
5123     *Nc = 0;
5124   } else if (vertexchart) {            /* If we only have a vertex chart, we must have degree k=1 */
5125     *k = 1;
5126   } else {                      /* Assume the full interpolated mesh is in the chart; lines in particular */
5127     /* An order k SEM disc has k-1 dofs on an edge */
5128     ierr = PetscSectionGetFieldDof(section, line, field, k);CHKERRQ(ierr);
5129     *k = *k / *Nc + 1;
5130   }
5131   PetscFunctionReturn(0);
5132 }
5133 
5134 /*@
5135 
5136   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
5137   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
5138   section provided (or the section of the DM).
5139 
5140   Input Parameters:
5141 + dm      - The DM
5142 . point   - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE
5143 - section - The PetscSection to reorder, or NULL for the default section
5144 
5145   Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
5146   degree of the basis.
5147 
5148   Example:
5149   A typical interpolated single-quad mesh might order points as
5150 .vb
5151   [c0, v1, v2, v3, v4, e5, e6, e7, e8]
5152 
5153   v4 -- e6 -- v3
5154   |           |
5155   e7    c0    e8
5156   |           |
5157   v1 -- e5 -- v2
5158 .ve
5159 
5160   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
5161   dofs in the order of points, e.g.,
5162 .vb
5163     c0 -> [0,1,2,3]
5164     v1 -> [4]
5165     ...
5166     e5 -> [8, 9]
5167 .ve
5168 
5169   which corresponds to the dofs
5170 .vb
5171     6   10  11  7
5172     13  2   3   15
5173     12  0   1   14
5174     4   8   9   5
5175 .ve
5176 
5177   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
5178 .vb
5179   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
5180 .ve
5181 
5182   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
5183 .vb
5184    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
5185 .ve
5186 
5187   Level: developer
5188 
5189 .seealso: DMGetLocalSection(), PetscSectionSetClosurePermutation(), DMSetGlobalSection()
5190 @*/
5191 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
5192 {
5193   DMLabel        label;
5194   PetscInt       dim, depth = -1, eStart = -1, Nf;
5195   PetscBool      vertexchart;
5196   PetscErrorCode ierr;
5197 
5198   PetscFunctionBegin;
5199   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5200   if (dim < 1) PetscFunctionReturn(0);
5201   if (point < 0) {
5202     PetscInt sStart,sEnd;
5203 
5204     ierr = DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd);CHKERRQ(ierr);
5205     point = sEnd-sStart ? sStart : point;
5206   }
5207   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
5208   if (point >= 0) { ierr = DMLabelGetValue(label, point, &depth);CHKERRQ(ierr); }
5209   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5210   if (depth == 1) {eStart = point;}
5211   else if  (depth == dim) {
5212     const PetscInt *cone;
5213 
5214     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
5215     if (dim == 2) eStart = cone[0];
5216     else if (dim == 3) {
5217       const PetscInt *cone2;
5218       ierr = DMPlexGetCone(dm, cone[0], &cone2);CHKERRQ(ierr);
5219       eStart = cone2[0];
5220     } 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);
5221   } 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);
5222   {                             /* Determine whether the chart covers all points or just vertices. */
5223     PetscInt pStart,pEnd,cStart,cEnd;
5224     ierr = DMPlexGetDepthStratum(dm,0,&pStart,&pEnd);CHKERRQ(ierr);
5225     ierr = PetscSectionGetChart(section,&cStart,&cEnd);CHKERRQ(ierr);
5226     if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Just vertices */
5227     else vertexchart = PETSC_FALSE;                                 /* Assume all interpolated points are in chart */
5228   }
5229   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
5230   for (PetscInt d=1; d<=dim; d++) {
5231     PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
5232     PetscInt *perm;
5233 
5234     for (f = 0; f < Nf; ++f) {
5235       ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
5236       size += PetscPowInt(k+1, d)*Nc;
5237     }
5238     ierr = PetscMalloc1(size, &perm);CHKERRQ(ierr);
5239     for (f = 0; f < Nf; ++f) {
5240       switch (d) {
5241       case 1:
5242         ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
5243         /*
5244          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
5245          We want              [ vtx0; edge of length k-1; vtx1 ]
5246          */
5247         for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset;
5248         for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset;
5249         for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset;
5250         foffset = offset;
5251         break;
5252       case 2:
5253         /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
5254         ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
5255         /* The SEM order is
5256 
5257          v_lb, {e_b}, v_rb,
5258          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
5259          v_lt, reverse {e_t}, v_rt
5260          */
5261         {
5262           const PetscInt of   = 0;
5263           const PetscInt oeb  = of   + PetscSqr(k-1);
5264           const PetscInt oer  = oeb  + (k-1);
5265           const PetscInt oet  = oer  + (k-1);
5266           const PetscInt oel  = oet  + (k-1);
5267           const PetscInt ovlb = oel  + (k-1);
5268           const PetscInt ovrb = ovlb + 1;
5269           const PetscInt ovrt = ovrb + 1;
5270           const PetscInt ovlt = ovrt + 1;
5271           PetscInt       o;
5272 
5273           /* bottom */
5274           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
5275           for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5276           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
5277           /* middle */
5278           for (i = 0; i < k-1; ++i) {
5279             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
5280             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;
5281             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
5282           }
5283           /* top */
5284           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
5285           for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5286           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
5287           foffset = offset;
5288         }
5289         break;
5290       case 3:
5291         /* The original hex closure is
5292 
5293          {c,
5294          f_b, f_t, f_f, f_b, f_r, f_l,
5295          e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
5296          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
5297          */
5298         ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
5299         /* The SEM order is
5300          Bottom Slice
5301          v_blf, {e^{(k-1)-n}_bf}, v_brf,
5302          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
5303          v_blb, {e_bb}, v_brb,
5304 
5305          Middle Slice (j)
5306          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
5307          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
5308          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
5309 
5310          Top Slice
5311          v_tlf, {e_tf}, v_trf,
5312          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
5313          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
5314          */
5315         {
5316           const PetscInt oc    = 0;
5317           const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
5318           const PetscInt oft   = ofb   + PetscSqr(k-1);
5319           const PetscInt off   = oft   + PetscSqr(k-1);
5320           const PetscInt ofk   = off   + PetscSqr(k-1);
5321           const PetscInt ofr   = ofk   + PetscSqr(k-1);
5322           const PetscInt ofl   = ofr   + PetscSqr(k-1);
5323           const PetscInt oebl  = ofl   + PetscSqr(k-1);
5324           const PetscInt oebb  = oebl  + (k-1);
5325           const PetscInt oebr  = oebb  + (k-1);
5326           const PetscInt oebf  = oebr  + (k-1);
5327           const PetscInt oetf  = oebf  + (k-1);
5328           const PetscInt oetr  = oetf  + (k-1);
5329           const PetscInt oetb  = oetr  + (k-1);
5330           const PetscInt oetl  = oetb  + (k-1);
5331           const PetscInt oerf  = oetl  + (k-1);
5332           const PetscInt oelf  = oerf  + (k-1);
5333           const PetscInt oelb  = oelf  + (k-1);
5334           const PetscInt oerb  = oelb  + (k-1);
5335           const PetscInt ovblf = oerb  + (k-1);
5336           const PetscInt ovblb = ovblf + 1;
5337           const PetscInt ovbrb = ovblb + 1;
5338           const PetscInt ovbrf = ovbrb + 1;
5339           const PetscInt ovtlf = ovbrf + 1;
5340           const PetscInt ovtrf = ovtlf + 1;
5341           const PetscInt ovtrb = ovtrf + 1;
5342           const PetscInt ovtlb = ovtrb + 1;
5343           PetscInt       o, n;
5344 
5345           /* Bottom Slice */
5346           /*   bottom */
5347           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
5348           for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5349           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
5350           /*   middle */
5351           for (i = 0; i < k-1; ++i) {
5352             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
5353             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;}
5354             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
5355           }
5356           /*   top */
5357           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
5358           for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5359           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
5360 
5361           /* Middle Slice */
5362           for (j = 0; j < k-1; ++j) {
5363             /*   bottom */
5364             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
5365             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;
5366             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
5367             /*   middle */
5368             for (i = 0; i < k-1; ++i) {
5369               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
5370               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;
5371               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
5372             }
5373             /*   top */
5374             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
5375             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;
5376             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
5377           }
5378 
5379           /* Top Slice */
5380           /*   bottom */
5381           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
5382           for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5383           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
5384           /*   middle */
5385           for (i = 0; i < k-1; ++i) {
5386             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
5387             for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
5388             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
5389           }
5390           /*   top */
5391           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
5392           for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5393           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
5394 
5395           foffset = offset;
5396         }
5397         break;
5398       default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", d);
5399       }
5400     }
5401     if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
5402     /* Check permutation */
5403     {
5404       PetscInt *check;
5405 
5406       ierr = PetscMalloc1(size, &check);CHKERRQ(ierr);
5407       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]);}
5408       for (i = 0; i < size; ++i) check[perm[i]] = i;
5409       for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
5410       ierr = PetscFree(check);CHKERRQ(ierr);
5411     }
5412     ierr = PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm);CHKERRQ(ierr);
5413   }
5414   PetscFunctionReturn(0);
5415 }
5416 
5417 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
5418 {
5419   PetscDS        prob;
5420   PetscInt       depth, Nf, h;
5421   DMLabel        label;
5422   PetscErrorCode ierr;
5423 
5424   PetscFunctionBeginHot;
5425   ierr = DMGetDS(dm, &prob);CHKERRQ(ierr);
5426   Nf      = prob->Nf;
5427   label   = dm->depthLabel;
5428   *dspace = NULL;
5429   if (field < Nf) {
5430     PetscObject disc = prob->disc[field];
5431 
5432     if (disc->classid == PETSCFE_CLASSID) {
5433       PetscDualSpace dsp;
5434 
5435       ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr);
5436       ierr = DMLabelGetNumValues(label,&depth);CHKERRQ(ierr);
5437       ierr = DMLabelGetValue(label,point,&h);CHKERRQ(ierr);
5438       h    = depth - 1 - h;
5439       if (h) {
5440         ierr = PetscDualSpaceGetHeightSubspace(dsp,h,dspace);CHKERRQ(ierr);
5441       } else {
5442         *dspace = dsp;
5443       }
5444     }
5445   }
5446   PetscFunctionReturn(0);
5447 }
5448 
5449 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5450 {
5451   PetscScalar    *array, *vArray;
5452   const PetscInt *cone, *coneO;
5453   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
5454   PetscErrorCode  ierr;
5455 
5456   PetscFunctionBeginHot;
5457   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5458   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
5459   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
5460   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
5461   if (!values || !*values) {
5462     if ((point >= pStart) && (point < pEnd)) {
5463       PetscInt dof;
5464 
5465       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5466       size += dof;
5467     }
5468     for (p = 0; p < numPoints; ++p) {
5469       const PetscInt cp = cone[p];
5470       PetscInt       dof;
5471 
5472       if ((cp < pStart) || (cp >= pEnd)) continue;
5473       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
5474       size += dof;
5475     }
5476     if (!values) {
5477       if (csize) *csize = size;
5478       PetscFunctionReturn(0);
5479     }
5480     ierr = DMGetWorkArray(dm, size, MPIU_SCALAR, &array);CHKERRQ(ierr);
5481   } else {
5482     array = *values;
5483   }
5484   size = 0;
5485   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
5486   if ((point >= pStart) && (point < pEnd)) {
5487     PetscInt     dof, off, d;
5488     PetscScalar *varr;
5489 
5490     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5491     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5492     varr = &vArray[off];
5493     for (d = 0; d < dof; ++d, ++offset) {
5494       array[offset] = varr[d];
5495     }
5496     size += dof;
5497   }
5498   for (p = 0; p < numPoints; ++p) {
5499     const PetscInt cp = cone[p];
5500     PetscInt       o  = coneO[p];
5501     PetscInt       dof, off, d;
5502     PetscScalar   *varr;
5503 
5504     if ((cp < pStart) || (cp >= pEnd)) continue;
5505     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
5506     ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
5507     varr = &vArray[off];
5508     if (o >= 0) {
5509       for (d = 0; d < dof; ++d, ++offset) {
5510         array[offset] = varr[d];
5511       }
5512     } else {
5513       for (d = dof-1; d >= 0; --d, ++offset) {
5514         array[offset] = varr[d];
5515       }
5516     }
5517     size += dof;
5518   }
5519   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
5520   if (!*values) {
5521     if (csize) *csize = size;
5522     *values = array;
5523   } else {
5524     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
5525     *csize = size;
5526   }
5527   PetscFunctionReturn(0);
5528 }
5529 
5530 /* Compress out points not in the section */
5531 PETSC_STATIC_INLINE PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
5532 {
5533   const PetscInt np = *numPoints;
5534   PetscInt       pStart, pEnd, p, q;
5535   PetscErrorCode ierr;
5536 
5537   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5538   for (p = 0, q = 0; p < np; ++p) {
5539     const PetscInt r = points[p*2];
5540     if ((r >= pStart) && (r < pEnd)) {
5541       points[q*2]   = r;
5542       points[q*2+1] = points[p*2+1];
5543       ++q;
5544     }
5545   }
5546   *numPoints = q;
5547   return 0;
5548 }
5549 
5550 /* Compressed closure does not apply closure permutation */
5551 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5552 {
5553   const PetscInt *cla = NULL;
5554   PetscInt       np, *pts = NULL;
5555   PetscErrorCode ierr;
5556 
5557   PetscFunctionBeginHot;
5558   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);CHKERRQ(ierr);
5559   if (*clPoints) {
5560     PetscInt dof, off;
5561 
5562     ierr = PetscSectionGetDof(*clSec, point, &dof);CHKERRQ(ierr);
5563     ierr = PetscSectionGetOffset(*clSec, point, &off);CHKERRQ(ierr);
5564     ierr = ISGetIndices(*clPoints, &cla);CHKERRQ(ierr);
5565     np   = dof/2;
5566     pts  = (PetscInt *) &cla[off];
5567   } else {
5568     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);CHKERRQ(ierr);
5569     ierr = CompressPoints_Private(section, &np, pts);CHKERRQ(ierr);
5570   }
5571   *numPoints = np;
5572   *points    = pts;
5573   *clp       = cla;
5574   PetscFunctionReturn(0);
5575 }
5576 
5577 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5578 {
5579   PetscErrorCode ierr;
5580 
5581   PetscFunctionBeginHot;
5582   if (!*clPoints) {
5583     ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);CHKERRQ(ierr);
5584   } else {
5585     ierr = ISRestoreIndices(*clPoints, clp);CHKERRQ(ierr);
5586   }
5587   *numPoints = 0;
5588   *points    = NULL;
5589   *clSec     = NULL;
5590   *clPoints  = NULL;
5591   *clp       = NULL;
5592   PetscFunctionReturn(0);
5593 }
5594 
5595 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[])
5596 {
5597   PetscInt          offset = 0, p;
5598   const PetscInt    **perms = NULL;
5599   const PetscScalar **flips = NULL;
5600   PetscErrorCode    ierr;
5601 
5602   PetscFunctionBeginHot;
5603   *size = 0;
5604   ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5605   for (p = 0; p < numPoints; p++) {
5606     const PetscInt    point = points[2*p];
5607     const PetscInt    *perm = perms ? perms[p] : NULL;
5608     const PetscScalar *flip = flips ? flips[p] : NULL;
5609     PetscInt          dof, off, d;
5610     const PetscScalar *varr;
5611 
5612     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5613     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5614     varr = &vArray[off];
5615     if (clperm) {
5616       if (perm) {
5617         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
5618       } else {
5619         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
5620       }
5621       if (flip) {
5622         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
5623       }
5624     } else {
5625       if (perm) {
5626         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
5627       } else {
5628         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
5629       }
5630       if (flip) {
5631         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
5632       }
5633     }
5634     offset += dof;
5635   }
5636   ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5637   *size = offset;
5638   PetscFunctionReturn(0);
5639 }
5640 
5641 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[])
5642 {
5643   PetscInt          offset = 0, f;
5644   PetscErrorCode    ierr;
5645 
5646   PetscFunctionBeginHot;
5647   *size = 0;
5648   for (f = 0; f < numFields; ++f) {
5649     PetscInt          p;
5650     const PetscInt    **perms = NULL;
5651     const PetscScalar **flips = NULL;
5652 
5653     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5654     for (p = 0; p < numPoints; p++) {
5655       const PetscInt    point = points[2*p];
5656       PetscInt          fdof, foff, b;
5657       const PetscScalar *varr;
5658       const PetscInt    *perm = perms ? perms[p] : NULL;
5659       const PetscScalar *flip = flips ? flips[p] : NULL;
5660 
5661       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5662       ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
5663       varr = &vArray[foff];
5664       if (clperm) {
5665         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
5666         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
5667         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
5668       } else {
5669         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
5670         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
5671         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
5672       }
5673       offset += fdof;
5674     }
5675     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5676   }
5677   *size = offset;
5678   PetscFunctionReturn(0);
5679 }
5680 
5681 /*@C
5682   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
5683 
5684   Not collective
5685 
5686   Input Parameters:
5687 + dm - The DM
5688 . section - The section describing the layout in v, or NULL to use the default section
5689 . v - The local vector
5690 - point - The point in the DM
5691 
5692   Input/Output Parameters:
5693 + csize  - The size of the input values array, or NULL; on output the number of values in the closure
5694 - values - An array to use for the values, or NULL to have it allocated automatically;
5695            if the user provided NULL, it is a borrowed array and should not be freed
5696 
5697 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
5698 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
5699 $ assembly function, and a user may already have allocated storage for this operation.
5700 $
5701 $ A typical use could be
5702 $
5703 $  values = NULL;
5704 $  ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
5705 $  for (cl = 0; cl < clSize; ++cl) {
5706 $    <Compute on closure>
5707 $  }
5708 $  ierr = DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
5709 $
5710 $ or
5711 $
5712 $  PetscMalloc1(clMaxSize, &values);
5713 $  for (p = pStart; p < pEnd; ++p) {
5714 $    clSize = clMaxSize;
5715 $    ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
5716 $    for (cl = 0; cl < clSize; ++cl) {
5717 $      <Compute on closure>
5718 $    }
5719 $  }
5720 $  PetscFree(values);
5721 
5722   Fortran Notes:
5723   Since it returns an array, this routine is only available in Fortran 90, and you must
5724   include petsc.h90 in your code.
5725 
5726   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5727 
5728   Level: intermediate
5729 
5730 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5731 @*/
5732 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5733 {
5734   PetscSection       clSection;
5735   IS                 clPoints;
5736   PetscInt          *points = NULL;
5737   const PetscInt    *clp, *perm;
5738   PetscInt           depth, numFields, numPoints, asize;
5739   PetscErrorCode     ierr;
5740 
5741   PetscFunctionBeginHot;
5742   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5743   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5744   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5745   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5746   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5747   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5748   if (depth == 1 && numFields < 2) {
5749     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
5750     PetscFunctionReturn(0);
5751   }
5752   /* Get points */
5753   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5754   /* Get sizes */
5755   asize = 0;
5756   for (PetscInt p = 0; p < numPoints*2; p += 2) {
5757     PetscInt dof;
5758     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5759     asize += dof;
5760   }
5761   if (values) {
5762     const PetscScalar *vArray;
5763     PetscInt          size;
5764 
5765     if (*values) {
5766       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);
5767     } else {ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, values);CHKERRQ(ierr);}
5768     ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm);CHKERRQ(ierr);
5769     ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr);
5770     /* Get values */
5771     if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values);CHKERRQ(ierr);}
5772     else               {ierr = DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values);CHKERRQ(ierr);}
5773     if (PetscUnlikely(asize != size)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %D does not match Vec closure size %D", asize, size);
5774     /* Cleanup array */
5775     ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr);
5776   }
5777   if (csize) *csize = asize;
5778   /* Cleanup points */
5779   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5780   PetscFunctionReturn(0);
5781 }
5782 
5783 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
5784 {
5785   DMLabel            depthLabel;
5786   PetscSection       clSection;
5787   IS                 clPoints;
5788   PetscScalar       *array;
5789   const PetscScalar *vArray;
5790   PetscInt          *points = NULL;
5791   const PetscInt    *clp, *perm = NULL;
5792   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;
5793   PetscErrorCode     ierr;
5794 
5795   PetscFunctionBeginHot;
5796   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5797   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5798   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5799   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5800   ierr = DMPlexGetDepth(dm, &mdepth);CHKERRQ(ierr);
5801   ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr);
5802   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5803   if (mdepth == 1 && numFields < 2) {
5804     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
5805     PetscFunctionReturn(0);
5806   }
5807   /* Get points */
5808   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5809   for (clsize=0,p=0; p<Np; p++) {
5810     PetscInt dof;
5811     ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr);
5812     clsize += dof;
5813   }
5814   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm);CHKERRQ(ierr);
5815   /* Filter points */
5816   for (p = 0; p < numPoints*2; p += 2) {
5817     PetscInt dep;
5818 
5819     ierr = DMLabelGetValue(depthLabel, points[p], &dep);CHKERRQ(ierr);
5820     if (dep != depth) continue;
5821     points[Np*2+0] = points[p];
5822     points[Np*2+1] = points[p+1];
5823     ++Np;
5824   }
5825   /* Get array */
5826   if (!values || !*values) {
5827     PetscInt asize = 0, dof;
5828 
5829     for (p = 0; p < Np*2; p += 2) {
5830       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5831       asize += dof;
5832     }
5833     if (!values) {
5834       ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5835       if (csize) *csize = asize;
5836       PetscFunctionReturn(0);
5837     }
5838     ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);CHKERRQ(ierr);
5839   } else {
5840     array = *values;
5841   }
5842   ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr);
5843   /* Get values */
5844   if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array);CHKERRQ(ierr);}
5845   else               {ierr = DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array);CHKERRQ(ierr);}
5846   /* Cleanup points */
5847   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5848   /* Cleanup array */
5849   ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr);
5850   if (!*values) {
5851     if (csize) *csize = size;
5852     *values = array;
5853   } else {
5854     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
5855     *csize = size;
5856   }
5857   PetscFunctionReturn(0);
5858 }
5859 
5860 /*@C
5861   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
5862 
5863   Not collective
5864 
5865   Input Parameters:
5866 + dm - The DM
5867 . section - The section describing the layout in v, or NULL to use the default section
5868 . v - The local vector
5869 . point - The point in the DM
5870 . csize - The number of values in the closure, or NULL
5871 - values - The array of values, which is a borrowed array and should not be freed
5872 
5873   Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()
5874 
5875   Fortran Notes:
5876   Since it returns an array, this routine is only available in Fortran 90, and you must
5877   include petsc.h90 in your code.
5878 
5879   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5880 
5881   Level: intermediate
5882 
5883 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5884 @*/
5885 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5886 {
5887   PetscInt       size = 0;
5888   PetscErrorCode ierr;
5889 
5890   PetscFunctionBegin;
5891   /* Should work without recalculating size */
5892   ierr = DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);CHKERRQ(ierr);
5893   *values = NULL;
5894   PetscFunctionReturn(0);
5895 }
5896 
5897 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
5898 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
5899 
5900 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[])
5901 {
5902   PetscInt        cdof;   /* The number of constraints on this point */
5903   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5904   PetscScalar    *a;
5905   PetscInt        off, cind = 0, k;
5906   PetscErrorCode  ierr;
5907 
5908   PetscFunctionBegin;
5909   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5910   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5911   a    = &array[off];
5912   if (!cdof || setBC) {
5913     if (clperm) {
5914       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
5915       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
5916     } else {
5917       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
5918       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
5919     }
5920   } else {
5921     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5922     if (clperm) {
5923       if (perm) {for (k = 0; k < dof; ++k) {
5924           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5925           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
5926         }
5927       } else {
5928         for (k = 0; k < dof; ++k) {
5929           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5930           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
5931         }
5932       }
5933     } else {
5934       if (perm) {
5935         for (k = 0; k < dof; ++k) {
5936           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5937           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
5938         }
5939       } else {
5940         for (k = 0; k < dof; ++k) {
5941           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5942           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
5943         }
5944       }
5945     }
5946   }
5947   PetscFunctionReturn(0);
5948 }
5949 
5950 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[])
5951 {
5952   PetscInt        cdof;   /* The number of constraints on this point */
5953   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5954   PetscScalar    *a;
5955   PetscInt        off, cind = 0, k;
5956   PetscErrorCode  ierr;
5957 
5958   PetscFunctionBegin;
5959   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5960   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5961   a    = &array[off];
5962   if (cdof) {
5963     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5964     if (clperm) {
5965       if (perm) {
5966         for (k = 0; k < dof; ++k) {
5967           if ((cind < cdof) && (k == cdofs[cind])) {
5968             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
5969             cind++;
5970           }
5971         }
5972       } else {
5973         for (k = 0; k < dof; ++k) {
5974           if ((cind < cdof) && (k == cdofs[cind])) {
5975             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
5976             cind++;
5977           }
5978         }
5979       }
5980     } else {
5981       if (perm) {
5982         for (k = 0; k < dof; ++k) {
5983           if ((cind < cdof) && (k == cdofs[cind])) {
5984             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
5985             cind++;
5986           }
5987         }
5988       } else {
5989         for (k = 0; k < dof; ++k) {
5990           if ((cind < cdof) && (k == cdofs[cind])) {
5991             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
5992             cind++;
5993           }
5994         }
5995       }
5996     }
5997   }
5998   PetscFunctionReturn(0);
5999 }
6000 
6001 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[])
6002 {
6003   PetscScalar    *a;
6004   PetscInt        fdof, foff, fcdof, foffset = *offset;
6005   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6006   PetscInt        cind = 0, b;
6007   PetscErrorCode  ierr;
6008 
6009   PetscFunctionBegin;
6010   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6011   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
6012   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
6013   a    = &array[foff];
6014   if (!fcdof || setBC) {
6015     if (clperm) {
6016       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
6017       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
6018     } else {
6019       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
6020       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
6021     }
6022   } else {
6023     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6024     if (clperm) {
6025       if (perm) {
6026         for (b = 0; b < fdof; b++) {
6027           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6028           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
6029         }
6030       } else {
6031         for (b = 0; b < fdof; b++) {
6032           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6033           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
6034         }
6035       }
6036     } else {
6037       if (perm) {
6038         for (b = 0; b < fdof; b++) {
6039           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6040           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
6041         }
6042       } else {
6043         for (b = 0; b < fdof; b++) {
6044           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6045           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
6046         }
6047       }
6048     }
6049   }
6050   *offset += fdof;
6051   PetscFunctionReturn(0);
6052 }
6053 
6054 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[])
6055 {
6056   PetscScalar    *a;
6057   PetscInt        fdof, foff, fcdof, foffset = *offset;
6058   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6059   PetscInt        Nc, cind = 0, ncind = 0, b;
6060   PetscBool       ncSet, fcSet;
6061   PetscErrorCode  ierr;
6062 
6063   PetscFunctionBegin;
6064   ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
6065   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6066   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
6067   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
6068   a    = &array[foff];
6069   if (fcdof) {
6070     /* We just override fcdof and fcdofs with Ncc and comps */
6071     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6072     if (clperm) {
6073       if (perm) {
6074         if (comps) {
6075           for (b = 0; b < fdof; b++) {
6076             ncSet = fcSet = PETSC_FALSE;
6077             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6078             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6079             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
6080           }
6081         } else {
6082           for (b = 0; b < fdof; b++) {
6083             if ((cind < fcdof) && (b == fcdofs[cind])) {
6084               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
6085               ++cind;
6086             }
6087           }
6088         }
6089       } else {
6090         if (comps) {
6091           for (b = 0; b < fdof; b++) {
6092             ncSet = fcSet = PETSC_FALSE;
6093             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6094             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6095             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
6096           }
6097         } else {
6098           for (b = 0; b < fdof; b++) {
6099             if ((cind < fcdof) && (b == fcdofs[cind])) {
6100               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
6101               ++cind;
6102             }
6103           }
6104         }
6105       }
6106     } else {
6107       if (perm) {
6108         if (comps) {
6109           for (b = 0; b < fdof; b++) {
6110             ncSet = fcSet = PETSC_FALSE;
6111             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6112             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6113             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
6114           }
6115         } else {
6116           for (b = 0; b < fdof; b++) {
6117             if ((cind < fcdof) && (b == fcdofs[cind])) {
6118               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
6119               ++cind;
6120             }
6121           }
6122         }
6123       } else {
6124         if (comps) {
6125           for (b = 0; b < fdof; b++) {
6126             ncSet = fcSet = PETSC_FALSE;
6127             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6128             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6129             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
6130           }
6131         } else {
6132           for (b = 0; b < fdof; b++) {
6133             if ((cind < fcdof) && (b == fcdofs[cind])) {
6134               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
6135               ++cind;
6136             }
6137           }
6138         }
6139       }
6140     }
6141   }
6142   *offset += fdof;
6143   PetscFunctionReturn(0);
6144 }
6145 
6146 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6147 {
6148   PetscScalar    *array;
6149   const PetscInt *cone, *coneO;
6150   PetscInt        pStart, pEnd, p, numPoints, off, dof;
6151   PetscErrorCode  ierr;
6152 
6153   PetscFunctionBeginHot;
6154   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6155   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
6156   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
6157   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
6158   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6159   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
6160     const PetscInt cp = !p ? point : cone[p-1];
6161     const PetscInt o  = !p ? 0     : coneO[p-1];
6162 
6163     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
6164     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
6165     /* ADD_VALUES */
6166     {
6167       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6168       PetscScalar    *a;
6169       PetscInt        cdof, coff, cind = 0, k;
6170 
6171       ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
6172       ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
6173       a    = &array[coff];
6174       if (!cdof) {
6175         if (o >= 0) {
6176           for (k = 0; k < dof; ++k) {
6177             a[k] += values[off+k];
6178           }
6179         } else {
6180           for (k = 0; k < dof; ++k) {
6181             a[k] += values[off+dof-k-1];
6182           }
6183         }
6184       } else {
6185         ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
6186         if (o >= 0) {
6187           for (k = 0; k < dof; ++k) {
6188             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6189             a[k] += values[off+k];
6190           }
6191         } else {
6192           for (k = 0; k < dof; ++k) {
6193             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6194             a[k] += values[off+dof-k-1];
6195           }
6196         }
6197       }
6198     }
6199   }
6200   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6201   PetscFunctionReturn(0);
6202 }
6203 
6204 /*@C
6205   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
6206 
6207   Not collective
6208 
6209   Input Parameters:
6210 + dm - The DM
6211 . section - The section describing the layout in v, or NULL to use the default section
6212 . v - The local vector
6213 . point - The point in the DM
6214 . values - The array of values
6215 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
6216          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
6217 
6218   Fortran Notes:
6219   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
6220 
6221   Level: intermediate
6222 
6223 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
6224 @*/
6225 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6226 {
6227   PetscSection    clSection;
6228   IS              clPoints;
6229   PetscScalar    *array;
6230   PetscInt       *points = NULL;
6231   const PetscInt *clp, *clperm = NULL;
6232   PetscInt        depth, numFields, numPoints, p, clsize;
6233   PetscErrorCode  ierr;
6234 
6235   PetscFunctionBeginHot;
6236   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6237   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
6238   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6239   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6240   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6241   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6242   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
6243     ierr = DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);CHKERRQ(ierr);
6244     PetscFunctionReturn(0);
6245   }
6246   /* Get points */
6247   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6248   for (clsize=0,p=0; p<numPoints; p++) {
6249     PetscInt dof;
6250     ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr);
6251     clsize += dof;
6252   }
6253   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm);CHKERRQ(ierr);
6254   /* Get array */
6255   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6256   /* Get values */
6257   if (numFields > 0) {
6258     PetscInt offset = 0, f;
6259     for (f = 0; f < numFields; ++f) {
6260       const PetscInt    **perms = NULL;
6261       const PetscScalar **flips = NULL;
6262 
6263       ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6264       switch (mode) {
6265       case INSERT_VALUES:
6266         for (p = 0; p < numPoints; p++) {
6267           const PetscInt    point = points[2*p];
6268           const PetscInt    *perm = perms ? perms[p] : NULL;
6269           const PetscScalar *flip = flips ? flips[p] : NULL;
6270           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
6271         } break;
6272       case INSERT_ALL_VALUES:
6273         for (p = 0; p < numPoints; p++) {
6274           const PetscInt    point = points[2*p];
6275           const PetscInt    *perm = perms ? perms[p] : NULL;
6276           const PetscScalar *flip = flips ? flips[p] : NULL;
6277           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
6278         } break;
6279       case INSERT_BC_VALUES:
6280         for (p = 0; p < numPoints; p++) {
6281           const PetscInt    point = points[2*p];
6282           const PetscInt    *perm = perms ? perms[p] : NULL;
6283           const PetscScalar *flip = flips ? flips[p] : NULL;
6284           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
6285         } break;
6286       case ADD_VALUES:
6287         for (p = 0; p < numPoints; p++) {
6288           const PetscInt    point = points[2*p];
6289           const PetscInt    *perm = perms ? perms[p] : NULL;
6290           const PetscScalar *flip = flips ? flips[p] : NULL;
6291           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
6292         } break;
6293       case ADD_ALL_VALUES:
6294         for (p = 0; p < numPoints; p++) {
6295           const PetscInt    point = points[2*p];
6296           const PetscInt    *perm = perms ? perms[p] : NULL;
6297           const PetscScalar *flip = flips ? flips[p] : NULL;
6298           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
6299         } break;
6300       case ADD_BC_VALUES:
6301         for (p = 0; p < numPoints; p++) {
6302           const PetscInt    point = points[2*p];
6303           const PetscInt    *perm = perms ? perms[p] : NULL;
6304           const PetscScalar *flip = flips ? flips[p] : NULL;
6305           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
6306         } break;
6307       default:
6308         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6309       }
6310       ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6311     }
6312   } else {
6313     PetscInt dof, off;
6314     const PetscInt    **perms = NULL;
6315     const PetscScalar **flips = NULL;
6316 
6317     ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6318     switch (mode) {
6319     case INSERT_VALUES:
6320       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6321         const PetscInt    point = points[2*p];
6322         const PetscInt    *perm = perms ? perms[p] : NULL;
6323         const PetscScalar *flip = flips ? flips[p] : NULL;
6324         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6325         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
6326       } break;
6327     case INSERT_ALL_VALUES:
6328       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6329         const PetscInt    point = points[2*p];
6330         const PetscInt    *perm = perms ? perms[p] : NULL;
6331         const PetscScalar *flip = flips ? flips[p] : NULL;
6332         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6333         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
6334       } break;
6335     case INSERT_BC_VALUES:
6336       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6337         const PetscInt    point = points[2*p];
6338         const PetscInt    *perm = perms ? perms[p] : NULL;
6339         const PetscScalar *flip = flips ? flips[p] : NULL;
6340         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6341         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
6342       } break;
6343     case ADD_VALUES:
6344       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6345         const PetscInt    point = points[2*p];
6346         const PetscInt    *perm = perms ? perms[p] : NULL;
6347         const PetscScalar *flip = flips ? flips[p] : NULL;
6348         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6349         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
6350       } break;
6351     case ADD_ALL_VALUES:
6352       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6353         const PetscInt    point = points[2*p];
6354         const PetscInt    *perm = perms ? perms[p] : NULL;
6355         const PetscScalar *flip = flips ? flips[p] : NULL;
6356         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6357         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
6358       } break;
6359     case ADD_BC_VALUES:
6360       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6361         const PetscInt    point = points[2*p];
6362         const PetscInt    *perm = perms ? perms[p] : NULL;
6363         const PetscScalar *flip = flips ? flips[p] : NULL;
6364         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6365         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
6366       } break;
6367     default:
6368       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6369     }
6370     ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6371   }
6372   /* Cleanup points */
6373   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6374   /* Cleanup array */
6375   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6376   PetscFunctionReturn(0);
6377 }
6378 
6379 /* Check whether the given point is in the label. If not, update the offset to skip this point */
6380 PETSC_STATIC_INLINE PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset)
6381 {
6382   PetscFunctionBegin;
6383   if (label) {
6384     PetscInt       val, fdof;
6385     PetscErrorCode ierr;
6386 
6387     /* There is a problem with this:
6388          Suppose we have two label values, defining surfaces, interecting along a line in 3D. When we add cells to the label, the cells that
6389        touch both surfaces must pick a label value. Thus we miss setting values for the surface with that other value intersecting that cell.
6390        Thus I am only going to check val != -1, not val != labelId
6391     */
6392     ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
6393     if (val < 0) {
6394       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6395       *offset += fdof;
6396       PetscFunctionReturn(1);
6397     }
6398   }
6399   PetscFunctionReturn(0);
6400 }
6401 
6402 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
6403 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)
6404 {
6405   PetscSection      clSection;
6406   IS                clPoints;
6407   PetscScalar       *array;
6408   PetscInt          *points = NULL;
6409   const PetscInt    *clp;
6410   PetscInt          numFields, numPoints, p;
6411   PetscInt          offset = 0, f;
6412   PetscErrorCode    ierr;
6413 
6414   PetscFunctionBeginHot;
6415   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6416   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
6417   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6418   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6419   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6420   /* Get points */
6421   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6422   /* Get array */
6423   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6424   /* Get values */
6425   for (f = 0; f < numFields; ++f) {
6426     const PetscInt    **perms = NULL;
6427     const PetscScalar **flips = NULL;
6428 
6429     if (!fieldActive[f]) {
6430       for (p = 0; p < numPoints*2; p += 2) {
6431         PetscInt fdof;
6432         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6433         offset += fdof;
6434       }
6435       continue;
6436     }
6437     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6438     switch (mode) {
6439     case INSERT_VALUES:
6440       for (p = 0; p < numPoints; p++) {
6441         const PetscInt    point = points[2*p];
6442         const PetscInt    *perm = perms ? perms[p] : NULL;
6443         const PetscScalar *flip = flips ? flips[p] : NULL;
6444         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6445         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array);
6446       } break;
6447     case INSERT_ALL_VALUES:
6448       for (p = 0; p < numPoints; p++) {
6449         const PetscInt    point = points[2*p];
6450         const PetscInt    *perm = perms ? perms[p] : NULL;
6451         const PetscScalar *flip = flips ? flips[p] : NULL;
6452         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6453         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array);
6454       } break;
6455     case INSERT_BC_VALUES:
6456       for (p = 0; p < numPoints; p++) {
6457         const PetscInt    point = points[2*p];
6458         const PetscInt    *perm = perms ? perms[p] : NULL;
6459         const PetscScalar *flip = flips ? flips[p] : NULL;
6460         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6461         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array);
6462       } break;
6463     case ADD_VALUES:
6464       for (p = 0; p < numPoints; p++) {
6465         const PetscInt    point = points[2*p];
6466         const PetscInt    *perm = perms ? perms[p] : NULL;
6467         const PetscScalar *flip = flips ? flips[p] : NULL;
6468         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6469         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array);
6470       } break;
6471     case ADD_ALL_VALUES:
6472       for (p = 0; p < numPoints; p++) {
6473         const PetscInt    point = points[2*p];
6474         const PetscInt    *perm = perms ? perms[p] : NULL;
6475         const PetscScalar *flip = flips ? flips[p] : NULL;
6476         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6477         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array);
6478       } break;
6479     default:
6480       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6481     }
6482     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6483   }
6484   /* Cleanup points */
6485   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6486   /* Cleanup array */
6487   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6488   PetscFunctionReturn(0);
6489 }
6490 
6491 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
6492 {
6493   PetscMPIInt    rank;
6494   PetscInt       i, j;
6495   PetscErrorCode ierr;
6496 
6497   PetscFunctionBegin;
6498   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr);
6499   ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);CHKERRQ(ierr);
6500   for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);}
6501   for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);}
6502   numCIndices = numCIndices ? numCIndices : numRIndices;
6503   if (!values) PetscFunctionReturn(0);
6504   for (i = 0; i < numRIndices; i++) {
6505     ierr = PetscViewerASCIIPrintf(viewer, "[%d]", rank);CHKERRQ(ierr);
6506     for (j = 0; j < numCIndices; j++) {
6507 #if defined(PETSC_USE_COMPLEX)
6508       ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr);
6509 #else
6510       ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr);
6511 #endif
6512     }
6513     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
6514   }
6515   PetscFunctionReturn(0);
6516 }
6517 
6518 /*
6519   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
6520 
6521   Input Parameters:
6522 + section - The section for this data layout
6523 . islocal - Is the section (and thus indices being requested) local or global?
6524 . point   - The point contributing dofs with these indices
6525 . off     - The global offset of this point
6526 . loff    - The local offset of each field
6527 . setBC   - The flag determining whether to include indices of boundary values
6528 . perm    - A permutation of the dofs on this point, or NULL
6529 - indperm - A permutation of the entire indices array, or NULL
6530 
6531   Output Parameter:
6532 . indices - Indices for dofs on this point
6533 
6534   Level: developer
6535 
6536   Note: The indices could be local or global, depending on the value of 'off'.
6537 */
6538 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
6539 {
6540   PetscInt        dof;   /* The number of unknowns on this point */
6541   PetscInt        cdof;  /* The number of constraints on this point */
6542   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6543   PetscInt        cind = 0, k;
6544   PetscErrorCode  ierr;
6545 
6546   PetscFunctionBegin;
6547   if (!islocal && setBC) SETERRQ(PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC");
6548   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6549   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6550   if (!cdof || setBC) {
6551     for (k = 0; k < dof; ++k) {
6552       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
6553       const PetscInt ind    = indperm ? indperm[preind] : preind;
6554 
6555       indices[ind] = off + k;
6556     }
6557   } else {
6558     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6559     for (k = 0; k < dof; ++k) {
6560       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
6561       const PetscInt ind    = indperm ? indperm[preind] : preind;
6562 
6563       if ((cind < cdof) && (k == cdofs[cind])) {
6564         /* Insert check for returning constrained indices */
6565         indices[ind] = -(off+k+1);
6566         ++cind;
6567       } else {
6568         indices[ind] = off + k - (islocal ? 0 : cind);
6569       }
6570     }
6571   }
6572   *loff += dof;
6573   PetscFunctionReturn(0);
6574 }
6575 
6576 /*
6577  DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.
6578 
6579  Input Parameters:
6580 + section - a section (global or local)
6581 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global
6582 . point - point within section
6583 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
6584 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
6585 . setBC - identify constrained (boundary condition) points via involution.
6586 . perms - perms[f][permsoff][:] is a permutation of dofs within each field
6587 . permsoff - offset
6588 - indperm - index permutation
6589 
6590  Output Parameter:
6591 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
6592 . indices - array to hold indices (as defined by section) of each dof associated with point
6593 
6594  Notes:
6595  If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
6596  If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
6597  in the local vector.
6598 
6599  If section is global and setBC=false, the indices for constrained points are negative (and their value is not
6600  significant).  It is invalid to call with a global section and setBC=true.
6601 
6602  Developer Note:
6603  The section is only used for field layout, so islocal is technically a statement about the offset (off).  At some point
6604  in the future, global sections may have fields set, in which case we could pass the global section and obtain the
6605  offset could be obtained from the section instead of passing it explicitly as we do now.
6606 
6607  Example:
6608  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
6609  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
6610  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
6611  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.
6612 
6613  Level: developer
6614 */
6615 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[])
6616 {
6617   PetscInt       numFields, foff, f;
6618   PetscErrorCode ierr;
6619 
6620   PetscFunctionBegin;
6621   if (!islocal && setBC) SETERRQ(PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC");
6622   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6623   for (f = 0, foff = 0; f < numFields; ++f) {
6624     PetscInt        fdof, cfdof;
6625     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6626     PetscInt        cind = 0, b;
6627     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
6628 
6629     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6630     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
6631     if (!cfdof || setBC) {
6632       for (b = 0; b < fdof; ++b) {
6633         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6634         const PetscInt ind    = indperm ? indperm[preind] : preind;
6635 
6636         indices[ind] = off+foff+b;
6637       }
6638     } else {
6639       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6640       for (b = 0; b < fdof; ++b) {
6641         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6642         const PetscInt ind    = indperm ? indperm[preind] : preind;
6643 
6644         if ((cind < cfdof) && (b == fcdofs[cind])) {
6645           indices[ind] = -(off+foff+b+1);
6646           ++cind;
6647         } else {
6648           indices[ind] = off + foff + b - (islocal ? 0 : cind);
6649         }
6650       }
6651     }
6652     foff     += (setBC || islocal ? fdof : (fdof - cfdof));
6653     foffs[f] += fdof;
6654   }
6655   PetscFunctionReturn(0);
6656 }
6657 
6658 /*
6659   This version believes the globalSection offsets for each field, rather than just the point offset
6660 
6661  . foffs - The offset into 'indices' for each field, since it is segregated by field
6662 
6663  Notes:
6664  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
6665  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
6666 */
6667 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
6668 {
6669   PetscInt       numFields, foff, f;
6670   PetscErrorCode ierr;
6671 
6672   PetscFunctionBegin;
6673   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6674   for (f = 0; f < numFields; ++f) {
6675     PetscInt        fdof, cfdof;
6676     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6677     PetscInt        cind = 0, b;
6678     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
6679 
6680     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6681     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
6682     ierr = PetscSectionGetFieldOffset(globalSection, point, f, &foff);CHKERRQ(ierr);
6683     if (!cfdof) {
6684       for (b = 0; b < fdof; ++b) {
6685         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6686         const PetscInt ind    = indperm ? indperm[preind] : preind;
6687 
6688         indices[ind] = foff+b;
6689       }
6690     } else {
6691       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6692       for (b = 0; b < fdof; ++b) {
6693         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6694         const PetscInt ind    = indperm ? indperm[preind] : preind;
6695 
6696         if ((cind < cfdof) && (b == fcdofs[cind])) {
6697           indices[ind] = -(foff+b+1);
6698           ++cind;
6699         } else {
6700           indices[ind] = foff+b-cind;
6701         }
6702       }
6703     }
6704     foffs[f] += fdof;
6705   }
6706   PetscFunctionReturn(0);
6707 }
6708 
6709 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)
6710 {
6711   Mat             cMat;
6712   PetscSection    aSec, cSec;
6713   IS              aIS;
6714   PetscInt        aStart = -1, aEnd = -1;
6715   const PetscInt  *anchors;
6716   PetscInt        numFields, f, p, q, newP = 0;
6717   PetscInt        newNumPoints = 0, newNumIndices = 0;
6718   PetscInt        *newPoints, *indices, *newIndices;
6719   PetscInt        maxAnchor, maxDof;
6720   PetscInt        newOffsets[32];
6721   PetscInt        *pointMatOffsets[32];
6722   PetscInt        *newPointOffsets[32];
6723   PetscScalar     *pointMat[32];
6724   PetscScalar     *newValues=NULL,*tmpValues;
6725   PetscBool       anyConstrained = PETSC_FALSE;
6726   PetscErrorCode  ierr;
6727 
6728   PetscFunctionBegin;
6729   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6730   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6731   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6732 
6733   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
6734   /* if there are point-to-point constraints */
6735   if (aSec) {
6736     ierr = PetscArrayzero(newOffsets, 32);CHKERRQ(ierr);
6737     ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
6738     ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
6739     /* figure out how many points are going to be in the new element matrix
6740      * (we allow double counting, because it's all just going to be summed
6741      * into the global matrix anyway) */
6742     for (p = 0; p < 2*numPoints; p+=2) {
6743       PetscInt b    = points[p];
6744       PetscInt bDof = 0, bSecDof;
6745 
6746       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
6747       if (!bSecDof) {
6748         continue;
6749       }
6750       if (b >= aStart && b < aEnd) {
6751         ierr = PetscSectionGetDof(aSec,b,&bDof);CHKERRQ(ierr);
6752       }
6753       if (bDof) {
6754         /* this point is constrained */
6755         /* it is going to be replaced by its anchors */
6756         PetscInt bOff, q;
6757 
6758         anyConstrained = PETSC_TRUE;
6759         newNumPoints  += bDof;
6760         ierr = PetscSectionGetOffset(aSec,b,&bOff);CHKERRQ(ierr);
6761         for (q = 0; q < bDof; q++) {
6762           PetscInt a = anchors[bOff + q];
6763           PetscInt aDof;
6764 
6765           ierr           = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
6766           newNumIndices += aDof;
6767           for (f = 0; f < numFields; ++f) {
6768             PetscInt fDof;
6769 
6770             ierr             = PetscSectionGetFieldDof(section, a, f, &fDof);CHKERRQ(ierr);
6771             newOffsets[f+1] += fDof;
6772           }
6773         }
6774       }
6775       else {
6776         /* this point is not constrained */
6777         newNumPoints++;
6778         newNumIndices += bSecDof;
6779         for (f = 0; f < numFields; ++f) {
6780           PetscInt fDof;
6781 
6782           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
6783           newOffsets[f+1] += fDof;
6784         }
6785       }
6786     }
6787   }
6788   if (!anyConstrained) {
6789     if (outNumPoints)  *outNumPoints  = 0;
6790     if (outNumIndices) *outNumIndices = 0;
6791     if (outPoints)     *outPoints     = NULL;
6792     if (outValues)     *outValues     = NULL;
6793     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
6794     PetscFunctionReturn(0);
6795   }
6796 
6797   if (outNumPoints)  *outNumPoints  = newNumPoints;
6798   if (outNumIndices) *outNumIndices = newNumIndices;
6799 
6800   for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
6801 
6802   if (!outPoints && !outValues) {
6803     if (offsets) {
6804       for (f = 0; f <= numFields; f++) {
6805         offsets[f] = newOffsets[f];
6806       }
6807     }
6808     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
6809     PetscFunctionReturn(0);
6810   }
6811 
6812   if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
6813 
6814   ierr = DMGetDefaultConstraints(dm, &cSec, &cMat);CHKERRQ(ierr);
6815 
6816   /* workspaces */
6817   if (numFields) {
6818     for (f = 0; f < numFields; f++) {
6819       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
6820       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
6821     }
6822   }
6823   else {
6824     ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
6825     ierr = DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
6826   }
6827 
6828   /* get workspaces for the point-to-point matrices */
6829   if (numFields) {
6830     PetscInt totalOffset, totalMatOffset;
6831 
6832     for (p = 0; p < numPoints; p++) {
6833       PetscInt b    = points[2*p];
6834       PetscInt bDof = 0, bSecDof;
6835 
6836       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
6837       if (!bSecDof) {
6838         for (f = 0; f < numFields; f++) {
6839           newPointOffsets[f][p + 1] = 0;
6840           pointMatOffsets[f][p + 1] = 0;
6841         }
6842         continue;
6843       }
6844       if (b >= aStart && b < aEnd) {
6845         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6846       }
6847       if (bDof) {
6848         for (f = 0; f < numFields; f++) {
6849           PetscInt fDof, q, bOff, allFDof = 0;
6850 
6851           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
6852           ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
6853           for (q = 0; q < bDof; q++) {
6854             PetscInt a = anchors[bOff + q];
6855             PetscInt aFDof;
6856 
6857             ierr     = PetscSectionGetFieldDof(section, a, f, &aFDof);CHKERRQ(ierr);
6858             allFDof += aFDof;
6859           }
6860           newPointOffsets[f][p+1] = allFDof;
6861           pointMatOffsets[f][p+1] = fDof * allFDof;
6862         }
6863       }
6864       else {
6865         for (f = 0; f < numFields; f++) {
6866           PetscInt fDof;
6867 
6868           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
6869           newPointOffsets[f][p+1] = fDof;
6870           pointMatOffsets[f][p+1] = 0;
6871         }
6872       }
6873     }
6874     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
6875       newPointOffsets[f][0] = totalOffset;
6876       pointMatOffsets[f][0] = totalMatOffset;
6877       for (p = 0; p < numPoints; p++) {
6878         newPointOffsets[f][p+1] += newPointOffsets[f][p];
6879         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
6880       }
6881       totalOffset    = newPointOffsets[f][numPoints];
6882       totalMatOffset = pointMatOffsets[f][numPoints];
6883       ierr = DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
6884     }
6885   }
6886   else {
6887     for (p = 0; p < numPoints; p++) {
6888       PetscInt b    = points[2*p];
6889       PetscInt bDof = 0, bSecDof;
6890 
6891       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
6892       if (!bSecDof) {
6893         newPointOffsets[0][p + 1] = 0;
6894         pointMatOffsets[0][p + 1] = 0;
6895         continue;
6896       }
6897       if (b >= aStart && b < aEnd) {
6898         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6899       }
6900       if (bDof) {
6901         PetscInt bOff, q, allDof = 0;
6902 
6903         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
6904         for (q = 0; q < bDof; q++) {
6905           PetscInt a = anchors[bOff + q], aDof;
6906 
6907           ierr    = PetscSectionGetDof(section, a, &aDof);CHKERRQ(ierr);
6908           allDof += aDof;
6909         }
6910         newPointOffsets[0][p+1] = allDof;
6911         pointMatOffsets[0][p+1] = bSecDof * allDof;
6912       }
6913       else {
6914         newPointOffsets[0][p+1] = bSecDof;
6915         pointMatOffsets[0][p+1] = 0;
6916       }
6917     }
6918     newPointOffsets[0][0] = 0;
6919     pointMatOffsets[0][0] = 0;
6920     for (p = 0; p < numPoints; p++) {
6921       newPointOffsets[0][p+1] += newPointOffsets[0][p];
6922       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
6923     }
6924     ierr = DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
6925   }
6926 
6927   /* output arrays */
6928   ierr = DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
6929 
6930   /* get the point-to-point matrices; construct newPoints */
6931   ierr = PetscSectionGetMaxDof(aSec, &maxAnchor);CHKERRQ(ierr);
6932   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6933   ierr = DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
6934   ierr = DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
6935   if (numFields) {
6936     for (p = 0, newP = 0; p < numPoints; p++) {
6937       PetscInt b    = points[2*p];
6938       PetscInt o    = points[2*p+1];
6939       PetscInt bDof = 0, bSecDof;
6940 
6941       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
6942       if (!bSecDof) {
6943         continue;
6944       }
6945       if (b >= aStart && b < aEnd) {
6946         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6947       }
6948       if (bDof) {
6949         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
6950 
6951         fStart[0] = 0;
6952         fEnd[0]   = 0;
6953         for (f = 0; f < numFields; f++) {
6954           PetscInt fDof;
6955 
6956           ierr        = PetscSectionGetFieldDof(cSec, b, f, &fDof);CHKERRQ(ierr);
6957           fStart[f+1] = fStart[f] + fDof;
6958           fEnd[f+1]   = fStart[f+1];
6959         }
6960         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
6961         ierr = DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices);CHKERRQ(ierr);
6962 
6963         fAnchorStart[0] = 0;
6964         fAnchorEnd[0]   = 0;
6965         for (f = 0; f < numFields; f++) {
6966           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
6967 
6968           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
6969           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
6970         }
6971         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
6972         for (q = 0; q < bDof; q++) {
6973           PetscInt a = anchors[bOff + q], aOff;
6974 
6975           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
6976           newPoints[2*(newP + q)]     = a;
6977           newPoints[2*(newP + q) + 1] = 0;
6978           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
6979           ierr = DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices);CHKERRQ(ierr);
6980         }
6981         newP += bDof;
6982 
6983         if (outValues) {
6984           /* get the point-to-point submatrix */
6985           for (f = 0; f < numFields; f++) {
6986             ierr = MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);CHKERRQ(ierr);
6987           }
6988         }
6989       }
6990       else {
6991         newPoints[2 * newP]     = b;
6992         newPoints[2 * newP + 1] = o;
6993         newP++;
6994       }
6995     }
6996   } else {
6997     for (p = 0; p < numPoints; p++) {
6998       PetscInt b    = points[2*p];
6999       PetscInt o    = points[2*p+1];
7000       PetscInt bDof = 0, bSecDof;
7001 
7002       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
7003       if (!bSecDof) {
7004         continue;
7005       }
7006       if (b >= aStart && b < aEnd) {
7007         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
7008       }
7009       if (bDof) {
7010         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
7011 
7012         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
7013         ierr = DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices);CHKERRQ(ierr);
7014 
7015         ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr);
7016         for (q = 0; q < bDof; q++) {
7017           PetscInt a = anchors[bOff + q], aOff;
7018 
7019           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
7020 
7021           newPoints[2*(newP + q)]     = a;
7022           newPoints[2*(newP + q) + 1] = 0;
7023           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
7024           ierr = DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices);CHKERRQ(ierr);
7025         }
7026         newP += bDof;
7027 
7028         /* get the point-to-point submatrix */
7029         if (outValues) {
7030           ierr = MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);CHKERRQ(ierr);
7031         }
7032       }
7033       else {
7034         newPoints[2 * newP]     = b;
7035         newPoints[2 * newP + 1] = o;
7036         newP++;
7037       }
7038     }
7039   }
7040 
7041   if (outValues) {
7042     ierr = DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
7043     ierr = PetscArrayzero(tmpValues,newNumIndices*numIndices);CHKERRQ(ierr);
7044     /* multiply constraints on the right */
7045     if (numFields) {
7046       for (f = 0; f < numFields; f++) {
7047         PetscInt oldOff = offsets[f];
7048 
7049         for (p = 0; p < numPoints; p++) {
7050           PetscInt cStart = newPointOffsets[f][p];
7051           PetscInt b      = points[2 * p];
7052           PetscInt c, r, k;
7053           PetscInt dof;
7054 
7055           ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
7056           if (!dof) {
7057             continue;
7058           }
7059           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7060             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
7061             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
7062 
7063             for (r = 0; r < numIndices; r++) {
7064               for (c = 0; c < nCols; c++) {
7065                 for (k = 0; k < dof; k++) {
7066                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
7067                 }
7068               }
7069             }
7070           }
7071           else {
7072             /* copy this column as is */
7073             for (r = 0; r < numIndices; r++) {
7074               for (c = 0; c < dof; c++) {
7075                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7076               }
7077             }
7078           }
7079           oldOff += dof;
7080         }
7081       }
7082     }
7083     else {
7084       PetscInt oldOff = 0;
7085       for (p = 0; p < numPoints; p++) {
7086         PetscInt cStart = newPointOffsets[0][p];
7087         PetscInt b      = points[2 * p];
7088         PetscInt c, r, k;
7089         PetscInt dof;
7090 
7091         ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
7092         if (!dof) {
7093           continue;
7094         }
7095         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7096           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
7097           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
7098 
7099           for (r = 0; r < numIndices; r++) {
7100             for (c = 0; c < nCols; c++) {
7101               for (k = 0; k < dof; k++) {
7102                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
7103               }
7104             }
7105           }
7106         }
7107         else {
7108           /* copy this column as is */
7109           for (r = 0; r < numIndices; r++) {
7110             for (c = 0; c < dof; c++) {
7111               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7112             }
7113           }
7114         }
7115         oldOff += dof;
7116       }
7117     }
7118 
7119     if (multiplyLeft) {
7120       ierr = DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr);
7121       ierr = PetscArrayzero(newValues,newNumIndices*newNumIndices);CHKERRQ(ierr);
7122       /* multiply constraints transpose on the left */
7123       if (numFields) {
7124         for (f = 0; f < numFields; f++) {
7125           PetscInt oldOff = offsets[f];
7126 
7127           for (p = 0; p < numPoints; p++) {
7128             PetscInt rStart = newPointOffsets[f][p];
7129             PetscInt b      = points[2 * p];
7130             PetscInt c, r, k;
7131             PetscInt dof;
7132 
7133             ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
7134             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7135               PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
7136               const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
7137 
7138               for (r = 0; r < nRows; r++) {
7139                 for (c = 0; c < newNumIndices; c++) {
7140                   for (k = 0; k < dof; k++) {
7141                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7142                   }
7143                 }
7144               }
7145             }
7146             else {
7147               /* copy this row as is */
7148               for (r = 0; r < dof; r++) {
7149                 for (c = 0; c < newNumIndices; c++) {
7150                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7151                 }
7152               }
7153             }
7154             oldOff += dof;
7155           }
7156         }
7157       }
7158       else {
7159         PetscInt oldOff = 0;
7160 
7161         for (p = 0; p < numPoints; p++) {
7162           PetscInt rStart = newPointOffsets[0][p];
7163           PetscInt b      = points[2 * p];
7164           PetscInt c, r, k;
7165           PetscInt dof;
7166 
7167           ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
7168           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7169             PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
7170             const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
7171 
7172             for (r = 0; r < nRows; r++) {
7173               for (c = 0; c < newNumIndices; c++) {
7174                 for (k = 0; k < dof; k++) {
7175                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7176                 }
7177               }
7178             }
7179           }
7180           else {
7181             /* copy this row as is */
7182             for (r = 0; r < dof; r++) {
7183               for (c = 0; c < newNumIndices; c++) {
7184                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7185               }
7186             }
7187           }
7188           oldOff += dof;
7189         }
7190       }
7191 
7192       ierr = DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
7193     }
7194     else {
7195       newValues = tmpValues;
7196     }
7197   }
7198 
7199   /* clean up */
7200   ierr = DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
7201   ierr = DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
7202 
7203   if (numFields) {
7204     for (f = 0; f < numFields; f++) {
7205       ierr = DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
7206       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
7207       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
7208     }
7209   }
7210   else {
7211     ierr = DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
7212     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
7213     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
7214   }
7215   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
7216 
7217   /* output */
7218   if (outPoints) {
7219     *outPoints = newPoints;
7220   }
7221   else {
7222     ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
7223   }
7224   if (outValues) {
7225     *outValues = newValues;
7226   }
7227   for (f = 0; f <= numFields; f++) {
7228     offsets[f] = newOffsets[f];
7229   }
7230   PetscFunctionReturn(0);
7231 }
7232 
7233 /*@C
7234   DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.
7235 
7236   Not collective
7237 
7238   Input Parameters:
7239 + dm         - The DM
7240 . section    - The PetscSection describing the points (a local section)
7241 . idxSection - The PetscSection from which to obtain indices (may be local or global)
7242 . point      - The point defining the closure
7243 - useClPerm  - Use the closure point permutation if available
7244 
7245   Output Parameters:
7246 + numIndices - The number of dof indices in the closure of point with the input sections
7247 . indices    - The dof indices
7248 . outOffsets - Array to write the field offsets into, or NULL
7249 - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
7250 
7251   Notes:
7252   Must call DMPlexRestoreClosureIndices() to free allocated memory
7253 
7254   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
7255   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
7256   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
7257   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
7258   indices (with the above semantics) are implied.
7259 
7260   Level: advanced
7261 
7262 .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection()
7263 @*/
7264 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm,
7265                                        PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7266 {
7267   /* Closure ordering */
7268   PetscSection        clSection;
7269   IS                  clPoints;
7270   const PetscInt     *clp;
7271   PetscInt           *points;
7272   const PetscInt     *clperm = NULL;
7273   /* Dof permutation and sign flips */
7274   const PetscInt    **perms[32] = {NULL};
7275   const PetscScalar **flips[32] = {NULL};
7276   PetscScalar        *valCopy   = NULL;
7277   /* Hanging node constraints */
7278   PetscInt           *pointsC = NULL;
7279   PetscScalar        *valuesC = NULL;
7280   PetscInt            NclC, NiC;
7281 
7282   PetscInt           *idx;
7283   PetscInt            Nf, Ncl, Ni = 0, offsets[32], p, f;
7284   PetscBool           isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
7285   PetscErrorCode      ierr;
7286 
7287   PetscFunctionBeginHot;
7288   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7289   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7290   PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3);
7291   if (numIndices) PetscValidPointer(numIndices, 6);
7292   if (indices)    PetscValidPointer(indices, 7);
7293   if (outOffsets) PetscValidPointer(outOffsets, 8);
7294   if (values)     PetscValidPointer(values, 9);
7295   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
7296   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
7297   ierr = PetscArrayzero(offsets, 32);CHKERRQ(ierr);
7298   /* 1) Get points in closure */
7299   ierr = DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr);
7300   if (useClPerm) {
7301     PetscInt depth, clsize;
7302     ierr = DMPlexGetPointDepth(dm, point, &depth);CHKERRQ(ierr);
7303     for (clsize=0,p=0; p<Ncl; p++) {
7304       PetscInt dof;
7305       ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr);
7306       clsize += dof;
7307     }
7308     ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm);CHKERRQ(ierr);
7309   }
7310   /* 2) Get number of indices on these points and field offsets from section */
7311   for (p = 0; p < Ncl*2; p += 2) {
7312     PetscInt dof, fdof;
7313 
7314     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7315     for (f = 0; f < Nf; ++f) {
7316       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7317       offsets[f+1] += fdof;
7318     }
7319     Ni += dof;
7320   }
7321   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
7322   if (Nf && offsets[Nf] != Ni) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Ni);
7323   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
7324   for (f = 0; f < PetscMax(1, Nf); ++f) {
7325     if (Nf) {ierr = PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7326     else    {ierr = PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7327     /* may need to apply sign changes to the element matrix */
7328     if (values && flips[f]) {
7329       PetscInt foffset = offsets[f];
7330 
7331       for (p = 0; p < Ncl; ++p) {
7332         PetscInt           pnt  = points[2*p], fdof;
7333         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
7334 
7335         if (!Nf) {ierr = PetscSectionGetDof(section, pnt, &fdof);CHKERRQ(ierr);}
7336         else     {ierr = PetscSectionGetFieldDof(section, pnt, f, &fdof);CHKERRQ(ierr);}
7337         if (flip) {
7338           PetscInt i, j, k;
7339 
7340           if (!valCopy) {
7341             ierr = DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy);CHKERRQ(ierr);
7342             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
7343             *values = valCopy;
7344           }
7345           for (i = 0; i < fdof; ++i) {
7346             PetscScalar fval = flip[i];
7347 
7348             for (k = 0; k < Ni; ++k) {
7349               valCopy[Ni * (foffset + i) + k] *= fval;
7350               valCopy[Ni * k + (foffset + i)] *= fval;
7351             }
7352           }
7353         }
7354         foffset += fdof;
7355       }
7356     }
7357   }
7358   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
7359   ierr = DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE);CHKERRQ(ierr);
7360   if (NclC) {
7361     if (valCopy) {ierr = DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy);CHKERRQ(ierr);}
7362     for (f = 0; f < PetscMax(1, Nf); ++f) {
7363       if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7364       else    {ierr = PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7365     }
7366     for (f = 0; f < PetscMax(1, Nf); ++f) {
7367       if (Nf) {ierr = PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]);CHKERRQ(ierr);}
7368       else    {ierr = PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]);CHKERRQ(ierr);}
7369     }
7370     ierr = DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr);
7371     Ncl     = NclC;
7372     Ni      = NiC;
7373     points  = pointsC;
7374     if (values) *values = valuesC;
7375   }
7376   /* 5) Calculate indices */
7377   ierr = DMGetWorkArray(dm, Ni, MPIU_INT, &idx);CHKERRQ(ierr);
7378   if (Nf) {
7379     PetscInt  idxOff;
7380     PetscBool useFieldOffsets;
7381 
7382     if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];}
7383     ierr = PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets);CHKERRQ(ierr);
7384     if (useFieldOffsets) {
7385       for (p = 0; p < Ncl; ++p) {
7386         const PetscInt pnt = points[p*2];
7387 
7388         ierr = DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx);CHKERRQ(ierr);
7389       }
7390     } else {
7391       for (p = 0; p < Ncl; ++p) {
7392         const PetscInt pnt = points[p*2];
7393 
7394         ierr = PetscSectionGetOffset(idxSection, pnt, &idxOff);CHKERRQ(ierr);
7395         /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
7396          * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
7397          * global section. */
7398         ierr = DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx);CHKERRQ(ierr);
7399       }
7400     }
7401   } else {
7402     PetscInt off = 0, idxOff;
7403 
7404     for (p = 0; p < Ncl; ++p) {
7405       const PetscInt  pnt  = points[p*2];
7406       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
7407 
7408       ierr = PetscSectionGetOffset(idxSection, pnt, &idxOff);CHKERRQ(ierr);
7409       /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
7410        * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
7411       ierr = DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx);CHKERRQ(ierr);
7412     }
7413   }
7414   /* 6) Cleanup */
7415   for (f = 0; f < PetscMax(1, Nf); ++f) {
7416     if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7417     else    {ierr = PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7418   }
7419   if (NclC) {
7420     ierr = DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC);CHKERRQ(ierr);
7421   } else {
7422     ierr = DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr);
7423   }
7424 
7425   if (numIndices) *numIndices = Ni;
7426   if (indices)    *indices    = idx;
7427   PetscFunctionReturn(0);
7428 }
7429 
7430 /*@C
7431   DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.
7432 
7433   Not collective
7434 
7435   Input Parameters:
7436 + dm         - The DM
7437 . section    - The PetscSection describing the points (a local section)
7438 . idxSection - The PetscSection from which to obtain indices (may be local or global)
7439 . point      - The point defining the closure
7440 - useClPerm  - Use the closure point permutation if available
7441 
7442   Output Parameters:
7443 + numIndices - The number of dof indices in the closure of point with the input sections
7444 . indices    - The dof indices
7445 . outOffsets - Array to write the field offsets into, or NULL
7446 - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
7447 
7448   Notes:
7449   If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values).
7450 
7451   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
7452   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
7453   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
7454   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
7455   indices (with the above semantics) are implied.
7456 
7457   Level: advanced
7458 
7459 .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection()
7460 @*/
7461 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm,
7462                                            PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7463 {
7464   PetscErrorCode ierr;
7465 
7466   PetscFunctionBegin;
7467   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7468   PetscValidPointer(indices, 7);
7469   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, indices);CHKERRQ(ierr);
7470   PetscFunctionReturn(0);
7471 }
7472 
7473 /*@C
7474   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
7475 
7476   Not collective
7477 
7478   Input Parameters:
7479 + dm - The DM
7480 . section - The section describing the layout in v, or NULL to use the default section
7481 . globalSection - The section describing the layout in v, or NULL to use the default global section
7482 . A - The matrix
7483 . point - The point in the DM
7484 . values - The array of values
7485 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7486 
7487   Fortran Notes:
7488   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
7489 
7490   Level: intermediate
7491 
7492 .seealso DMPlexMatSetClosureGeneral(), DMPlexVecGetClosure(), DMPlexVecSetClosure()
7493 @*/
7494 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7495 {
7496   DM_Plex           *mesh = (DM_Plex*) dm->data;
7497   PetscInt          *indices;
7498   PetscInt           numIndices;
7499   const PetscScalar *valuesOrig = values;
7500   PetscErrorCode     ierr;
7501 
7502   PetscFunctionBegin;
7503   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7504   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
7505   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7506   if (!globalSection) {ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
7507   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
7508   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
7509 
7510   ierr = DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7511 
7512   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);}
7513   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7514   if (ierr) {
7515     PetscMPIInt    rank;
7516     PetscErrorCode ierr2;
7517 
7518     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2);
7519     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7520     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
7521     ierr2 = DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr2);
7522     if (values != valuesOrig) {ierr2 = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values);CHKERRQ(ierr2);}
7523     SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values");
7524   }
7525   if (mesh->printFEM > 1) {
7526     PetscInt i;
7527     ierr = PetscPrintf(PETSC_COMM_SELF, "  Indices:");CHKERRQ(ierr);
7528     for (i = 0; i < numIndices; ++i) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);CHKERRQ(ierr);}
7529     ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
7530   }
7531 
7532   ierr = DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7533   if (values != valuesOrig) {ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values);CHKERRQ(ierr);}
7534   PetscFunctionReturn(0);
7535 }
7536 
7537 /*@C
7538   DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section
7539 
7540   Not collective
7541 
7542   Input Parameters:
7543 + dmRow - The DM for the row fields
7544 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow
7545 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow
7546 . dmCol - The DM for the column fields
7547 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol
7548 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol
7549 . A - The matrix
7550 . point - The point in the DMs
7551 . values - The array of values
7552 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7553 
7554   Level: intermediate
7555 
7556 .seealso DMPlexMatSetClosure(), DMPlexVecGetClosure(), DMPlexVecSetClosure()
7557 @*/
7558 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7559 {
7560   DM_Plex           *mesh = (DM_Plex*) dmRow->data;
7561   PetscInt          *indicesRow, *indicesCol;
7562   PetscInt           numIndicesRow, numIndicesCol;
7563   const PetscScalar *valuesOrig = values;
7564   PetscErrorCode     ierr;
7565 
7566   PetscFunctionBegin;
7567   PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1);
7568   if (!sectionRow) {ierr = DMGetLocalSection(dmRow, &sectionRow);CHKERRQ(ierr);}
7569   PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2);
7570   if (!globalSectionRow) {ierr = DMGetGlobalSection(dmRow, &globalSectionRow);CHKERRQ(ierr);}
7571   PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3);
7572   PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4);
7573   if (!sectionCol) {ierr = DMGetLocalSection(dmCol, &sectionCol);CHKERRQ(ierr);}
7574   PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5);
7575   if (!globalSectionCol) {ierr = DMGetGlobalSection(dmCol, &globalSectionCol);CHKERRQ(ierr);}
7576   PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6);
7577   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
7578 
7579   ierr = DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7580   ierr = DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7581 
7582   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values);CHKERRQ(ierr);}
7583   ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode);
7584   if (ierr) {
7585     PetscMPIInt    rank;
7586     PetscErrorCode ierr2;
7587 
7588     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2);
7589     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7590     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values);CHKERRQ(ierr2);
7591     ierr2 = DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr2);
7592     ierr2 = DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr2);
7593     if (values != valuesOrig) {ierr2 = DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values);CHKERRQ(ierr2);}
7594     CHKERRQ(ierr);
7595   }
7596 
7597   ierr = DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7598   ierr = DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7599   if (values != valuesOrig) {ierr = DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values);CHKERRQ(ierr);}
7600   PetscFunctionReturn(0);
7601 }
7602 
7603 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7604 {
7605   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
7606   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
7607   PetscInt       *cpoints = NULL;
7608   PetscInt       *findices, *cindices;
7609   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7610   PetscInt        foffsets[32], coffsets[32];
7611   DMPolytopeType  ct;
7612   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
7613   PetscErrorCode  ierr;
7614 
7615   PetscFunctionBegin;
7616   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
7617   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
7618   if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);}
7619   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
7620   if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);}
7621   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
7622   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
7623   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
7624   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
7625   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
7626   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
7627   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
7628   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7629   ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr);
7630   ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr);
7631   /* Column indices */
7632   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7633   maxFPoints = numCPoints;
7634   /* Compress out points not in the section */
7635   /*   TODO: Squeeze out points with 0 dof as well */
7636   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
7637   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
7638     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
7639       cpoints[q*2]   = cpoints[p];
7640       cpoints[q*2+1] = cpoints[p+1];
7641       ++q;
7642     }
7643   }
7644   numCPoints = q;
7645   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
7646     PetscInt fdof;
7647 
7648     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
7649     if (!dof) continue;
7650     for (f = 0; f < numFields; ++f) {
7651       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
7652       coffsets[f+1] += fdof;
7653     }
7654     numCIndices += dof;
7655   }
7656   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
7657   /* Row indices */
7658   ierr = DMPlexGetCellType(dmc, point, &ct);CHKERRQ(ierr);
7659   {
7660     DMPlexTransform tr;
7661     DMPolytopeType *rct;
7662     PetscInt       *rsize, *rcone, *rornt, Nt;
7663 
7664     ierr = DMPlexTransformCreate(PETSC_COMM_SELF, &tr);CHKERRQ(ierr);
7665     ierr = DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR);CHKERRQ(ierr);
7666     ierr = DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt);CHKERRQ(ierr);
7667     numSubcells = rsize[Nt-1];
7668     ierr = DMPlexTransformDestroy(&tr);CHKERRQ(ierr);
7669   }
7670   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7671   for (r = 0, q = 0; r < numSubcells; ++r) {
7672     /* TODO Map from coarse to fine cells */
7673     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7674     /* Compress out points not in the section */
7675     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
7676     for (p = 0; p < numFPoints*2; p += 2) {
7677       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
7678         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
7679         if (!dof) continue;
7680         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
7681         if (s < q) continue;
7682         ftotpoints[q*2]   = fpoints[p];
7683         ftotpoints[q*2+1] = fpoints[p+1];
7684         ++q;
7685       }
7686     }
7687     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7688   }
7689   numFPoints = q;
7690   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
7691     PetscInt fdof;
7692 
7693     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
7694     if (!dof) continue;
7695     for (f = 0; f < numFields; ++f) {
7696       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
7697       foffsets[f+1] += fdof;
7698     }
7699     numFIndices += dof;
7700   }
7701   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
7702 
7703   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
7704   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
7705   ierr = DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
7706   ierr = DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
7707   if (numFields) {
7708     const PetscInt **permsF[32] = {NULL};
7709     const PetscInt **permsC[32] = {NULL};
7710 
7711     for (f = 0; f < numFields; f++) {
7712       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7713       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7714     }
7715     for (p = 0; p < numFPoints; p++) {
7716       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7717       ierr = DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr);
7718     }
7719     for (p = 0; p < numCPoints; p++) {
7720       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7721       ierr = DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr);
7722     }
7723     for (f = 0; f < numFields; f++) {
7724       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7725       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7726     }
7727   } else {
7728     const PetscInt **permsF = NULL;
7729     const PetscInt **permsC = NULL;
7730 
7731     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7732     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7733     for (p = 0, off = 0; p < numFPoints; p++) {
7734       const PetscInt *perm = permsF ? permsF[p] : NULL;
7735 
7736       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7737       ierr = DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr);
7738     }
7739     for (p = 0, off = 0; p < numCPoints; p++) {
7740       const PetscInt *perm = permsC ? permsC[p] : NULL;
7741 
7742       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7743       ierr = DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr);
7744     }
7745     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7746     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7747   }
7748   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);}
7749   /* TODO: flips */
7750   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
7751   if (ierr) {
7752     PetscMPIInt    rank;
7753     PetscErrorCode ierr2;
7754 
7755     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2);
7756     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7757     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
7758     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
7759     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
7760     CHKERRQ(ierr);
7761   }
7762   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7763   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7764   ierr = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
7765   ierr = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
7766   PetscFunctionReturn(0);
7767 }
7768 
7769 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
7770 {
7771   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
7772   PetscInt      *cpoints = NULL;
7773   PetscInt       foffsets[32], coffsets[32];
7774   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7775   DMPolytopeType ct;
7776   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
7777   PetscErrorCode ierr;
7778 
7779   PetscFunctionBegin;
7780   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
7781   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
7782   if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);}
7783   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
7784   if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);}
7785   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
7786   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
7787   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
7788   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
7789   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
7790   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
7791   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7792   ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr);
7793   ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr);
7794   /* Column indices */
7795   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7796   maxFPoints = numCPoints;
7797   /* Compress out points not in the section */
7798   /*   TODO: Squeeze out points with 0 dof as well */
7799   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
7800   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
7801     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
7802       cpoints[q*2]   = cpoints[p];
7803       cpoints[q*2+1] = cpoints[p+1];
7804       ++q;
7805     }
7806   }
7807   numCPoints = q;
7808   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
7809     PetscInt fdof;
7810 
7811     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
7812     if (!dof) continue;
7813     for (f = 0; f < numFields; ++f) {
7814       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
7815       coffsets[f+1] += fdof;
7816     }
7817     numCIndices += dof;
7818   }
7819   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
7820   /* Row indices */
7821   ierr = DMPlexGetCellType(dmc, point, &ct);CHKERRQ(ierr);
7822   {
7823     DMPlexTransform tr;
7824     DMPolytopeType *rct;
7825     PetscInt       *rsize, *rcone, *rornt, Nt;
7826 
7827     ierr = DMPlexTransformCreate(PETSC_COMM_SELF, &tr);CHKERRQ(ierr);
7828     ierr = DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR);CHKERRQ(ierr);
7829     ierr = DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt);CHKERRQ(ierr);
7830     numSubcells = rsize[Nt-1];
7831     ierr = DMPlexTransformDestroy(&tr);CHKERRQ(ierr);
7832   }
7833   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7834   for (r = 0, q = 0; r < numSubcells; ++r) {
7835     /* TODO Map from coarse to fine cells */
7836     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7837     /* Compress out points not in the section */
7838     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
7839     for (p = 0; p < numFPoints*2; p += 2) {
7840       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
7841         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
7842         if (!dof) continue;
7843         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
7844         if (s < q) continue;
7845         ftotpoints[q*2]   = fpoints[p];
7846         ftotpoints[q*2+1] = fpoints[p+1];
7847         ++q;
7848       }
7849     }
7850     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7851   }
7852   numFPoints = q;
7853   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
7854     PetscInt fdof;
7855 
7856     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
7857     if (!dof) continue;
7858     for (f = 0; f < numFields; ++f) {
7859       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
7860       foffsets[f+1] += fdof;
7861     }
7862     numFIndices += dof;
7863   }
7864   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
7865 
7866   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
7867   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
7868   if (numFields) {
7869     const PetscInt **permsF[32] = {NULL};
7870     const PetscInt **permsC[32] = {NULL};
7871 
7872     for (f = 0; f < numFields; f++) {
7873       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7874       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7875     }
7876     for (p = 0; p < numFPoints; p++) {
7877       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7878       ierr = DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr);
7879     }
7880     for (p = 0; p < numCPoints; p++) {
7881       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7882       ierr = DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr);
7883     }
7884     for (f = 0; f < numFields; f++) {
7885       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7886       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7887     }
7888   } else {
7889     const PetscInt **permsF = NULL;
7890     const PetscInt **permsC = NULL;
7891 
7892     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7893     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7894     for (p = 0, off = 0; p < numFPoints; p++) {
7895       const PetscInt *perm = permsF ? permsF[p] : NULL;
7896 
7897       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7898       ierr = DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr);
7899     }
7900     for (p = 0, off = 0; p < numCPoints; p++) {
7901       const PetscInt *perm = permsC ? permsC[p] : NULL;
7902 
7903       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7904       ierr = DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr);
7905     }
7906     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7907     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7908   }
7909   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7910   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7911   PetscFunctionReturn(0);
7912 }
7913 
7914 /*@C
7915   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
7916 
7917   Input Parameter:
7918 . dm   - The DMPlex object
7919 
7920   Output Parameter:
7921 . cellHeight - The height of a cell
7922 
7923   Level: developer
7924 
7925 .seealso DMPlexSetVTKCellHeight()
7926 @*/
7927 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
7928 {
7929   DM_Plex *mesh = (DM_Plex*) dm->data;
7930 
7931   PetscFunctionBegin;
7932   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7933   PetscValidPointer(cellHeight, 2);
7934   *cellHeight = mesh->vtkCellHeight;
7935   PetscFunctionReturn(0);
7936 }
7937 
7938 /*@C
7939   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
7940 
7941   Input Parameters:
7942 + dm   - The DMPlex object
7943 - cellHeight - The height of a cell
7944 
7945   Level: developer
7946 
7947 .seealso DMPlexGetVTKCellHeight()
7948 @*/
7949 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
7950 {
7951   DM_Plex *mesh = (DM_Plex*) dm->data;
7952 
7953   PetscFunctionBegin;
7954   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7955   mesh->vtkCellHeight = cellHeight;
7956   PetscFunctionReturn(0);
7957 }
7958 
7959 /*@
7960   DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions
7961 
7962   Input Parameter:
7963 . dm - The DMPlex object
7964 
7965   Output Parameters:
7966 + gcStart - The first ghost cell, or NULL
7967 - gcEnd   - The upper bound on ghost cells, or NULL
7968 
7969   Level: advanced
7970 
7971 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum()
7972 @*/
7973 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd)
7974 {
7975   DMLabel        ctLabel;
7976   PetscErrorCode ierr;
7977 
7978   PetscFunctionBegin;
7979   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7980   ierr = DMPlexGetCellTypeLabel(dm, &ctLabel);CHKERRQ(ierr);
7981   ierr = DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd);CHKERRQ(ierr);
7982   PetscFunctionReturn(0);
7983 }
7984 
7985 /* We can easily have a form that takes an IS instead */
7986 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
7987 {
7988   PetscSection   section, globalSection;
7989   PetscInt      *numbers, p;
7990   PetscErrorCode ierr;
7991 
7992   PetscFunctionBegin;
7993   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
7994   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
7995   for (p = pStart; p < pEnd; ++p) {
7996     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
7997   }
7998   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
7999   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8000   ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr);
8001   for (p = pStart; p < pEnd; ++p) {
8002     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
8003     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
8004     else                       numbers[p-pStart] += shift;
8005   }
8006   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
8007   if (globalSize) {
8008     PetscLayout layout;
8009     ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr);
8010     ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr);
8011     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
8012   }
8013   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
8014   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8015   PetscFunctionReturn(0);
8016 }
8017 
8018 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
8019 {
8020   PetscInt       cellHeight, cStart, cEnd;
8021   PetscErrorCode ierr;
8022 
8023   PetscFunctionBegin;
8024   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8025   if (includeHybrid) {ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);}
8026   else               {ierr = DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);}
8027   ierr = DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);CHKERRQ(ierr);
8028   PetscFunctionReturn(0);
8029 }
8030 
8031 /*@
8032   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
8033 
8034   Input Parameter:
8035 . dm   - The DMPlex object
8036 
8037   Output Parameter:
8038 . globalCellNumbers - Global cell numbers for all cells on this process
8039 
8040   Level: developer
8041 
8042 .seealso DMPlexGetVertexNumbering()
8043 @*/
8044 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
8045 {
8046   DM_Plex       *mesh = (DM_Plex*) dm->data;
8047   PetscErrorCode ierr;
8048 
8049   PetscFunctionBegin;
8050   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8051   if (!mesh->globalCellNumbers) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);CHKERRQ(ierr);}
8052   *globalCellNumbers = mesh->globalCellNumbers;
8053   PetscFunctionReturn(0);
8054 }
8055 
8056 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
8057 {
8058   PetscInt       vStart, vEnd;
8059   PetscErrorCode ierr;
8060 
8061   PetscFunctionBegin;
8062   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8063   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8064   ierr = DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);CHKERRQ(ierr);
8065   PetscFunctionReturn(0);
8066 }
8067 
8068 /*@
8069   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
8070 
8071   Input Parameter:
8072 . dm   - The DMPlex object
8073 
8074   Output Parameter:
8075 . globalVertexNumbers - Global vertex numbers for all vertices on this process
8076 
8077   Level: developer
8078 
8079 .seealso DMPlexGetCellNumbering()
8080 @*/
8081 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
8082 {
8083   DM_Plex       *mesh = (DM_Plex*) dm->data;
8084   PetscErrorCode ierr;
8085 
8086   PetscFunctionBegin;
8087   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8088   if (!mesh->globalVertexNumbers) {ierr = DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);CHKERRQ(ierr);}
8089   *globalVertexNumbers = mesh->globalVertexNumbers;
8090   PetscFunctionReturn(0);
8091 }
8092 
8093 /*@
8094   DMPlexCreatePointNumbering - Create a global numbering for all points on this process
8095 
8096   Input Parameter:
8097 . dm   - The DMPlex object
8098 
8099   Output Parameter:
8100 . globalPointNumbers - Global numbers for all points on this process
8101 
8102   Level: developer
8103 
8104 .seealso DMPlexGetCellNumbering()
8105 @*/
8106 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
8107 {
8108   IS             nums[4];
8109   PetscInt       depths[4], gdepths[4], starts[4];
8110   PetscInt       depth, d, shift = 0;
8111   PetscErrorCode ierr;
8112 
8113   PetscFunctionBegin;
8114   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8115   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8116   /* For unstratified meshes use dim instead of depth */
8117   if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);}
8118   for (d = 0; d <= depth; ++d) {
8119     PetscInt end;
8120 
8121     depths[d] = depth-d;
8122     ierr = DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);CHKERRQ(ierr);
8123     if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
8124   }
8125   ierr = PetscSortIntWithArray(depth+1, starts, depths);CHKERRQ(ierr);
8126   ierr = MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRMPI(ierr);
8127   for (d = 0; d <= depth; ++d) {
8128     if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
8129   }
8130   for (d = 0; d <= depth; ++d) {
8131     PetscInt pStart, pEnd, gsize;
8132 
8133     ierr = DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);CHKERRQ(ierr);
8134     ierr = DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr);
8135     shift += gsize;
8136   }
8137   ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);CHKERRQ(ierr);
8138   for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);}
8139   PetscFunctionReturn(0);
8140 }
8141 
8142 /*@
8143   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
8144 
8145   Input Parameter:
8146 . dm - The DMPlex object
8147 
8148   Output Parameter:
8149 . ranks - The rank field
8150 
8151   Options Database Keys:
8152 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
8153 
8154   Level: intermediate
8155 
8156 .seealso: DMView()
8157 @*/
8158 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
8159 {
8160   DM             rdm;
8161   PetscFE        fe;
8162   PetscScalar   *r;
8163   PetscMPIInt    rank;
8164   DMPolytopeType ct;
8165   PetscInt       dim, cStart, cEnd, c;
8166   PetscBool      simplex;
8167   PetscErrorCode ierr;
8168 
8169   PetscFunctionBeginUser;
8170   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8171   PetscValidPointer(ranks, 2);
8172   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRMPI(ierr);
8173   ierr = DMClone(dm, &rdm);CHKERRQ(ierr);
8174   ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr);
8175   ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8176   ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr);
8177   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
8178   ierr = PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe);CHKERRQ(ierr);
8179   ierr = PetscObjectSetName((PetscObject) fe, "rank");CHKERRQ(ierr);
8180   ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
8181   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
8182   ierr = DMCreateDS(rdm);CHKERRQ(ierr);
8183   ierr = DMCreateGlobalVector(rdm, ranks);CHKERRQ(ierr);
8184   ierr = PetscObjectSetName((PetscObject) *ranks, "partition");CHKERRQ(ierr);
8185   ierr = VecGetArray(*ranks, &r);CHKERRQ(ierr);
8186   for (c = cStart; c < cEnd; ++c) {
8187     PetscScalar *lr;
8188 
8189     ierr = DMPlexPointGlobalRef(rdm, c, r, &lr);CHKERRQ(ierr);
8190     if (lr) *lr = rank;
8191   }
8192   ierr = VecRestoreArray(*ranks, &r);CHKERRQ(ierr);
8193   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
8194   PetscFunctionReturn(0);
8195 }
8196 
8197 /*@
8198   DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
8199 
8200   Input Parameters:
8201 + dm    - The DMPlex
8202 - label - The DMLabel
8203 
8204   Output Parameter:
8205 . val - The label value field
8206 
8207   Options Database Keys:
8208 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer
8209 
8210   Level: intermediate
8211 
8212 .seealso: DMView()
8213 @*/
8214 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
8215 {
8216   DM             rdm;
8217   PetscFE        fe;
8218   PetscScalar   *v;
8219   PetscInt       dim, cStart, cEnd, c;
8220   PetscErrorCode ierr;
8221 
8222   PetscFunctionBeginUser;
8223   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8224   PetscValidPointer(label, 2);
8225   PetscValidPointer(val, 3);
8226   ierr = DMClone(dm, &rdm);CHKERRQ(ierr);
8227   ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr);
8228   ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);CHKERRQ(ierr);
8229   ierr = PetscObjectSetName((PetscObject) fe, "label_value");CHKERRQ(ierr);
8230   ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
8231   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
8232   ierr = DMCreateDS(rdm);CHKERRQ(ierr);
8233   ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8234   ierr = DMCreateGlobalVector(rdm, val);CHKERRQ(ierr);
8235   ierr = PetscObjectSetName((PetscObject) *val, "label_value");CHKERRQ(ierr);
8236   ierr = VecGetArray(*val, &v);CHKERRQ(ierr);
8237   for (c = cStart; c < cEnd; ++c) {
8238     PetscScalar *lv;
8239     PetscInt     cval;
8240 
8241     ierr = DMPlexPointGlobalRef(rdm, c, v, &lv);CHKERRQ(ierr);
8242     ierr = DMLabelGetValue(label, c, &cval);CHKERRQ(ierr);
8243     *lv = cval;
8244   }
8245   ierr = VecRestoreArray(*val, &v);CHKERRQ(ierr);
8246   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
8247   PetscFunctionReturn(0);
8248 }
8249 
8250 /*@
8251   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
8252 
8253   Input Parameter:
8254 . dm - The DMPlex object
8255 
8256   Notes:
8257   This is a useful diagnostic when creating meshes programmatically.
8258 
8259   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8260 
8261   Level: developer
8262 
8263 .seealso: DMCreate(), DMSetFromOptions()
8264 @*/
8265 PetscErrorCode DMPlexCheckSymmetry(DM dm)
8266 {
8267   PetscSection    coneSection, supportSection;
8268   const PetscInt *cone, *support;
8269   PetscInt        coneSize, c, supportSize, s;
8270   PetscInt        pStart, pEnd, p, pp, csize, ssize;
8271   PetscBool       storagecheck = PETSC_TRUE;
8272   PetscErrorCode  ierr;
8273 
8274   PetscFunctionBegin;
8275   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8276   ierr = DMViewFromOptions(dm, NULL, "-sym_dm_view");CHKERRQ(ierr);
8277   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
8278   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
8279   /* Check that point p is found in the support of its cone points, and vice versa */
8280   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
8281   for (p = pStart; p < pEnd; ++p) {
8282     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
8283     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
8284     for (c = 0; c < coneSize; ++c) {
8285       PetscBool dup = PETSC_FALSE;
8286       PetscInt  d;
8287       for (d = c-1; d >= 0; --d) {
8288         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
8289       }
8290       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
8291       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
8292       for (s = 0; s < supportSize; ++s) {
8293         if (support[s] == p) break;
8294       }
8295       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
8296         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);CHKERRQ(ierr);
8297         for (s = 0; s < coneSize; ++s) {
8298           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);CHKERRQ(ierr);
8299         }
8300         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8301         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);CHKERRQ(ierr);
8302         for (s = 0; s < supportSize; ++s) {
8303           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);CHKERRQ(ierr);
8304         }
8305         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8306         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
8307         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
8308       }
8309     }
8310     ierr = DMPlexGetTreeParent(dm, p, &pp, NULL);CHKERRQ(ierr);
8311     if (p != pp) { storagecheck = PETSC_FALSE; continue; }
8312     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
8313     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
8314     for (s = 0; s < supportSize; ++s) {
8315       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
8316       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8317       for (c = 0; c < coneSize; ++c) {
8318         ierr = DMPlexGetTreeParent(dm, cone[c], &pp, NULL);CHKERRQ(ierr);
8319         if (cone[c] != pp) { c = 0; break; }
8320         if (cone[c] == p) break;
8321       }
8322       if (c >= coneSize) {
8323         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);CHKERRQ(ierr);
8324         for (c = 0; c < supportSize; ++c) {
8325           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);CHKERRQ(ierr);
8326         }
8327         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8328         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);CHKERRQ(ierr);
8329         for (c = 0; c < coneSize; ++c) {
8330           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);CHKERRQ(ierr);
8331         }
8332         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8333         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
8334       }
8335     }
8336   }
8337   if (storagecheck) {
8338     ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
8339     ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
8340     if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
8341   }
8342   PetscFunctionReturn(0);
8343 }
8344 
8345 /*
8346   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.
8347 */
8348 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit)
8349 {
8350   DMPolytopeType  cct;
8351   PetscInt        ptpoints[4];
8352   const PetscInt *cone, *ccone, *ptcone;
8353   PetscInt        coneSize, cp, cconeSize, ccp, npt = 0, pt;
8354   PetscErrorCode  ierr;
8355 
8356   PetscFunctionBegin;
8357   *unsplit = 0;
8358   switch (ct) {
8359     case DM_POLYTOPE_POINT_PRISM_TENSOR:
8360       ptpoints[npt++] = c;
8361       break;
8362     case DM_POLYTOPE_SEG_PRISM_TENSOR:
8363       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8364       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8365       for (cp = 0; cp < coneSize; ++cp) {
8366         ierr = DMPlexGetCellType(dm, cone[cp], &cct);CHKERRQ(ierr);
8367         if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp];
8368       }
8369       break;
8370     case DM_POLYTOPE_TRI_PRISM_TENSOR:
8371     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8372       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8373       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8374       for (cp = 0; cp < coneSize; ++cp) {
8375         ierr = DMPlexGetCone(dm, cone[cp], &ccone);CHKERRQ(ierr);
8376         ierr = DMPlexGetConeSize(dm, cone[cp], &cconeSize);CHKERRQ(ierr);
8377         for (ccp = 0; ccp < cconeSize; ++ccp) {
8378           ierr = DMPlexGetCellType(dm, ccone[ccp], &cct);CHKERRQ(ierr);
8379           if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) {
8380             PetscInt p;
8381             for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break;
8382             if (p == npt) ptpoints[npt++] = ccone[ccp];
8383           }
8384         }
8385       }
8386       break;
8387     default: break;
8388   }
8389   for (pt = 0; pt < npt; ++pt) {
8390     ierr = DMPlexGetCone(dm, ptpoints[pt], &ptcone);CHKERRQ(ierr);
8391     if (ptcone[0] == ptcone[1]) ++(*unsplit);
8392   }
8393   PetscFunctionReturn(0);
8394 }
8395 
8396 /*@
8397   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
8398 
8399   Input Parameters:
8400 + dm - The DMPlex object
8401 - cellHeight - Normally 0
8402 
8403   Notes:
8404   This is a useful diagnostic when creating meshes programmatically.
8405   Currently applicable only to homogeneous simplex or tensor meshes.
8406 
8407   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8408 
8409   Level: developer
8410 
8411 .seealso: DMCreate(), DMSetFromOptions()
8412 @*/
8413 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
8414 {
8415   DMPlexInterpolatedFlag interp;
8416   DMPolytopeType         ct;
8417   PetscInt               vStart, vEnd, cStart, cEnd, c;
8418   PetscErrorCode         ierr;
8419 
8420   PetscFunctionBegin;
8421   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8422   ierr = DMPlexIsInterpolated(dm, &interp);CHKERRQ(ierr);
8423   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8424   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8425   for (c = cStart; c < cEnd; ++c) {
8426     PetscInt *closure = NULL;
8427     PetscInt  coneSize, closureSize, cl, Nv = 0;
8428 
8429     ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
8430     if ((PetscInt) ct < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has no cell type", c);
8431     if (ct == DM_POLYTOPE_UNKNOWN) continue;
8432     if (interp == DMPLEX_INTERPOLATED_FULL) {
8433       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8434       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));
8435     }
8436     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8437     for (cl = 0; cl < closureSize*2; cl += 2) {
8438       const PetscInt p = closure[cl];
8439       if ((p >= vStart) && (p < vEnd)) ++Nv;
8440     }
8441     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8442     /* Special Case: Tensor faces with identified vertices */
8443     if (Nv < DMPolytopeTypeGetNumVertices(ct)) {
8444       PetscInt unsplit;
8445 
8446       ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr);
8447       if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue;
8448     }
8449     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));
8450   }
8451   PetscFunctionReturn(0);
8452 }
8453 
8454 /*@
8455   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
8456 
8457   Not Collective
8458 
8459   Input Parameters:
8460 + dm - The DMPlex object
8461 - cellHeight - Normally 0
8462 
8463   Notes:
8464   This is a useful diagnostic when creating meshes programmatically.
8465   This routine is only relevant for meshes that are fully interpolated across all ranks.
8466   It will error out if a partially interpolated mesh is given on some rank.
8467   It will do nothing for locally uninterpolated mesh (as there is nothing to check).
8468 
8469   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8470 
8471   Level: developer
8472 
8473 .seealso: DMCreate(), DMPlexGetVTKCellHeight(), DMSetFromOptions()
8474 @*/
8475 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
8476 {
8477   PetscInt       dim, depth, vStart, vEnd, cStart, cEnd, c, h;
8478   PetscErrorCode ierr;
8479   DMPlexInterpolatedFlag interpEnum;
8480 
8481   PetscFunctionBegin;
8482   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8483   ierr = DMPlexIsInterpolated(dm, &interpEnum);CHKERRQ(ierr);
8484   if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0);
8485   if (interpEnum == DMPLEX_INTERPOLATED_PARTIAL) {
8486     PetscMPIInt rank;
8487     MPI_Comm    comm;
8488 
8489     ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
8490     ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
8491     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Mesh is only partially interpolated on rank %d, this is currently not supported", rank);
8492   }
8493 
8494   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8495   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8496   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8497   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
8498     ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr);
8499     for (c = cStart; c < cEnd; ++c) {
8500       const PetscInt      *cone, *ornt, *faceSizes, *faces;
8501       const DMPolytopeType *faceTypes;
8502       DMPolytopeType        ct;
8503       PetscInt              numFaces, coneSize, f;
8504       PetscInt             *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit;
8505 
8506       ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
8507       ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr);
8508       if (unsplit) continue;
8509       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8510       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8511       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
8512       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8513       for (cl = 0; cl < closureSize*2; cl += 2) {
8514         const PetscInt p = closure[cl];
8515         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
8516       }
8517       ierr = DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces);CHKERRQ(ierr);
8518       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);
8519       for (f = 0; f < numFaces; ++f) {
8520         DMPolytopeType fct;
8521         PetscInt       *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
8522 
8523         ierr = DMPlexGetCellType(dm, cone[f], &fct);CHKERRQ(ierr);
8524         ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
8525         for (cl = 0; cl < fclosureSize*2; cl += 2) {
8526           const PetscInt p = fclosure[cl];
8527           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
8528         }
8529         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]);
8530         for (v = 0; v < fnumCorners; ++v) {
8531           if (fclosure[v] != faces[fOff+v]) {
8532             PetscInt v1;
8533 
8534             ierr = PetscPrintf(PETSC_COMM_SELF, "face closure:");CHKERRQ(ierr);
8535             for (v1 = 0; v1 < fnumCorners; ++v1) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", fclosure[v1]);CHKERRQ(ierr);}
8536             ierr = PetscPrintf(PETSC_COMM_SELF, "\ncell face:");CHKERRQ(ierr);
8537             for (v1 = 0; v1 < fnumCorners; ++v1) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", faces[fOff+v1]);CHKERRQ(ierr);}
8538             ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8539             SETERRQ9(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D of type %s (cone idx %d, ornt %D) of cell %D of type %s vertex %D, %D != %D", cone[f], DMPolytopeTypes[fct], f, ornt[f], c, DMPolytopeTypes[ct], v, fclosure[v], faces[fOff+v]);
8540           }
8541         }
8542         ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
8543         fOff += faceSizes[f];
8544       }
8545       ierr = DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces);CHKERRQ(ierr);
8546       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8547     }
8548   }
8549   PetscFunctionReturn(0);
8550 }
8551 
8552 /*@
8553   DMPlexCheckGeometry - Check the geometry of mesh cells
8554 
8555   Input Parameter:
8556 . dm - The DMPlex object
8557 
8558   Notes:
8559   This is a useful diagnostic when creating meshes programmatically.
8560 
8561   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8562 
8563   Level: developer
8564 
8565 .seealso: DMCreate(), DMSetFromOptions()
8566 @*/
8567 PetscErrorCode DMPlexCheckGeometry(DM dm)
8568 {
8569   Vec            coordinates;
8570   PetscReal      detJ, J[9], refVol = 1.0;
8571   PetscReal      vol;
8572   PetscBool      periodic;
8573   PetscInt       dim, depth, dE, d, cStart, cEnd, c;
8574   PetscErrorCode ierr;
8575 
8576   PetscFunctionBegin;
8577   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8578   ierr = DMGetCoordinateDim(dm, &dE);CHKERRQ(ierr);
8579   if (dim != dE) PetscFunctionReturn(0);
8580   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8581   ierr = DMGetPeriodicity(dm, &periodic, NULL, NULL, NULL);CHKERRQ(ierr);
8582   for (d = 0; d < dim; ++d) refVol *= 2.0;
8583   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8584   /* Make sure local coordinates are created, because that step is collective */
8585   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8586   for (c = cStart; c < cEnd; ++c) {
8587     DMPolytopeType ct;
8588     PetscInt       unsplit;
8589     PetscBool      ignoreZeroVol = PETSC_FALSE;
8590 
8591     ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
8592     switch (ct) {
8593       case DM_POLYTOPE_SEG_PRISM_TENSOR:
8594       case DM_POLYTOPE_TRI_PRISM_TENSOR:
8595       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8596         ignoreZeroVol = PETSC_TRUE; break;
8597       default: break;
8598     }
8599     switch (ct) {
8600       case DM_POLYTOPE_TRI_PRISM:
8601       case DM_POLYTOPE_TRI_PRISM_TENSOR:
8602       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8603       case DM_POLYTOPE_PYRAMID:
8604         continue;
8605       default: break;
8606     }
8607     ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr);
8608     if (unsplit) continue;
8609     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);CHKERRQ(ierr);
8610     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);
8611     ierr = PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);CHKERRQ(ierr);
8612     if (depth > 1 && !periodic) {
8613       ierr = DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);CHKERRQ(ierr);
8614       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);
8615       ierr = PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);CHKERRQ(ierr);
8616     }
8617   }
8618   PetscFunctionReturn(0);
8619 }
8620 
8621 /*@
8622   DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex.
8623 
8624   Input Parameters:
8625 . dm - The DMPlex object
8626 
8627   Notes:
8628   This is mainly intended for debugging/testing purposes.
8629   It currently checks only meshes with no partition overlapping.
8630 
8631   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8632 
8633   Level: developer
8634 
8635 .seealso: DMGetPointSF(), DMSetFromOptions()
8636 @*/
8637 PetscErrorCode DMPlexCheckPointSF(DM dm)
8638 {
8639   PetscSF         pointSF;
8640   PetscInt        cellHeight, cStart, cEnd, l, nleaves, nroots, overlap;
8641   const PetscInt *locals, *rootdegree;
8642   PetscBool       distributed;
8643   PetscErrorCode  ierr;
8644 
8645   PetscFunctionBegin;
8646   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8647   ierr = DMGetPointSF(dm, &pointSF);CHKERRQ(ierr);
8648   ierr = DMPlexIsDistributed(dm, &distributed);CHKERRQ(ierr);
8649   if (!distributed) PetscFunctionReturn(0);
8650   ierr = DMPlexGetOverlap(dm, &overlap);CHKERRQ(ierr);
8651   if (overlap) {
8652     ierr = PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping");CHKERRQ(ierr);
8653     PetscFunctionReturn(0);
8654   }
8655   if (!pointSF) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but does not have PointSF attached");
8656   ierr = PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, NULL);CHKERRQ(ierr);
8657   if (nroots < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set");
8658   ierr = PetscSFComputeDegreeBegin(pointSF, &rootdegree);CHKERRQ(ierr);
8659   ierr = PetscSFComputeDegreeEnd(pointSF, &rootdegree);CHKERRQ(ierr);
8660 
8661   /* 1) check there are no faces in 2D, cells in 3D, in interface */
8662   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8663   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8664   for (l = 0; l < nleaves; ++l) {
8665     const PetscInt point = locals[l];
8666 
8667     if (point >= cStart && point < cEnd) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D which is a cell", point);
8668   }
8669 
8670   /* 2) if some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
8671   for (l = 0; l < nleaves; ++l) {
8672     const PetscInt  point = locals[l];
8673     const PetscInt *cone;
8674     PetscInt        coneSize, c, idx;
8675 
8676     ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
8677     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
8678     for (c = 0; c < coneSize; ++c) {
8679       if (!rootdegree[cone[c]]) {
8680         ierr = PetscFindInt(cone[c], nleaves, locals, &idx);CHKERRQ(ierr);
8681         if (idx < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D but not %D from its cone", point, cone[c]);
8682       }
8683     }
8684   }
8685   PetscFunctionReturn(0);
8686 }
8687 
8688 PetscErrorCode DMPlexCheckAll_Internal(DM dm, PetscInt cellHeight)
8689 {
8690   PetscErrorCode ierr;
8691 
8692   PetscFunctionBegin;
8693   ierr = DMPlexCheckSymmetry(dm);CHKERRQ(ierr);
8694   ierr = DMPlexCheckSkeleton(dm, cellHeight);CHKERRQ(ierr);
8695   ierr = DMPlexCheckFaces(dm, cellHeight);CHKERRQ(ierr);
8696   ierr = DMPlexCheckGeometry(dm);CHKERRQ(ierr);
8697   ierr = DMPlexCheckPointSF(dm);CHKERRQ(ierr);
8698   ierr = DMPlexCheckInterfaceCones(dm);CHKERRQ(ierr);
8699   PetscFunctionReturn(0);
8700 }
8701 
8702 typedef struct cell_stats
8703 {
8704   PetscReal min, max, sum, squaresum;
8705   PetscInt  count;
8706 } cell_stats_t;
8707 
8708 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
8709 {
8710   PetscInt i, N = *len;
8711 
8712   for (i = 0; i < N; i++) {
8713     cell_stats_t *A = (cell_stats_t *) a;
8714     cell_stats_t *B = (cell_stats_t *) b;
8715 
8716     B->min = PetscMin(A->min,B->min);
8717     B->max = PetscMax(A->max,B->max);
8718     B->sum += A->sum;
8719     B->squaresum += A->squaresum;
8720     B->count += A->count;
8721   }
8722 }
8723 
8724 /*@
8725   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
8726 
8727   Collective on dm
8728 
8729   Input Parameters:
8730 + dm        - The DMPlex object
8731 . output    - If true, statistics will be displayed on stdout
8732 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output
8733 
8734   Notes:
8735   This is mainly intended for debugging/testing purposes.
8736 
8737   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8738 
8739   Level: developer
8740 
8741 .seealso: DMSetFromOptions(), DMPlexComputeOrthogonalQuality()
8742 @*/
8743 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
8744 {
8745   DM             dmCoarse;
8746   cell_stats_t   stats, globalStats;
8747   MPI_Comm       comm = PetscObjectComm((PetscObject)dm);
8748   PetscReal      *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
8749   PetscReal      limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
8750   PetscInt       cdim, cStart, cEnd, c, eStart, eEnd, count = 0;
8751   PetscMPIInt    rank,size;
8752   PetscErrorCode ierr;
8753 
8754   PetscFunctionBegin;
8755   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8756   stats.min   = PETSC_MAX_REAL;
8757   stats.max   = PETSC_MIN_REAL;
8758   stats.sum   = stats.squaresum = 0.;
8759   stats.count = 0;
8760 
8761   ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr);
8762   ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
8763   ierr = DMGetCoordinateDim(dm,&cdim);CHKERRQ(ierr);
8764   ierr = PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ);CHKERRQ(ierr);
8765   ierr = DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd);CHKERRQ(ierr);
8766   ierr = DMPlexGetDepthStratum(dm,1,&eStart,&eEnd);CHKERRQ(ierr);
8767   for (c = cStart; c < cEnd; c++) {
8768     PetscInt  i;
8769     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
8770 
8771     ierr = DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);CHKERRQ(ierr);
8772     if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
8773     for (i = 0; i < PetscSqr(cdim); ++i) {
8774       frobJ    += J[i] * J[i];
8775       frobInvJ += invJ[i] * invJ[i];
8776     }
8777     cond2 = frobJ * frobInvJ;
8778     cond  = PetscSqrtReal(cond2);
8779 
8780     stats.min        = PetscMin(stats.min,cond);
8781     stats.max        = PetscMax(stats.max,cond);
8782     stats.sum       += cond;
8783     stats.squaresum += cond2;
8784     stats.count++;
8785     if (output && cond > limit) {
8786       PetscSection coordSection;
8787       Vec          coordsLocal;
8788       PetscScalar *coords = NULL;
8789       PetscInt     Nv, d, clSize, cl, *closure = NULL;
8790 
8791       ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8792       ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8793       ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr);
8794       ierr = PetscSynchronizedPrintf(comm, "[%d] Cell %D cond %g\n", rank, c, (double) cond);CHKERRQ(ierr);
8795       for (i = 0; i < Nv/cdim; ++i) {
8796         ierr = PetscSynchronizedPrintf(comm, "  Vertex %D: (", i);CHKERRQ(ierr);
8797         for (d = 0; d < cdim; ++d) {
8798           if (d > 0) {ierr = PetscSynchronizedPrintf(comm, ", ");CHKERRQ(ierr);}
8799           ierr = PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]));CHKERRQ(ierr);
8800         }
8801         ierr = PetscSynchronizedPrintf(comm, ")\n");CHKERRQ(ierr);
8802       }
8803       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
8804       for (cl = 0; cl < clSize*2; cl += 2) {
8805         const PetscInt edge = closure[cl];
8806 
8807         if ((edge >= eStart) && (edge < eEnd)) {
8808           PetscReal len;
8809 
8810           ierr = DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL);CHKERRQ(ierr);
8811           ierr = PetscSynchronizedPrintf(comm, "  Edge %D: length %g\n", edge, (double) len);CHKERRQ(ierr);
8812         }
8813       }
8814       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
8815       ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr);
8816     }
8817   }
8818   if (output) {ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);}
8819 
8820   if (size > 1) {
8821     PetscMPIInt   blockLengths[2] = {4,1};
8822     MPI_Aint      blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
8823     MPI_Datatype  blockTypes[2]   = {MPIU_REAL,MPIU_INT}, statType;
8824     MPI_Op        statReduce;
8825 
8826     ierr = MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);CHKERRMPI(ierr);
8827     ierr = MPI_Type_commit(&statType);CHKERRMPI(ierr);
8828     ierr = MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);CHKERRMPI(ierr);
8829     ierr = MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);CHKERRMPI(ierr);
8830     ierr = MPI_Op_free(&statReduce);CHKERRMPI(ierr);
8831     ierr = MPI_Type_free(&statType);CHKERRMPI(ierr);
8832   } else {
8833     ierr = PetscArraycpy(&globalStats,&stats,1);CHKERRQ(ierr);
8834   }
8835   if (rank == 0) {
8836     count = globalStats.count;
8837     min   = globalStats.min;
8838     max   = globalStats.max;
8839     mean  = globalStats.sum / globalStats.count;
8840     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
8841   }
8842 
8843   if (output) {
8844     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);
8845   }
8846   ierr = PetscFree2(J,invJ);CHKERRQ(ierr);
8847 
8848   ierr = DMGetCoarseDM(dm,&dmCoarse);CHKERRQ(ierr);
8849   if (dmCoarse) {
8850     PetscBool isplex;
8851 
8852     ierr = PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);CHKERRQ(ierr);
8853     if (isplex) {
8854       ierr = DMPlexCheckCellShape(dmCoarse,output,condLimit);CHKERRQ(ierr);
8855     }
8856   }
8857   PetscFunctionReturn(0);
8858 }
8859 
8860 /*@
8861   DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with
8862   orthogonal quality below given tolerance.
8863 
8864   Collective on dm
8865 
8866   Input Parameters:
8867 + dm   - The DMPlex object
8868 . fv   - Optional PetscFV object for pre-computed cell/face centroid information
8869 - atol - [0, 1] Absolute tolerance for tagging cells.
8870 
8871   Output Parameters:
8872 + OrthQual      - Vec containing orthogonal quality per cell
8873 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE
8874 
8875   Options Database Keys:
8876 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is
8877 supported.
8878 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector.
8879 
8880   Notes:
8881   Orthogonal quality is given by the following formula:
8882 
8883   \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]
8884 
8885   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
8886   is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the
8887   current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by
8888   calculating the cosine of the angle between these vectors.
8889 
8890   Orthogonal quality ranges from 1 (best) to 0 (worst).
8891 
8892   This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for
8893   pre-computed FVM cell data, but if it is not passed in then this data will be computed.
8894 
8895   Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance.
8896 
8897   Level: intermediate
8898 
8899 .seealso: DMPlexCheckCellShape(), DMCreateLabel()
8900 @*/
8901 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel)
8902 {
8903   PetscInt                nc, cellHeight, cStart, cEnd, cell, cellIter = 0;
8904   PetscInt                *idx;
8905   PetscScalar             *oqVals;
8906   const PetscScalar       *cellGeomArr, *faceGeomArr;
8907   PetscReal               *ci, *fi, *Ai;
8908   MPI_Comm                comm;
8909   Vec                     cellgeom, facegeom;
8910   DM                      dmFace, dmCell;
8911   IS                      glob;
8912   ISLocalToGlobalMapping  ltog;
8913   PetscViewer             vwr;
8914   PetscErrorCode          ierr;
8915 
8916   PetscFunctionBegin;
8917   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8918   if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);}
8919   PetscValidPointer(OrthQual, 4);
8920   if (PetscUnlikelyDebug(atol < 0.0 || atol > 1.0)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol);
8921   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
8922   ierr = DMGetDimension(dm, &nc);CHKERRQ(ierr);
8923   if (nc < 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %D)", nc);
8924   {
8925     DMPlexInterpolatedFlag interpFlag;
8926 
8927     ierr = DMPlexIsInterpolated(dm, &interpFlag);CHKERRQ(ierr);
8928     if (interpFlag != DMPLEX_INTERPOLATED_FULL) {
8929       PetscMPIInt rank;
8930 
8931       ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
8932       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank);
8933     }
8934   }
8935   if (OrthQualLabel) {
8936     PetscValidPointer(OrthQualLabel, 5);
8937     ierr = DMCreateLabel(dm, "Orthogonal_Quality");CHKERRQ(ierr);
8938     ierr = DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel);CHKERRQ(ierr);
8939   } else {*OrthQualLabel = NULL;}
8940   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8941   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8942   ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob);CHKERRQ(ierr);
8943   ierr = ISLocalToGlobalMappingCreateIS(glob, &ltog);CHKERRQ(ierr);
8944   ierr = ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH);CHKERRQ(ierr);
8945   ierr = VecCreate(comm, OrthQual);CHKERRQ(ierr);
8946   ierr = VecSetType(*OrthQual, VECSTANDARD);CHKERRQ(ierr);
8947   ierr = VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE);CHKERRQ(ierr);
8948   ierr = VecSetLocalToGlobalMapping(*OrthQual, ltog);CHKERRQ(ierr);
8949   ierr = VecSetUp(*OrthQual);CHKERRQ(ierr);
8950   ierr = ISDestroy(&glob);CHKERRQ(ierr);
8951   ierr = ISLocalToGlobalMappingDestroy(&ltog);CHKERRQ(ierr);
8952   ierr = DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL);CHKERRQ(ierr);
8953   ierr = VecGetArrayRead(cellgeom, &cellGeomArr);CHKERRQ(ierr);
8954   ierr = VecGetArrayRead(facegeom, &faceGeomArr);CHKERRQ(ierr);
8955   ierr = VecGetDM(cellgeom, &dmCell);CHKERRQ(ierr);
8956   ierr = VecGetDM(facegeom, &dmFace);CHKERRQ(ierr);
8957   ierr = PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai);CHKERRQ(ierr);
8958   for (cell = cStart; cell < cEnd; cellIter++,cell++) {
8959     PetscInt           cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE;
8960     PetscInt           cellarr[2], *adj = NULL;
8961     PetscScalar        *cArr, *fArr;
8962     PetscReal          minvalc = 1.0, minvalf = 1.0;
8963     PetscFVCellGeom    *cg;
8964 
8965     idx[cellIter] = cell-cStart;
8966     cellarr[0] = cell;
8967     /* Make indexing into cellGeom easier */
8968     ierr = DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg);CHKERRQ(ierr);
8969     ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj);CHKERRQ(ierr);
8970     /* Technically 1 too big, but easier than fiddling with empty adjacency array */
8971     ierr = PetscCalloc2(adjSize, &cArr, adjSize, &fArr);CHKERRQ(ierr);
8972     for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) {
8973       PetscInt         i;
8974       const PetscInt   neigh = adj[cellneigh];
8975       PetscReal        normci = 0, normfi = 0, normai = 0;
8976       PetscFVCellGeom  *cgneigh;
8977       PetscFVFaceGeom  *fg;
8978 
8979       /* Don't count ourselves in the neighbor list */
8980       if (neigh == cell) continue;
8981       ierr = DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh);CHKERRQ(ierr);
8982       cellarr[1] = neigh;
8983       {
8984         PetscInt       numcovpts;
8985         const PetscInt *covpts;
8986 
8987         ierr = DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts);CHKERRQ(ierr);
8988         ierr = DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg);CHKERRQ(ierr);
8989         ierr = DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts);CHKERRQ(ierr);
8990       }
8991 
8992       /* Compute c_i, f_i and their norms */
8993       for (i = 0; i < nc; i++) {
8994         ci[i] = cgneigh->centroid[i] - cg->centroid[i];
8995         fi[i] = fg->centroid[i] - cg->centroid[i];
8996         Ai[i] = fg->normal[i];
8997         normci += PetscPowReal(ci[i], 2);
8998         normfi += PetscPowReal(fi[i], 2);
8999         normai += PetscPowReal(Ai[i], 2);
9000       }
9001       normci = PetscSqrtReal(normci);
9002       normfi = PetscSqrtReal(normfi);
9003       normai = PetscSqrtReal(normai);
9004 
9005       /* Normalize and compute for each face-cell-normal pair */
9006       for (i = 0; i < nc; i++) {
9007         ci[i] = ci[i]/normci;
9008         fi[i] = fi[i]/normfi;
9009         Ai[i] = Ai[i]/normai;
9010         /* PetscAbs because I don't know if normals are guaranteed to point out */
9011         cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]);
9012         fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]);
9013       }
9014       if (PetscRealPart(cArr[cellneighiter]) < minvalc) {
9015         minvalc = PetscRealPart(cArr[cellneighiter]);
9016       }
9017       if (PetscRealPart(fArr[cellneighiter]) < minvalf) {
9018         minvalf = PetscRealPart(fArr[cellneighiter]);
9019       }
9020     }
9021     ierr = PetscFree(adj);CHKERRQ(ierr);
9022     ierr = PetscFree2(cArr, fArr);CHKERRQ(ierr);
9023     /* Defer to cell if they're equal */
9024     oqVals[cellIter] = PetscMin(minvalf, minvalc);
9025     if (OrthQualLabel) {
9026       if (PetscRealPart(oqVals[cellIter]) <= atol) {ierr = DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE);CHKERRQ(ierr);}
9027     }
9028   }
9029   ierr = VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES);CHKERRQ(ierr);
9030   ierr = VecAssemblyBegin(*OrthQual);CHKERRQ(ierr);
9031   ierr = VecAssemblyEnd(*OrthQual);CHKERRQ(ierr);
9032   ierr = VecRestoreArrayRead(cellgeom, &cellGeomArr);CHKERRQ(ierr);
9033   ierr = VecRestoreArrayRead(facegeom, &faceGeomArr);CHKERRQ(ierr);
9034   ierr = PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL);CHKERRQ(ierr);
9035   if (OrthQualLabel) {
9036     if (vwr) {ierr = DMLabelView(*OrthQualLabel, vwr);CHKERRQ(ierr);}
9037   }
9038   ierr = PetscFree5(idx, oqVals, ci, fi, Ai);CHKERRQ(ierr);
9039   ierr = PetscViewerDestroy(&vwr);CHKERRQ(ierr);
9040   ierr = VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view");CHKERRQ(ierr);
9041   PetscFunctionReturn(0);
9042 }
9043 
9044 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect
9045  * interpolator construction */
9046 static PetscErrorCode DMGetFullDM(DM dm, DM *odm)
9047 {
9048   PetscSection   section, newSection, gsection;
9049   PetscSF        sf;
9050   PetscBool      hasConstraints, ghasConstraints;
9051   PetscErrorCode ierr;
9052 
9053   PetscFunctionBegin;
9054   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9055   PetscValidPointer(odm,2);
9056   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
9057   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
9058   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRMPI(ierr);
9059   if (!ghasConstraints) {
9060     ierr = PetscObjectReference((PetscObject)dm);CHKERRQ(ierr);
9061     *odm = dm;
9062     PetscFunctionReturn(0);
9063   }
9064   ierr = DMClone(dm, odm);CHKERRQ(ierr);
9065   ierr = DMCopyFields(dm, *odm);CHKERRQ(ierr);
9066   ierr = DMGetLocalSection(*odm, &newSection);CHKERRQ(ierr);
9067   ierr = DMGetPointSF(*odm, &sf);CHKERRQ(ierr);
9068   ierr = PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
9069   ierr = DMSetGlobalSection(*odm, gsection);CHKERRQ(ierr);
9070   ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
9071   PetscFunctionReturn(0);
9072 }
9073 
9074 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift)
9075 {
9076   DM             dmco, dmfo;
9077   Mat            interpo;
9078   Vec            rscale;
9079   Vec            cglobalo, clocal;
9080   Vec            fglobal, fglobalo, flocal;
9081   PetscBool      regular;
9082   PetscErrorCode ierr;
9083 
9084   PetscFunctionBegin;
9085   ierr = DMGetFullDM(dmc, &dmco);CHKERRQ(ierr);
9086   ierr = DMGetFullDM(dmf, &dmfo);CHKERRQ(ierr);
9087   ierr = DMSetCoarseDM(dmfo, dmco);CHKERRQ(ierr);
9088   ierr = DMPlexGetRegularRefinement(dmf, &regular);CHKERRQ(ierr);
9089   ierr = DMPlexSetRegularRefinement(dmfo, regular);CHKERRQ(ierr);
9090   ierr = DMCreateInterpolation(dmco, dmfo, &interpo, &rscale);CHKERRQ(ierr);
9091   ierr = DMCreateGlobalVector(dmco, &cglobalo);CHKERRQ(ierr);
9092   ierr = DMCreateLocalVector(dmc, &clocal);CHKERRQ(ierr);
9093   ierr = VecSet(cglobalo, 0.);CHKERRQ(ierr);
9094   ierr = VecSet(clocal, 0.);CHKERRQ(ierr);
9095   ierr = DMCreateGlobalVector(dmf, &fglobal);CHKERRQ(ierr);
9096   ierr = DMCreateGlobalVector(dmfo, &fglobalo);CHKERRQ(ierr);
9097   ierr = DMCreateLocalVector(dmf, &flocal);CHKERRQ(ierr);
9098   ierr = VecSet(fglobal, 0.);CHKERRQ(ierr);
9099   ierr = VecSet(fglobalo, 0.);CHKERRQ(ierr);
9100   ierr = VecSet(flocal, 0.);CHKERRQ(ierr);
9101   ierr = DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL);CHKERRQ(ierr);
9102   ierr = DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo);CHKERRQ(ierr);
9103   ierr = DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo);CHKERRQ(ierr);
9104   ierr = MatMult(interpo, cglobalo, fglobalo);CHKERRQ(ierr);
9105   ierr = DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal);CHKERRQ(ierr);
9106   ierr = DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal);CHKERRQ(ierr);
9107   ierr = DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal);CHKERRQ(ierr);
9108   ierr = DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal);CHKERRQ(ierr);
9109   *shift = fglobal;
9110   ierr = VecDestroy(&flocal);CHKERRQ(ierr);
9111   ierr = VecDestroy(&fglobalo);CHKERRQ(ierr);
9112   ierr = VecDestroy(&clocal);CHKERRQ(ierr);
9113   ierr = VecDestroy(&cglobalo);CHKERRQ(ierr);
9114   ierr = VecDestroy(&rscale);CHKERRQ(ierr);
9115   ierr = MatDestroy(&interpo);CHKERRQ(ierr);
9116   ierr = DMDestroy(&dmfo);CHKERRQ(ierr);
9117   ierr = DMDestroy(&dmco);CHKERRQ(ierr);
9118   PetscFunctionReturn(0);
9119 }
9120 
9121 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
9122 {
9123   PetscObject    shifto;
9124   Vec            shift;
9125 
9126   PetscErrorCode ierr;
9127 
9128   PetscFunctionBegin;
9129   if (!interp) {
9130     Vec rscale;
9131 
9132     ierr = DMCreateInterpolation(coarse, fine, &interp, &rscale);CHKERRQ(ierr);
9133     ierr = VecDestroy(&rscale);CHKERRQ(ierr);
9134   } else {
9135     ierr = PetscObjectReference((PetscObject)interp);CHKERRQ(ierr);
9136   }
9137   ierr = PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto);CHKERRQ(ierr);
9138   if (!shifto) {
9139     ierr = DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift);CHKERRQ(ierr);
9140     ierr = PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift);CHKERRQ(ierr);
9141     shifto = (PetscObject) shift;
9142     ierr = VecDestroy(&shift);CHKERRQ(ierr);
9143   }
9144   shift = (Vec) shifto;
9145   ierr = MatInterpolate(interp, coarseSol, fineSol);CHKERRQ(ierr);
9146   ierr = VecAXPY(fineSol, 1.0, shift);CHKERRQ(ierr);
9147   ierr = MatDestroy(&interp);CHKERRQ(ierr);
9148   PetscFunctionReturn(0);
9149 }
9150 
9151 /* Pointwise interpolation
9152      Just code FEM for now
9153      u^f = I u^c
9154      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
9155      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
9156      I_{ij} = psi^f_i phi^c_j
9157 */
9158 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
9159 {
9160   PetscSection   gsc, gsf;
9161   PetscInt       m, n;
9162   void          *ctx;
9163   DM             cdm;
9164   PetscBool      regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE;
9165   PetscErrorCode ierr;
9166 
9167   PetscFunctionBegin;
9168   ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
9169   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
9170   ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
9171   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
9172 
9173   ierr = PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);CHKERRQ(ierr);
9174   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr);
9175   ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
9176   ierr = MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);CHKERRQ(ierr);
9177   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
9178 
9179   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
9180   ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
9181   if (!isRefined || (regular && cdm == dmCoarse)) {ierr = DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx);CHKERRQ(ierr);}
9182   else                                            {ierr = DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
9183   ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr);
9184   if (scaling) {
9185     /* Use naive scaling */
9186     ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr);
9187   }
9188   PetscFunctionReturn(0);
9189 }
9190 
9191 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
9192 {
9193   PetscErrorCode ierr;
9194   VecScatter     ctx;
9195 
9196   PetscFunctionBegin;
9197   ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);CHKERRQ(ierr);
9198   ierr = MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);CHKERRQ(ierr);
9199   ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr);
9200   PetscFunctionReturn(0);
9201 }
9202 
9203 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux,
9204                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
9205                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
9206                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
9207 {
9208   g0[0] = 1.0;
9209 }
9210 
9211 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
9212 {
9213   PetscSection   gsc, gsf;
9214   PetscInt       m, n;
9215   void          *ctx;
9216   DM             cdm;
9217   PetscBool      regular;
9218   PetscErrorCode ierr;
9219 
9220   PetscFunctionBegin;
9221   if (dmFine == dmCoarse) {
9222     DM       dmc;
9223     PetscDS  ds;
9224     Vec      u;
9225     IS       cellIS;
9226     PetscFormKey key;
9227     PetscInt depth;
9228 
9229     ierr = DMClone(dmFine, &dmc);CHKERRQ(ierr);
9230     ierr = DMCopyDisc(dmFine, dmc);CHKERRQ(ierr);
9231     ierr = DMGetDS(dmc, &ds);CHKERRQ(ierr);
9232     ierr = PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL);CHKERRQ(ierr);
9233     ierr = DMCreateMatrix(dmc, mass);CHKERRQ(ierr);
9234     ierr = DMGetGlobalVector(dmc, &u);CHKERRQ(ierr);
9235     ierr = DMPlexGetDepth(dmc, &depth);CHKERRQ(ierr);
9236     ierr = DMGetStratumIS(dmc, "depth", depth, &cellIS);CHKERRQ(ierr);
9237     ierr = MatZeroEntries(*mass);CHKERRQ(ierr);
9238     key.label = NULL;
9239     key.value = 0;
9240     key.field = 0;
9241     key.part  = 0;
9242     ierr = DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL);CHKERRQ(ierr);
9243     ierr = ISDestroy(&cellIS);CHKERRQ(ierr);
9244     ierr = DMRestoreGlobalVector(dmc, &u);CHKERRQ(ierr);
9245     ierr = DMDestroy(&dmc);CHKERRQ(ierr);
9246   } else {
9247     ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
9248     ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
9249     ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
9250     ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
9251 
9252     ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);CHKERRQ(ierr);
9253     ierr = MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
9254     ierr = MatSetType(*mass, dmCoarse->mattype);CHKERRQ(ierr);
9255     ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
9256 
9257     ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
9258     ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
9259     if (regular && cdm == dmCoarse) {ierr = DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
9260     else                            {ierr = DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
9261   }
9262   ierr = MatViewFromOptions(*mass, NULL, "-mass_mat_view");CHKERRQ(ierr);
9263   PetscFunctionReturn(0);
9264 }
9265 
9266 /*@
9267   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
9268 
9269   Input Parameter:
9270 . dm - The DMPlex object
9271 
9272   Output Parameter:
9273 . regular - The flag
9274 
9275   Level: intermediate
9276 
9277 .seealso: DMPlexSetRegularRefinement()
9278 @*/
9279 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
9280 {
9281   PetscFunctionBegin;
9282   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9283   PetscValidPointer(regular, 2);
9284   *regular = ((DM_Plex *) dm->data)->regularRefinement;
9285   PetscFunctionReturn(0);
9286 }
9287 
9288 /*@
9289   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
9290 
9291   Input Parameters:
9292 + dm - The DMPlex object
9293 - regular - The flag
9294 
9295   Level: intermediate
9296 
9297 .seealso: DMPlexGetRegularRefinement()
9298 @*/
9299 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
9300 {
9301   PetscFunctionBegin;
9302   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9303   ((DM_Plex *) dm->data)->regularRefinement = regular;
9304   PetscFunctionReturn(0);
9305 }
9306 
9307 /* anchors */
9308 /*@
9309   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
9310   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
9311 
9312   not collective
9313 
9314   Input Parameter:
9315 . dm - The DMPlex object
9316 
9317   Output Parameters:
9318 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
9319 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
9320 
9321   Level: intermediate
9322 
9323 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
9324 @*/
9325 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
9326 {
9327   DM_Plex *plex = (DM_Plex *)dm->data;
9328   PetscErrorCode ierr;
9329 
9330   PetscFunctionBegin;
9331   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9332   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);}
9333   if (anchorSection) *anchorSection = plex->anchorSection;
9334   if (anchorIS) *anchorIS = plex->anchorIS;
9335   PetscFunctionReturn(0);
9336 }
9337 
9338 /*@
9339   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
9340   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
9341   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
9342 
9343   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
9344   DMGetConstraints() and filling in the entries in the constraint matrix.
9345 
9346   collective on dm
9347 
9348   Input Parameters:
9349 + dm - The DMPlex object
9350 . 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).
9351 - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
9352 
9353   The reference counts of anchorSection and anchorIS are incremented.
9354 
9355   Level: intermediate
9356 
9357 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
9358 @*/
9359 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
9360 {
9361   DM_Plex        *plex = (DM_Plex *)dm->data;
9362   PetscMPIInt    result;
9363   PetscErrorCode ierr;
9364 
9365   PetscFunctionBegin;
9366   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9367   if (anchorSection) {
9368     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
9369     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRMPI(ierr);
9370     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
9371   }
9372   if (anchorIS) {
9373     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
9374     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRMPI(ierr);
9375     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
9376   }
9377 
9378   ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr);
9379   ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr);
9380   plex->anchorSection = anchorSection;
9381 
9382   ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr);
9383   ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr);
9384   plex->anchorIS = anchorIS;
9385 
9386   if (PetscUnlikelyDebug(anchorIS && anchorSection)) {
9387     PetscInt size, a, pStart, pEnd;
9388     const PetscInt *anchors;
9389 
9390     ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
9391     ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr);
9392     ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr);
9393     for (a = 0; a < size; a++) {
9394       PetscInt p;
9395 
9396       p = anchors[a];
9397       if (p >= pStart && p < pEnd) {
9398         PetscInt dof;
9399 
9400         ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
9401         if (dof) {
9402           PetscErrorCode ierr2;
9403 
9404           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
9405           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
9406         }
9407       }
9408     }
9409     ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr);
9410   }
9411   /* reset the generic constraints */
9412   ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr);
9413   PetscFunctionReturn(0);
9414 }
9415 
9416 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
9417 {
9418   PetscSection anchorSection;
9419   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
9420   PetscErrorCode ierr;
9421 
9422   PetscFunctionBegin;
9423   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9424   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
9425   ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr);
9426   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
9427   if (numFields) {
9428     PetscInt f;
9429     ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr);
9430 
9431     for (f = 0; f < numFields; f++) {
9432       PetscInt numComp;
9433 
9434       ierr = PetscSectionGetFieldComponents(section,f,&numComp);CHKERRQ(ierr);
9435       ierr = PetscSectionSetFieldComponents(*cSec,f,numComp);CHKERRQ(ierr);
9436     }
9437   }
9438   ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
9439   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
9440   pStart = PetscMax(pStart,sStart);
9441   pEnd   = PetscMin(pEnd,sEnd);
9442   pEnd   = PetscMax(pStart,pEnd);
9443   ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr);
9444   for (p = pStart; p < pEnd; p++) {
9445     ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
9446     if (dof) {
9447       ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
9448       ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr);
9449       for (f = 0; f < numFields; f++) {
9450         ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
9451         ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr);
9452       }
9453     }
9454   }
9455   ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr);
9456   ierr = PetscObjectSetName((PetscObject) *cSec, "Constraint Section");CHKERRQ(ierr);
9457   PetscFunctionReturn(0);
9458 }
9459 
9460 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
9461 {
9462   PetscSection   aSec;
9463   PetscInt       pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
9464   const PetscInt *anchors;
9465   PetscInt       numFields, f;
9466   IS             aIS;
9467   PetscErrorCode ierr;
9468   MatType        mtype;
9469   PetscBool      iscuda,iskokkos;
9470 
9471   PetscFunctionBegin;
9472   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9473   ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr);
9474   ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr);
9475   ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr);
9476   ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr);
9477   ierr = PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda);CHKERRQ(ierr);
9478   if (!iscuda) { ierr = PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda);CHKERRQ(ierr); }
9479   ierr = PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos);CHKERRQ(ierr);
9480   if (!iskokkos) { ierr = PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos);CHKERRQ(ierr); }
9481   if (iscuda) mtype = MATSEQAIJCUSPARSE;
9482   else if (iskokkos) mtype = MATSEQAIJKOKKOS;
9483   else mtype = MATSEQAIJ;
9484   ierr = MatSetType(*cMat,mtype);CHKERRQ(ierr);
9485   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
9486   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
9487   /* cSec will be a subset of aSec and section */
9488   ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
9489   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
9490   ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr);
9491   i[0] = 0;
9492   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
9493   for (p = pStart; p < pEnd; p++) {
9494     PetscInt rDof, rOff, r;
9495 
9496     ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
9497     if (!rDof) continue;
9498     ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
9499     if (numFields) {
9500       for (f = 0; f < numFields; f++) {
9501         annz = 0;
9502         for (r = 0; r < rDof; r++) {
9503           a = anchors[rOff + r];
9504           if (a < sStart || a >= sEnd) continue;
9505           ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
9506           annz += aDof;
9507         }
9508         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
9509         ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr);
9510         for (q = 0; q < dof; q++) {
9511           i[off + q + 1] = i[off + q] + annz;
9512         }
9513       }
9514     } else {
9515       annz = 0;
9516       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
9517       for (q = 0; q < dof; q++) {
9518         a = anchors[rOff + q];
9519         if (a < sStart || a >= sEnd) continue;
9520         ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
9521         annz += aDof;
9522       }
9523       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
9524       ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr);
9525       for (q = 0; q < dof; q++) {
9526         i[off + q + 1] = i[off + q] + annz;
9527       }
9528     }
9529   }
9530   nnz = i[m];
9531   ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr);
9532   offset = 0;
9533   for (p = pStart; p < pEnd; p++) {
9534     if (numFields) {
9535       for (f = 0; f < numFields; f++) {
9536         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
9537         for (q = 0; q < dof; q++) {
9538           PetscInt rDof, rOff, r;
9539           ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
9540           ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
9541           for (r = 0; r < rDof; r++) {
9542             PetscInt s;
9543 
9544             a = anchors[rOff + r];
9545             if (a < sStart || a >= sEnd) continue;
9546             ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
9547             ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr);
9548             for (s = 0; s < aDof; s++) {
9549               j[offset++] = aOff + s;
9550             }
9551           }
9552         }
9553       }
9554     } else {
9555       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
9556       for (q = 0; q < dof; q++) {
9557         PetscInt rDof, rOff, r;
9558         ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
9559         ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
9560         for (r = 0; r < rDof; r++) {
9561           PetscInt s;
9562 
9563           a = anchors[rOff + r];
9564           if (a < sStart || a >= sEnd) continue;
9565           ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
9566           ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr);
9567           for (s = 0; s < aDof; s++) {
9568             j[offset++] = aOff + s;
9569           }
9570         }
9571       }
9572     }
9573   }
9574   ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr);
9575   ierr = PetscFree(i);CHKERRQ(ierr);
9576   ierr = PetscFree(j);CHKERRQ(ierr);
9577   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
9578   PetscFunctionReturn(0);
9579 }
9580 
9581 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
9582 {
9583   DM_Plex        *plex = (DM_Plex *)dm->data;
9584   PetscSection   anchorSection, section, cSec;
9585   Mat            cMat;
9586   PetscErrorCode ierr;
9587 
9588   PetscFunctionBegin;
9589   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9590   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
9591   if (anchorSection) {
9592     PetscInt Nf;
9593 
9594     ierr = DMGetLocalSection(dm,&section);CHKERRQ(ierr);
9595     ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr);
9596     ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr);
9597     ierr = DMGetNumFields(dm,&Nf);CHKERRQ(ierr);
9598     if (Nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);}
9599     ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr);
9600     ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr);
9601     ierr = MatDestroy(&cMat);CHKERRQ(ierr);
9602   }
9603   PetscFunctionReturn(0);
9604 }
9605 
9606 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
9607 {
9608   IS             subis;
9609   PetscSection   section, subsection;
9610   PetscErrorCode ierr;
9611 
9612   PetscFunctionBegin;
9613   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
9614   if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
9615   if (!subdm)   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
9616   /* Create subdomain */
9617   ierr = DMPlexFilter(dm, label, value, subdm);CHKERRQ(ierr);
9618   /* Create submodel */
9619   ierr = DMPlexGetSubpointIS(*subdm, &subis);CHKERRQ(ierr);
9620   ierr = PetscSectionCreateSubmeshSection(section, subis, &subsection);CHKERRQ(ierr);
9621   ierr = DMSetLocalSection(*subdm, subsection);CHKERRQ(ierr);
9622   ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
9623   ierr = DMCopyDisc(dm, *subdm);CHKERRQ(ierr);
9624   /* Create map from submodel to global model */
9625   if (is) {
9626     PetscSection    sectionGlobal, subsectionGlobal;
9627     IS              spIS;
9628     const PetscInt *spmap;
9629     PetscInt       *subIndices;
9630     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
9631     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
9632 
9633     ierr = DMPlexGetSubpointIS(*subdm, &spIS);CHKERRQ(ierr);
9634     ierr = ISGetIndices(spIS, &spmap);CHKERRQ(ierr);
9635     ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
9636     ierr = DMGetGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
9637     ierr = DMGetGlobalSection(*subdm, &subsectionGlobal);CHKERRQ(ierr);
9638     ierr = PetscSectionGetChart(subsection, &pStart, &pEnd);CHKERRQ(ierr);
9639     for (p = pStart; p < pEnd; ++p) {
9640       PetscInt gdof, pSubSize  = 0;
9641 
9642       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
9643       if (gdof > 0) {
9644         for (f = 0; f < Nf; ++f) {
9645           PetscInt fdof, fcdof;
9646 
9647           ierr     = PetscSectionGetFieldDof(subsection, p, f, &fdof);CHKERRQ(ierr);
9648           ierr     = PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);CHKERRQ(ierr);
9649           pSubSize += fdof-fcdof;
9650         }
9651         subSize += pSubSize;
9652         if (pSubSize) {
9653           if (bs < 0) {
9654             bs = pSubSize;
9655           } else if (bs != pSubSize) {
9656             /* Layout does not admit a pointwise block size */
9657             bs = 1;
9658           }
9659         }
9660       }
9661     }
9662     /* Must have same blocksize on all procs (some might have no points) */
9663     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
9664     ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr);
9665     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
9666     else                            {bs = bsMinMax[0];}
9667     ierr = PetscMalloc1(subSize, &subIndices);CHKERRQ(ierr);
9668     for (p = pStart; p < pEnd; ++p) {
9669       PetscInt gdof, goff;
9670 
9671       ierr = PetscSectionGetDof(subsectionGlobal, p, &gdof);CHKERRQ(ierr);
9672       if (gdof > 0) {
9673         const PetscInt point = spmap[p];
9674 
9675         ierr = PetscSectionGetOffset(sectionGlobal, point, &goff);CHKERRQ(ierr);
9676         for (f = 0; f < Nf; ++f) {
9677           PetscInt fdof, fcdof, fc, f2, poff = 0;
9678 
9679           /* Can get rid of this loop by storing field information in the global section */
9680           for (f2 = 0; f2 < f; ++f2) {
9681             ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
9682             ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
9683             poff += fdof-fcdof;
9684           }
9685           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
9686           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
9687           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
9688             subIndices[subOff] = goff+poff+fc;
9689           }
9690         }
9691       }
9692     }
9693     ierr = ISRestoreIndices(spIS, &spmap);CHKERRQ(ierr);
9694     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);
9695     if (bs > 1) {
9696       /* We need to check that the block size does not come from non-contiguous fields */
9697       PetscInt i, j, set = 1;
9698       for (i = 0; i < subSize; i += bs) {
9699         for (j = 0; j < bs; ++j) {
9700           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
9701         }
9702       }
9703       if (set) {ierr = ISSetBlockSize(*is, bs);CHKERRQ(ierr);}
9704     }
9705     /* Attach nullspace */
9706     for (f = 0; f < Nf; ++f) {
9707       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
9708       if ((*subdm)->nullspaceConstructors[f]) break;
9709     }
9710     if (f < Nf) {
9711       MatNullSpace nullSpace;
9712       ierr = (*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace);CHKERRQ(ierr);
9713 
9714       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
9715       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
9716     }
9717   }
9718   PetscFunctionReturn(0);
9719 }
9720 
9721 /*@
9722   DMPlexMonitorThroughput - Report the cell throughput of FE integration
9723 
9724   Input Parameter:
9725 - dm - The DM
9726 
9727   Level: developer
9728 
9729   Options Database Keys:
9730 . -dm_plex_monitor_throughput - Activate the monitor
9731 
9732 .seealso: DMSetFromOptions(), DMPlexCreate()
9733 @*/
9734 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy)
9735 {
9736 #if defined(PETSC_USE_LOG)
9737   PetscStageLog      stageLog;
9738   PetscLogEvent      event;
9739   PetscLogStage      stage;
9740   PetscEventPerfInfo eventInfo;
9741   PetscReal          cellRate, flopRate;
9742   PetscInt           cStart, cEnd, Nf, N;
9743   const char        *name;
9744   PetscErrorCode     ierr;
9745 #endif
9746 
9747   PetscFunctionBegin;
9748   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9749 #if defined(PETSC_USE_LOG)
9750   ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
9751   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9752   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
9753   ierr = PetscLogGetStageLog(&stageLog);CHKERRQ(ierr);
9754   ierr = PetscStageLogGetCurrent(stageLog, &stage);CHKERRQ(ierr);
9755   ierr = PetscLogEventGetId("DMPlexResidualFE", &event);CHKERRQ(ierr);
9756   ierr = PetscLogEventGetPerfInfo(stage, event, &eventInfo);CHKERRQ(ierr);
9757   N        = (cEnd - cStart)*Nf*eventInfo.count;
9758   flopRate = eventInfo.flops/eventInfo.time;
9759   cellRate = N/eventInfo.time;
9760   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);
9761 #else
9762   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log.");
9763 #endif
9764   PetscFunctionReturn(0);
9765 }
9766