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