xref: /petsc/src/dm/impls/plex/plex.c (revision b122ec5aa1bd4469eb4e0673542fb7de3f411254)
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,DMPLEX_TopologyView,DMPLEX_LabelsView,DMPLEX_CoordinatesView,DMPLEX_SectionView,DMPLEX_GlobalVectorView,DMPLEX_LocalVectorView,DMPLEX_TopologyLoad,DMPLEX_LabelsLoad,DMPLEX_CoordinatesLoad,DMPLEX_SectionLoad,DMPLEX_GlobalVectorLoad,DMPLEX_LocalVectorLoad;
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 
37   PetscFunctionBegin;
38   CHKERRQ(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
39   if (cEnd <= cStart) {*simplex = PETSC_FALSE; PetscFunctionReturn(0);}
40   CHKERRQ(DMPlexGetCellType(dm, cStart, &ct));
41   *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
42   PetscFunctionReturn(0);
43 }
44 
45 /*@
46   DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells
47 
48   Input Parameters:
49 + dm     - The DMPlex object
50 - height - The cell height in the Plex, 0 is the default
51 
52   Output Parameters:
53 + cStart - The first "normal" cell
54 - cEnd   - The upper bound on "normal"" cells
55 
56   Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
57 
58   Level: developer
59 
60 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum()
61 @*/
62 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd)
63 {
64   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
65   PetscInt       cS, cE, c;
66 
67   PetscFunctionBegin;
68   CHKERRQ(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE));
69   for (c = cS; c < cE; ++c) {
70     DMPolytopeType cct;
71 
72     CHKERRQ(DMPlexGetCellType(dm, c, &cct));
73     if ((PetscInt) cct < 0) break;
74     switch (cct) {
75       case DM_POLYTOPE_POINT:
76       case DM_POLYTOPE_SEGMENT:
77       case DM_POLYTOPE_TRIANGLE:
78       case DM_POLYTOPE_QUADRILATERAL:
79       case DM_POLYTOPE_TETRAHEDRON:
80       case DM_POLYTOPE_HEXAHEDRON:
81         ct = cct;
82         break;
83       default: break;
84     }
85     if (ct != DM_POLYTOPE_UNKNOWN) break;
86   }
87   if (ct != DM_POLYTOPE_UNKNOWN) {
88     DMLabel ctLabel;
89 
90     CHKERRQ(DMPlexGetCellTypeLabel(dm, &ctLabel));
91     CHKERRQ(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE));
92   }
93   if (cStart) *cStart = cS;
94   if (cEnd)   *cEnd   = cE;
95   PetscFunctionReturn(0);
96 }
97 
98 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
99 {
100   PetscInt       cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd;
101   PetscInt       vcdof[2] = {0,0}, globalvcdof[2];
102 
103   PetscFunctionBegin;
104   *ft  = PETSC_VTK_INVALID;
105   CHKERRQ(DMGetCoordinateDim(dm, &cdim));
106   CHKERRQ(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
107   CHKERRQ(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
108   CHKERRQ(PetscSectionGetChart(section, &pStart, &pEnd));
109   if (field >= 0) {
110     if ((vStart >= pStart) && (vStart < pEnd)) CHKERRQ(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]));
111     if ((cStart >= pStart) && (cStart < pEnd)) CHKERRQ(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]));
112   } else {
113     if ((vStart >= pStart) && (vStart < pEnd)) CHKERRQ(PetscSectionGetDof(section, vStart, &vcdof[0]));
114     if ((cStart >= pStart) && (cStart < pEnd)) CHKERRQ(PetscSectionGetDof(section, cStart, &vcdof[1]));
115   }
116   CHKERRMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
117   if (globalvcdof[0]) {
118     *sStart = vStart;
119     *sEnd   = vEnd;
120     if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
121     else                        *ft = PETSC_VTK_POINT_FIELD;
122   } else if (globalvcdof[1]) {
123     *sStart = cStart;
124     *sEnd   = cEnd;
125     if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
126     else                        *ft = PETSC_VTK_CELL_FIELD;
127   } else {
128     if (field >= 0) {
129       const char *fieldname;
130 
131       CHKERRQ(PetscSectionGetFieldName(section, field, &fieldname));
132       CHKERRQ(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section field %D \"%s\"\n", field, fieldname));
133     } else {
134       CHKERRQ(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section\"%s\"\n"));
135     }
136   }
137   PetscFunctionReturn(0);
138 }
139 
140 /*@
141   DMPlexVecView1D - Plot many 1D solutions on the same line graph
142 
143   Collective on dm
144 
145   Input Parameters:
146 + dm - The DMPlex
147 . n  - The number of vectors
148 . u  - The array of local vectors
149 - viewer - The Draw viewer
150 
151   Level: advanced
152 
153 .seealso: VecViewFromOptions(), VecView()
154 @*/
155 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer)
156 {
157   PetscDS            ds;
158   PetscDraw          draw = NULL;
159   PetscDrawLG        lg;
160   Vec                coordinates;
161   const PetscScalar *coords, **sol;
162   PetscReal         *vals;
163   PetscInt          *Nc;
164   PetscInt           Nf, f, c, Nl, l, i, vStart, vEnd, v;
165   char             **names;
166 
167   PetscFunctionBegin;
168   CHKERRQ(DMGetDS(dm, &ds));
169   CHKERRQ(PetscDSGetNumFields(ds, &Nf));
170   CHKERRQ(PetscDSGetTotalComponents(ds, &Nl));
171   CHKERRQ(PetscDSGetComponents(ds, &Nc));
172 
173   CHKERRQ(PetscViewerDrawGetDraw(viewer, 0, &draw));
174   if (!draw) PetscFunctionReturn(0);
175   CHKERRQ(PetscDrawLGCreate(draw, n*Nl, &lg));
176 
177   CHKERRQ(PetscMalloc3(n, &sol, n*Nl, &names, n*Nl, &vals));
178   for (i = 0, l = 0; i < n; ++i) {
179     const char *vname;
180 
181     CHKERRQ(PetscObjectGetName((PetscObject) u[i], &vname));
182     for (f = 0; f < Nf; ++f) {
183       PetscObject disc;
184       const char *fname;
185       char        tmpname[PETSC_MAX_PATH_LEN];
186 
187       CHKERRQ(PetscDSGetDiscretization(ds, f, &disc));
188       /* TODO Create names for components */
189       for (c = 0; c < Nc[f]; ++c, ++l) {
190         CHKERRQ(PetscObjectGetName(disc, &fname));
191         CHKERRQ(PetscStrcpy(tmpname, vname));
192         CHKERRQ(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN));
193         CHKERRQ(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN));
194         CHKERRQ(PetscStrallocpy(tmpname, &names[l]));
195       }
196     }
197   }
198   CHKERRQ(PetscDrawLGSetLegend(lg, (const char *const *) names));
199   /* Just add P_1 support for now */
200   CHKERRQ(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
201   CHKERRQ(DMGetCoordinatesLocal(dm, &coordinates));
202   CHKERRQ(VecGetArrayRead(coordinates, &coords));
203   for (i = 0; i < n; ++i) CHKERRQ(VecGetArrayRead(u[i], &sol[i]));
204   for (v = vStart; v < vEnd; ++v) {
205     PetscScalar *x, *svals;
206 
207     CHKERRQ(DMPlexPointLocalRead(dm, v, coords, &x));
208     for (i = 0; i < n; ++i) {
209       CHKERRQ(DMPlexPointLocalRead(dm, v, sol[i], &svals));
210       for (l = 0; l < Nl; ++l) vals[i*Nl + l] = PetscRealPart(svals[l]);
211     }
212     CHKERRQ(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals));
213   }
214   CHKERRQ(VecRestoreArrayRead(coordinates, &coords));
215   for (i = 0; i < n; ++i) CHKERRQ(VecRestoreArrayRead(u[i], &sol[i]));
216   for (l = 0; l < n*Nl; ++l) CHKERRQ(PetscFree(names[l]));
217   CHKERRQ(PetscFree3(sol, names, vals));
218 
219   CHKERRQ(PetscDrawLGDraw(lg));
220   CHKERRQ(PetscDrawLGDestroy(&lg));
221   PetscFunctionReturn(0);
222 }
223 
224 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer)
225 {
226   DM             dm;
227 
228   PetscFunctionBegin;
229   CHKERRQ(VecGetDM(u, &dm));
230   CHKERRQ(DMPlexVecView1D(dm, 1, &u, viewer));
231   PetscFunctionReturn(0);
232 }
233 
234 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer)
235 {
236   DM                 dm;
237   PetscSection       s;
238   PetscDraw          draw, popup;
239   DM                 cdm;
240   PetscSection       coordSection;
241   Vec                coordinates;
242   const PetscScalar *coords, *array;
243   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
244   PetscReal          vbound[2], time;
245   PetscBool          flg;
246   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
247   const char        *name;
248   char               title[PETSC_MAX_PATH_LEN];
249 
250   PetscFunctionBegin;
251   CHKERRQ(PetscViewerDrawGetDraw(viewer, 0, &draw));
252   CHKERRQ(VecGetDM(v, &dm));
253   CHKERRQ(DMGetCoordinateDim(dm, &dim));
254   CHKERRQ(DMGetLocalSection(dm, &s));
255   CHKERRQ(PetscSectionGetNumFields(s, &Nf));
256   CHKERRQ(DMGetCoarsenLevel(dm, &level));
257   CHKERRQ(DMGetCoordinateDM(dm, &cdm));
258   CHKERRQ(DMGetLocalSection(cdm, &coordSection));
259   CHKERRQ(DMGetCoordinatesLocal(dm, &coordinates));
260   CHKERRQ(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
261   CHKERRQ(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
262 
263   CHKERRQ(PetscObjectGetName((PetscObject) v, &name));
264   CHKERRQ(DMGetOutputSequenceNumber(dm, &step, &time));
265 
266   CHKERRQ(VecGetLocalSize(coordinates, &N));
267   CHKERRQ(VecGetArrayRead(coordinates, &coords));
268   for (c = 0; c < N; c += dim) {
269     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
270     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
271   }
272   CHKERRQ(VecRestoreArrayRead(coordinates, &coords));
273   CHKERRQ(PetscDrawClear(draw));
274 
275   /* Could implement something like DMDASelectFields() */
276   for (f = 0; f < Nf; ++f) {
277     DM   fdm = dm;
278     Vec  fv  = v;
279     IS   fis;
280     char prefix[PETSC_MAX_PATH_LEN];
281     const char *fname;
282 
283     CHKERRQ(PetscSectionGetFieldComponents(s, f, &Nc));
284     CHKERRQ(PetscSectionGetFieldName(s, f, &fname));
285 
286     if (v->hdr.prefix) CHKERRQ(PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix)));
287     else               {prefix[0] = '\0';}
288     if (Nf > 1) {
289       CHKERRQ(DMCreateSubDM(dm, 1, &f, &fis, &fdm));
290       CHKERRQ(VecGetSubVector(v, fis, &fv));
291       CHKERRQ(PetscStrlcat(prefix, fname,sizeof(prefix)));
292       CHKERRQ(PetscStrlcat(prefix, "_",sizeof(prefix)));
293     }
294     for (comp = 0; comp < Nc; ++comp, ++w) {
295       PetscInt nmax = 2;
296 
297       CHKERRQ(PetscViewerDrawGetDraw(viewer, w, &draw));
298       if (Nc > 1) CHKERRQ(PetscSNPrintf(title, sizeof(title), "%s:%s_%D Step: %D Time: %.4g", name, fname, comp, step, time));
299       else        CHKERRQ(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %D Time: %.4g", name, fname, step, time));
300       CHKERRQ(PetscDrawSetTitle(draw, title));
301 
302       /* TODO Get max and min only for this component */
303       CHKERRQ(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg));
304       if (!flg) {
305         CHKERRQ(VecMin(fv, NULL, &vbound[0]));
306         CHKERRQ(VecMax(fv, NULL, &vbound[1]));
307         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
308       }
309       CHKERRQ(PetscDrawGetPopup(draw, &popup));
310       CHKERRQ(PetscDrawScalePopup(popup, vbound[0], vbound[1]));
311       CHKERRQ(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]));
312 
313       CHKERRQ(VecGetArrayRead(fv, &array));
314       for (c = cStart; c < cEnd; ++c) {
315         PetscScalar *coords = NULL, *a = NULL;
316         PetscInt     numCoords, color[4] = {-1,-1,-1,-1};
317 
318         CHKERRQ(DMPlexPointLocalRead(fdm, c, array, &a));
319         if (a) {
320           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
321           color[1] = color[2] = color[3] = color[0];
322         } else {
323           PetscScalar *vals = NULL;
324           PetscInt     numVals, va;
325 
326           CHKERRQ(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals));
327           PetscCheckFalse(numVals % Nc,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);
328           switch (numVals/Nc) {
329           case 3: /* P1 Triangle */
330           case 4: /* P1 Quadrangle */
331             for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]);
332             break;
333           case 6: /* P2 Triangle */
334           case 8: /* P2 Quadrangle */
335             for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]);
336             break;
337           default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc);
338           }
339           CHKERRQ(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals));
340         }
341         CHKERRQ(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords));
342         switch (numCoords) {
343         case 6:
344         case 12: /* Localized triangle */
345           CHKERRQ(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]));
346           break;
347         case 8:
348         case 16: /* Localized quadrilateral */
349           CHKERRQ(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]));
350           CHKERRQ(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]));
351           break;
352         default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
353         }
354         CHKERRQ(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords));
355       }
356       CHKERRQ(VecRestoreArrayRead(fv, &array));
357       CHKERRQ(PetscDrawFlush(draw));
358       CHKERRQ(PetscDrawPause(draw));
359       CHKERRQ(PetscDrawSave(draw));
360     }
361     if (Nf > 1) {
362       CHKERRQ(VecRestoreSubVector(v, fis, &fv));
363       CHKERRQ(ISDestroy(&fis));
364       CHKERRQ(DMDestroy(&fdm));
365     }
366   }
367   PetscFunctionReturn(0);
368 }
369 
370 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
371 {
372   DM        dm;
373   PetscDraw draw;
374   PetscInt  dim;
375   PetscBool isnull;
376 
377   PetscFunctionBegin;
378   CHKERRQ(PetscViewerDrawGetDraw(viewer, 0, &draw));
379   CHKERRQ(PetscDrawIsNull(draw, &isnull));
380   if (isnull) PetscFunctionReturn(0);
381 
382   CHKERRQ(VecGetDM(v, &dm));
383   CHKERRQ(DMGetCoordinateDim(dm, &dim));
384   switch (dim) {
385   case 1: CHKERRQ(VecView_Plex_Local_Draw_1D(v, viewer));break;
386   case 2: CHKERRQ(VecView_Plex_Local_Draw_2D(v, viewer));break;
387   default: SETERRQ(PetscObjectComm((PetscObject) v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim);
388   }
389   PetscFunctionReturn(0);
390 }
391 
392 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
393 {
394   DM                      dm;
395   Vec                     locv;
396   const char              *name;
397   PetscSection            section;
398   PetscInt                pStart, pEnd;
399   PetscInt                numFields;
400   PetscViewerVTKFieldType ft;
401 
402   PetscFunctionBegin;
403   CHKERRQ(VecGetDM(v, &dm));
404   CHKERRQ(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */
405   CHKERRQ(PetscObjectGetName((PetscObject) v, &name));
406   CHKERRQ(PetscObjectSetName((PetscObject) locv, name));
407   CHKERRQ(VecCopy(v, locv));
408   CHKERRQ(DMGetLocalSection(dm, &section));
409   CHKERRQ(PetscSectionGetNumFields(section, &numFields));
410   if (!numFields) {
411     CHKERRQ(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft));
412     CHKERRQ(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv));
413   } else {
414     PetscInt f;
415 
416     for (f = 0; f < numFields; f++) {
417       CHKERRQ(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft));
418       if (ft == PETSC_VTK_INVALID) continue;
419       CHKERRQ(PetscObjectReference((PetscObject)locv));
420       CHKERRQ(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv));
421     }
422     CHKERRQ(VecDestroy(&locv));
423   }
424   PetscFunctionReturn(0);
425 }
426 
427 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
428 {
429   DM             dm;
430   PetscBool      isvtk, ishdf5, isdraw, isglvis;
431 
432   PetscFunctionBegin;
433   CHKERRQ(VecGetDM(v, &dm));
434   PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
435   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk));
436   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5));
437   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw));
438   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis));
439   if (isvtk || ishdf5 || isdraw || isglvis) {
440     PetscInt    i,numFields;
441     PetscObject fe;
442     PetscBool   fem = PETSC_FALSE;
443     Vec         locv = v;
444     const char  *name;
445     PetscInt    step;
446     PetscReal   time;
447 
448     CHKERRQ(DMGetNumFields(dm, &numFields));
449     for (i=0; i<numFields; i++) {
450       CHKERRQ(DMGetField(dm, i, NULL, &fe));
451       if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; }
452     }
453     if (fem) {
454       PetscObject isZero;
455 
456       CHKERRQ(DMGetLocalVector(dm, &locv));
457       CHKERRQ(PetscObjectGetName((PetscObject) v, &name));
458       CHKERRQ(PetscObjectSetName((PetscObject) locv, name));
459       CHKERRQ(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero));
460       CHKERRQ(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero));
461       CHKERRQ(VecCopy(v, locv));
462       CHKERRQ(DMGetOutputSequenceNumber(dm, NULL, &time));
463       CHKERRQ(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL));
464     }
465     if (isvtk) {
466       CHKERRQ(VecView_Plex_Local_VTK(locv, viewer));
467     } else if (ishdf5) {
468 #if defined(PETSC_HAVE_HDF5)
469       CHKERRQ(VecView_Plex_Local_HDF5_Internal(locv, viewer));
470 #else
471       SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
472 #endif
473     } else if (isdraw) {
474       CHKERRQ(VecView_Plex_Local_Draw(locv, viewer));
475     } else if (isglvis) {
476       CHKERRQ(DMGetOutputSequenceNumber(dm, &step, NULL));
477       CHKERRQ(PetscViewerGLVisSetSnapId(viewer, step));
478       CHKERRQ(VecView_GLVis(locv, viewer));
479     }
480     if (fem) {
481       CHKERRQ(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL));
482       CHKERRQ(DMRestoreLocalVector(dm, &locv));
483     }
484   } else {
485     PetscBool isseq;
486 
487     CHKERRQ(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq));
488     if (isseq) CHKERRQ(VecView_Seq(v, viewer));
489     else       CHKERRQ(VecView_MPI(v, viewer));
490   }
491   PetscFunctionReturn(0);
492 }
493 
494 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
495 {
496   DM        dm;
497   PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii;
498 
499   PetscFunctionBegin;
500   CHKERRQ(VecGetDM(v, &dm));
501   PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
502   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,      &isvtk));
503   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5));
504   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,     &isdraw));
505   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS,    &isglvis));
506   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii));
507   if (isvtk || isdraw || isglvis) {
508     Vec         locv;
509     PetscObject isZero;
510     const char *name;
511 
512     CHKERRQ(DMGetLocalVector(dm, &locv));
513     CHKERRQ(PetscObjectGetName((PetscObject) v, &name));
514     CHKERRQ(PetscObjectSetName((PetscObject) locv, name));
515     CHKERRQ(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv));
516     CHKERRQ(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv));
517     CHKERRQ(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero));
518     CHKERRQ(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero));
519     CHKERRQ(VecView_Plex_Local(locv, viewer));
520     CHKERRQ(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL));
521     CHKERRQ(DMRestoreLocalVector(dm, &locv));
522   } else if (ishdf5) {
523 #if defined(PETSC_HAVE_HDF5)
524     CHKERRQ(VecView_Plex_HDF5_Internal(v, viewer));
525 #else
526     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
527 #endif
528   } else if (isexodusii) {
529 #if defined(PETSC_HAVE_EXODUSII)
530     CHKERRQ(VecView_PlexExodusII_Internal(v, viewer));
531 #else
532     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
533 #endif
534   } else {
535     PetscBool isseq;
536 
537     CHKERRQ(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq));
538     if (isseq) CHKERRQ(VecView_Seq(v, viewer));
539     else       CHKERRQ(VecView_MPI(v, viewer));
540   }
541   PetscFunctionReturn(0);
542 }
543 
544 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
545 {
546   DM                dm;
547   MPI_Comm          comm;
548   PetscViewerFormat format;
549   Vec               v;
550   PetscBool         isvtk, ishdf5;
551 
552   PetscFunctionBegin;
553   CHKERRQ(VecGetDM(originalv, &dm));
554   CHKERRQ(PetscObjectGetComm((PetscObject) originalv, &comm));
555   PetscCheck(dm,comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
556   CHKERRQ(PetscViewerGetFormat(viewer, &format));
557   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
558   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk));
559   if (format == PETSC_VIEWER_NATIVE) {
560     /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
561     /* this need a better fix */
562     if (dm->useNatural) {
563       if (dm->sfNatural) {
564         const char *vecname;
565         PetscInt    n, nroots;
566 
567         CHKERRQ(VecGetLocalSize(originalv, &n));
568         CHKERRQ(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL));
569         if (n == nroots) {
570           CHKERRQ(DMGetGlobalVector(dm, &v));
571           CHKERRQ(DMPlexGlobalToNaturalBegin(dm, originalv, v));
572           CHKERRQ(DMPlexGlobalToNaturalEnd(dm, originalv, v));
573           CHKERRQ(PetscObjectGetName((PetscObject) originalv, &vecname));
574           CHKERRQ(PetscObjectSetName((PetscObject) v, vecname));
575         } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
576       } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
577     } else v = originalv;
578   } else v = originalv;
579 
580   if (ishdf5) {
581 #if defined(PETSC_HAVE_HDF5)
582     CHKERRQ(VecView_Plex_HDF5_Native_Internal(v, viewer));
583 #else
584     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
585 #endif
586   } else if (isvtk) {
587     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
588   } else {
589     PetscBool isseq;
590 
591     CHKERRQ(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq));
592     if (isseq) CHKERRQ(VecView_Seq(v, viewer));
593     else       CHKERRQ(VecView_MPI(v, viewer));
594   }
595   if (v != originalv) CHKERRQ(DMRestoreGlobalVector(dm, &v));
596   PetscFunctionReturn(0);
597 }
598 
599 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
600 {
601   DM             dm;
602   PetscBool      ishdf5;
603 
604   PetscFunctionBegin;
605   CHKERRQ(VecGetDM(v, &dm));
606   PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
607   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
608   if (ishdf5) {
609     DM          dmBC;
610     Vec         gv;
611     const char *name;
612 
613     CHKERRQ(DMGetOutputDM(dm, &dmBC));
614     CHKERRQ(DMGetGlobalVector(dmBC, &gv));
615     CHKERRQ(PetscObjectGetName((PetscObject) v, &name));
616     CHKERRQ(PetscObjectSetName((PetscObject) gv, name));
617     CHKERRQ(VecLoad_Default(gv, viewer));
618     CHKERRQ(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v));
619     CHKERRQ(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v));
620     CHKERRQ(DMRestoreGlobalVector(dmBC, &gv));
621   } else {
622     CHKERRQ(VecLoad_Default(v, viewer));
623   }
624   PetscFunctionReturn(0);
625 }
626 
627 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
628 {
629   DM             dm;
630   PetscBool      ishdf5,isexodusii;
631 
632   PetscFunctionBegin;
633   CHKERRQ(VecGetDM(v, &dm));
634   PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
635   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5));
636   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii));
637   if (ishdf5) {
638 #if defined(PETSC_HAVE_HDF5)
639     CHKERRQ(VecLoad_Plex_HDF5_Internal(v, viewer));
640 #else
641     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
642 #endif
643   } else if (isexodusii) {
644 #if defined(PETSC_HAVE_EXODUSII)
645     CHKERRQ(VecLoad_PlexExodusII_Internal(v, viewer));
646 #else
647     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
648 #endif
649   } else {
650     CHKERRQ(VecLoad_Default(v, viewer));
651   }
652   PetscFunctionReturn(0);
653 }
654 
655 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
656 {
657   DM                dm;
658   PetscViewerFormat format;
659   PetscBool         ishdf5;
660 
661   PetscFunctionBegin;
662   CHKERRQ(VecGetDM(originalv, &dm));
663   PetscCheck(dm,PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
664   CHKERRQ(PetscViewerGetFormat(viewer, &format));
665   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
666   if (format == PETSC_VIEWER_NATIVE) {
667     if (dm->useNatural) {
668       if (dm->sfNatural) {
669         if (ishdf5) {
670 #if defined(PETSC_HAVE_HDF5)
671           Vec         v;
672           const char *vecname;
673 
674           CHKERRQ(DMGetGlobalVector(dm, &v));
675           CHKERRQ(PetscObjectGetName((PetscObject) originalv, &vecname));
676           CHKERRQ(PetscObjectSetName((PetscObject) v, vecname));
677           CHKERRQ(VecLoad_Plex_HDF5_Native_Internal(v, viewer));
678           CHKERRQ(DMPlexNaturalToGlobalBegin(dm, v, originalv));
679           CHKERRQ(DMPlexNaturalToGlobalEnd(dm, v, originalv));
680           CHKERRQ(DMRestoreGlobalVector(dm, &v));
681 #else
682           SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
683 #endif
684         } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
685       }
686     } else {
687       CHKERRQ(VecLoad_Default(originalv, viewer));
688     }
689   }
690   PetscFunctionReturn(0);
691 }
692 
693 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
694 {
695   PetscSection       coordSection;
696   Vec                coordinates;
697   DMLabel            depthLabel, celltypeLabel;
698   const char        *name[4];
699   const PetscScalar *a;
700   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
701 
702   PetscFunctionBegin;
703   CHKERRQ(DMGetDimension(dm, &dim));
704   CHKERRQ(DMGetCoordinatesLocal(dm, &coordinates));
705   CHKERRQ(DMGetCoordinateSection(dm, &coordSection));
706   CHKERRQ(DMPlexGetDepthLabel(dm, &depthLabel));
707   CHKERRQ(DMPlexGetCellTypeLabel(dm, &celltypeLabel));
708   CHKERRQ(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
709   CHKERRQ(PetscSectionGetChart(coordSection, &pStart, &pEnd));
710   CHKERRQ(VecGetArrayRead(coordinates, &a));
711   name[0]     = "vertex";
712   name[1]     = "edge";
713   name[dim-1] = "face";
714   name[dim]   = "cell";
715   for (c = cStart; c < cEnd; ++c) {
716     PetscInt *closure = NULL;
717     PetscInt  closureSize, cl, ct;
718 
719     CHKERRQ(DMLabelGetValue(celltypeLabel, c, &ct));
720     CHKERRQ(PetscViewerASCIIPrintf(viewer, "Geometry for cell %D polytope type %s:\n", c, DMPolytopeTypes[ct]));
721     CHKERRQ(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
722     CHKERRQ(PetscViewerASCIIPushTab(viewer));
723     for (cl = 0; cl < closureSize*2; cl += 2) {
724       PetscInt point = closure[cl], depth, dof, off, d, p;
725 
726       if ((point < pStart) || (point >= pEnd)) continue;
727       CHKERRQ(PetscSectionGetDof(coordSection, point, &dof));
728       if (!dof) continue;
729       CHKERRQ(DMLabelGetValue(depthLabel, point, &depth));
730       CHKERRQ(PetscSectionGetOffset(coordSection, point, &off));
731       CHKERRQ(PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point));
732       for (p = 0; p < dof/dim; ++p) {
733         CHKERRQ(PetscViewerASCIIPrintf(viewer, " ("));
734         for (d = 0; d < dim; ++d) {
735           if (d > 0) CHKERRQ(PetscViewerASCIIPrintf(viewer, ", "));
736           CHKERRQ(PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d])));
737         }
738         CHKERRQ(PetscViewerASCIIPrintf(viewer, ")"));
739       }
740       CHKERRQ(PetscViewerASCIIPrintf(viewer, "\n"));
741     }
742     CHKERRQ(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
743     CHKERRQ(PetscViewerASCIIPopTab(viewer));
744   }
745   CHKERRQ(VecRestoreArrayRead(coordinates, &a));
746   PetscFunctionReturn(0);
747 }
748 
749 typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem;
750 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL};
751 
752 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[])
753 {
754   PetscInt       i;
755 
756   PetscFunctionBegin;
757   if (dim > 3) {
758     for (i = 0; i < dim; ++i) CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i])));
759   } else {
760     PetscReal coords[3], trcoords[3];
761 
762     for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]);
763     switch (cs) {
764       case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break;
765       case CS_POLAR:
766         PetscCheckFalse(dim != 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %D", dim);
767         trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
768         trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
769         break;
770       case CS_CYLINDRICAL:
771         PetscCheckFalse(dim != 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %D", dim);
772         trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
773         trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
774         trcoords[2] = coords[2];
775         break;
776       case CS_SPHERICAL:
777         PetscCheckFalse(dim != 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %D", dim);
778         trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2]));
779         trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]);
780         trcoords[2] = PetscAtan2Real(coords[1], coords[0]);
781         break;
782     }
783     for (i = 0; i < dim; ++i) CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i]));
784   }
785   PetscFunctionReturn(0);
786 }
787 
788 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
789 {
790   DM_Plex          *mesh = (DM_Plex*) dm->data;
791   DM                cdm;
792   PetscSection      coordSection;
793   Vec               coordinates;
794   PetscViewerFormat format;
795 
796   PetscFunctionBegin;
797   CHKERRQ(DMGetCoordinateDM(dm, &cdm));
798   CHKERRQ(DMGetLocalSection(cdm, &coordSection));
799   CHKERRQ(DMGetCoordinatesLocal(dm, &coordinates));
800   CHKERRQ(PetscViewerGetFormat(viewer, &format));
801   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
802     const char *name;
803     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
804     PetscInt    pStart, pEnd, p, numLabels, l;
805     PetscMPIInt rank, size;
806 
807     CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
808     CHKERRMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
809     CHKERRQ(PetscObjectGetName((PetscObject) dm, &name));
810     CHKERRQ(DMPlexGetChart(dm, &pStart, &pEnd));
811     CHKERRQ(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
812     CHKERRQ(DMGetDimension(dm, &dim));
813     CHKERRQ(DMPlexGetVTKCellHeight(dm, &cellHeight));
814     if (name) CHKERRQ(PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
815     else      CHKERRQ(PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s"));
816     if (cellHeight) CHKERRQ(PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight));
817     CHKERRQ(PetscViewerASCIIPrintf(viewer, "Supports:\n", name));
818     CHKERRQ(PetscViewerASCIIPushSynchronized(viewer));
819     CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %D\n", rank, maxSupportSize));
820     for (p = pStart; p < pEnd; ++p) {
821       PetscInt dof, off, s;
822 
823       CHKERRQ(PetscSectionGetDof(mesh->supportSection, p, &dof));
824       CHKERRQ(PetscSectionGetOffset(mesh->supportSection, p, &off));
825       for (s = off; s < off+dof; ++s) {
826         CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]));
827       }
828     }
829     CHKERRQ(PetscViewerFlush(viewer));
830     CHKERRQ(PetscViewerASCIIPrintf(viewer, "Cones:\n", name));
831     CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %D\n", rank, maxConeSize));
832     for (p = pStart; p < pEnd; ++p) {
833       PetscInt dof, off, c;
834 
835       CHKERRQ(PetscSectionGetDof(mesh->coneSection, p, &dof));
836       CHKERRQ(PetscSectionGetOffset(mesh->coneSection, p, &off));
837       for (c = off; c < off+dof; ++c) {
838         CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]));
839       }
840     }
841     CHKERRQ(PetscViewerFlush(viewer));
842     CHKERRQ(PetscViewerASCIIPopSynchronized(viewer));
843     if (coordSection && coordinates) {
844       CoordSystem        cs = CS_CARTESIAN;
845       const PetscScalar *array;
846       PetscInt           Nf, Nc, pStart, pEnd, p;
847       PetscMPIInt        rank;
848       const char        *name;
849 
850       CHKERRQ(PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL));
851       CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
852       CHKERRQ(PetscSectionGetNumFields(coordSection, &Nf));
853       PetscCheckFalse(Nf != 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %D", Nf);
854       CHKERRQ(PetscSectionGetFieldComponents(coordSection, 0, &Nc));
855       CHKERRQ(PetscSectionGetChart(coordSection, &pStart, &pEnd));
856       CHKERRQ(PetscObjectGetName((PetscObject) coordinates, &name));
857       CHKERRQ(PetscViewerASCIIPrintf(viewer, "%s with %D fields\n", name, Nf));
858       CHKERRQ(PetscViewerASCIIPrintf(viewer, "  field 0 with %D components\n", Nc));
859       if (cs != CS_CARTESIAN) CHKERRQ(PetscViewerASCIIPrintf(viewer, "  output coordinate system: %s\n", CoordSystems[cs]));
860 
861       CHKERRQ(VecGetArrayRead(coordinates, &array));
862       CHKERRQ(PetscViewerASCIIPushSynchronized(viewer));
863       CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank));
864       for (p = pStart; p < pEnd; ++p) {
865         PetscInt dof, off;
866 
867         CHKERRQ(PetscSectionGetDof(coordSection, p, &dof));
868         CHKERRQ(PetscSectionGetOffset(coordSection, p, &off));
869         CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4D) dim %2D offset %3D", p, dof, off));
870         CHKERRQ(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off]));
871         CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
872       }
873       CHKERRQ(PetscViewerFlush(viewer));
874       CHKERRQ(PetscViewerASCIIPopSynchronized(viewer));
875       CHKERRQ(VecRestoreArrayRead(coordinates, &array));
876     }
877     CHKERRQ(DMGetNumLabels(dm, &numLabels));
878     if (numLabels) CHKERRQ(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
879     for (l = 0; l < numLabels; ++l) {
880       DMLabel     label;
881       PetscBool   isdepth;
882       const char *name;
883 
884       CHKERRQ(DMGetLabelName(dm, l, &name));
885       CHKERRQ(PetscStrcmp(name, "depth", &isdepth));
886       if (isdepth) continue;
887       CHKERRQ(DMGetLabel(dm, name, &label));
888       CHKERRQ(DMLabelView(label, viewer));
889     }
890     if (size > 1) {
891       PetscSF sf;
892 
893       CHKERRQ(DMGetPointSF(dm, &sf));
894       CHKERRQ(PetscSFView(sf, viewer));
895     }
896     CHKERRQ(PetscViewerFlush(viewer));
897   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
898     const char  *name, *color;
899     const char  *defcolors[3]  = {"gray", "orange", "green"};
900     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
901     char         lname[PETSC_MAX_PATH_LEN];
902     PetscReal    scale         = 2.0;
903     PetscReal    tikzscale     = 1.0;
904     PetscBool    useNumbers    = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE;
905     double       tcoords[3];
906     PetscScalar *coords;
907     PetscInt     numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n;
908     PetscMPIInt  rank, size;
909     char         **names, **colors, **lcolors;
910     PetscBool    flg, lflg;
911     PetscBT      wp = NULL;
912     PetscInt     pEnd, pStart;
913 
914     CHKERRQ(DMGetDimension(dm, &dim));
915     CHKERRQ(DMPlexGetDepth(dm, &depth));
916     CHKERRQ(DMGetNumLabels(dm, &numLabels));
917     numLabels  = PetscMax(numLabels, 10);
918     numColors  = 10;
919     numLColors = 10;
920     CHKERRQ(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors));
921     CHKERRQ(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL));
922     CHKERRQ(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL));
923     CHKERRQ(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL));
924     for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers;
925     for (d = 0; d < 4; ++d) drawColors[d]  = PETSC_TRUE;
926     n = 4;
927     CHKERRQ(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg));
928     PetscCheckFalse(flg && n != dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %D != %D dim+1", n, dim+1);
929     CHKERRQ(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg));
930     PetscCheckFalse(flg && n != dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %D != %D dim+1", n, dim+1);
931     CHKERRQ(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels));
932     if (!useLabels) numLabels = 0;
933     CHKERRQ(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors));
934     if (!useColors) {
935       numColors = 3;
936       for (c = 0; c < numColors; ++c) CHKERRQ(PetscStrallocpy(defcolors[c], &colors[c]));
937     }
938     CHKERRQ(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors));
939     if (!useColors) {
940       numLColors = 4;
941       for (c = 0; c < numLColors; ++c) CHKERRQ(PetscStrallocpy(deflcolors[c], &lcolors[c]));
942     }
943     CHKERRQ(PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg));
944     plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3);
945     CHKERRQ(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg));
946     PetscCheckFalse(flg && plotEdges && depth < dim,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated");
947     if (depth < dim) plotEdges = PETSC_FALSE;
948     CHKERRQ(PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL));
949 
950     /* filter points with labelvalue != labeldefaultvalue */
951     CHKERRQ(DMPlexGetChart(dm, &pStart, &pEnd));
952     CHKERRQ(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
953     CHKERRQ(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
954     CHKERRQ(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
955     if (lflg) {
956       DMLabel lbl;
957 
958       CHKERRQ(DMGetLabel(dm, lname, &lbl));
959       if (lbl) {
960         PetscInt val, defval;
961 
962         CHKERRQ(DMLabelGetDefaultValue(lbl, &defval));
963         CHKERRQ(PetscBTCreate(pEnd-pStart, &wp));
964         for (c = pStart;  c < pEnd; c++) {
965           PetscInt *closure = NULL;
966           PetscInt  closureSize;
967 
968           CHKERRQ(DMLabelGetValue(lbl, c, &val));
969           if (val == defval) continue;
970 
971           CHKERRQ(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
972           for (p = 0; p < closureSize*2; p += 2) {
973             CHKERRQ(PetscBTSet(wp, closure[p] - pStart));
974           }
975           CHKERRQ(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
976         }
977       }
978     }
979 
980     CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
981     CHKERRMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
982     CHKERRQ(PetscObjectGetName((PetscObject) dm, &name));
983     CHKERRQ(PetscViewerASCIIPrintf(viewer, "\
984 \\documentclass[tikz]{standalone}\n\n\
985 \\usepackage{pgflibraryshapes}\n\
986 \\usetikzlibrary{backgrounds}\n\
987 \\usetikzlibrary{arrows}\n\
988 \\begin{document}\n"));
989     if (size > 1) {
990       CHKERRQ(PetscViewerASCIIPrintf(viewer, "%s for process ", name));
991       for (p = 0; p < size; ++p) {
992         if (p > 0 && p == size-1) {
993           CHKERRQ(PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p));
994         } else if (p > 0) {
995           CHKERRQ(PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p));
996         }
997         CHKERRQ(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p));
998       }
999       CHKERRQ(PetscViewerASCIIPrintf(viewer, ".\n\n\n"));
1000     }
1001     if (drawHasse) {
1002       PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart));
1003 
1004       CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%D}\n", vStart));
1005       CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%D}\n", vEnd-1));
1006       CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%D}\n", vEnd-vStart));
1007       CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.));
1008       CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%D}\n", eStart));
1009       CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%D}\n", eEnd-1));
1010       CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.));
1011       CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%D}\n", eEnd-eStart));
1012       CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%D}\n", cStart));
1013       CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%D}\n", cEnd-1));
1014       CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%D}\n", cEnd-cStart));
1015       CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.));
1016     }
1017     CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale));
1018 
1019     /* Plot vertices */
1020     CHKERRQ(VecGetArray(coordinates, &coords));
1021     CHKERRQ(PetscViewerASCIIPushSynchronized(viewer));
1022     for (v = vStart; v < vEnd; ++v) {
1023       PetscInt  off, dof, d;
1024       PetscBool isLabeled = PETSC_FALSE;
1025 
1026       if (wp && !PetscBTLookup(wp,v - pStart)) continue;
1027       CHKERRQ(PetscSectionGetDof(coordSection, v, &dof));
1028       CHKERRQ(PetscSectionGetOffset(coordSection, v, &off));
1029       CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
1030       PetscCheck(dof <= 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
1031       for (d = 0; d < dof; ++d) {
1032         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
1033         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1034       }
1035       /* Rotate coordinates since PGF makes z point out of the page instead of up */
1036       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
1037       for (d = 0; d < dof; ++d) {
1038         if (d > 0) CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, ","));
1039         CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d]));
1040       }
1041       if (drawHasse) color = colors[0%numColors];
1042       else           color = colors[rank%numColors];
1043       for (l = 0; l < numLabels; ++l) {
1044         PetscInt val;
1045         CHKERRQ(DMGetLabelValue(dm, names[l], v, &val));
1046         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
1047       }
1048       if (drawNumbers[0]) {
1049         CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v));
1050       } else if (drawColors[0]) {
1051         CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color));
1052       } else {
1053         CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [] {};\n", v, rank));
1054       }
1055     }
1056     CHKERRQ(VecRestoreArray(coordinates, &coords));
1057     CHKERRQ(PetscViewerFlush(viewer));
1058     /* Plot edges */
1059     if (plotEdges) {
1060       CHKERRQ(VecGetArray(coordinates, &coords));
1061       CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\path\n"));
1062       for (e = eStart; e < eEnd; ++e) {
1063         const PetscInt *cone;
1064         PetscInt        coneSize, offA, offB, dof, d;
1065 
1066         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
1067         CHKERRQ(DMPlexGetConeSize(dm, e, &coneSize));
1068         PetscCheckFalse(coneSize != 2,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
1069         CHKERRQ(DMPlexGetCone(dm, e, &cone));
1070         CHKERRQ(PetscSectionGetDof(coordSection, cone[0], &dof));
1071         CHKERRQ(PetscSectionGetOffset(coordSection, cone[0], &offA));
1072         CHKERRQ(PetscSectionGetOffset(coordSection, cone[1], &offB));
1073         CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, "("));
1074         for (d = 0; d < dof; ++d) {
1075           tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
1076           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1077         }
1078         /* Rotate coordinates since PGF makes z point out of the page instead of up */
1079         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
1080         for (d = 0; d < dof; ++d) {
1081           if (d > 0) CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, ","));
1082           CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]));
1083         }
1084         if (drawHasse) color = colors[1%numColors];
1085         else           color = colors[rank%numColors];
1086         for (l = 0; l < numLabels; ++l) {
1087           PetscInt val;
1088           CHKERRQ(DMGetLabelValue(dm, names[l], v, &val));
1089           if (val >= 0) {color = lcolors[l%numLColors]; break;}
1090         }
1091         CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e));
1092       }
1093       CHKERRQ(VecRestoreArray(coordinates, &coords));
1094       CHKERRQ(PetscViewerFlush(viewer));
1095       CHKERRQ(PetscViewerASCIIPrintf(viewer, "(0,0);\n"));
1096     }
1097     /* Plot cells */
1098     if (dim == 3 || !drawNumbers[1]) {
1099       for (e = eStart; e < eEnd; ++e) {
1100         const PetscInt *cone;
1101 
1102         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
1103         color = colors[rank%numColors];
1104         for (l = 0; l < numLabels; ++l) {
1105           PetscInt val;
1106           CHKERRQ(DMGetLabelValue(dm, names[l], e, &val));
1107           if (val >= 0) {color = lcolors[l%numLColors]; break;}
1108         }
1109         CHKERRQ(DMPlexGetCone(dm, e, &cone));
1110         CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank));
1111       }
1112     } else {
1113        DMPolytopeType ct;
1114 
1115       /* Drawing a 2D polygon */
1116       for (c = cStart; c < cEnd; ++c) {
1117         if (wp && !PetscBTLookup(wp, c - pStart)) continue;
1118         CHKERRQ(DMPlexGetCellType(dm, c, &ct));
1119         if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR ||
1120             ct == DM_POLYTOPE_TRI_PRISM_TENSOR ||
1121             ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
1122           const PetscInt *cone;
1123           PetscInt        coneSize, e;
1124 
1125           CHKERRQ(DMPlexGetCone(dm, c, &cone));
1126           CHKERRQ(DMPlexGetConeSize(dm, c, &coneSize));
1127           for (e = 0; e < coneSize; ++e) {
1128             const PetscInt *econe;
1129 
1130             CHKERRQ(DMPlexGetCone(dm, cone[e], &econe));
1131             CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d) -- (%D_%d);\n", colors[rank%numColors], econe[0], rank, cone[e], rank, econe[1], rank));
1132           }
1133         } else {
1134           PetscInt *closure = NULL;
1135           PetscInt  closureSize, Nv = 0, v;
1136 
1137           CHKERRQ(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1138           for (p = 0; p < closureSize*2; p += 2) {
1139             const PetscInt point = closure[p];
1140 
1141             if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point;
1142           }
1143           CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]));
1144           for (v = 0; v <= Nv; ++v) {
1145             const PetscInt vertex = closure[v%Nv];
1146 
1147             if (v > 0) {
1148               if (plotEdges) {
1149                 const PetscInt *edge;
1150                 PetscInt        endpoints[2], ne;
1151 
1152                 endpoints[0] = closure[v-1]; endpoints[1] = vertex;
1153                 CHKERRQ(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge));
1154                 PetscCheckFalse(ne != 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %D, %D", endpoints[0], endpoints[1]);
1155                 CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d) -- ", edge[0], rank));
1156                 CHKERRQ(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge));
1157               } else {
1158                 CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, " -- "));
1159               }
1160             }
1161             CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", vertex, rank));
1162           }
1163           CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, ";\n"));
1164           CHKERRQ(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1165         }
1166       }
1167     }
1168     CHKERRQ(VecGetArray(coordinates, &coords));
1169     for (c = cStart; c < cEnd; ++c) {
1170       double    ccoords[3] = {0.0, 0.0, 0.0};
1171       PetscBool isLabeled  = PETSC_FALSE;
1172       PetscInt *closure    = NULL;
1173       PetscInt  closureSize, dof, d, n = 0;
1174 
1175       if (wp && !PetscBTLookup(wp,c - pStart)) continue;
1176       CHKERRQ(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1177       CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
1178       for (p = 0; p < closureSize*2; p += 2) {
1179         const PetscInt point = closure[p];
1180         PetscInt       off;
1181 
1182         if ((point < vStart) || (point >= vEnd)) continue;
1183         CHKERRQ(PetscSectionGetDof(coordSection, point, &dof));
1184         CHKERRQ(PetscSectionGetOffset(coordSection, point, &off));
1185         for (d = 0; d < dof; ++d) {
1186           tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
1187           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1188         }
1189         /* Rotate coordinates since PGF makes z point out of the page instead of up */
1190         if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
1191         for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];}
1192         ++n;
1193       }
1194       for (d = 0; d < dof; ++d) {ccoords[d] /= n;}
1195       CHKERRQ(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1196       for (d = 0; d < dof; ++d) {
1197         if (d > 0) CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, ","));
1198         CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d]));
1199       }
1200       if (drawHasse) color = colors[depth%numColors];
1201       else           color = colors[rank%numColors];
1202       for (l = 0; l < numLabels; ++l) {
1203         PetscInt val;
1204         CHKERRQ(DMGetLabelValue(dm, names[l], c, &val));
1205         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
1206       }
1207       if (drawNumbers[dim]) {
1208         CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", c, rank, color, c));
1209       } else if (drawColors[dim]) {
1210         CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color));
1211       } else {
1212         CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [] {};\n", c, rank));
1213       }
1214     }
1215     CHKERRQ(VecRestoreArray(coordinates, &coords));
1216     if (drawHasse) {
1217       color = colors[depth%numColors];
1218       CHKERRQ(PetscViewerASCIIPrintf(viewer, "%% Cells\n"));
1219       CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n"));
1220       CHKERRQ(PetscViewerASCIIPrintf(viewer, "{\n"));
1221       CHKERRQ(PetscViewerASCIIPrintf(viewer, "  \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color));
1222       CHKERRQ(PetscViewerASCIIPrintf(viewer, "}\n"));
1223 
1224       color = colors[1%numColors];
1225       CHKERRQ(PetscViewerASCIIPrintf(viewer, "%% Edges\n"));
1226       CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n"));
1227       CHKERRQ(PetscViewerASCIIPrintf(viewer, "{\n"));
1228       CHKERRQ(PetscViewerASCIIPrintf(viewer, "  \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color));
1229       CHKERRQ(PetscViewerASCIIPrintf(viewer, "}\n"));
1230 
1231       color = colors[0%numColors];
1232       CHKERRQ(PetscViewerASCIIPrintf(viewer, "%% Vertices\n"));
1233       CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n"));
1234       CHKERRQ(PetscViewerASCIIPrintf(viewer, "{\n"));
1235       CHKERRQ(PetscViewerASCIIPrintf(viewer, "  \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color));
1236       CHKERRQ(PetscViewerASCIIPrintf(viewer, "}\n"));
1237 
1238       for (p = pStart; p < pEnd; ++p) {
1239         const PetscInt *cone;
1240         PetscInt        coneSize, cp;
1241 
1242         CHKERRQ(DMPlexGetCone(dm, p, &cone));
1243         CHKERRQ(DMPlexGetConeSize(dm, p, &coneSize));
1244         for (cp = 0; cp < coneSize; ++cp) {
1245           CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%D_%d) -- (%D_%d);\n", cone[cp], rank, p, rank));
1246         }
1247       }
1248     }
1249     CHKERRQ(PetscViewerFlush(viewer));
1250     CHKERRQ(PetscViewerASCIIPopSynchronized(viewer));
1251     CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n"));
1252     CHKERRQ(PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name));
1253     for (l = 0; l < numLabels;  ++l) CHKERRQ(PetscFree(names[l]));
1254     for (c = 0; c < numColors;  ++c) CHKERRQ(PetscFree(colors[c]));
1255     for (c = 0; c < numLColors; ++c) CHKERRQ(PetscFree(lcolors[c]));
1256     CHKERRQ(PetscFree3(names, colors, lcolors));
1257     CHKERRQ(PetscBTDestroy(&wp));
1258   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
1259     Vec                    cown,acown;
1260     VecScatter             sct;
1261     ISLocalToGlobalMapping g2l;
1262     IS                     gid,acis;
1263     MPI_Comm               comm,ncomm = MPI_COMM_NULL;
1264     MPI_Group              ggroup,ngroup;
1265     PetscScalar            *array,nid;
1266     const PetscInt         *idxs;
1267     PetscInt               *idxs2,*start,*adjacency,*work;
1268     PetscInt64             lm[3],gm[3];
1269     PetscInt               i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight;
1270     PetscMPIInt            d1,d2,rank;
1271 
1272     CHKERRQ(PetscObjectGetComm((PetscObject)dm,&comm));
1273     CHKERRMPI(MPI_Comm_rank(comm,&rank));
1274 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1275     CHKERRMPI(MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm));
1276 #endif
1277     if (ncomm != MPI_COMM_NULL) {
1278       CHKERRMPI(MPI_Comm_group(comm,&ggroup));
1279       CHKERRMPI(MPI_Comm_group(ncomm,&ngroup));
1280       d1   = 0;
1281       CHKERRMPI(MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2));
1282       nid  = d2;
1283       CHKERRMPI(MPI_Group_free(&ggroup));
1284       CHKERRMPI(MPI_Group_free(&ngroup));
1285       CHKERRMPI(MPI_Comm_free(&ncomm));
1286     } else nid = 0.0;
1287 
1288     /* Get connectivity */
1289     CHKERRQ(DMPlexGetVTKCellHeight(dm,&cellHeight));
1290     CHKERRQ(DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid));
1291 
1292     /* filter overlapped local cells */
1293     CHKERRQ(DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd));
1294     CHKERRQ(ISGetIndices(gid,&idxs));
1295     CHKERRQ(ISGetLocalSize(gid,&cum));
1296     CHKERRQ(PetscMalloc1(cum,&idxs2));
1297     for (c = cStart, cum = 0; c < cEnd; c++) {
1298       if (idxs[c-cStart] < 0) continue;
1299       idxs2[cum++] = idxs[c-cStart];
1300     }
1301     CHKERRQ(ISRestoreIndices(gid,&idxs));
1302     PetscCheckFalse(numVertices != cum,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %D != %D",numVertices,cum);
1303     CHKERRQ(ISDestroy(&gid));
1304     CHKERRQ(ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid));
1305 
1306     /* support for node-aware cell locality */
1307     CHKERRQ(ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis));
1308     CHKERRQ(VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown));
1309     CHKERRQ(VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown));
1310     CHKERRQ(VecGetArray(cown,&array));
1311     for (c = 0; c < numVertices; c++) array[c] = nid;
1312     CHKERRQ(VecRestoreArray(cown,&array));
1313     CHKERRQ(VecScatterCreate(cown,acis,acown,NULL,&sct));
1314     CHKERRQ(VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD));
1315     CHKERRQ(VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD));
1316     CHKERRQ(ISDestroy(&acis));
1317     CHKERRQ(VecScatterDestroy(&sct));
1318     CHKERRQ(VecDestroy(&cown));
1319 
1320     /* compute edgeCut */
1321     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]);
1322     CHKERRQ(PetscMalloc1(cum,&work));
1323     CHKERRQ(ISLocalToGlobalMappingCreateIS(gid,&g2l));
1324     CHKERRQ(ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH));
1325     CHKERRQ(ISDestroy(&gid));
1326     CHKERRQ(VecGetArray(acown,&array));
1327     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
1328       PetscInt totl;
1329 
1330       totl = start[c+1]-start[c];
1331       CHKERRQ(ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work));
1332       for (i = 0; i < totl; i++) {
1333         if (work[i] < 0) {
1334           ect  += 1;
1335           ectn += (array[i + start[c]] != nid) ? 0 : 1;
1336         }
1337       }
1338     }
1339     CHKERRQ(PetscFree(work));
1340     CHKERRQ(VecRestoreArray(acown,&array));
1341     lm[0] = numVertices > 0 ?  numVertices : PETSC_MAX_INT;
1342     lm[1] = -numVertices;
1343     CHKERRMPI(MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm));
1344     CHKERRQ(PetscViewerASCIIPrintf(viewer,"  Cell balance: %.2f (max %D, min %D",-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0]));
1345     lm[0] = ect; /* edgeCut */
1346     lm[1] = ectn; /* node-aware edgeCut */
1347     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
1348     CHKERRMPI(MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm));
1349     CHKERRQ(PetscViewerASCIIPrintf(viewer,", empty %D)\n",(PetscInt)gm[2]));
1350 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1351     CHKERRQ(PetscViewerASCIIPrintf(viewer,"  Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.));
1352 #else
1353     CHKERRQ(PetscViewerASCIIPrintf(viewer,"  Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0));
1354 #endif
1355     CHKERRQ(ISLocalToGlobalMappingDestroy(&g2l));
1356     CHKERRQ(PetscFree(start));
1357     CHKERRQ(PetscFree(adjacency));
1358     CHKERRQ(VecDestroy(&acown));
1359   } else {
1360     const char    *name;
1361     PetscInt      *sizes, *hybsizes, *ghostsizes;
1362     PetscInt       locDepth, depth, cellHeight, dim, d;
1363     PetscInt       pStart, pEnd, p, gcStart, gcEnd, gcNum;
1364     PetscInt       numLabels, l, maxSize = 17;
1365     DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN;
1366     MPI_Comm       comm;
1367     PetscMPIInt    size, rank;
1368 
1369     CHKERRQ(PetscObjectGetComm((PetscObject) dm, &comm));
1370     CHKERRMPI(MPI_Comm_size(comm, &size));
1371     CHKERRMPI(MPI_Comm_rank(comm, &rank));
1372     CHKERRQ(DMGetDimension(dm, &dim));
1373     CHKERRQ(DMPlexGetVTKCellHeight(dm, &cellHeight));
1374     CHKERRQ(PetscObjectGetName((PetscObject) dm, &name));
1375     if (name) CHKERRQ(PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
1376     else      CHKERRQ(PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s"));
1377     if (cellHeight) CHKERRQ(PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight));
1378     CHKERRQ(DMPlexGetDepth(dm, &locDepth));
1379     CHKERRMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm));
1380     CHKERRQ(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd));
1381     gcNum = gcEnd - gcStart;
1382     if (size < maxSize) CHKERRQ(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes));
1383     else                CHKERRQ(PetscCalloc3(3,    &sizes, 3,    &hybsizes, 3,    &ghostsizes));
1384     for (d = 0; d <= depth; d++) {
1385       PetscInt Nc[2] = {0, 0}, ict;
1386 
1387       CHKERRQ(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
1388       if (pStart < pEnd) CHKERRQ(DMPlexGetCellType(dm, pStart, &ct0));
1389       ict  = ct0;
1390       CHKERRMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm));
1391       ct0  = (DMPolytopeType) ict;
1392       for (p = pStart; p < pEnd; ++p) {
1393         DMPolytopeType ct;
1394 
1395         CHKERRQ(DMPlexGetCellType(dm, p, &ct));
1396         if (ct == ct0) ++Nc[0];
1397         else           ++Nc[1];
1398       }
1399       if (size < maxSize) {
1400         CHKERRMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes,    1, MPIU_INT, 0, comm));
1401         CHKERRMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm));
1402         if (d == depth) CHKERRMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm));
1403         CHKERRQ(PetscViewerASCIIPrintf(viewer, "  Number of %D-cells per rank:", (depth == 1) && d ? dim : d));
1404         for (p = 0; p < size; ++p) {
1405           if (rank == 0) {
1406             CHKERRQ(PetscViewerASCIIPrintf(viewer, " %D", sizes[p]+hybsizes[p]));
1407             if (hybsizes[p]   > 0) CHKERRQ(PetscViewerASCIIPrintf(viewer, " (%D)", hybsizes[p]));
1408             if (ghostsizes[p] > 0) CHKERRQ(PetscViewerASCIIPrintf(viewer, " [%D]", ghostsizes[p]));
1409           }
1410         }
1411       } else {
1412         PetscInt locMinMax[2];
1413 
1414         locMinMax[0] = Nc[0]+Nc[1]; locMinMax[1] = Nc[0]+Nc[1];
1415         CHKERRQ(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
1416         locMinMax[0] = Nc[1]; locMinMax[1] = Nc[1];
1417         CHKERRQ(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes));
1418         if (d == depth) {
1419           locMinMax[0] = gcNum; locMinMax[1] = gcNum;
1420           CHKERRQ(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes));
1421         }
1422         CHKERRQ(PetscViewerASCIIPrintf(viewer, "  Min/Max of %D-cells per rank:", (depth == 1) && d ? dim : d));
1423         CHKERRQ(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
1424         if (hybsizes[0]   > 0) CHKERRQ(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1]));
1425         if (ghostsizes[0] > 0) CHKERRQ(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1]));
1426       }
1427       CHKERRQ(PetscViewerASCIIPrintf(viewer, "\n"));
1428     }
1429     CHKERRQ(PetscFree3(sizes, hybsizes, ghostsizes));
1430     {
1431       const PetscReal      *maxCell;
1432       const PetscReal      *L;
1433       const DMBoundaryType *bd;
1434       PetscBool             per, localized;
1435 
1436       CHKERRQ(DMGetPeriodicity(dm, &per, &maxCell, &L, &bd));
1437       CHKERRQ(DMGetCoordinatesLocalized(dm, &localized));
1438       if (per) {
1439         CHKERRQ(PetscViewerASCIIPrintf(viewer, "Periodic mesh ("));
1440         CHKERRQ(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1441         for (d = 0; d < dim; ++d) {
1442           if (bd && d > 0) CHKERRQ(PetscViewerASCIIPrintf(viewer, ", "));
1443           if (bd)    CHKERRQ(PetscViewerASCIIPrintf(viewer, "%s", DMBoundaryTypes[bd[d]]));
1444         }
1445         CHKERRQ(PetscViewerASCIIPrintf(viewer, ") coordinates %s\n", localized ? "localized" : "not localized"));
1446         CHKERRQ(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1447       }
1448     }
1449     CHKERRQ(DMGetNumLabels(dm, &numLabels));
1450     if (numLabels) CHKERRQ(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
1451     for (l = 0; l < numLabels; ++l) {
1452       DMLabel         label;
1453       const char     *name;
1454       IS              valueIS;
1455       const PetscInt *values;
1456       PetscInt        numValues, v;
1457 
1458       CHKERRQ(DMGetLabelName(dm, l, &name));
1459       CHKERRQ(DMGetLabel(dm, name, &label));
1460       CHKERRQ(DMLabelGetNumValues(label, &numValues));
1461       CHKERRQ(PetscViewerASCIIPrintf(viewer, "  %s: %D strata with value/size (", name, numValues));
1462       CHKERRQ(DMLabelGetValueIS(label, &valueIS));
1463       CHKERRQ(ISGetIndices(valueIS, &values));
1464       CHKERRQ(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1465       for (v = 0; v < numValues; ++v) {
1466         PetscInt size;
1467 
1468         CHKERRQ(DMLabelGetStratumSize(label, values[v], &size));
1469         if (v > 0) CHKERRQ(PetscViewerASCIIPrintf(viewer, ", "));
1470         CHKERRQ(PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size));
1471       }
1472       CHKERRQ(PetscViewerASCIIPrintf(viewer, ")\n"));
1473       CHKERRQ(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1474       CHKERRQ(ISRestoreIndices(valueIS, &values));
1475       CHKERRQ(ISDestroy(&valueIS));
1476     }
1477     {
1478       char    **labelNames;
1479       PetscInt  Nl = numLabels;
1480       PetscBool flg;
1481 
1482       CHKERRQ(PetscMalloc1(Nl, &labelNames));
1483       CHKERRQ(PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg));
1484       for (l = 0; l < Nl; ++l) {
1485         DMLabel label;
1486 
1487         CHKERRQ(DMHasLabel(dm, labelNames[l], &flg));
1488         if (flg) {
1489           CHKERRQ(DMGetLabel(dm, labelNames[l], &label));
1490           CHKERRQ(DMLabelView(label, viewer));
1491         }
1492         CHKERRQ(PetscFree(labelNames[l]));
1493       }
1494       CHKERRQ(PetscFree(labelNames));
1495     }
1496     /* If no fields are specified, people do not want to see adjacency */
1497     if (dm->Nf) {
1498       PetscInt f;
1499 
1500       for (f = 0; f < dm->Nf; ++f) {
1501         const char *name;
1502 
1503         CHKERRQ(PetscObjectGetName(dm->fields[f].disc, &name));
1504         if (numLabels) CHKERRQ(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name));
1505         CHKERRQ(PetscViewerASCIIPushTab(viewer));
1506         if (dm->fields[f].label) CHKERRQ(DMLabelView(dm->fields[f].label, viewer));
1507         if (dm->fields[f].adjacency[0]) {
1508           if (dm->fields[f].adjacency[1]) CHKERRQ(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n"));
1509           else                            CHKERRQ(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n"));
1510         } else {
1511           if (dm->fields[f].adjacency[1]) CHKERRQ(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n"));
1512           else                            CHKERRQ(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n"));
1513         }
1514         CHKERRQ(PetscViewerASCIIPopTab(viewer));
1515       }
1516     }
1517     CHKERRQ(DMGetCoarseDM(dm, &cdm));
1518     if (cdm) {
1519       CHKERRQ(PetscViewerASCIIPushTab(viewer));
1520       CHKERRQ(DMPlexView_Ascii(cdm, viewer));
1521       CHKERRQ(PetscViewerASCIIPopTab(viewer));
1522     }
1523   }
1524   PetscFunctionReturn(0);
1525 }
1526 
1527 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[])
1528 {
1529   DMPolytopeType ct;
1530   PetscMPIInt    rank;
1531   PetscInt       cdim;
1532 
1533   PetscFunctionBegin;
1534   CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
1535   CHKERRQ(DMPlexGetCellType(dm, cell, &ct));
1536   CHKERRQ(DMGetCoordinateDim(dm, &cdim));
1537   switch (ct) {
1538   case DM_POLYTOPE_SEGMENT:
1539   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1540     switch (cdim) {
1541     case 1:
1542     {
1543       const PetscReal y  = 0.5;  /* TODO Put it in the middle of the viewport */
1544       const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */
1545 
1546       CHKERRQ(PetscDrawLine(draw, PetscRealPart(coords[0]), y,    PetscRealPart(coords[1]), y,    PETSC_DRAW_BLACK));
1547       CHKERRQ(PetscDrawLine(draw, PetscRealPart(coords[0]), y+dy, PetscRealPart(coords[0]), y-dy, PETSC_DRAW_BLACK));
1548       CHKERRQ(PetscDrawLine(draw, PetscRealPart(coords[1]), y+dy, PetscRealPart(coords[1]), y-dy, PETSC_DRAW_BLACK));
1549     }
1550     break;
1551     case 2:
1552     {
1553       const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1]));
1554       const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0]));
1555       const PetscReal l  = 0.1/PetscSqrtReal(dx*dx + dy*dy);
1556 
1557       CHKERRQ(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1558       CHKERRQ(PetscDrawLine(draw, PetscRealPart(coords[0])+l*dx, PetscRealPart(coords[1])+l*dy, PetscRealPart(coords[0])-l*dx, PetscRealPart(coords[1])-l*dy, PETSC_DRAW_BLACK));
1559       CHKERRQ(PetscDrawLine(draw, PetscRealPart(coords[2])+l*dx, PetscRealPart(coords[3])+l*dy, PetscRealPart(coords[2])-l*dx, PetscRealPart(coords[3])-l*dy, PETSC_DRAW_BLACK));
1560     }
1561     break;
1562     default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %D", cdim);
1563     }
1564     break;
1565   case DM_POLYTOPE_TRIANGLE:
1566     CHKERRQ(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1567                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1568                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1569                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2));
1570     CHKERRQ(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1571     CHKERRQ(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
1572     CHKERRQ(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1573     break;
1574   case DM_POLYTOPE_QUADRILATERAL:
1575     CHKERRQ(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1576                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1577                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1578                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2));
1579     CHKERRQ(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]),
1580                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1581                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1582                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2));
1583     CHKERRQ(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1584     CHKERRQ(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
1585     CHKERRQ(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
1586     CHKERRQ(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1587     break;
1588   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1589   }
1590   PetscFunctionReturn(0);
1591 }
1592 
1593 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1594 {
1595   DMPolytopeType ct;
1596   PetscReal      centroid[2] = {0., 0.};
1597   PetscMPIInt    rank;
1598   PetscInt       fillColor, v, e, d;
1599 
1600   PetscFunctionBegin;
1601   CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
1602   CHKERRQ(DMPlexGetCellType(dm, cell, &ct));
1603   fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2;
1604   switch (ct) {
1605   case DM_POLYTOPE_TRIANGLE:
1606     {
1607       PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.};
1608 
1609       for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;}
1610       for (e = 0; e < 3; ++e) {
1611         refCoords[0] = refVertices[e*2+0];
1612         refCoords[1] = refVertices[e*2+1];
1613         for (d = 1; d <= edgeDiv; ++d) {
1614           refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv;
1615           refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv;
1616         }
1617         CHKERRQ(DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords));
1618         for (d = 0; d < edgeDiv; ++d) {
1619           CHKERRQ(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));
1620           CHKERRQ(PetscDrawLine(draw, edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], PETSC_DRAW_BLACK));
1621         }
1622       }
1623     }
1624     break;
1625   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1626   }
1627   PetscFunctionReturn(0);
1628 }
1629 
1630 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1631 {
1632   PetscDraw          draw;
1633   DM                 cdm;
1634   PetscSection       coordSection;
1635   Vec                coordinates;
1636   const PetscScalar *coords;
1637   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
1638   PetscReal         *refCoords, *edgeCoords;
1639   PetscBool          isnull, drawAffine = PETSC_TRUE;
1640   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4;
1641 
1642   PetscFunctionBegin;
1643   CHKERRQ(DMGetCoordinateDim(dm, &dim));
1644   PetscCheckFalse(dim > 2,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
1645   CHKERRQ(PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL));
1646   if (!drawAffine) CHKERRQ(PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords));
1647   CHKERRQ(DMGetCoordinateDM(dm, &cdm));
1648   CHKERRQ(DMGetLocalSection(cdm, &coordSection));
1649   CHKERRQ(DMGetCoordinatesLocal(dm, &coordinates));
1650   CHKERRQ(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1651   CHKERRQ(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1652 
1653   CHKERRQ(PetscViewerDrawGetDraw(viewer, 0, &draw));
1654   CHKERRQ(PetscDrawIsNull(draw, &isnull));
1655   if (isnull) PetscFunctionReturn(0);
1656   CHKERRQ(PetscDrawSetTitle(draw, "Mesh"));
1657 
1658   CHKERRQ(VecGetLocalSize(coordinates, &N));
1659   CHKERRQ(VecGetArrayRead(coordinates, &coords));
1660   for (c = 0; c < N; c += dim) {
1661     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
1662     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1663   }
1664   CHKERRQ(VecRestoreArrayRead(coordinates, &coords));
1665   CHKERRMPI(MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm)));
1666   CHKERRMPI(MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm)));
1667   CHKERRQ(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]));
1668   CHKERRQ(PetscDrawClear(draw));
1669 
1670   for (c = cStart; c < cEnd; ++c) {
1671     PetscScalar *coords = NULL;
1672     PetscInt     numCoords;
1673 
1674     CHKERRQ(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords));
1675     if (drawAffine) {
1676       CHKERRQ(DMPlexDrawCell(dm, draw, c, coords));
1677     } else {
1678       CHKERRQ(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords));
1679     }
1680     CHKERRQ(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords));
1681   }
1682   if (!drawAffine) CHKERRQ(PetscFree2(refCoords, edgeCoords));
1683   CHKERRQ(PetscDrawFlush(draw));
1684   CHKERRQ(PetscDrawPause(draw));
1685   CHKERRQ(PetscDrawSave(draw));
1686   PetscFunctionReturn(0);
1687 }
1688 
1689 #if defined(PETSC_HAVE_EXODUSII)
1690 #include <exodusII.h>
1691 #include <petscviewerexodusii.h>
1692 #endif
1693 
1694 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1695 {
1696   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus;
1697   char           name[PETSC_MAX_PATH_LEN];
1698 
1699   PetscFunctionBegin;
1700   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1701   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1702   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII,    &iascii));
1703   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,      &isvtk));
1704   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5));
1705   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,     &isdraw));
1706   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS,    &isglvis));
1707   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus));
1708   if (iascii) {
1709     PetscViewerFormat format;
1710     CHKERRQ(PetscViewerGetFormat(viewer, &format));
1711     if (format == PETSC_VIEWER_ASCII_GLVIS) {
1712       CHKERRQ(DMPlexView_GLVis(dm, viewer));
1713     } else {
1714       CHKERRQ(DMPlexView_Ascii(dm, viewer));
1715     }
1716   } else if (ishdf5) {
1717 #if defined(PETSC_HAVE_HDF5)
1718     CHKERRQ(DMPlexView_HDF5_Internal(dm, viewer));
1719 #else
1720     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1721 #endif
1722   } else if (isvtk) {
1723     CHKERRQ(DMPlexVTKWriteAll((PetscObject) dm,viewer));
1724   } else if (isdraw) {
1725     CHKERRQ(DMPlexView_Draw(dm, viewer));
1726   } else if (isglvis) {
1727     CHKERRQ(DMPlexView_GLVis(dm, viewer));
1728 #if defined(PETSC_HAVE_EXODUSII)
1729   } else if (isexodus) {
1730 /*
1731       exodusII requires that all sets be part of exactly one cell set.
1732       If the dm does not have a "Cell Sets" label defined, we create one
1733       with ID 1, containig all cells.
1734       Note that if the Cell Sets label is defined but does not cover all cells,
1735       we may still have a problem. This should probably be checked here or in the viewer;
1736     */
1737     PetscInt numCS;
1738     CHKERRQ(DMGetLabelSize(dm,"Cell Sets",&numCS));
1739     if (!numCS) {
1740       PetscInt cStart, cEnd, c;
1741       CHKERRQ(DMCreateLabel(dm, "Cell Sets"));
1742       CHKERRQ(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1743       for (c = cStart; c < cEnd; ++c) CHKERRQ(DMSetLabelValue(dm, "Cell Sets", c, 1));
1744     }
1745     CHKERRQ(DMView_PlexExodusII(dm, viewer));
1746 #endif
1747   } else {
1748     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1749   }
1750   /* Optionally view the partition */
1751   CHKERRQ(PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg));
1752   if (flg) {
1753     Vec ranks;
1754     CHKERRQ(DMPlexCreateRankField(dm, &ranks));
1755     CHKERRQ(VecView(ranks, viewer));
1756     CHKERRQ(VecDestroy(&ranks));
1757   }
1758   /* Optionally view a label */
1759   CHKERRQ(PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg));
1760   if (flg) {
1761     DMLabel label;
1762     Vec     val;
1763 
1764     CHKERRQ(DMGetLabel(dm, name, &label));
1765     PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
1766     CHKERRQ(DMPlexCreateLabelField(dm, label, &val));
1767     CHKERRQ(VecView(val, viewer));
1768     CHKERRQ(VecDestroy(&val));
1769   }
1770   PetscFunctionReturn(0);
1771 }
1772 
1773 /*@
1774   DMPlexTopologyView - Saves a DMPlex topology into a file
1775 
1776   Collective on DM
1777 
1778   Input Parameters:
1779 + dm     - The DM whose topology is to be saved
1780 - viewer - The PetscViewer for saving
1781 
1782   Level: advanced
1783 
1784 .seealso: DMView(), DMPlexCoordinatesView(), DMPlexLabelsView(), DMPlexTopologyLoad()
1785 @*/
1786 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
1787 {
1788   PetscBool      ishdf5;
1789 
1790   PetscFunctionBegin;
1791   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1792   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1793   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
1794   CHKERRQ(PetscLogEventBegin(DMPLEX_TopologyView,viewer,0,0,0));
1795   if (ishdf5) {
1796 #if defined(PETSC_HAVE_HDF5)
1797     PetscViewerFormat format;
1798     CHKERRQ(PetscViewerGetFormat(viewer, &format));
1799     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1800       IS globalPointNumbering;
1801 
1802       CHKERRQ(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
1803       CHKERRQ(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer));
1804       CHKERRQ(ISDestroy(&globalPointNumbering));
1805     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
1806 #else
1807     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1808 #endif
1809   }
1810   CHKERRQ(PetscLogEventEnd(DMPLEX_TopologyView,viewer,0,0,0));
1811   PetscFunctionReturn(0);
1812 }
1813 
1814 /*@
1815   DMPlexCoordinatesView - Saves DMPlex coordinates into a file
1816 
1817   Collective on DM
1818 
1819   Input Parameters:
1820 + dm     - The DM whose coordinates are to be saved
1821 - viewer - The PetscViewer for saving
1822 
1823   Level: advanced
1824 
1825 .seealso: DMView(), DMPlexTopologyView(), DMPlexLabelsView(), DMPlexCoordinatesLoad()
1826 @*/
1827 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
1828 {
1829   PetscBool      ishdf5;
1830 
1831   PetscFunctionBegin;
1832   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1833   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1834   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
1835   CHKERRQ(PetscLogEventBegin(DMPLEX_CoordinatesView,viewer,0,0,0));
1836   if (ishdf5) {
1837 #if defined(PETSC_HAVE_HDF5)
1838     PetscViewerFormat format;
1839     CHKERRQ(PetscViewerGetFormat(viewer, &format));
1840     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1841       CHKERRQ(DMPlexCoordinatesView_HDF5_Internal(dm, viewer));
1842     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1843 #else
1844     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1845 #endif
1846   }
1847   CHKERRQ(PetscLogEventEnd(DMPLEX_CoordinatesView,viewer,0,0,0));
1848   PetscFunctionReturn(0);
1849 }
1850 
1851 /*@
1852   DMPlexLabelsView - Saves DMPlex labels into a file
1853 
1854   Collective on DM
1855 
1856   Input Parameters:
1857 + dm     - The DM whose labels are to be saved
1858 - viewer - The PetscViewer for saving
1859 
1860   Level: advanced
1861 
1862 .seealso: DMView(), DMPlexTopologyView(), DMPlexCoordinatesView(), DMPlexLabelsLoad()
1863 @*/
1864 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
1865 {
1866   PetscBool      ishdf5;
1867 
1868   PetscFunctionBegin;
1869   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1870   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1871   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
1872   CHKERRQ(PetscLogEventBegin(DMPLEX_LabelsView,viewer,0,0,0));
1873   if (ishdf5) {
1874 #if defined(PETSC_HAVE_HDF5)
1875     IS                globalPointNumbering;
1876     PetscViewerFormat format;
1877 
1878     CHKERRQ(PetscViewerGetFormat(viewer, &format));
1879     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1880       CHKERRQ(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
1881       CHKERRQ(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer));
1882       CHKERRQ(ISDestroy(&globalPointNumbering));
1883     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1884 #else
1885     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1886 #endif
1887   }
1888   CHKERRQ(PetscLogEventEnd(DMPLEX_LabelsView,viewer,0,0,0));
1889   PetscFunctionReturn(0);
1890 }
1891 
1892 /*@
1893   DMPlexSectionView - Saves a section associated with a DMPlex
1894 
1895   Collective on DM
1896 
1897   Input Parameters:
1898 + dm         - The DM that contains the topology on which the section to be saved is defined
1899 . viewer     - The PetscViewer for saving
1900 - sectiondm  - The DM that contains the section to be saved
1901 
1902   Level: advanced
1903 
1904   Notes:
1905   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.
1906 
1907   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.
1908 
1909 .seealso: DMView(), DMPlexTopologyView(), DMPlexCoordinatesView(), DMPlexLabelsView(), DMPlexGlobalVectorView(), DMPlexLocalVectorView(), PetscSectionView(), DMPlexSectionLoad()
1910 @*/
1911 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
1912 {
1913   PetscBool      ishdf5;
1914 
1915   PetscFunctionBegin;
1916   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1917   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1918   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
1919   CHKERRQ(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5));
1920   CHKERRQ(PetscLogEventBegin(DMPLEX_SectionView,viewer,0,0,0));
1921   if (ishdf5) {
1922 #if defined(PETSC_HAVE_HDF5)
1923     CHKERRQ(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm));
1924 #else
1925     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1926 #endif
1927   }
1928   CHKERRQ(PetscLogEventEnd(DMPLEX_SectionView,viewer,0,0,0));
1929   PetscFunctionReturn(0);
1930 }
1931 
1932 /*@
1933   DMPlexGlobalVectorView - Saves a global vector
1934 
1935   Collective on DM
1936 
1937   Input Parameters:
1938 + dm        - The DM that represents the topology
1939 . viewer    - The PetscViewer to save data with
1940 . sectiondm - The DM that contains the global section on which vec is defined
1941 - vec       - The global vector to be saved
1942 
1943   Level: advanced
1944 
1945   Notes:
1946   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.
1947 
1948   Typical calling sequence
1949 $       DMCreate(PETSC_COMM_WORLD, &dm);
1950 $       DMSetType(dm, DMPLEX);
1951 $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
1952 $       DMClone(dm, &sectiondm);
1953 $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
1954 $       PetscSectionCreate(PETSC_COMM_WORLD, &section);
1955 $       DMPlexGetChart(sectiondm, &pStart, &pEnd);
1956 $       PetscSectionSetChart(section, pStart, pEnd);
1957 $       PetscSectionSetUp(section);
1958 $       DMSetLocalSection(sectiondm, section);
1959 $       PetscSectionDestroy(&section);
1960 $       DMGetGlobalVector(sectiondm, &vec);
1961 $       PetscObjectSetName((PetscObject)vec, "vec_name");
1962 $       DMPlexTopologyView(dm, viewer);
1963 $       DMPlexSectionView(dm, viewer, sectiondm);
1964 $       DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
1965 $       DMRestoreGlobalVector(sectiondm, &vec);
1966 $       DMDestroy(&sectiondm);
1967 $       DMDestroy(&dm);
1968 
1969 .seealso: DMPlexTopologyView(), DMPlexSectionView(), DMPlexLocalVectorView(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad()
1970 @*/
1971 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
1972 {
1973   PetscBool       ishdf5;
1974 
1975   PetscFunctionBegin;
1976   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1977   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1978   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
1979   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
1980   /* Check consistency */
1981   {
1982     PetscSection  section;
1983     PetscBool     includesConstraints;
1984     PetscInt      m, m1;
1985 
1986     CHKERRQ(VecGetLocalSize(vec, &m1));
1987     CHKERRQ(DMGetGlobalSection(sectiondm, &section));
1988     CHKERRQ(PetscSectionGetIncludesConstraints(section, &includesConstraints));
1989     if (includesConstraints) CHKERRQ(PetscSectionGetStorageSize(section, &m));
1990     else CHKERRQ(PetscSectionGetConstrainedStorageSize(section, &m));
1991     PetscCheckFalse(m1 != m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%D) != global section storage size (%D)", m1, m);
1992   }
1993   CHKERRQ(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
1994   CHKERRQ(PetscLogEventBegin(DMPLEX_GlobalVectorView,viewer,0,0,0));
1995   if (ishdf5) {
1996 #if defined(PETSC_HAVE_HDF5)
1997     CHKERRQ(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
1998 #else
1999     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2000 #endif
2001   }
2002   CHKERRQ(PetscLogEventEnd(DMPLEX_GlobalVectorView,viewer,0,0,0));
2003   PetscFunctionReturn(0);
2004 }
2005 
2006 /*@
2007   DMPlexLocalVectorView - Saves a local vector
2008 
2009   Collective on DM
2010 
2011   Input Parameters:
2012 + dm        - The DM that represents the topology
2013 . viewer    - The PetscViewer to save data with
2014 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm
2015 - vec       - The local vector to be saved
2016 
2017   Level: advanced
2018 
2019   Notes:
2020   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.
2021 
2022   Typical calling sequence
2023 $       DMCreate(PETSC_COMM_WORLD, &dm);
2024 $       DMSetType(dm, DMPLEX);
2025 $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
2026 $       DMClone(dm, &sectiondm);
2027 $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2028 $       PetscSectionCreate(PETSC_COMM_WORLD, &section);
2029 $       DMPlexGetChart(sectiondm, &pStart, &pEnd);
2030 $       PetscSectionSetChart(section, pStart, pEnd);
2031 $       PetscSectionSetUp(section);
2032 $       DMSetLocalSection(sectiondm, section);
2033 $       DMGetLocalVector(sectiondm, &vec);
2034 $       PetscObjectSetName((PetscObject)vec, "vec_name");
2035 $       DMPlexTopologyView(dm, viewer);
2036 $       DMPlexSectionView(dm, viewer, sectiondm);
2037 $       DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
2038 $       DMRestoreLocalVector(sectiondm, &vec);
2039 $       DMDestroy(&sectiondm);
2040 $       DMDestroy(&dm);
2041 
2042 .seealso: DMPlexTopologyView(), DMPlexSectionView(), DMPlexGlobalVectorView(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad()
2043 @*/
2044 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2045 {
2046   PetscBool       ishdf5;
2047 
2048   PetscFunctionBegin;
2049   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2050   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2051   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2052   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
2053   /* Check consistency */
2054   {
2055     PetscSection  section;
2056     PetscBool     includesConstraints;
2057     PetscInt      m, m1;
2058 
2059     CHKERRQ(VecGetLocalSize(vec, &m1));
2060     CHKERRQ(DMGetLocalSection(sectiondm, &section));
2061     CHKERRQ(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2062     if (includesConstraints) CHKERRQ(PetscSectionGetStorageSize(section, &m));
2063     else CHKERRQ(PetscSectionGetConstrainedStorageSize(section, &m));
2064     PetscCheckFalse(m1 != m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%D) != local section storage size (%D)", m1, m);
2065   }
2066   CHKERRQ(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2067   CHKERRQ(PetscLogEventBegin(DMPLEX_LocalVectorView,viewer,0,0,0));
2068   if (ishdf5) {
2069 #if defined(PETSC_HAVE_HDF5)
2070     CHKERRQ(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
2071 #else
2072     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2073 #endif
2074   }
2075   CHKERRQ(PetscLogEventEnd(DMPLEX_LocalVectorView,viewer,0,0,0));
2076   PetscFunctionReturn(0);
2077 }
2078 
2079 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
2080 {
2081   PetscBool      ishdf5;
2082 
2083   PetscFunctionBegin;
2084   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2085   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2086   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5));
2087   if (ishdf5) {
2088 #if defined(PETSC_HAVE_HDF5)
2089     PetscViewerFormat format;
2090     CHKERRQ(PetscViewerGetFormat(viewer, &format));
2091     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
2092       CHKERRQ(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer));
2093     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2094       CHKERRQ(DMPlexLoad_HDF5_Internal(dm, viewer));
2095     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2096     PetscFunctionReturn(0);
2097 #else
2098     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2099 #endif
2100   } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
2101 }
2102 
2103 /*@
2104   DMPlexTopologyLoad - Loads a topology into a DMPlex
2105 
2106   Collective on DM
2107 
2108   Input Parameters:
2109 + dm     - The DM into which the topology is loaded
2110 - viewer - The PetscViewer for the saved topology
2111 
2112   Output Parameters:
2113 . 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
2114 
2115   Level: advanced
2116 
2117 .seealso: DMLoad(), DMPlexCoordinatesLoad(), DMPlexLabelsLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat()
2118 @*/
2119 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
2120 {
2121   PetscBool      ishdf5;
2122 
2123   PetscFunctionBegin;
2124   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2125   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2126   if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3);
2127   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
2128   CHKERRQ(PetscLogEventBegin(DMPLEX_TopologyLoad,viewer,0,0,0));
2129   if (ishdf5) {
2130 #if defined(PETSC_HAVE_HDF5)
2131     PetscViewerFormat format;
2132     CHKERRQ(PetscViewerGetFormat(viewer, &format));
2133     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2134       CHKERRQ(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2135     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2136 #else
2137     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2138 #endif
2139   }
2140   CHKERRQ(PetscLogEventEnd(DMPLEX_TopologyLoad,viewer,0,0,0));
2141   PetscFunctionReturn(0);
2142 }
2143 
2144 /*@
2145   DMPlexCoordinatesLoad - Loads coordinates into a DMPlex
2146 
2147   Collective on DM
2148 
2149   Input Parameters:
2150 + dm     - The DM into which the coordinates are loaded
2151 . viewer - The PetscViewer for the saved coordinates
2152 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
2153 
2154   Level: advanced
2155 
2156 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexLabelsLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat()
2157 @*/
2158 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2159 {
2160   PetscBool      ishdf5;
2161 
2162   PetscFunctionBegin;
2163   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2164   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2165   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
2166   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
2167   CHKERRQ(PetscLogEventBegin(DMPLEX_CoordinatesLoad,viewer,0,0,0));
2168   if (ishdf5) {
2169 #if defined(PETSC_HAVE_HDF5)
2170     PetscViewerFormat format;
2171     CHKERRQ(PetscViewerGetFormat(viewer, &format));
2172     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2173       CHKERRQ(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2174     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2175 #else
2176     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2177 #endif
2178   }
2179   CHKERRQ(PetscLogEventEnd(DMPLEX_CoordinatesLoad,viewer,0,0,0));
2180   PetscFunctionReturn(0);
2181 }
2182 
2183 /*@
2184   DMPlexLabelsLoad - Loads labels into a DMPlex
2185 
2186   Collective on DM
2187 
2188   Input Parameters:
2189 + dm     - The DM into which the labels are loaded
2190 . viewer - The PetscViewer for the saved labels
2191 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
2192 
2193   Level: advanced
2194 
2195   Notes:
2196   The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs.
2197 
2198 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexCoordinatesLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat()
2199 @*/
2200 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2201 {
2202   PetscBool      ishdf5;
2203 
2204   PetscFunctionBegin;
2205   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2206   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2207   if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
2208   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
2209   CHKERRQ(PetscLogEventBegin(DMPLEX_LabelsLoad,viewer,0,0,0));
2210   if (ishdf5) {
2211 #if defined(PETSC_HAVE_HDF5)
2212     PetscViewerFormat format;
2213 
2214     CHKERRQ(PetscViewerGetFormat(viewer, &format));
2215     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2216       CHKERRQ(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2217     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2218 #else
2219     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2220 #endif
2221   }
2222   CHKERRQ(PetscLogEventEnd(DMPLEX_LabelsLoad,viewer,0,0,0));
2223   PetscFunctionReturn(0);
2224 }
2225 
2226 /*@
2227   DMPlexSectionLoad - Loads section into a DMPlex
2228 
2229   Collective on DM
2230 
2231   Input Parameters:
2232 + dm          - The DM that represents the topology
2233 . viewer      - The PetscViewer that represents the on-disk section (sectionA)
2234 . sectiondm   - The DM into which the on-disk section (sectionA) is migrated
2235 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
2236 
2237   Output Parameters
2238 + 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)
2239 - 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)
2240 
2241   Level: advanced
2242 
2243   Notes:
2244   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.
2245 
2246   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.
2247 
2248   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.
2249 
2250   Example using 2 processes:
2251 $  NX (number of points on dm): 4
2252 $  sectionA                   : the on-disk section
2253 $  vecA                       : a vector associated with sectionA
2254 $  sectionB                   : sectiondm's local section constructed in this function
2255 $  vecB (local)               : a vector associated with sectiondm's local section
2256 $  vecB (global)              : a vector associated with sectiondm's global section
2257 $
2258 $                                     rank 0    rank 1
2259 $  vecA (global)                  : [.0 .4 .1 | .2 .3]        <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
2260 $  sectionA->atlasOff             :       0 2 | 1             <- loaded in PetscSectionLoad()
2261 $  sectionA->atlasDof             :       1 3 | 1             <- loaded in PetscSectionLoad()
2262 $  sectionA's global point numbers:       0 2 | 3             <- loaded in DMPlexSectionLoad()
2263 $  [0, NX)                        :       0 1 | 2 3           <- conceptual partition used in globalToLocalPointSF
2264 $  sectionB's global point numbers:     0 1 3 | 3 2           <- associated with [0, NX) by globalToLocalPointSF
2265 $  sectionB->atlasDof             :     1 0 1 | 1 3
2266 $  sectionB->atlasOff (no perm)   :     0 1 1 | 0 1
2267 $  vecB (local)                   :   [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
2268 $  vecB (global)                  :    [.0 .4 | .1 .2 .3]     <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
2269 $
2270 $  where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.
2271 
2272 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexCoordinatesLoad(), DMPlexLabelsLoad(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad(), PetscSectionLoad(), DMPlexSectionView()
2273 @*/
2274 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF)
2275 {
2276   PetscBool      ishdf5;
2277 
2278   PetscFunctionBegin;
2279   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2280   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2281   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2282   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4);
2283   if (globalDofSF) PetscValidPointer(globalDofSF, 5);
2284   if (localDofSF) PetscValidPointer(localDofSF, 6);
2285   CHKERRQ(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5));
2286   CHKERRQ(PetscLogEventBegin(DMPLEX_SectionLoad,viewer,0,0,0));
2287   if (ishdf5) {
2288 #if defined(PETSC_HAVE_HDF5)
2289     CHKERRQ(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF));
2290 #else
2291     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2292 #endif
2293   }
2294   CHKERRQ(PetscLogEventEnd(DMPLEX_SectionLoad,viewer,0,0,0));
2295   PetscFunctionReturn(0);
2296 }
2297 
2298 /*@
2299   DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector
2300 
2301   Collective on DM
2302 
2303   Input Parameters:
2304 + dm        - The DM that represents the topology
2305 . viewer    - The PetscViewer that represents the on-disk vector data
2306 . sectiondm - The DM that contains the global section on which vec is defined
2307 . sf        - The SF that migrates the on-disk vector data into vec
2308 - vec       - The global vector to set values of
2309 
2310   Level: advanced
2311 
2312   Notes:
2313   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.
2314 
2315   Typical calling sequence
2316 $       DMCreate(PETSC_COMM_WORLD, &dm);
2317 $       DMSetType(dm, DMPLEX);
2318 $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
2319 $       DMPlexTopologyLoad(dm, viewer, &sfX);
2320 $       DMClone(dm, &sectiondm);
2321 $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2322 $       DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL);
2323 $       DMGetGlobalVector(sectiondm, &vec);
2324 $       PetscObjectSetName((PetscObject)vec, "vec_name");
2325 $       DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec);
2326 $       DMRestoreGlobalVector(sectiondm, &vec);
2327 $       PetscSFDestroy(&gsf);
2328 $       PetscSFDestroy(&sfX);
2329 $       DMDestroy(&sectiondm);
2330 $       DMDestroy(&dm);
2331 
2332 .seealso: DMPlexTopologyLoad(), DMPlexSectionLoad(), DMPlexLocalVectorLoad(), DMPlexGlobalVectorView(), DMPlexLocalVectorView()
2333 @*/
2334 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2335 {
2336   PetscBool       ishdf5;
2337 
2338   PetscFunctionBegin;
2339   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2340   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2341   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2342   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
2343   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
2344   /* Check consistency */
2345   {
2346     PetscSection  section;
2347     PetscBool     includesConstraints;
2348     PetscInt      m, m1;
2349 
2350     CHKERRQ(VecGetLocalSize(vec, &m1));
2351     CHKERRQ(DMGetGlobalSection(sectiondm, &section));
2352     CHKERRQ(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2353     if (includesConstraints) CHKERRQ(PetscSectionGetStorageSize(section, &m));
2354     else CHKERRQ(PetscSectionGetConstrainedStorageSize(section, &m));
2355     PetscCheckFalse(m1 != m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%D) != global section storage size (%D)", m1, m);
2356   }
2357   CHKERRQ(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5));
2358   CHKERRQ(PetscLogEventBegin(DMPLEX_GlobalVectorLoad,viewer,0,0,0));
2359   if (ishdf5) {
2360 #if defined(PETSC_HAVE_HDF5)
2361     CHKERRQ(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
2362 #else
2363     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2364 #endif
2365   }
2366   CHKERRQ(PetscLogEventEnd(DMPLEX_GlobalVectorLoad,viewer,0,0,0));
2367   PetscFunctionReturn(0);
2368 }
2369 
2370 /*@
2371   DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector
2372 
2373   Collective on DM
2374 
2375   Input Parameters:
2376 + dm        - The DM that represents the topology
2377 . viewer    - The PetscViewer that represents the on-disk vector data
2378 . sectiondm - The DM that contains the local section on which vec is defined
2379 . sf        - The SF that migrates the on-disk vector data into vec
2380 - vec       - The local vector to set values of
2381 
2382   Level: advanced
2383 
2384   Notes:
2385   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.
2386 
2387   Typical calling sequence
2388 $       DMCreate(PETSC_COMM_WORLD, &dm);
2389 $       DMSetType(dm, DMPLEX);
2390 $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
2391 $       DMPlexTopologyLoad(dm, viewer, &sfX);
2392 $       DMClone(dm, &sectiondm);
2393 $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2394 $       DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf);
2395 $       DMGetLocalVector(sectiondm, &vec);
2396 $       PetscObjectSetName((PetscObject)vec, "vec_name");
2397 $       DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec);
2398 $       DMRestoreLocalVector(sectiondm, &vec);
2399 $       PetscSFDestroy(&lsf);
2400 $       PetscSFDestroy(&sfX);
2401 $       DMDestroy(&sectiondm);
2402 $       DMDestroy(&dm);
2403 
2404 .seealso: DMPlexTopologyLoad(), DMPlexSectionLoad(), DMPlexGlobalVectorLoad(), DMPlexGlobalVectorView(), DMPlexLocalVectorView()
2405 @*/
2406 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2407 {
2408   PetscBool       ishdf5;
2409 
2410   PetscFunctionBegin;
2411   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2412   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2413   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2414   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
2415   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
2416   /* Check consistency */
2417   {
2418     PetscSection  section;
2419     PetscBool     includesConstraints;
2420     PetscInt      m, m1;
2421 
2422     CHKERRQ(VecGetLocalSize(vec, &m1));
2423     CHKERRQ(DMGetLocalSection(sectiondm, &section));
2424     CHKERRQ(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2425     if (includesConstraints) CHKERRQ(PetscSectionGetStorageSize(section, &m));
2426     else CHKERRQ(PetscSectionGetConstrainedStorageSize(section, &m));
2427     PetscCheckFalse(m1 != m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%D) != local section storage size (%D)", m1, m);
2428   }
2429   CHKERRQ(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5));
2430   CHKERRQ(PetscLogEventBegin(DMPLEX_LocalVectorLoad,viewer,0,0,0));
2431   if (ishdf5) {
2432 #if defined(PETSC_HAVE_HDF5)
2433     CHKERRQ(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
2434 #else
2435     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2436 #endif
2437   }
2438   CHKERRQ(PetscLogEventEnd(DMPLEX_LocalVectorLoad,viewer,0,0,0));
2439   PetscFunctionReturn(0);
2440 }
2441 
2442 PetscErrorCode DMDestroy_Plex(DM dm)
2443 {
2444   DM_Plex       *mesh = (DM_Plex*) dm->data;
2445 
2446   PetscFunctionBegin;
2447   CHKERRQ(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL));
2448   CHKERRQ(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL));
2449   CHKERRQ(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL));
2450   CHKERRQ(PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL));
2451   if (--mesh->refct > 0) PetscFunctionReturn(0);
2452   CHKERRQ(PetscSectionDestroy(&mesh->coneSection));
2453   CHKERRQ(PetscFree(mesh->cones));
2454   CHKERRQ(PetscFree(mesh->coneOrientations));
2455   CHKERRQ(PetscSectionDestroy(&mesh->supportSection));
2456   CHKERRQ(PetscSectionDestroy(&mesh->subdomainSection));
2457   CHKERRQ(PetscFree(mesh->supports));
2458   CHKERRQ(PetscFree(mesh->facesTmp));
2459   CHKERRQ(PetscFree(mesh->tetgenOpts));
2460   CHKERRQ(PetscFree(mesh->triangleOpts));
2461   CHKERRQ(PetscFree(mesh->transformType));
2462   CHKERRQ(PetscPartitionerDestroy(&mesh->partitioner));
2463   CHKERRQ(DMLabelDestroy(&mesh->subpointMap));
2464   CHKERRQ(ISDestroy(&mesh->subpointIS));
2465   CHKERRQ(ISDestroy(&mesh->globalVertexNumbers));
2466   CHKERRQ(ISDestroy(&mesh->globalCellNumbers));
2467   CHKERRQ(PetscSectionDestroy(&mesh->anchorSection));
2468   CHKERRQ(ISDestroy(&mesh->anchorIS));
2469   CHKERRQ(PetscSectionDestroy(&mesh->parentSection));
2470   CHKERRQ(PetscFree(mesh->parents));
2471   CHKERRQ(PetscFree(mesh->childIDs));
2472   CHKERRQ(PetscSectionDestroy(&mesh->childSection));
2473   CHKERRQ(PetscFree(mesh->children));
2474   CHKERRQ(DMDestroy(&mesh->referenceTree));
2475   CHKERRQ(PetscGridHashDestroy(&mesh->lbox));
2476   CHKERRQ(PetscFree(mesh->neighbors));
2477   if (mesh->metricCtx) CHKERRQ(PetscFree(mesh->metricCtx));
2478   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
2479   CHKERRQ(PetscFree(mesh));
2480   PetscFunctionReturn(0);
2481 }
2482 
2483 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
2484 {
2485   PetscSection           sectionGlobal;
2486   PetscInt               bs = -1, mbs;
2487   PetscInt               localSize;
2488   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
2489   MatType                mtype;
2490   ISLocalToGlobalMapping ltog;
2491 
2492   PetscFunctionBegin;
2493   CHKERRQ(MatInitializePackage());
2494   mtype = dm->mattype;
2495   CHKERRQ(DMGetGlobalSection(dm, &sectionGlobal));
2496   /* CHKERRQ(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */
2497   CHKERRQ(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize));
2498   CHKERRQ(MatCreate(PetscObjectComm((PetscObject)dm), J));
2499   CHKERRQ(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE));
2500   CHKERRQ(MatSetType(*J, mtype));
2501   CHKERRQ(MatSetFromOptions(*J));
2502   CHKERRQ(MatGetBlockSize(*J, &mbs));
2503   if (mbs > 1) bs = mbs;
2504   CHKERRQ(PetscStrcmp(mtype, MATSHELL, &isShell));
2505   CHKERRQ(PetscStrcmp(mtype, MATBAIJ, &isBlock));
2506   CHKERRQ(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock));
2507   CHKERRQ(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock));
2508   CHKERRQ(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock));
2509   CHKERRQ(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock));
2510   CHKERRQ(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock));
2511   CHKERRQ(PetscStrcmp(mtype, MATIS, &isMatIS));
2512   if (!isShell) {
2513     PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
2514     PetscInt  *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2];
2515     PetscInt  pStart, pEnd, p, dof, cdof;
2516 
2517     CHKERRQ(DMGetLocalToGlobalMapping(dm,&ltog));
2518     CHKERRQ(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
2519     for (p = pStart; p < pEnd; ++p) {
2520       PetscInt bdof;
2521 
2522       CHKERRQ(PetscSectionGetDof(sectionGlobal, p, &dof));
2523       CHKERRQ(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof));
2524       dof  = dof < 0 ? -(dof+1) : dof;
2525       bdof = cdof && (dof-cdof) ? 1 : dof;
2526       if (dof) {
2527         if (bs < 0)          {bs = bdof;}
2528         else if (bs != bdof) {bs = 1; break;}
2529       }
2530     }
2531     /* Must have same blocksize on all procs (some might have no points) */
2532     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
2533     bsLocal[1] = bs;
2534     CHKERRQ(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax));
2535     if (bsMinMax[0] != bsMinMax[1]) bs = 1;
2536     else bs = bsMinMax[0];
2537     bs = PetscMax(1,bs);
2538     CHKERRQ(MatSetLocalToGlobalMapping(*J,ltog,ltog));
2539     if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters
2540       CHKERRQ(MatSetBlockSize(*J, bs));
2541       CHKERRQ(MatSetUp(*J));
2542     } else {
2543       CHKERRQ(PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu));
2544       CHKERRQ(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix));
2545       CHKERRQ(PetscFree4(dnz, onz, dnzu, onzu));
2546     }
2547   }
2548   CHKERRQ(MatSetDM(*J, dm));
2549   PetscFunctionReturn(0);
2550 }
2551 
2552 /*@
2553   DMPlexGetSubdomainSection - Returns the section associated with the subdomain
2554 
2555   Not collective
2556 
2557   Input Parameter:
2558 . mesh - The DMPlex
2559 
2560   Output Parameters:
2561 . subsection - The subdomain section
2562 
2563   Level: developer
2564 
2565 .seealso:
2566 @*/
2567 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
2568 {
2569   DM_Plex       *mesh = (DM_Plex*) dm->data;
2570 
2571   PetscFunctionBegin;
2572   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2573   if (!mesh->subdomainSection) {
2574     PetscSection section;
2575     PetscSF      sf;
2576 
2577     CHKERRQ(PetscSFCreate(PETSC_COMM_SELF,&sf));
2578     CHKERRQ(DMGetLocalSection(dm,&section));
2579     CHKERRQ(PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection));
2580     CHKERRQ(PetscSFDestroy(&sf));
2581   }
2582   *subsection = mesh->subdomainSection;
2583   PetscFunctionReturn(0);
2584 }
2585 
2586 /*@
2587   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
2588 
2589   Not collective
2590 
2591   Input Parameter:
2592 . mesh - The DMPlex
2593 
2594   Output Parameters:
2595 + pStart - The first mesh point
2596 - pEnd   - The upper bound for mesh points
2597 
2598   Level: beginner
2599 
2600 .seealso: DMPlexCreate(), DMPlexSetChart()
2601 @*/
2602 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
2603 {
2604   DM_Plex       *mesh = (DM_Plex*) dm->data;
2605 
2606   PetscFunctionBegin;
2607   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2608   CHKERRQ(PetscSectionGetChart(mesh->coneSection, pStart, pEnd));
2609   PetscFunctionReturn(0);
2610 }
2611 
2612 /*@
2613   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
2614 
2615   Not collective
2616 
2617   Input Parameters:
2618 + mesh - The DMPlex
2619 . pStart - The first mesh point
2620 - pEnd   - The upper bound for mesh points
2621 
2622   Output Parameters:
2623 
2624   Level: beginner
2625 
2626 .seealso: DMPlexCreate(), DMPlexGetChart()
2627 @*/
2628 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
2629 {
2630   DM_Plex       *mesh = (DM_Plex*) dm->data;
2631 
2632   PetscFunctionBegin;
2633   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2634   CHKERRQ(PetscSectionSetChart(mesh->coneSection, pStart, pEnd));
2635   CHKERRQ(PetscSectionSetChart(mesh->supportSection, pStart, pEnd));
2636   PetscFunctionReturn(0);
2637 }
2638 
2639 /*@
2640   DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
2641 
2642   Not collective
2643 
2644   Input Parameters:
2645 + mesh - The DMPlex
2646 - p - The point, which must lie in the chart set with DMPlexSetChart()
2647 
2648   Output Parameter:
2649 . size - The cone size for point p
2650 
2651   Level: beginner
2652 
2653 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2654 @*/
2655 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
2656 {
2657   DM_Plex       *mesh = (DM_Plex*) dm->data;
2658 
2659   PetscFunctionBegin;
2660   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2661   PetscValidIntPointer(size, 3);
2662   CHKERRQ(PetscSectionGetDof(mesh->coneSection, p, size));
2663   PetscFunctionReturn(0);
2664 }
2665 
2666 /*@
2667   DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
2668 
2669   Not collective
2670 
2671   Input Parameters:
2672 + mesh - The DMPlex
2673 . p - The point, which must lie in the chart set with DMPlexSetChart()
2674 - size - The cone size for point p
2675 
2676   Output Parameter:
2677 
2678   Note:
2679   This should be called after DMPlexSetChart().
2680 
2681   Level: beginner
2682 
2683 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
2684 @*/
2685 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
2686 {
2687   DM_Plex       *mesh = (DM_Plex*) dm->data;
2688 
2689   PetscFunctionBegin;
2690   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2691   CHKERRQ(PetscSectionSetDof(mesh->coneSection, p, size));
2692 
2693   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
2694   PetscFunctionReturn(0);
2695 }
2696 
2697 /*@
2698   DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG
2699 
2700   Not collective
2701 
2702   Input Parameters:
2703 + mesh - The DMPlex
2704 . p - The point, which must lie in the chart set with DMPlexSetChart()
2705 - size - The additional cone size for point p
2706 
2707   Output Parameter:
2708 
2709   Note:
2710   This should be called after DMPlexSetChart().
2711 
2712   Level: beginner
2713 
2714 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
2715 @*/
2716 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
2717 {
2718   DM_Plex       *mesh = (DM_Plex*) dm->data;
2719   PetscInt       csize;
2720 
2721   PetscFunctionBegin;
2722   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2723   CHKERRQ(PetscSectionAddDof(mesh->coneSection, p, size));
2724   CHKERRQ(PetscSectionGetDof(mesh->coneSection, p, &csize));
2725 
2726   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
2727   PetscFunctionReturn(0);
2728 }
2729 
2730 /*@C
2731   DMPlexGetCone - Return the points on the in-edges for this point in the DAG
2732 
2733   Not collective
2734 
2735   Input Parameters:
2736 + dm - The DMPlex
2737 - p - The point, which must lie in the chart set with DMPlexSetChart()
2738 
2739   Output Parameter:
2740 . cone - An array of points which are on the in-edges for point p
2741 
2742   Level: beginner
2743 
2744   Fortran Notes:
2745   Since it returns an array, this routine is only available in Fortran 90, and you must
2746   include petsc.h90 in your code.
2747   You must also call DMPlexRestoreCone() after you finish using the returned array.
2748   DMPlexRestoreCone() is not needed/available in C.
2749 
2750 .seealso: DMPlexGetConeSize(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart()
2751 @*/
2752 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
2753 {
2754   DM_Plex       *mesh = (DM_Plex*) dm->data;
2755   PetscInt       off;
2756 
2757   PetscFunctionBegin;
2758   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2759   PetscValidPointer(cone, 3);
2760   CHKERRQ(PetscSectionGetOffset(mesh->coneSection, p, &off));
2761   *cone = &mesh->cones[off];
2762   PetscFunctionReturn(0);
2763 }
2764 
2765 /*@C
2766   DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
2767 
2768   Not collective
2769 
2770   Input Parameters:
2771 + dm - The DMPlex
2772 - p - The IS of points, which must lie in the chart set with DMPlexSetChart()
2773 
2774   Output Parameters:
2775 + pConesSection - PetscSection describing the layout of pCones
2776 - pCones - An array of points which are on the in-edges for the point set p
2777 
2778   Level: intermediate
2779 
2780 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart()
2781 @*/
2782 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
2783 {
2784   PetscSection        cs, newcs;
2785   PetscInt            *cones;
2786   PetscInt            *newarr=NULL;
2787   PetscInt            n;
2788 
2789   PetscFunctionBegin;
2790   CHKERRQ(DMPlexGetCones(dm, &cones));
2791   CHKERRQ(DMPlexGetConeSection(dm, &cs));
2792   CHKERRQ(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL));
2793   if (pConesSection) *pConesSection = newcs;
2794   if (pCones) {
2795     CHKERRQ(PetscSectionGetStorageSize(newcs, &n));
2796     CHKERRQ(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones));
2797   }
2798   PetscFunctionReturn(0);
2799 }
2800 
2801 /*@
2802   DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.
2803 
2804   Not collective
2805 
2806   Input Parameters:
2807 + dm - The DMPlex
2808 - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2809 
2810   Output Parameter:
2811 . expandedPoints - An array of vertices recursively expanded from input points
2812 
2813   Level: advanced
2814 
2815   Notes:
2816   Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections.
2817   There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate.
2818 
2819 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexRestoreConeRecursive(), DMPlexGetDepth()
2820 @*/
2821 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
2822 {
2823   IS                  *expandedPointsAll;
2824   PetscInt            depth;
2825 
2826   PetscFunctionBegin;
2827   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2828   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
2829   PetscValidPointer(expandedPoints, 3);
2830   CHKERRQ(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
2831   *expandedPoints = expandedPointsAll[0];
2832   CHKERRQ(PetscObjectReference((PetscObject)expandedPointsAll[0]));
2833   CHKERRQ(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
2834   PetscFunctionReturn(0);
2835 }
2836 
2837 /*@
2838   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).
2839 
2840   Not collective
2841 
2842   Input Parameters:
2843 + dm - The DMPlex
2844 - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2845 
2846   Output Parameters:
2847 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
2848 . expandedPoints - (optional) An array of index sets with recursively expanded cones
2849 - sections - (optional) An array of sections which describe mappings from points to their cone points
2850 
2851   Level: advanced
2852 
2853   Notes:
2854   Like DMPlexGetConeTuple() but recursive.
2855 
2856   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.
2857   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.
2858 
2859   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:
2860   (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d];
2861   (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d].
2862 
2863 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexRestoreConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth()
2864 @*/
2865 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
2866 {
2867   const PetscInt      *arr0=NULL, *cone=NULL;
2868   PetscInt            *arr=NULL, *newarr=NULL;
2869   PetscInt            d, depth_, i, n, newn, cn, co, start, end;
2870   IS                  *expandedPoints_;
2871   PetscSection        *sections_;
2872 
2873   PetscFunctionBegin;
2874   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2875   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
2876   if (depth) PetscValidIntPointer(depth, 3);
2877   if (expandedPoints) PetscValidPointer(expandedPoints, 4);
2878   if (sections) PetscValidPointer(sections, 5);
2879   CHKERRQ(ISGetLocalSize(points, &n));
2880   CHKERRQ(ISGetIndices(points, &arr0));
2881   CHKERRQ(DMPlexGetDepth(dm, &depth_));
2882   CHKERRQ(PetscCalloc1(depth_, &expandedPoints_));
2883   CHKERRQ(PetscCalloc1(depth_, &sections_));
2884   arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */
2885   for (d=depth_-1; d>=0; d--) {
2886     CHKERRQ(PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]));
2887     CHKERRQ(PetscSectionSetChart(sections_[d], 0, n));
2888     for (i=0; i<n; i++) {
2889       CHKERRQ(DMPlexGetDepthStratum(dm, d+1, &start, &end));
2890       if (arr[i] >= start && arr[i] < end) {
2891         CHKERRQ(DMPlexGetConeSize(dm, arr[i], &cn));
2892         CHKERRQ(PetscSectionSetDof(sections_[d], i, cn));
2893       } else {
2894         CHKERRQ(PetscSectionSetDof(sections_[d], i, 1));
2895       }
2896     }
2897     CHKERRQ(PetscSectionSetUp(sections_[d]));
2898     CHKERRQ(PetscSectionGetStorageSize(sections_[d], &newn));
2899     CHKERRQ(PetscMalloc1(newn, &newarr));
2900     for (i=0; i<n; i++) {
2901       CHKERRQ(PetscSectionGetDof(sections_[d], i, &cn));
2902       CHKERRQ(PetscSectionGetOffset(sections_[d], i, &co));
2903       if (cn > 1) {
2904         CHKERRQ(DMPlexGetCone(dm, arr[i], &cone));
2905         CHKERRQ(PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt)));
2906       } else {
2907         newarr[co] = arr[i];
2908       }
2909     }
2910     CHKERRQ(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]));
2911     arr = newarr;
2912     n = newn;
2913   }
2914   CHKERRQ(ISRestoreIndices(points, &arr0));
2915   *depth = depth_;
2916   if (expandedPoints) *expandedPoints = expandedPoints_;
2917   else {
2918     for (d=0; d<depth_; d++) CHKERRQ(ISDestroy(&expandedPoints_[d]));
2919     CHKERRQ(PetscFree(expandedPoints_));
2920   }
2921   if (sections) *sections = sections_;
2922   else {
2923     for (d=0; d<depth_; d++) CHKERRQ(PetscSectionDestroy(&sections_[d]));
2924     CHKERRQ(PetscFree(sections_));
2925   }
2926   PetscFunctionReturn(0);
2927 }
2928 
2929 /*@
2930   DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive
2931 
2932   Not collective
2933 
2934   Input Parameters:
2935 + dm - The DMPlex
2936 - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2937 
2938   Output Parameters:
2939 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
2940 . expandedPoints - (optional) An array of recursively expanded cones
2941 - sections - (optional) An array of sections which describe mappings from points to their cone points
2942 
2943   Level: advanced
2944 
2945   Notes:
2946   See DMPlexGetConeRecursive() for details.
2947 
2948 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth()
2949 @*/
2950 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
2951 {
2952   PetscInt            d, depth_;
2953 
2954   PetscFunctionBegin;
2955   CHKERRQ(DMPlexGetDepth(dm, &depth_));
2956   PetscCheckFalse(depth && *depth != depth_,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
2957   if (depth) *depth = 0;
2958   if (expandedPoints) {
2959     for (d=0; d<depth_; d++) CHKERRQ(ISDestroy(&((*expandedPoints)[d])));
2960     CHKERRQ(PetscFree(*expandedPoints));
2961   }
2962   if (sections)  {
2963     for (d=0; d<depth_; d++) CHKERRQ(PetscSectionDestroy(&((*sections)[d])));
2964     CHKERRQ(PetscFree(*sections));
2965   }
2966   PetscFunctionReturn(0);
2967 }
2968 
2969 /*@
2970   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
2971 
2972   Not collective
2973 
2974   Input Parameters:
2975 + mesh - The DMPlex
2976 . p - The point, which must lie in the chart set with DMPlexSetChart()
2977 - cone - An array of points which are on the in-edges for point p
2978 
2979   Output Parameter:
2980 
2981   Note:
2982   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
2983 
2984   Level: beginner
2985 
2986 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
2987 @*/
2988 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
2989 {
2990   DM_Plex       *mesh = (DM_Plex*) dm->data;
2991   PetscInt       pStart, pEnd;
2992   PetscInt       dof, off, c;
2993 
2994   PetscFunctionBegin;
2995   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2996   CHKERRQ(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
2997   CHKERRQ(PetscSectionGetDof(mesh->coneSection, p, &dof));
2998   if (dof) PetscValidIntPointer(cone, 3);
2999   CHKERRQ(PetscSectionGetOffset(mesh->coneSection, p, &off));
3000   PetscCheckFalse((p < pStart) || (p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
3001   for (c = 0; c < dof; ++c) {
3002     PetscCheckFalse((cone[c] < pStart) || (cone[c] >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd);
3003     mesh->cones[off+c] = cone[c];
3004   }
3005   PetscFunctionReturn(0);
3006 }
3007 
3008 /*@C
3009   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
3010 
3011   Not collective
3012 
3013   Input Parameters:
3014 + mesh - The DMPlex
3015 - p - The point, which must lie in the chart set with DMPlexSetChart()
3016 
3017   Output Parameter:
3018 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
3019                     integer giving the prescription for cone traversal.
3020 
3021   Level: beginner
3022 
3023   Notes:
3024   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3025   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3026   of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv()
3027   with the identity.
3028 
3029   Fortran Notes:
3030   Since it returns an array, this routine is only available in Fortran 90, and you must
3031   include petsc.h90 in your code.
3032   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
3033   DMPlexRestoreConeOrientation() is not needed/available in C.
3034 
3035 .seealso: DMPolytopeTypeComposeOrientation(), DMPolytopeTypeComposeOrientationInv(), DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
3036 @*/
3037 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
3038 {
3039   DM_Plex       *mesh = (DM_Plex*) dm->data;
3040   PetscInt       off;
3041 
3042   PetscFunctionBegin;
3043   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3044   if (PetscDefined(USE_DEBUG)) {
3045     PetscInt dof;
3046     CHKERRQ(PetscSectionGetDof(mesh->coneSection, p, &dof));
3047     if (dof) PetscValidPointer(coneOrientation, 3);
3048   }
3049   CHKERRQ(PetscSectionGetOffset(mesh->coneSection, p, &off));
3050 
3051   *coneOrientation = &mesh->coneOrientations[off];
3052   PetscFunctionReturn(0);
3053 }
3054 
3055 /*@
3056   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
3057 
3058   Not collective
3059 
3060   Input Parameters:
3061 + mesh - The DMPlex
3062 . p - The point, which must lie in the chart set with DMPlexSetChart()
3063 - coneOrientation - An array of orientations
3064   Output Parameter:
3065 
3066   Notes:
3067   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
3068 
3069   The meaning of coneOrientation is detailed in DMPlexGetConeOrientation().
3070 
3071   Level: beginner
3072 
3073 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
3074 @*/
3075 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
3076 {
3077   DM_Plex       *mesh = (DM_Plex*) dm->data;
3078   PetscInt       pStart, pEnd;
3079   PetscInt       dof, off, c;
3080 
3081   PetscFunctionBegin;
3082   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3083   CHKERRQ(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3084   CHKERRQ(PetscSectionGetDof(mesh->coneSection, p, &dof));
3085   if (dof) PetscValidIntPointer(coneOrientation, 3);
3086   CHKERRQ(PetscSectionGetOffset(mesh->coneSection, p, &off));
3087   PetscCheckFalse((p < pStart) || (p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
3088   for (c = 0; c < dof; ++c) {
3089     PetscInt cdof, o = coneOrientation[c];
3090 
3091     CHKERRQ(PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof));
3092     PetscCheckFalse(o && ((o < -(cdof+1)) || (o >= cdof)),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof);
3093     mesh->coneOrientations[off+c] = o;
3094   }
3095   PetscFunctionReturn(0);
3096 }
3097 
3098 /*@
3099   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
3100 
3101   Not collective
3102 
3103   Input Parameters:
3104 + mesh - The DMPlex
3105 . p - The point, which must lie in the chart set with DMPlexSetChart()
3106 . conePos - The local index in the cone where the point should be put
3107 - conePoint - The mesh point to insert
3108 
3109   Level: beginner
3110 
3111 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
3112 @*/
3113 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
3114 {
3115   DM_Plex       *mesh = (DM_Plex*) dm->data;
3116   PetscInt       pStart, pEnd;
3117   PetscInt       dof, off;
3118 
3119   PetscFunctionBegin;
3120   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3121   CHKERRQ(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3122   PetscCheckFalse((p < pStart) || (p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
3123   PetscCheckFalse((conePoint < pStart) || (conePoint >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd);
3124   CHKERRQ(PetscSectionGetDof(mesh->coneSection, p, &dof));
3125   CHKERRQ(PetscSectionGetOffset(mesh->coneSection, p, &off));
3126   PetscCheckFalse((conePos < 0) || (conePos >= dof),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
3127   mesh->cones[off+conePos] = conePoint;
3128   PetscFunctionReturn(0);
3129 }
3130 
3131 /*@
3132   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
3133 
3134   Not collective
3135 
3136   Input Parameters:
3137 + mesh - The DMPlex
3138 . p - The point, which must lie in the chart set with DMPlexSetChart()
3139 . conePos - The local index in the cone where the point should be put
3140 - coneOrientation - The point orientation to insert
3141 
3142   Level: beginner
3143 
3144   Notes:
3145   The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation().
3146 
3147 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
3148 @*/
3149 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
3150 {
3151   DM_Plex       *mesh = (DM_Plex*) dm->data;
3152   PetscInt       pStart, pEnd;
3153   PetscInt       dof, off;
3154 
3155   PetscFunctionBegin;
3156   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3157   CHKERRQ(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3158   PetscCheckFalse((p < pStart) || (p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
3159   CHKERRQ(PetscSectionGetDof(mesh->coneSection, p, &dof));
3160   CHKERRQ(PetscSectionGetOffset(mesh->coneSection, p, &off));
3161   PetscCheckFalse((conePos < 0) || (conePos >= dof),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
3162   mesh->coneOrientations[off+conePos] = coneOrientation;
3163   PetscFunctionReturn(0);
3164 }
3165 
3166 /*@
3167   DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
3168 
3169   Not collective
3170 
3171   Input Parameters:
3172 + mesh - The DMPlex
3173 - p - The point, which must lie in the chart set with DMPlexSetChart()
3174 
3175   Output Parameter:
3176 . size - The support size for point p
3177 
3178   Level: beginner
3179 
3180 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
3181 @*/
3182 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
3183 {
3184   DM_Plex       *mesh = (DM_Plex*) dm->data;
3185 
3186   PetscFunctionBegin;
3187   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3188   PetscValidIntPointer(size, 3);
3189   CHKERRQ(PetscSectionGetDof(mesh->supportSection, p, size));
3190   PetscFunctionReturn(0);
3191 }
3192 
3193 /*@
3194   DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
3195 
3196   Not collective
3197 
3198   Input Parameters:
3199 + mesh - The DMPlex
3200 . p - The point, which must lie in the chart set with DMPlexSetChart()
3201 - size - The support size for point p
3202 
3203   Output Parameter:
3204 
3205   Note:
3206   This should be called after DMPlexSetChart().
3207 
3208   Level: beginner
3209 
3210 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
3211 @*/
3212 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
3213 {
3214   DM_Plex       *mesh = (DM_Plex*) dm->data;
3215 
3216   PetscFunctionBegin;
3217   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3218   CHKERRQ(PetscSectionSetDof(mesh->supportSection, p, size));
3219 
3220   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
3221   PetscFunctionReturn(0);
3222 }
3223 
3224 /*@C
3225   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
3226 
3227   Not collective
3228 
3229   Input Parameters:
3230 + mesh - The DMPlex
3231 - p - The point, which must lie in the chart set with DMPlexSetChart()
3232 
3233   Output Parameter:
3234 . support - An array of points which are on the out-edges for point p
3235 
3236   Level: beginner
3237 
3238   Fortran Notes:
3239   Since it returns an array, this routine is only available in Fortran 90, and you must
3240   include petsc.h90 in your code.
3241   You must also call DMPlexRestoreSupport() after you finish using the returned array.
3242   DMPlexRestoreSupport() is not needed/available in C.
3243 
3244 .seealso: DMPlexGetSupportSize(), DMPlexSetSupport(), DMPlexGetCone(), DMPlexSetChart()
3245 @*/
3246 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
3247 {
3248   DM_Plex       *mesh = (DM_Plex*) dm->data;
3249   PetscInt       off;
3250 
3251   PetscFunctionBegin;
3252   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3253   PetscValidPointer(support, 3);
3254   CHKERRQ(PetscSectionGetOffset(mesh->supportSection, p, &off));
3255   *support = &mesh->supports[off];
3256   PetscFunctionReturn(0);
3257 }
3258 
3259 /*@
3260   DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers
3261 
3262   Not collective
3263 
3264   Input Parameters:
3265 + mesh - The DMPlex
3266 . p - The point, which must lie in the chart set with DMPlexSetChart()
3267 - support - An array of points which are on the out-edges for point p
3268 
3269   Output Parameter:
3270 
3271   Note:
3272   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
3273 
3274   Level: beginner
3275 
3276 .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
3277 @*/
3278 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
3279 {
3280   DM_Plex       *mesh = (DM_Plex*) dm->data;
3281   PetscInt       pStart, pEnd;
3282   PetscInt       dof, off, c;
3283 
3284   PetscFunctionBegin;
3285   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3286   CHKERRQ(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
3287   CHKERRQ(PetscSectionGetDof(mesh->supportSection, p, &dof));
3288   if (dof) PetscValidIntPointer(support, 3);
3289   CHKERRQ(PetscSectionGetOffset(mesh->supportSection, p, &off));
3290   PetscCheckFalse((p < pStart) || (p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
3291   for (c = 0; c < dof; ++c) {
3292     PetscCheckFalse((support[c] < pStart) || (support[c] >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd);
3293     mesh->supports[off+c] = support[c];
3294   }
3295   PetscFunctionReturn(0);
3296 }
3297 
3298 /*@
3299   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
3300 
3301   Not collective
3302 
3303   Input Parameters:
3304 + mesh - The DMPlex
3305 . p - The point, which must lie in the chart set with DMPlexSetChart()
3306 . supportPos - The local index in the cone where the point should be put
3307 - supportPoint - The mesh point to insert
3308 
3309   Level: beginner
3310 
3311 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
3312 @*/
3313 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
3314 {
3315   DM_Plex       *mesh = (DM_Plex*) dm->data;
3316   PetscInt       pStart, pEnd;
3317   PetscInt       dof, off;
3318 
3319   PetscFunctionBegin;
3320   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3321   CHKERRQ(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
3322   CHKERRQ(PetscSectionGetDof(mesh->supportSection, p, &dof));
3323   CHKERRQ(PetscSectionGetOffset(mesh->supportSection, p, &off));
3324   PetscCheckFalse((p < pStart) || (p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
3325   PetscCheckFalse((supportPoint < pStart) || (supportPoint >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd);
3326   PetscCheckFalse(supportPos >= dof,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof);
3327   mesh->supports[off+supportPos] = supportPoint;
3328   PetscFunctionReturn(0);
3329 }
3330 
3331 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */
3332 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o)
3333 {
3334   switch (ct) {
3335     case DM_POLYTOPE_SEGMENT:
3336       if (o == -1) return -2;
3337       break;
3338     case DM_POLYTOPE_TRIANGLE:
3339       if (o == -3) return -1;
3340       if (o == -2) return -3;
3341       if (o == -1) return -2;
3342       break;
3343     case DM_POLYTOPE_QUADRILATERAL:
3344       if (o == -4) return -2;
3345       if (o == -3) return -1;
3346       if (o == -2) return -4;
3347       if (o == -1) return -3;
3348       break;
3349     default: return o;
3350   }
3351   return o;
3352 }
3353 
3354 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */
3355 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o)
3356 {
3357   switch (ct) {
3358     case DM_POLYTOPE_SEGMENT:
3359       if ((o == -2) || (o == 1)) return -1;
3360       if (o == -1) return 0;
3361       break;
3362     case DM_POLYTOPE_TRIANGLE:
3363       if (o == -3) return -2;
3364       if (o == -2) return -1;
3365       if (o == -1) return -3;
3366       break;
3367     case DM_POLYTOPE_QUADRILATERAL:
3368       if (o == -4) return -2;
3369       if (o == -3) return -1;
3370       if (o == -2) return -4;
3371       if (o == -1) return -3;
3372       break;
3373     default: return o;
3374   }
3375   return o;
3376 }
3377 
3378 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */
3379 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm)
3380 {
3381   PetscInt       pStart, pEnd, p;
3382 
3383   PetscFunctionBegin;
3384   CHKERRQ(DMPlexGetChart(dm, &pStart, &pEnd));
3385   for (p = pStart; p < pEnd; ++p) {
3386     const PetscInt *cone, *ornt;
3387     PetscInt        coneSize, c;
3388 
3389     CHKERRQ(DMPlexGetConeSize(dm, p, &coneSize));
3390     CHKERRQ(DMPlexGetCone(dm, p, &cone));
3391     CHKERRQ(DMPlexGetConeOrientation(dm, p, &ornt));
3392     for (c = 0; c < coneSize; ++c) {
3393       DMPolytopeType ct;
3394       const PetscInt o = ornt[c];
3395 
3396       CHKERRQ(DMPlexGetCellType(dm, cone[c], &ct));
3397       switch (ct) {
3398         case DM_POLYTOPE_SEGMENT:
3399           if ((o == -2) || (o == 1)) CHKERRQ(DMPlexInsertConeOrientation(dm, p, c, -1));
3400           if (o == -1) CHKERRQ(DMPlexInsertConeOrientation(dm, p, c, 0));
3401           break;
3402         case DM_POLYTOPE_TRIANGLE:
3403           if (o == -3) CHKERRQ(DMPlexInsertConeOrientation(dm, p, c, -2));
3404           if (o == -2) CHKERRQ(DMPlexInsertConeOrientation(dm, p, c, -1));
3405           if (o == -1) CHKERRQ(DMPlexInsertConeOrientation(dm, p, c, -3));
3406           break;
3407         case DM_POLYTOPE_QUADRILATERAL:
3408           if (o == -4) CHKERRQ(DMPlexInsertConeOrientation(dm, p, c, -2));
3409           if (o == -3) CHKERRQ(DMPlexInsertConeOrientation(dm, p, c, -1));
3410           if (o == -2) CHKERRQ(DMPlexInsertConeOrientation(dm, p, c, -4));
3411           if (o == -1) CHKERRQ(DMPlexInsertConeOrientation(dm, p, c, -3));
3412           break;
3413         default: break;
3414       }
3415     }
3416   }
3417   PetscFunctionReturn(0);
3418 }
3419 
3420 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3421 {
3422   DMPolytopeType  ct = DM_POLYTOPE_UNKNOWN;
3423   PetscInt       *closure;
3424   const PetscInt *tmp = NULL, *tmpO = NULL;
3425   PetscInt        off = 0, tmpSize, t;
3426 
3427   PetscFunctionBeginHot;
3428   if (ornt) {
3429     CHKERRQ(DMPlexGetCellType(dm, p, &ct));
3430     if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3431   }
3432   if (*points) {
3433     closure = *points;
3434   } else {
3435     PetscInt maxConeSize, maxSupportSize;
3436     CHKERRQ(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3437     CHKERRQ(DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure));
3438   }
3439   if (useCone) {
3440     CHKERRQ(DMPlexGetConeSize(dm, p, &tmpSize));
3441     CHKERRQ(DMPlexGetCone(dm, p, &tmp));
3442     CHKERRQ(DMPlexGetConeOrientation(dm, p, &tmpO));
3443   } else {
3444     CHKERRQ(DMPlexGetSupportSize(dm, p, &tmpSize));
3445     CHKERRQ(DMPlexGetSupport(dm, p, &tmp));
3446   }
3447   if (ct == DM_POLYTOPE_UNKNOWN) {
3448     closure[off++] = p;
3449     closure[off++] = 0;
3450     for (t = 0; t < tmpSize; ++t) {
3451       closure[off++] = tmp[t];
3452       closure[off++] = tmpO ? tmpO[t] : 0;
3453     }
3454   } else {
3455     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt);
3456 
3457     /* We assume that cells with a valid type have faces with a valid type */
3458     closure[off++] = p;
3459     closure[off++] = ornt;
3460     for (t = 0; t < tmpSize; ++t) {
3461       DMPolytopeType ft;
3462 
3463       CHKERRQ(DMPlexGetCellType(dm, tmp[t], &ft));
3464       closure[off++] = tmp[arr[t]];
3465       closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0;
3466     }
3467   }
3468   if (numPoints) *numPoints = tmpSize+1;
3469   if (points)    *points    = closure;
3470   PetscFunctionReturn(0);
3471 }
3472 
3473 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */
3474 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points)
3475 {
3476   const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
3477   const PetscInt *cone, *ornt;
3478   PetscInt       *pts,  *closure = NULL;
3479   DMPolytopeType  ft;
3480   PetscInt        maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize;
3481   PetscInt        dim, coneSize, c, d, clSize, cl;
3482 
3483   PetscFunctionBeginHot;
3484   CHKERRQ(DMGetDimension(dm, &dim));
3485   CHKERRQ(DMPlexGetConeSize(dm, point, &coneSize));
3486   CHKERRQ(DMPlexGetCone(dm, point, &cone));
3487   CHKERRQ(DMPlexGetConeOrientation(dm, point, &ornt));
3488   CHKERRQ(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3489   coneSeries    = (maxConeSize    > 1) ? ((PetscPowInt(maxConeSize,    dim+1)-1)/(maxConeSize-1))    : dim+1;
3490   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1;
3491   maxSize       = PetscMax(coneSeries, supportSeries);
3492   if (*points) {pts  = *points;}
3493   else         CHKERRQ(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts));
3494   c    = 0;
3495   pts[c++] = point;
3496   pts[c++] = o;
3497   CHKERRQ(DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft));
3498   CHKERRQ(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure));
3499   for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];}
3500   CHKERRQ(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure));
3501   for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];}
3502   CHKERRQ(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure));
3503   for (d = 2; d < coneSize; ++d) {
3504     CHKERRQ(DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft));
3505     pts[c++] = cone[arr[d*2+0]];
3506     pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]);
3507   }
3508   if (dim >= 3) {
3509     for (d = 2; d < coneSize; ++d) {
3510       const PetscInt  fpoint = cone[arr[d*2+0]];
3511       const PetscInt *fcone, *fornt;
3512       PetscInt        fconeSize, fc, i;
3513 
3514       CHKERRQ(DMPlexGetCellType(dm, fpoint, &ft));
3515       const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]));
3516       CHKERRQ(DMPlexGetConeSize(dm, fpoint, &fconeSize));
3517       CHKERRQ(DMPlexGetCone(dm, fpoint, &fcone));
3518       CHKERRQ(DMPlexGetConeOrientation(dm, fpoint, &fornt));
3519       for (fc = 0; fc < fconeSize; ++fc) {
3520         const PetscInt cp = fcone[farr[fc*2+0]];
3521         const PetscInt co = farr[fc*2+1];
3522 
3523         for (i = 0; i < c; i += 2) if (pts[i] == cp) break;
3524         if (i == c) {
3525           CHKERRQ(DMPlexGetCellType(dm, cp, &ft));
3526           pts[c++] = cp;
3527           pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]);
3528         }
3529       }
3530     }
3531   }
3532   *numPoints = c/2;
3533   *points    = pts;
3534   PetscFunctionReturn(0);
3535 }
3536 
3537 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3538 {
3539   DMPolytopeType ct;
3540   PetscInt      *closure, *fifo;
3541   PetscInt       closureSize = 0, fifoStart = 0, fifoSize = 0;
3542   PetscInt       maxConeSize, maxSupportSize, coneSeries, supportSeries;
3543   PetscInt       depth, maxSize;
3544 
3545   PetscFunctionBeginHot;
3546   CHKERRQ(DMPlexGetDepth(dm, &depth));
3547   if (depth == 1) {
3548     CHKERRQ(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points));
3549     PetscFunctionReturn(0);
3550   }
3551   CHKERRQ(DMPlexGetCellType(dm, p, &ct));
3552   if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3553   if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
3554     CHKERRQ(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points));
3555     PetscFunctionReturn(0);
3556   }
3557   CHKERRQ(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3558   coneSeries    = (maxConeSize    > 1) ? ((PetscPowInt(maxConeSize,    depth+1)-1)/(maxConeSize-1))    : depth+1;
3559   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1;
3560   maxSize       = PetscMax(coneSeries, supportSeries);
3561   CHKERRQ(DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo));
3562   if (*points) {closure = *points;}
3563   else         CHKERRQ(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure));
3564   closure[closureSize++] = p;
3565   closure[closureSize++] = ornt;
3566   fifo[fifoSize++]       = p;
3567   fifo[fifoSize++]       = ornt;
3568   fifo[fifoSize++]       = ct;
3569   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
3570   while (fifoSize - fifoStart) {
3571     const PetscInt       q    = fifo[fifoStart++];
3572     const PetscInt       o    = fifo[fifoStart++];
3573     const DMPolytopeType qt   = (DMPolytopeType) fifo[fifoStart++];
3574     const PetscInt      *qarr = DMPolytopeTypeGetArrangment(qt, o);
3575     const PetscInt      *tmp, *tmpO;
3576     PetscInt             tmpSize, t;
3577 
3578     if (PetscDefined(USE_DEBUG)) {
3579       PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2;
3580       PetscCheckFalse(o && (o >= nO || o < -nO),PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %D not in [%D,%D) for %s %D", o, -nO, nO, DMPolytopeTypes[qt], q);
3581     }
3582     if (useCone) {
3583       CHKERRQ(DMPlexGetConeSize(dm, q, &tmpSize));
3584       CHKERRQ(DMPlexGetCone(dm, q, &tmp));
3585       CHKERRQ(DMPlexGetConeOrientation(dm, q, &tmpO));
3586     } else {
3587       CHKERRQ(DMPlexGetSupportSize(dm, q, &tmpSize));
3588       CHKERRQ(DMPlexGetSupport(dm, q, &tmp));
3589       tmpO = NULL;
3590     }
3591     for (t = 0; t < tmpSize; ++t) {
3592       const PetscInt ip = useCone && qarr ? qarr[t*2]   : t;
3593       const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0;
3594       const PetscInt cp = tmp[ip];
3595       CHKERRQ(DMPlexGetCellType(dm, cp, &ct));
3596       const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0;
3597       PetscInt       c;
3598 
3599       /* Check for duplicate */
3600       for (c = 0; c < closureSize; c += 2) {
3601         if (closure[c] == cp) break;
3602       }
3603       if (c == closureSize) {
3604         closure[closureSize++] = cp;
3605         closure[closureSize++] = co;
3606         fifo[fifoSize++]       = cp;
3607         fifo[fifoSize++]       = co;
3608         fifo[fifoSize++]       = ct;
3609       }
3610     }
3611   }
3612   CHKERRQ(DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo));
3613   if (numPoints) *numPoints = closureSize/2;
3614   if (points)    *points    = closure;
3615   PetscFunctionReturn(0);
3616 }
3617 
3618 /*@C
3619   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
3620 
3621   Not collective
3622 
3623   Input Parameters:
3624 + dm      - The DMPlex
3625 . p       - The mesh point
3626 - useCone - PETSC_TRUE for the closure, otherwise return the star
3627 
3628   Input/Output Parameter:
3629 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...];
3630            if NULL on input, internal storage will be returned, otherwise the provided array is used
3631 
3632   Output Parameter:
3633 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints
3634 
3635   Note:
3636   If using internal storage (points is NULL on input), each call overwrites the last output.
3637 
3638   Fortran Notes:
3639   Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code.
3640 
3641   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3642 
3643   Level: beginner
3644 
3645 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
3646 @*/
3647 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3648 {
3649   PetscFunctionBeginHot;
3650   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3651   if (numPoints) PetscValidIntPointer(numPoints, 4);
3652   if (points)    PetscValidPointer(points, 5);
3653   CHKERRQ(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points));
3654   PetscFunctionReturn(0);
3655 }
3656 
3657 /*@C
3658   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
3659 
3660   Not collective
3661 
3662   Input Parameters:
3663 + dm        - The DMPlex
3664 . p         - The mesh point
3665 . useCone   - PETSC_TRUE for the closure, otherwise return the star
3666 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints
3667 - points    - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
3668 
3669   Note:
3670   If not using internal storage (points is not NULL on input), this call is unnecessary
3671 
3672   Fortran Notes:
3673   Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code.
3674 
3675   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3676 
3677   Level: beginner
3678 
3679 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
3680 @*/
3681 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3682 {
3683   PetscFunctionBeginHot;
3684   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3685   if (numPoints) *numPoints = 0;
3686   CHKERRQ(DMRestoreWorkArray(dm, 0, MPIU_INT, points));
3687   PetscFunctionReturn(0);
3688 }
3689 
3690 /*@
3691   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
3692 
3693   Not collective
3694 
3695   Input Parameter:
3696 . mesh - The DMPlex
3697 
3698   Output Parameters:
3699 + maxConeSize - The maximum number of in-edges
3700 - maxSupportSize - The maximum number of out-edges
3701 
3702   Level: beginner
3703 
3704 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
3705 @*/
3706 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
3707 {
3708   DM_Plex *mesh = (DM_Plex*) dm->data;
3709 
3710   PetscFunctionBegin;
3711   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3712   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
3713   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
3714   PetscFunctionReturn(0);
3715 }
3716 
3717 PetscErrorCode DMSetUp_Plex(DM dm)
3718 {
3719   DM_Plex       *mesh = (DM_Plex*) dm->data;
3720   PetscInt       size;
3721 
3722   PetscFunctionBegin;
3723   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3724   CHKERRQ(PetscSectionSetUp(mesh->coneSection));
3725   CHKERRQ(PetscSectionGetStorageSize(mesh->coneSection, &size));
3726   CHKERRQ(PetscMalloc1(size, &mesh->cones));
3727   CHKERRQ(PetscCalloc1(size, &mesh->coneOrientations));
3728   CHKERRQ(PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt)));
3729   if (mesh->maxSupportSize) {
3730     CHKERRQ(PetscSectionSetUp(mesh->supportSection));
3731     CHKERRQ(PetscSectionGetStorageSize(mesh->supportSection, &size));
3732     CHKERRQ(PetscMalloc1(size, &mesh->supports));
3733     CHKERRQ(PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt)));
3734   }
3735   PetscFunctionReturn(0);
3736 }
3737 
3738 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
3739 {
3740   PetscFunctionBegin;
3741   if (subdm) CHKERRQ(DMClone(dm, subdm));
3742   CHKERRQ(DMCreateSectionSubDM(dm, numFields, fields, is, subdm));
3743   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
3744   if (dm->useNatural && dm->sfMigration) {
3745     PetscSF        sfMigrationInv,sfNatural;
3746     PetscSection   section, sectionSeq;
3747 
3748     (*subdm)->sfMigration = dm->sfMigration;
3749     CHKERRQ(PetscObjectReference((PetscObject) dm->sfMigration));
3750     CHKERRQ(DMGetLocalSection((*subdm), &section));
3751     CHKERRQ(PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv));
3752     CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq));
3753     CHKERRQ(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq));
3754 
3755     CHKERRQ(DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural));
3756     (*subdm)->sfNatural = sfNatural;
3757     CHKERRQ(PetscSectionDestroy(&sectionSeq));
3758     CHKERRQ(PetscSFDestroy(&sfMigrationInv));
3759   }
3760   PetscFunctionReturn(0);
3761 }
3762 
3763 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
3764 {
3765   PetscInt       i = 0;
3766 
3767   PetscFunctionBegin;
3768   CHKERRQ(DMClone(dms[0], superdm));
3769   CHKERRQ(DMCreateSectionSuperDM(dms, len, is, superdm));
3770   (*superdm)->useNatural = PETSC_FALSE;
3771   for (i = 0; i < len; i++) {
3772     if (dms[i]->useNatural && dms[i]->sfMigration) {
3773       PetscSF        sfMigrationInv,sfNatural;
3774       PetscSection   section, sectionSeq;
3775 
3776       (*superdm)->sfMigration = dms[i]->sfMigration;
3777       CHKERRQ(PetscObjectReference((PetscObject) dms[i]->sfMigration));
3778       (*superdm)->useNatural = PETSC_TRUE;
3779       CHKERRQ(DMGetLocalSection((*superdm), &section));
3780       CHKERRQ(PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv));
3781       CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq));
3782       CHKERRQ(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq));
3783 
3784       CHKERRQ(DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural));
3785       (*superdm)->sfNatural = sfNatural;
3786       CHKERRQ(PetscSectionDestroy(&sectionSeq));
3787       CHKERRQ(PetscSFDestroy(&sfMigrationInv));
3788       break;
3789     }
3790   }
3791   PetscFunctionReturn(0);
3792 }
3793 
3794 /*@
3795   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
3796 
3797   Not collective
3798 
3799   Input Parameter:
3800 . mesh - The DMPlex
3801 
3802   Output Parameter:
3803 
3804   Note:
3805   This should be called after all calls to DMPlexSetCone()
3806 
3807   Level: beginner
3808 
3809 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
3810 @*/
3811 PetscErrorCode DMPlexSymmetrize(DM dm)
3812 {
3813   DM_Plex       *mesh = (DM_Plex*) dm->data;
3814   PetscInt      *offsets;
3815   PetscInt       supportSize;
3816   PetscInt       pStart, pEnd, p;
3817 
3818   PetscFunctionBegin;
3819   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3820   PetscCheck(!mesh->supports,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
3821   CHKERRQ(PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0));
3822   /* Calculate support sizes */
3823   CHKERRQ(DMPlexGetChart(dm, &pStart, &pEnd));
3824   for (p = pStart; p < pEnd; ++p) {
3825     PetscInt dof, off, c;
3826 
3827     CHKERRQ(PetscSectionGetDof(mesh->coneSection, p, &dof));
3828     CHKERRQ(PetscSectionGetOffset(mesh->coneSection, p, &off));
3829     for (c = off; c < off+dof; ++c) {
3830       CHKERRQ(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1));
3831     }
3832   }
3833   for (p = pStart; p < pEnd; ++p) {
3834     PetscInt dof;
3835 
3836     CHKERRQ(PetscSectionGetDof(mesh->supportSection, p, &dof));
3837 
3838     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
3839   }
3840   CHKERRQ(PetscSectionSetUp(mesh->supportSection));
3841   /* Calculate supports */
3842   CHKERRQ(PetscSectionGetStorageSize(mesh->supportSection, &supportSize));
3843   CHKERRQ(PetscMalloc1(supportSize, &mesh->supports));
3844   CHKERRQ(PetscCalloc1(pEnd - pStart, &offsets));
3845   for (p = pStart; p < pEnd; ++p) {
3846     PetscInt dof, off, c;
3847 
3848     CHKERRQ(PetscSectionGetDof(mesh->coneSection, p, &dof));
3849     CHKERRQ(PetscSectionGetOffset(mesh->coneSection, p, &off));
3850     for (c = off; c < off+dof; ++c) {
3851       const PetscInt q = mesh->cones[c];
3852       PetscInt       offS;
3853 
3854       CHKERRQ(PetscSectionGetOffset(mesh->supportSection, q, &offS));
3855 
3856       mesh->supports[offS+offsets[q]] = p;
3857       ++offsets[q];
3858     }
3859   }
3860   CHKERRQ(PetscFree(offsets));
3861   CHKERRQ(PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0));
3862   PetscFunctionReturn(0);
3863 }
3864 
3865 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
3866 {
3867   IS             stratumIS;
3868 
3869   PetscFunctionBegin;
3870   if (pStart >= pEnd) PetscFunctionReturn(0);
3871   if (PetscDefined(USE_DEBUG)) {
3872     PetscInt  qStart, qEnd, numLevels, level;
3873     PetscBool overlap = PETSC_FALSE;
3874     CHKERRQ(DMLabelGetNumValues(label, &numLevels));
3875     for (level = 0; level < numLevels; level++) {
3876       CHKERRQ(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
3877       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;}
3878     }
3879     PetscCheck(!overlap,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);
3880   }
3881   CHKERRQ(ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS));
3882   CHKERRQ(DMLabelSetStratumIS(label, depth, stratumIS));
3883   CHKERRQ(ISDestroy(&stratumIS));
3884   PetscFunctionReturn(0);
3885 }
3886 
3887 /*@
3888   DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
3889   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
3890   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
3891   the DAG.
3892 
3893   Collective on dm
3894 
3895   Input Parameter:
3896 . mesh - The DMPlex
3897 
3898   Output Parameter:
3899 
3900   Notes:
3901   Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
3902   meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on
3903   until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
3904   manually via DMGetLabel().  The height is defined implicitly by height = maxDimension - depth, and can be accessed
3905   via DMPlexGetHeightStratum().  For example, cells have height 0 and faces have height 1.
3906 
3907   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
3908   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
3909   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
3910   to interpolate only that one (e0), so that
3911 $  cone(c0) = {e0, v2}
3912 $  cone(e0) = {v0, v1}
3913   If DMPlexStratify() is run on this mesh, it will give depths
3914 $  depth 0 = {v0, v1, v2}
3915 $  depth 1 = {e0, c0}
3916   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.
3917 
3918   DMPlexStratify() should be called after all calls to DMPlexSymmetrize()
3919 
3920   Level: beginner
3921 
3922 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexComputeCellTypes()
3923 @*/
3924 PetscErrorCode DMPlexStratify(DM dm)
3925 {
3926   DM_Plex       *mesh = (DM_Plex*) dm->data;
3927   DMLabel        label;
3928   PetscInt       pStart, pEnd, p;
3929   PetscInt       numRoots = 0, numLeaves = 0;
3930 
3931   PetscFunctionBegin;
3932   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3933   CHKERRQ(PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0));
3934 
3935   /* Create depth label */
3936   CHKERRQ(DMPlexGetChart(dm, &pStart, &pEnd));
3937   CHKERRQ(DMCreateLabel(dm, "depth"));
3938   CHKERRQ(DMPlexGetDepthLabel(dm, &label));
3939 
3940   {
3941     /* Initialize roots and count leaves */
3942     PetscInt sMin = PETSC_MAX_INT;
3943     PetscInt sMax = PETSC_MIN_INT;
3944     PetscInt coneSize, supportSize;
3945 
3946     for (p = pStart; p < pEnd; ++p) {
3947       CHKERRQ(DMPlexGetConeSize(dm, p, &coneSize));
3948       CHKERRQ(DMPlexGetSupportSize(dm, p, &supportSize));
3949       if (!coneSize && supportSize) {
3950         sMin = PetscMin(p, sMin);
3951         sMax = PetscMax(p, sMax);
3952         ++numRoots;
3953       } else if (!supportSize && coneSize) {
3954         ++numLeaves;
3955       } else if (!supportSize && !coneSize) {
3956         /* Isolated points */
3957         sMin = PetscMin(p, sMin);
3958         sMax = PetscMax(p, sMax);
3959       }
3960     }
3961     CHKERRQ(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1));
3962   }
3963 
3964   if (numRoots + numLeaves == (pEnd - pStart)) {
3965     PetscInt sMin = PETSC_MAX_INT;
3966     PetscInt sMax = PETSC_MIN_INT;
3967     PetscInt coneSize, supportSize;
3968 
3969     for (p = pStart; p < pEnd; ++p) {
3970       CHKERRQ(DMPlexGetConeSize(dm, p, &coneSize));
3971       CHKERRQ(DMPlexGetSupportSize(dm, p, &supportSize));
3972       if (!supportSize && coneSize) {
3973         sMin = PetscMin(p, sMin);
3974         sMax = PetscMax(p, sMax);
3975       }
3976     }
3977     CHKERRQ(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1));
3978   } else {
3979     PetscInt level = 0;
3980     PetscInt qStart, qEnd, q;
3981 
3982     CHKERRQ(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
3983     while (qEnd > qStart) {
3984       PetscInt sMin = PETSC_MAX_INT;
3985       PetscInt sMax = PETSC_MIN_INT;
3986 
3987       for (q = qStart; q < qEnd; ++q) {
3988         const PetscInt *support;
3989         PetscInt        supportSize, s;
3990 
3991         CHKERRQ(DMPlexGetSupportSize(dm, q, &supportSize));
3992         CHKERRQ(DMPlexGetSupport(dm, q, &support));
3993         for (s = 0; s < supportSize; ++s) {
3994           sMin = PetscMin(support[s], sMin);
3995           sMax = PetscMax(support[s], sMax);
3996         }
3997       }
3998       CHKERRQ(DMLabelGetNumValues(label, &level));
3999       CHKERRQ(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1));
4000       CHKERRQ(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4001     }
4002   }
4003   { /* just in case there is an empty process */
4004     PetscInt numValues, maxValues = 0, v;
4005 
4006     CHKERRQ(DMLabelGetNumValues(label, &numValues));
4007     CHKERRMPI(MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm)));
4008     for (v = numValues; v < maxValues; v++) {
4009       CHKERRQ(DMLabelAddStratum(label, v));
4010     }
4011   }
4012   CHKERRQ(PetscObjectStateGet((PetscObject) label, &mesh->depthState));
4013   CHKERRQ(PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0));
4014   PetscFunctionReturn(0);
4015 }
4016 
4017 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
4018 {
4019   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4020   PetscInt       dim, depth, pheight, coneSize;
4021 
4022   PetscFunctionBeginHot;
4023   CHKERRQ(DMGetDimension(dm, &dim));
4024   CHKERRQ(DMPlexGetDepth(dm, &depth));
4025   CHKERRQ(DMPlexGetConeSize(dm, p, &coneSize));
4026   pheight = depth - pdepth;
4027   if (depth <= 1) {
4028     switch (pdepth) {
4029       case 0: ct = DM_POLYTOPE_POINT;break;
4030       case 1:
4031         switch (coneSize) {
4032           case 2: ct = DM_POLYTOPE_SEGMENT;break;
4033           case 3: ct = DM_POLYTOPE_TRIANGLE;break;
4034           case 4:
4035           switch (dim) {
4036             case 2: ct = DM_POLYTOPE_QUADRILATERAL;break;
4037             case 3: ct = DM_POLYTOPE_TETRAHEDRON;break;
4038             default: break;
4039           }
4040           break;
4041         case 5: ct = DM_POLYTOPE_PYRAMID;break;
4042         case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break;
4043         case 8: ct = DM_POLYTOPE_HEXAHEDRON;break;
4044         default: break;
4045       }
4046     }
4047   } else {
4048     if (pdepth == 0) {
4049       ct = DM_POLYTOPE_POINT;
4050     } else if (pheight == 0) {
4051       switch (dim) {
4052         case 1:
4053           switch (coneSize) {
4054             case 2: ct = DM_POLYTOPE_SEGMENT;break;
4055             default: break;
4056           }
4057           break;
4058         case 2:
4059           switch (coneSize) {
4060             case 3: ct = DM_POLYTOPE_TRIANGLE;break;
4061             case 4: ct = DM_POLYTOPE_QUADRILATERAL;break;
4062             default: break;
4063           }
4064           break;
4065         case 3:
4066           switch (coneSize) {
4067             case 4: ct = DM_POLYTOPE_TETRAHEDRON;break;
4068             case 5:
4069             {
4070               const PetscInt *cone;
4071               PetscInt        faceConeSize;
4072 
4073               CHKERRQ(DMPlexGetCone(dm, p, &cone));
4074               CHKERRQ(DMPlexGetConeSize(dm, cone[0], &faceConeSize));
4075               switch (faceConeSize) {
4076                 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break;
4077                 case 4: ct = DM_POLYTOPE_PYRAMID;break;
4078               }
4079             }
4080             break;
4081             case 6: ct = DM_POLYTOPE_HEXAHEDRON;break;
4082             default: break;
4083           }
4084           break;
4085         default: break;
4086       }
4087     } else if (pheight > 0) {
4088       switch (coneSize) {
4089         case 2: ct = DM_POLYTOPE_SEGMENT;break;
4090         case 3: ct = DM_POLYTOPE_TRIANGLE;break;
4091         case 4: ct = DM_POLYTOPE_QUADRILATERAL;break;
4092         default: break;
4093       }
4094     }
4095   }
4096   *pt = ct;
4097   PetscFunctionReturn(0);
4098 }
4099 
4100 /*@
4101   DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size.
4102 
4103   Collective on dm
4104 
4105   Input Parameter:
4106 . mesh - The DMPlex
4107 
4108   DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify()
4109 
4110   Level: developer
4111 
4112   Note: This function is normally called automatically by Plex when a cell type is requested. It creates an
4113   internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable
4114   automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype").
4115 
4116 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexStratify(), DMGetLabel(), DMCreateLabel()
4117 @*/
4118 PetscErrorCode DMPlexComputeCellTypes(DM dm)
4119 {
4120   DM_Plex       *mesh;
4121   DMLabel        ctLabel;
4122   PetscInt       pStart, pEnd, p;
4123 
4124   PetscFunctionBegin;
4125   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4126   mesh = (DM_Plex *) dm->data;
4127   CHKERRQ(DMCreateLabel(dm, "celltype"));
4128   CHKERRQ(DMPlexGetCellTypeLabel(dm, &ctLabel));
4129   CHKERRQ(DMPlexGetChart(dm, &pStart, &pEnd));
4130   for (p = pStart; p < pEnd; ++p) {
4131     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4132     PetscInt       pdepth;
4133 
4134     CHKERRQ(DMPlexGetPointDepth(dm, p, &pdepth));
4135     CHKERRQ(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct));
4136     PetscCheckFalse(ct == DM_POLYTOPE_UNKNOWN,PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %D is screwed up", p);
4137     CHKERRQ(DMLabelSetValue(ctLabel, p, ct));
4138   }
4139   CHKERRQ(PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState));
4140   CHKERRQ(PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view"));
4141   PetscFunctionReturn(0);
4142 }
4143 
4144 /*@C
4145   DMPlexGetJoin - Get an array for the join of the set of points
4146 
4147   Not Collective
4148 
4149   Input Parameters:
4150 + dm - The DMPlex object
4151 . numPoints - The number of input points for the join
4152 - points - The input points
4153 
4154   Output Parameters:
4155 + numCoveredPoints - The number of points in the join
4156 - coveredPoints - The points in the join
4157 
4158   Level: intermediate
4159 
4160   Note: Currently, this is restricted to a single level join
4161 
4162   Fortran Notes:
4163   Since it returns an array, this routine is only available in Fortran 90, and you must
4164   include petsc.h90 in your code.
4165 
4166   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4167 
4168 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
4169 @*/
4170 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4171 {
4172   DM_Plex       *mesh = (DM_Plex*) dm->data;
4173   PetscInt      *join[2];
4174   PetscInt       joinSize, i = 0;
4175   PetscInt       dof, off, p, c, m;
4176 
4177   PetscFunctionBegin;
4178   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4179   PetscValidIntPointer(points, 3);
4180   PetscValidIntPointer(numCoveredPoints, 4);
4181   PetscValidPointer(coveredPoints, 5);
4182   CHKERRQ(DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]));
4183   CHKERRQ(DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]));
4184   /* Copy in support of first point */
4185   CHKERRQ(PetscSectionGetDof(mesh->supportSection, points[0], &dof));
4186   CHKERRQ(PetscSectionGetOffset(mesh->supportSection, points[0], &off));
4187   for (joinSize = 0; joinSize < dof; ++joinSize) {
4188     join[i][joinSize] = mesh->supports[off+joinSize];
4189   }
4190   /* Check each successive support */
4191   for (p = 1; p < numPoints; ++p) {
4192     PetscInt newJoinSize = 0;
4193 
4194     CHKERRQ(PetscSectionGetDof(mesh->supportSection, points[p], &dof));
4195     CHKERRQ(PetscSectionGetOffset(mesh->supportSection, points[p], &off));
4196     for (c = 0; c < dof; ++c) {
4197       const PetscInt point = mesh->supports[off+c];
4198 
4199       for (m = 0; m < joinSize; ++m) {
4200         if (point == join[i][m]) {
4201           join[1-i][newJoinSize++] = point;
4202           break;
4203         }
4204       }
4205     }
4206     joinSize = newJoinSize;
4207     i        = 1-i;
4208   }
4209   *numCoveredPoints = joinSize;
4210   *coveredPoints    = join[i];
4211   CHKERRQ(DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]));
4212   PetscFunctionReturn(0);
4213 }
4214 
4215 /*@C
4216   DMPlexRestoreJoin - Restore an array for the join of the set of points
4217 
4218   Not Collective
4219 
4220   Input Parameters:
4221 + dm - The DMPlex object
4222 . numPoints - The number of input points for the join
4223 - points - The input points
4224 
4225   Output Parameters:
4226 + numCoveredPoints - The number of points in the join
4227 - coveredPoints - The points in the join
4228 
4229   Fortran Notes:
4230   Since it returns an array, this routine is only available in Fortran 90, and you must
4231   include petsc.h90 in your code.
4232 
4233   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4234 
4235   Level: intermediate
4236 
4237 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
4238 @*/
4239 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4240 {
4241   PetscFunctionBegin;
4242   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4243   if (points) PetscValidIntPointer(points,3);
4244   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
4245   PetscValidPointer(coveredPoints, 5);
4246   CHKERRQ(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints));
4247   if (numCoveredPoints) *numCoveredPoints = 0;
4248   PetscFunctionReturn(0);
4249 }
4250 
4251 /*@C
4252   DMPlexGetFullJoin - Get an array for the join of the set of points
4253 
4254   Not Collective
4255 
4256   Input Parameters:
4257 + dm - The DMPlex object
4258 . numPoints - The number of input points for the join
4259 - points - The input points
4260 
4261   Output Parameters:
4262 + numCoveredPoints - The number of points in the join
4263 - coveredPoints - The points in the join
4264 
4265   Fortran Notes:
4266   Since it returns an array, this routine is only available in Fortran 90, and you must
4267   include petsc.h90 in your code.
4268 
4269   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4270 
4271   Level: intermediate
4272 
4273 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
4274 @*/
4275 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4276 {
4277   DM_Plex       *mesh = (DM_Plex*) dm->data;
4278   PetscInt      *offsets, **closures;
4279   PetscInt      *join[2];
4280   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
4281   PetscInt       p, d, c, m, ms;
4282 
4283   PetscFunctionBegin;
4284   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4285   PetscValidIntPointer(points, 3);
4286   PetscValidIntPointer(numCoveredPoints, 4);
4287   PetscValidPointer(coveredPoints, 5);
4288 
4289   CHKERRQ(DMPlexGetDepth(dm, &depth));
4290   CHKERRQ(PetscCalloc1(numPoints, &closures));
4291   CHKERRQ(DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets));
4292   ms      = mesh->maxSupportSize;
4293   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
4294   CHKERRQ(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]));
4295   CHKERRQ(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]));
4296 
4297   for (p = 0; p < numPoints; ++p) {
4298     PetscInt closureSize;
4299 
4300     CHKERRQ(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]));
4301 
4302     offsets[p*(depth+2)+0] = 0;
4303     for (d = 0; d < depth+1; ++d) {
4304       PetscInt pStart, pEnd, i;
4305 
4306       CHKERRQ(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
4307       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
4308         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
4309           offsets[p*(depth+2)+d+1] = i;
4310           break;
4311         }
4312       }
4313       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
4314     }
4315     PetscCheckFalse(offsets[p*(depth+2)+depth+1] != closureSize,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize);
4316   }
4317   for (d = 0; d < depth+1; ++d) {
4318     PetscInt dof;
4319 
4320     /* Copy in support of first point */
4321     dof = offsets[d+1] - offsets[d];
4322     for (joinSize = 0; joinSize < dof; ++joinSize) {
4323       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
4324     }
4325     /* Check each successive cone */
4326     for (p = 1; p < numPoints && joinSize; ++p) {
4327       PetscInt newJoinSize = 0;
4328 
4329       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
4330       for (c = 0; c < dof; ++c) {
4331         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
4332 
4333         for (m = 0; m < joinSize; ++m) {
4334           if (point == join[i][m]) {
4335             join[1-i][newJoinSize++] = point;
4336             break;
4337           }
4338         }
4339       }
4340       joinSize = newJoinSize;
4341       i        = 1-i;
4342     }
4343     if (joinSize) break;
4344   }
4345   *numCoveredPoints = joinSize;
4346   *coveredPoints    = join[i];
4347   for (p = 0; p < numPoints; ++p) {
4348     CHKERRQ(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]));
4349   }
4350   CHKERRQ(PetscFree(closures));
4351   CHKERRQ(DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets));
4352   CHKERRQ(DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]));
4353   PetscFunctionReturn(0);
4354 }
4355 
4356 /*@C
4357   DMPlexGetMeet - Get an array for the meet of the set of points
4358 
4359   Not Collective
4360 
4361   Input Parameters:
4362 + dm - The DMPlex object
4363 . numPoints - The number of input points for the meet
4364 - points - The input points
4365 
4366   Output Parameters:
4367 + numCoveredPoints - The number of points in the meet
4368 - coveredPoints - The points in the meet
4369 
4370   Level: intermediate
4371 
4372   Note: Currently, this is restricted to a single level meet
4373 
4374   Fortran Notes:
4375   Since it returns an array, this routine is only available in Fortran 90, and you must
4376   include petsc.h90 in your code.
4377 
4378   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4379 
4380 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
4381 @*/
4382 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
4383 {
4384   DM_Plex       *mesh = (DM_Plex*) dm->data;
4385   PetscInt      *meet[2];
4386   PetscInt       meetSize, i = 0;
4387   PetscInt       dof, off, p, c, m;
4388 
4389   PetscFunctionBegin;
4390   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4391   PetscValidIntPointer(points, 3);
4392   PetscValidIntPointer(numCoveringPoints, 4);
4393   PetscValidPointer(coveringPoints, 5);
4394   CHKERRQ(DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]));
4395   CHKERRQ(DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]));
4396   /* Copy in cone of first point */
4397   CHKERRQ(PetscSectionGetDof(mesh->coneSection, points[0], &dof));
4398   CHKERRQ(PetscSectionGetOffset(mesh->coneSection, points[0], &off));
4399   for (meetSize = 0; meetSize < dof; ++meetSize) {
4400     meet[i][meetSize] = mesh->cones[off+meetSize];
4401   }
4402   /* Check each successive cone */
4403   for (p = 1; p < numPoints; ++p) {
4404     PetscInt newMeetSize = 0;
4405 
4406     CHKERRQ(PetscSectionGetDof(mesh->coneSection, points[p], &dof));
4407     CHKERRQ(PetscSectionGetOffset(mesh->coneSection, points[p], &off));
4408     for (c = 0; c < dof; ++c) {
4409       const PetscInt point = mesh->cones[off+c];
4410 
4411       for (m = 0; m < meetSize; ++m) {
4412         if (point == meet[i][m]) {
4413           meet[1-i][newMeetSize++] = point;
4414           break;
4415         }
4416       }
4417     }
4418     meetSize = newMeetSize;
4419     i        = 1-i;
4420   }
4421   *numCoveringPoints = meetSize;
4422   *coveringPoints    = meet[i];
4423   CHKERRQ(DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]));
4424   PetscFunctionReturn(0);
4425 }
4426 
4427 /*@C
4428   DMPlexRestoreMeet - Restore an array for the meet of the set of points
4429 
4430   Not Collective
4431 
4432   Input Parameters:
4433 + dm - The DMPlex object
4434 . numPoints - The number of input points for the meet
4435 - points - The input points
4436 
4437   Output Parameters:
4438 + numCoveredPoints - The number of points in the meet
4439 - coveredPoints - The points in the meet
4440 
4441   Level: intermediate
4442 
4443   Fortran Notes:
4444   Since it returns an array, this routine is only available in Fortran 90, and you must
4445   include petsc.h90 in your code.
4446 
4447   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4448 
4449 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
4450 @*/
4451 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4452 {
4453   PetscFunctionBegin;
4454   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4455   if (points) PetscValidIntPointer(points,3);
4456   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
4457   PetscValidPointer(coveredPoints,5);
4458   CHKERRQ(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints));
4459   if (numCoveredPoints) *numCoveredPoints = 0;
4460   PetscFunctionReturn(0);
4461 }
4462 
4463 /*@C
4464   DMPlexGetFullMeet - Get an array for the meet of the set of points
4465 
4466   Not Collective
4467 
4468   Input Parameters:
4469 + dm - The DMPlex object
4470 . numPoints - The number of input points for the meet
4471 - points - The input points
4472 
4473   Output Parameters:
4474 + numCoveredPoints - The number of points in the meet
4475 - coveredPoints - The points in the meet
4476 
4477   Level: intermediate
4478 
4479   Fortran Notes:
4480   Since it returns an array, this routine is only available in Fortran 90, and you must
4481   include petsc.h90 in your code.
4482 
4483   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4484 
4485 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
4486 @*/
4487 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4488 {
4489   DM_Plex       *mesh = (DM_Plex*) dm->data;
4490   PetscInt      *offsets, **closures;
4491   PetscInt      *meet[2];
4492   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
4493   PetscInt       p, h, c, m, mc;
4494 
4495   PetscFunctionBegin;
4496   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4497   PetscValidIntPointer(points, 3);
4498   PetscValidIntPointer(numCoveredPoints, 4);
4499   PetscValidPointer(coveredPoints, 5);
4500 
4501   CHKERRQ(DMPlexGetDepth(dm, &height));
4502   CHKERRQ(PetscMalloc1(numPoints, &closures));
4503   CHKERRQ(DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets));
4504   mc      = mesh->maxConeSize;
4505   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
4506   CHKERRQ(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]));
4507   CHKERRQ(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]));
4508 
4509   for (p = 0; p < numPoints; ++p) {
4510     PetscInt closureSize;
4511 
4512     CHKERRQ(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]));
4513 
4514     offsets[p*(height+2)+0] = 0;
4515     for (h = 0; h < height+1; ++h) {
4516       PetscInt pStart, pEnd, i;
4517 
4518       CHKERRQ(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd));
4519       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
4520         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
4521           offsets[p*(height+2)+h+1] = i;
4522           break;
4523         }
4524       }
4525       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
4526     }
4527     PetscCheckFalse(offsets[p*(height+2)+height+1] != closureSize,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize);
4528   }
4529   for (h = 0; h < height+1; ++h) {
4530     PetscInt dof;
4531 
4532     /* Copy in cone of first point */
4533     dof = offsets[h+1] - offsets[h];
4534     for (meetSize = 0; meetSize < dof; ++meetSize) {
4535       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
4536     }
4537     /* Check each successive cone */
4538     for (p = 1; p < numPoints && meetSize; ++p) {
4539       PetscInt newMeetSize = 0;
4540 
4541       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
4542       for (c = 0; c < dof; ++c) {
4543         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
4544 
4545         for (m = 0; m < meetSize; ++m) {
4546           if (point == meet[i][m]) {
4547             meet[1-i][newMeetSize++] = point;
4548             break;
4549           }
4550         }
4551       }
4552       meetSize = newMeetSize;
4553       i        = 1-i;
4554     }
4555     if (meetSize) break;
4556   }
4557   *numCoveredPoints = meetSize;
4558   *coveredPoints    = meet[i];
4559   for (p = 0; p < numPoints; ++p) {
4560     CHKERRQ(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]));
4561   }
4562   CHKERRQ(PetscFree(closures));
4563   CHKERRQ(DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets));
4564   CHKERRQ(DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]));
4565   PetscFunctionReturn(0);
4566 }
4567 
4568 /*@C
4569   DMPlexEqual - Determine if two DMs have the same topology
4570 
4571   Not Collective
4572 
4573   Input Parameters:
4574 + dmA - A DMPlex object
4575 - dmB - A DMPlex object
4576 
4577   Output Parameters:
4578 . equal - PETSC_TRUE if the topologies are identical
4579 
4580   Level: intermediate
4581 
4582   Notes:
4583   We are not solving graph isomorphism, so we do not permutation.
4584 
4585 .seealso: DMPlexGetCone()
4586 @*/
4587 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
4588 {
4589   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;
4590 
4591   PetscFunctionBegin;
4592   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
4593   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
4594   PetscValidBoolPointer(equal, 3);
4595 
4596   *equal = PETSC_FALSE;
4597   CHKERRQ(DMPlexGetDepth(dmA, &depth));
4598   CHKERRQ(DMPlexGetDepth(dmB, &depthB));
4599   if (depth != depthB) PetscFunctionReturn(0);
4600   CHKERRQ(DMPlexGetChart(dmA, &pStart,  &pEnd));
4601   CHKERRQ(DMPlexGetChart(dmB, &pStartB, &pEndB));
4602   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0);
4603   for (p = pStart; p < pEnd; ++p) {
4604     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
4605     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
4606 
4607     CHKERRQ(DMPlexGetConeSize(dmA, p, &coneSize));
4608     CHKERRQ(DMPlexGetCone(dmA, p, &cone));
4609     CHKERRQ(DMPlexGetConeOrientation(dmA, p, &ornt));
4610     CHKERRQ(DMPlexGetConeSize(dmB, p, &coneSizeB));
4611     CHKERRQ(DMPlexGetCone(dmB, p, &coneB));
4612     CHKERRQ(DMPlexGetConeOrientation(dmB, p, &orntB));
4613     if (coneSize != coneSizeB) PetscFunctionReturn(0);
4614     for (c = 0; c < coneSize; ++c) {
4615       if (cone[c] != coneB[c]) PetscFunctionReturn(0);
4616       if (ornt[c] != orntB[c]) PetscFunctionReturn(0);
4617     }
4618     CHKERRQ(DMPlexGetSupportSize(dmA, p, &supportSize));
4619     CHKERRQ(DMPlexGetSupport(dmA, p, &support));
4620     CHKERRQ(DMPlexGetSupportSize(dmB, p, &supportSizeB));
4621     CHKERRQ(DMPlexGetSupport(dmB, p, &supportB));
4622     if (supportSize != supportSizeB) PetscFunctionReturn(0);
4623     for (s = 0; s < supportSize; ++s) {
4624       if (support[s] != supportB[s]) PetscFunctionReturn(0);
4625     }
4626   }
4627   *equal = PETSC_TRUE;
4628   PetscFunctionReturn(0);
4629 }
4630 
4631 /*@C
4632   DMPlexGetNumFaceVertices - Returns the number of vertices on a face
4633 
4634   Not Collective
4635 
4636   Input Parameters:
4637 + dm         - The DMPlex
4638 . cellDim    - The cell dimension
4639 - numCorners - The number of vertices on a cell
4640 
4641   Output Parameters:
4642 . numFaceVertices - The number of vertices on a face
4643 
4644   Level: developer
4645 
4646   Notes:
4647   Of course this can only work for a restricted set of symmetric shapes
4648 
4649 .seealso: DMPlexGetCone()
4650 @*/
4651 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
4652 {
4653   MPI_Comm       comm;
4654 
4655   PetscFunctionBegin;
4656   CHKERRQ(PetscObjectGetComm((PetscObject)dm,&comm));
4657   PetscValidIntPointer(numFaceVertices,4);
4658   switch (cellDim) {
4659   case 0:
4660     *numFaceVertices = 0;
4661     break;
4662   case 1:
4663     *numFaceVertices = 1;
4664     break;
4665   case 2:
4666     switch (numCorners) {
4667     case 3: /* triangle */
4668       *numFaceVertices = 2; /* Edge has 2 vertices */
4669       break;
4670     case 4: /* quadrilateral */
4671       *numFaceVertices = 2; /* Edge has 2 vertices */
4672       break;
4673     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
4674       *numFaceVertices = 3; /* Edge has 3 vertices */
4675       break;
4676     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
4677       *numFaceVertices = 3; /* Edge has 3 vertices */
4678       break;
4679     default:
4680       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
4681     }
4682     break;
4683   case 3:
4684     switch (numCorners) {
4685     case 4: /* tetradehdron */
4686       *numFaceVertices = 3; /* Face has 3 vertices */
4687       break;
4688     case 6: /* tet cohesive cells */
4689       *numFaceVertices = 4; /* Face has 4 vertices */
4690       break;
4691     case 8: /* hexahedron */
4692       *numFaceVertices = 4; /* Face has 4 vertices */
4693       break;
4694     case 9: /* tet cohesive Lagrange cells */
4695       *numFaceVertices = 6; /* Face has 6 vertices */
4696       break;
4697     case 10: /* quadratic tetrahedron */
4698       *numFaceVertices = 6; /* Face has 6 vertices */
4699       break;
4700     case 12: /* hex cohesive Lagrange cells */
4701       *numFaceVertices = 6; /* Face has 6 vertices */
4702       break;
4703     case 18: /* quadratic tet cohesive Lagrange cells */
4704       *numFaceVertices = 6; /* Face has 6 vertices */
4705       break;
4706     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
4707       *numFaceVertices = 9; /* Face has 9 vertices */
4708       break;
4709     default:
4710       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
4711     }
4712     break;
4713   default:
4714     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
4715   }
4716   PetscFunctionReturn(0);
4717 }
4718 
4719 /*@
4720   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
4721 
4722   Not Collective
4723 
4724   Input Parameter:
4725 . dm    - The DMPlex object
4726 
4727   Output Parameter:
4728 . depthLabel - The DMLabel recording point depth
4729 
4730   Level: developer
4731 
4732 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum(), DMPlexGetPointDepth(),
4733 @*/
4734 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
4735 {
4736   PetscFunctionBegin;
4737   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4738   PetscValidPointer(depthLabel, 2);
4739   *depthLabel = dm->depthLabel;
4740   PetscFunctionReturn(0);
4741 }
4742 
4743 /*@
4744   DMPlexGetDepth - Get the depth of the DAG representing this mesh
4745 
4746   Not Collective
4747 
4748   Input Parameter:
4749 . dm    - The DMPlex object
4750 
4751   Output Parameter:
4752 . depth - The number of strata (breadth first levels) in the DAG
4753 
4754   Level: developer
4755 
4756   Notes:
4757   This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel().
4758   The point depth is described more in detail in DMPlexGetDepthStratum().
4759   An empty mesh gives -1.
4760 
4761 .seealso: DMPlexGetDepthLabel(), DMPlexGetDepthStratum(), DMPlexGetPointDepth(), DMPlexSymmetrize()
4762 @*/
4763 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
4764 {
4765   DMLabel        label;
4766   PetscInt       d = 0;
4767 
4768   PetscFunctionBegin;
4769   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4770   PetscValidIntPointer(depth, 2);
4771   CHKERRQ(DMPlexGetDepthLabel(dm, &label));
4772   if (label) CHKERRQ(DMLabelGetNumValues(label, &d));
4773   *depth = d-1;
4774   PetscFunctionReturn(0);
4775 }
4776 
4777 /*@
4778   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
4779 
4780   Not Collective
4781 
4782   Input Parameters:
4783 + dm           - The DMPlex object
4784 - stratumValue - The requested depth
4785 
4786   Output Parameters:
4787 + start - The first point at this depth
4788 - end   - One beyond the last point at this depth
4789 
4790   Notes:
4791   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
4792   often "vertices".  If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next
4793   higher dimension, e.g., "edges".
4794 
4795   Level: developer
4796 
4797 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth(), DMPlexGetDepthLabel(), DMPlexGetPointDepth(), DMPlexSymmetrize(), DMPlexInterpolate()
4798 @*/
4799 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
4800 {
4801   DMLabel        label;
4802   PetscInt       pStart, pEnd;
4803 
4804   PetscFunctionBegin;
4805   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4806   if (start) {PetscValidIntPointer(start, 3); *start = 0;}
4807   if (end)   {PetscValidIntPointer(end,   4); *end   = 0;}
4808   CHKERRQ(DMPlexGetChart(dm, &pStart, &pEnd));
4809   if (pStart == pEnd) PetscFunctionReturn(0);
4810   if (stratumValue < 0) {
4811     if (start) *start = pStart;
4812     if (end)   *end   = pEnd;
4813     PetscFunctionReturn(0);
4814   }
4815   CHKERRQ(DMPlexGetDepthLabel(dm, &label));
4816   PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
4817   CHKERRQ(DMLabelGetStratumBounds(label, stratumValue, start, end));
4818   PetscFunctionReturn(0);
4819 }
4820 
4821 /*@
4822   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
4823 
4824   Not Collective
4825 
4826   Input Parameters:
4827 + dm           - The DMPlex object
4828 - stratumValue - The requested height
4829 
4830   Output Parameters:
4831 + start - The first point at this height
4832 - end   - One beyond the last point at this height
4833 
4834   Notes:
4835   Height indexing is related to topological codimension.  Height stratum 0 contains the highest topological dimension
4836   points, often called "cells" or "elements".  If the mesh is "interpolated" (see DMPlexInterpolate()), then height
4837   stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
4838 
4839   Level: developer
4840 
4841 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth(), DMPlexGetPointHeight()
4842 @*/
4843 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
4844 {
4845   DMLabel        label;
4846   PetscInt       depth, pStart, pEnd;
4847 
4848   PetscFunctionBegin;
4849   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4850   if (start) {PetscValidIntPointer(start, 3); *start = 0;}
4851   if (end)   {PetscValidIntPointer(end,   4); *end   = 0;}
4852   CHKERRQ(DMPlexGetChart(dm, &pStart, &pEnd));
4853   if (pStart == pEnd) PetscFunctionReturn(0);
4854   if (stratumValue < 0) {
4855     if (start) *start = pStart;
4856     if (end)   *end   = pEnd;
4857     PetscFunctionReturn(0);
4858   }
4859   CHKERRQ(DMPlexGetDepthLabel(dm, &label));
4860   PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
4861   CHKERRQ(DMLabelGetNumValues(label, &depth));
4862   CHKERRQ(DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end));
4863   PetscFunctionReturn(0);
4864 }
4865 
4866 /*@
4867   DMPlexGetPointDepth - Get the depth of a given point
4868 
4869   Not Collective
4870 
4871   Input Parameters:
4872 + dm    - The DMPlex object
4873 - point - The point
4874 
4875   Output Parameter:
4876 . depth - The depth of the point
4877 
4878   Level: intermediate
4879 
4880 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexGetPointHeight()
4881 @*/
4882 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
4883 {
4884   PetscFunctionBegin;
4885   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4886   PetscValidIntPointer(depth, 3);
4887   CHKERRQ(DMLabelGetValue(dm->depthLabel, point, depth));
4888   PetscFunctionReturn(0);
4889 }
4890 
4891 /*@
4892   DMPlexGetPointHeight - Get the height of a given point
4893 
4894   Not Collective
4895 
4896   Input Parameters:
4897 + dm    - The DMPlex object
4898 - point - The point
4899 
4900   Output Parameter:
4901 . height - The height of the point
4902 
4903   Level: intermediate
4904 
4905 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexGetPointDepth()
4906 @*/
4907 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
4908 {
4909   PetscInt       n, pDepth;
4910 
4911   PetscFunctionBegin;
4912   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4913   PetscValidIntPointer(height, 3);
4914   CHKERRQ(DMLabelGetNumValues(dm->depthLabel, &n));
4915   CHKERRQ(DMLabelGetValue(dm->depthLabel, point, &pDepth));
4916   *height = n - 1 - pDepth;  /* DAG depth is n-1 */
4917   PetscFunctionReturn(0);
4918 }
4919 
4920 /*@
4921   DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell
4922 
4923   Not Collective
4924 
4925   Input Parameter:
4926 . dm - The DMPlex object
4927 
4928   Output Parameter:
4929 . celltypeLabel - The DMLabel recording cell polytope type
4930 
4931   Note: This function will trigger automatica computation of cell types. This can be disabled by calling
4932   DMCreateLabel(dm, "celltype") beforehand.
4933 
4934   Level: developer
4935 
4936 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMCreateLabel()
4937 @*/
4938 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
4939 {
4940   PetscFunctionBegin;
4941   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4942   PetscValidPointer(celltypeLabel, 2);
4943   if (!dm->celltypeLabel) CHKERRQ(DMPlexComputeCellTypes(dm));
4944   *celltypeLabel = dm->celltypeLabel;
4945   PetscFunctionReturn(0);
4946 }
4947 
4948 /*@
4949   DMPlexGetCellType - Get the polytope type of a given cell
4950 
4951   Not Collective
4952 
4953   Input Parameters:
4954 + dm   - The DMPlex object
4955 - cell - The cell
4956 
4957   Output Parameter:
4958 . celltype - The polytope type of the cell
4959 
4960   Level: intermediate
4961 
4962 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth()
4963 @*/
4964 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
4965 {
4966   DMLabel        label;
4967   PetscInt       ct;
4968 
4969   PetscFunctionBegin;
4970   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4971   PetscValidPointer(celltype, 3);
4972   CHKERRQ(DMPlexGetCellTypeLabel(dm, &label));
4973   CHKERRQ(DMLabelGetValue(label, cell, &ct));
4974   PetscCheckFalse(ct < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %D has not been assigned a cell type", cell);
4975   *celltype = (DMPolytopeType) ct;
4976   PetscFunctionReturn(0);
4977 }
4978 
4979 /*@
4980   DMPlexSetCellType - Set the polytope type of a given cell
4981 
4982   Not Collective
4983 
4984   Input Parameters:
4985 + dm   - The DMPlex object
4986 . cell - The cell
4987 - celltype - The polytope type of the cell
4988 
4989   Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function
4990   is executed. This function will override the computed type. However, if automatic classification will not succeed
4991   and a user wants to manually specify all types, the classification must be disabled by calling
4992   DMCreaateLabel(dm, "celltype") before getting or setting any cell types.
4993 
4994   Level: advanced
4995 
4996 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexComputeCellTypes(), DMCreateLabel()
4997 @*/
4998 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
4999 {
5000   DMLabel        label;
5001 
5002   PetscFunctionBegin;
5003   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5004   CHKERRQ(DMPlexGetCellTypeLabel(dm, &label));
5005   CHKERRQ(DMLabelSetValue(label, cell, celltype));
5006   PetscFunctionReturn(0);
5007 }
5008 
5009 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
5010 {
5011   PetscSection   section, s;
5012   Mat            m;
5013   PetscInt       maxHeight;
5014 
5015   PetscFunctionBegin;
5016   CHKERRQ(DMClone(dm, cdm));
5017   CHKERRQ(DMPlexGetMaxProjectionHeight(dm, &maxHeight));
5018   CHKERRQ(DMPlexSetMaxProjectionHeight(*cdm, maxHeight));
5019   CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
5020   CHKERRQ(DMSetLocalSection(*cdm, section));
5021   CHKERRQ(PetscSectionDestroy(&section));
5022   CHKERRQ(PetscSectionCreate(PETSC_COMM_SELF, &s));
5023   CHKERRQ(MatCreate(PETSC_COMM_SELF, &m));
5024   CHKERRQ(DMSetDefaultConstraints(*cdm, s, m, NULL));
5025   CHKERRQ(PetscSectionDestroy(&s));
5026   CHKERRQ(MatDestroy(&m));
5027 
5028   CHKERRQ(DMSetNumFields(*cdm, 1));
5029   CHKERRQ(DMCreateDS(*cdm));
5030   PetscFunctionReturn(0);
5031 }
5032 
5033 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
5034 {
5035   Vec            coordsLocal;
5036   DM             coordsDM;
5037 
5038   PetscFunctionBegin;
5039   *field = NULL;
5040   CHKERRQ(DMGetCoordinatesLocal(dm,&coordsLocal));
5041   CHKERRQ(DMGetCoordinateDM(dm,&coordsDM));
5042   if (coordsLocal && coordsDM) {
5043     CHKERRQ(DMFieldCreateDS(coordsDM, 0, coordsLocal, field));
5044   }
5045   PetscFunctionReturn(0);
5046 }
5047 
5048 /*@C
5049   DMPlexGetConeSection - Return a section which describes the layout of cone data
5050 
5051   Not Collective
5052 
5053   Input Parameters:
5054 . dm        - The DMPlex object
5055 
5056   Output Parameter:
5057 . section - The PetscSection object
5058 
5059   Level: developer
5060 
5061 .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
5062 @*/
5063 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
5064 {
5065   DM_Plex *mesh = (DM_Plex*) dm->data;
5066 
5067   PetscFunctionBegin;
5068   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5069   if (section) *section = mesh->coneSection;
5070   PetscFunctionReturn(0);
5071 }
5072 
5073 /*@C
5074   DMPlexGetSupportSection - Return a section which describes the layout of support data
5075 
5076   Not Collective
5077 
5078   Input Parameters:
5079 . dm        - The DMPlex object
5080 
5081   Output Parameter:
5082 . section - The PetscSection object
5083 
5084   Level: developer
5085 
5086 .seealso: DMPlexGetConeSection()
5087 @*/
5088 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
5089 {
5090   DM_Plex *mesh = (DM_Plex*) dm->data;
5091 
5092   PetscFunctionBegin;
5093   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5094   if (section) *section = mesh->supportSection;
5095   PetscFunctionReturn(0);
5096 }
5097 
5098 /*@C
5099   DMPlexGetCones - Return cone data
5100 
5101   Not Collective
5102 
5103   Input Parameters:
5104 . dm        - The DMPlex object
5105 
5106   Output Parameter:
5107 . cones - The cone for each point
5108 
5109   Level: developer
5110 
5111 .seealso: DMPlexGetConeSection()
5112 @*/
5113 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
5114 {
5115   DM_Plex *mesh = (DM_Plex*) dm->data;
5116 
5117   PetscFunctionBegin;
5118   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5119   if (cones) *cones = mesh->cones;
5120   PetscFunctionReturn(0);
5121 }
5122 
5123 /*@C
5124   DMPlexGetConeOrientations - Return cone orientation data
5125 
5126   Not Collective
5127 
5128   Input Parameters:
5129 . dm        - The DMPlex object
5130 
5131   Output Parameter:
5132 . coneOrientations - The array of cone orientations for all points
5133 
5134   Level: developer
5135 
5136   Notes:
5137   The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation().
5138 
5139   The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation().
5140 
5141 .seealso: DMPlexGetConeSection(), DMPlexGetConeOrientation()
5142 @*/
5143 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
5144 {
5145   DM_Plex *mesh = (DM_Plex*) dm->data;
5146 
5147   PetscFunctionBegin;
5148   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5149   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
5150   PetscFunctionReturn(0);
5151 }
5152 
5153 /******************************** FEM Support **********************************/
5154 
5155 /*
5156  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
5157  representing a line in the section.
5158 */
5159 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k)
5160 {
5161   PetscFunctionBeginHot;
5162   CHKERRQ(PetscSectionGetFieldComponents(section, field, Nc));
5163   if (line < 0) {
5164     *k = 0;
5165     *Nc = 0;
5166   } else if (vertexchart) {            /* If we only have a vertex chart, we must have degree k=1 */
5167     *k = 1;
5168   } else {                      /* Assume the full interpolated mesh is in the chart; lines in particular */
5169     /* An order k SEM disc has k-1 dofs on an edge */
5170     CHKERRQ(PetscSectionGetFieldDof(section, line, field, k));
5171     *k = *k / *Nc + 1;
5172   }
5173   PetscFunctionReturn(0);
5174 }
5175 
5176 /*@
5177 
5178   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
5179   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
5180   section provided (or the section of the DM).
5181 
5182   Input Parameters:
5183 + dm      - The DM
5184 . point   - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE
5185 - section - The PetscSection to reorder, or NULL for the default section
5186 
5187   Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
5188   degree of the basis.
5189 
5190   Example:
5191   A typical interpolated single-quad mesh might order points as
5192 .vb
5193   [c0, v1, v2, v3, v4, e5, e6, e7, e8]
5194 
5195   v4 -- e6 -- v3
5196   |           |
5197   e7    c0    e8
5198   |           |
5199   v1 -- e5 -- v2
5200 .ve
5201 
5202   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
5203   dofs in the order of points, e.g.,
5204 .vb
5205     c0 -> [0,1,2,3]
5206     v1 -> [4]
5207     ...
5208     e5 -> [8, 9]
5209 .ve
5210 
5211   which corresponds to the dofs
5212 .vb
5213     6   10  11  7
5214     13  2   3   15
5215     12  0   1   14
5216     4   8   9   5
5217 .ve
5218 
5219   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
5220 .vb
5221   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
5222 .ve
5223 
5224   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
5225 .vb
5226    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
5227 .ve
5228 
5229   Level: developer
5230 
5231 .seealso: DMGetLocalSection(), PetscSectionSetClosurePermutation(), DMSetGlobalSection()
5232 @*/
5233 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
5234 {
5235   DMLabel        label;
5236   PetscInt       dim, depth = -1, eStart = -1, Nf;
5237   PetscBool      vertexchart;
5238 
5239   PetscFunctionBegin;
5240   CHKERRQ(DMGetDimension(dm, &dim));
5241   if (dim < 1) PetscFunctionReturn(0);
5242   if (point < 0) {
5243     PetscInt sStart,sEnd;
5244 
5245     CHKERRQ(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd));
5246     point = sEnd-sStart ? sStart : point;
5247   }
5248   CHKERRQ(DMPlexGetDepthLabel(dm, &label));
5249   if (point >= 0) CHKERRQ(DMLabelGetValue(label, point, &depth));
5250   if (!section) CHKERRQ(DMGetLocalSection(dm, &section));
5251   if (depth == 1) {eStart = point;}
5252   else if  (depth == dim) {
5253     const PetscInt *cone;
5254 
5255     CHKERRQ(DMPlexGetCone(dm, point, &cone));
5256     if (dim == 2) eStart = cone[0];
5257     else if (dim == 3) {
5258       const PetscInt *cone2;
5259       CHKERRQ(DMPlexGetCone(dm, cone[0], &cone2));
5260       eStart = cone2[0];
5261     } else SETERRQ(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);
5262   } else PetscCheckFalse(depth >= 0,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);
5263   {                             /* Determine whether the chart covers all points or just vertices. */
5264     PetscInt pStart,pEnd,cStart,cEnd;
5265     CHKERRQ(DMPlexGetDepthStratum(dm,0,&pStart,&pEnd));
5266     CHKERRQ(PetscSectionGetChart(section,&cStart,&cEnd));
5267     if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE;      /* Only vertices are in the chart */
5268     else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */
5269     else vertexchart = PETSC_TRUE;                                       /* Some interpolated points are not in chart; assume dofs only at cells and vertices */
5270   }
5271   CHKERRQ(PetscSectionGetNumFields(section, &Nf));
5272   for (PetscInt d=1; d<=dim; d++) {
5273     PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
5274     PetscInt *perm;
5275 
5276     for (f = 0; f < Nf; ++f) {
5277       CHKERRQ(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k));
5278       size += PetscPowInt(k+1, d)*Nc;
5279     }
5280     CHKERRQ(PetscMalloc1(size, &perm));
5281     for (f = 0; f < Nf; ++f) {
5282       switch (d) {
5283       case 1:
5284         CHKERRQ(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k));
5285         /*
5286          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
5287          We want              [ vtx0; edge of length k-1; vtx1 ]
5288          */
5289         for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset;
5290         for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset;
5291         for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset;
5292         foffset = offset;
5293         break;
5294       case 2:
5295         /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
5296         CHKERRQ(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k));
5297         /* The SEM order is
5298 
5299          v_lb, {e_b}, v_rb,
5300          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
5301          v_lt, reverse {e_t}, v_rt
5302          */
5303         {
5304           const PetscInt of   = 0;
5305           const PetscInt oeb  = of   + PetscSqr(k-1);
5306           const PetscInt oer  = oeb  + (k-1);
5307           const PetscInt oet  = oer  + (k-1);
5308           const PetscInt oel  = oet  + (k-1);
5309           const PetscInt ovlb = oel  + (k-1);
5310           const PetscInt ovrb = ovlb + 1;
5311           const PetscInt ovrt = ovrb + 1;
5312           const PetscInt ovlt = ovrt + 1;
5313           PetscInt       o;
5314 
5315           /* bottom */
5316           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
5317           for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5318           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
5319           /* middle */
5320           for (i = 0; i < k-1; ++i) {
5321             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
5322             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;
5323             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
5324           }
5325           /* top */
5326           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
5327           for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5328           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
5329           foffset = offset;
5330         }
5331         break;
5332       case 3:
5333         /* The original hex closure is
5334 
5335          {c,
5336          f_b, f_t, f_f, f_b, f_r, f_l,
5337          e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
5338          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
5339          */
5340         CHKERRQ(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k));
5341         /* The SEM order is
5342          Bottom Slice
5343          v_blf, {e^{(k-1)-n}_bf}, v_brf,
5344          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
5345          v_blb, {e_bb}, v_brb,
5346 
5347          Middle Slice (j)
5348          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
5349          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
5350          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
5351 
5352          Top Slice
5353          v_tlf, {e_tf}, v_trf,
5354          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
5355          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
5356          */
5357         {
5358           const PetscInt oc    = 0;
5359           const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
5360           const PetscInt oft   = ofb   + PetscSqr(k-1);
5361           const PetscInt off   = oft   + PetscSqr(k-1);
5362           const PetscInt ofk   = off   + PetscSqr(k-1);
5363           const PetscInt ofr   = ofk   + PetscSqr(k-1);
5364           const PetscInt ofl   = ofr   + PetscSqr(k-1);
5365           const PetscInt oebl  = ofl   + PetscSqr(k-1);
5366           const PetscInt oebb  = oebl  + (k-1);
5367           const PetscInt oebr  = oebb  + (k-1);
5368           const PetscInt oebf  = oebr  + (k-1);
5369           const PetscInt oetf  = oebf  + (k-1);
5370           const PetscInt oetr  = oetf  + (k-1);
5371           const PetscInt oetb  = oetr  + (k-1);
5372           const PetscInt oetl  = oetb  + (k-1);
5373           const PetscInt oerf  = oetl  + (k-1);
5374           const PetscInt oelf  = oerf  + (k-1);
5375           const PetscInt oelb  = oelf  + (k-1);
5376           const PetscInt oerb  = oelb  + (k-1);
5377           const PetscInt ovblf = oerb  + (k-1);
5378           const PetscInt ovblb = ovblf + 1;
5379           const PetscInt ovbrb = ovblb + 1;
5380           const PetscInt ovbrf = ovbrb + 1;
5381           const PetscInt ovtlf = ovbrf + 1;
5382           const PetscInt ovtrf = ovtlf + 1;
5383           const PetscInt ovtrb = ovtrf + 1;
5384           const PetscInt ovtlb = ovtrb + 1;
5385           PetscInt       o, n;
5386 
5387           /* Bottom Slice */
5388           /*   bottom */
5389           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
5390           for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5391           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
5392           /*   middle */
5393           for (i = 0; i < k-1; ++i) {
5394             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
5395             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;}
5396             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
5397           }
5398           /*   top */
5399           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
5400           for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5401           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
5402 
5403           /* Middle Slice */
5404           for (j = 0; j < k-1; ++j) {
5405             /*   bottom */
5406             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
5407             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;
5408             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
5409             /*   middle */
5410             for (i = 0; i < k-1; ++i) {
5411               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
5412               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;
5413               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
5414             }
5415             /*   top */
5416             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
5417             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;
5418             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
5419           }
5420 
5421           /* Top Slice */
5422           /*   bottom */
5423           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
5424           for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5425           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
5426           /*   middle */
5427           for (i = 0; i < k-1; ++i) {
5428             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
5429             for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
5430             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
5431           }
5432           /*   top */
5433           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
5434           for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5435           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
5436 
5437           foffset = offset;
5438         }
5439         break;
5440       default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", d);
5441       }
5442     }
5443     PetscCheckFalse(offset != size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
5444     /* Check permutation */
5445     {
5446       PetscInt *check;
5447 
5448       CHKERRQ(PetscMalloc1(size, &check));
5449       for (i = 0; i < size; ++i) {check[i] = -1; PetscCheckFalse(perm[i] < 0 || perm[i] >= size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%D] = %D", i, perm[i]);}
5450       for (i = 0; i < size; ++i) check[perm[i]] = i;
5451       for (i = 0; i < size; ++i) {PetscCheckFalse(check[i] < 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
5452       CHKERRQ(PetscFree(check));
5453     }
5454     CHKERRQ(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm));
5455     if (d == dim) { // Add permutation for localized (in case this is a coordinate DM)
5456       PetscInt *loc_perm;
5457       CHKERRQ(PetscMalloc1(size*2, &loc_perm));
5458       for (PetscInt i=0; i<size; i++) {
5459         loc_perm[i] = perm[i];
5460         loc_perm[size+i] = size + perm[i];
5461       }
5462       CHKERRQ(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size*2, PETSC_OWN_POINTER, loc_perm));
5463     }
5464   }
5465   PetscFunctionReturn(0);
5466 }
5467 
5468 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
5469 {
5470   PetscDS        prob;
5471   PetscInt       depth, Nf, h;
5472   DMLabel        label;
5473 
5474   PetscFunctionBeginHot;
5475   CHKERRQ(DMGetDS(dm, &prob));
5476   Nf      = prob->Nf;
5477   label   = dm->depthLabel;
5478   *dspace = NULL;
5479   if (field < Nf) {
5480     PetscObject disc = prob->disc[field];
5481 
5482     if (disc->classid == PETSCFE_CLASSID) {
5483       PetscDualSpace dsp;
5484 
5485       CHKERRQ(PetscFEGetDualSpace((PetscFE)disc,&dsp));
5486       CHKERRQ(DMLabelGetNumValues(label,&depth));
5487       CHKERRQ(DMLabelGetValue(label,point,&h));
5488       h    = depth - 1 - h;
5489       if (h) {
5490         CHKERRQ(PetscDualSpaceGetHeightSubspace(dsp,h,dspace));
5491       } else {
5492         *dspace = dsp;
5493       }
5494     }
5495   }
5496   PetscFunctionReturn(0);
5497 }
5498 
5499 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5500 {
5501   PetscScalar    *array, *vArray;
5502   const PetscInt *cone, *coneO;
5503   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
5504 
5505   PetscFunctionBeginHot;
5506   CHKERRQ(PetscSectionGetChart(section, &pStart, &pEnd));
5507   CHKERRQ(DMPlexGetConeSize(dm, point, &numPoints));
5508   CHKERRQ(DMPlexGetCone(dm, point, &cone));
5509   CHKERRQ(DMPlexGetConeOrientation(dm, point, &coneO));
5510   if (!values || !*values) {
5511     if ((point >= pStart) && (point < pEnd)) {
5512       PetscInt dof;
5513 
5514       CHKERRQ(PetscSectionGetDof(section, point, &dof));
5515       size += dof;
5516     }
5517     for (p = 0; p < numPoints; ++p) {
5518       const PetscInt cp = cone[p];
5519       PetscInt       dof;
5520 
5521       if ((cp < pStart) || (cp >= pEnd)) continue;
5522       CHKERRQ(PetscSectionGetDof(section, cp, &dof));
5523       size += dof;
5524     }
5525     if (!values) {
5526       if (csize) *csize = size;
5527       PetscFunctionReturn(0);
5528     }
5529     CHKERRQ(DMGetWorkArray(dm, size, MPIU_SCALAR, &array));
5530   } else {
5531     array = *values;
5532   }
5533   size = 0;
5534   CHKERRQ(VecGetArray(v, &vArray));
5535   if ((point >= pStart) && (point < pEnd)) {
5536     PetscInt     dof, off, d;
5537     PetscScalar *varr;
5538 
5539     CHKERRQ(PetscSectionGetDof(section, point, &dof));
5540     CHKERRQ(PetscSectionGetOffset(section, point, &off));
5541     varr = &vArray[off];
5542     for (d = 0; d < dof; ++d, ++offset) {
5543       array[offset] = varr[d];
5544     }
5545     size += dof;
5546   }
5547   for (p = 0; p < numPoints; ++p) {
5548     const PetscInt cp = cone[p];
5549     PetscInt       o  = coneO[p];
5550     PetscInt       dof, off, d;
5551     PetscScalar   *varr;
5552 
5553     if ((cp < pStart) || (cp >= pEnd)) continue;
5554     CHKERRQ(PetscSectionGetDof(section, cp, &dof));
5555     CHKERRQ(PetscSectionGetOffset(section, cp, &off));
5556     varr = &vArray[off];
5557     if (o >= 0) {
5558       for (d = 0; d < dof; ++d, ++offset) {
5559         array[offset] = varr[d];
5560       }
5561     } else {
5562       for (d = dof-1; d >= 0; --d, ++offset) {
5563         array[offset] = varr[d];
5564       }
5565     }
5566     size += dof;
5567   }
5568   CHKERRQ(VecRestoreArray(v, &vArray));
5569   if (!*values) {
5570     if (csize) *csize = size;
5571     *values = array;
5572   } else {
5573     PetscCheckFalse(size > *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
5574     *csize = size;
5575   }
5576   PetscFunctionReturn(0);
5577 }
5578 
5579 /* Compress out points not in the section */
5580 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
5581 {
5582   const PetscInt np = *numPoints;
5583   PetscInt       pStart, pEnd, p, q;
5584 
5585   CHKERRQ(PetscSectionGetChart(section, &pStart, &pEnd));
5586   for (p = 0, q = 0; p < np; ++p) {
5587     const PetscInt r = points[p*2];
5588     if ((r >= pStart) && (r < pEnd)) {
5589       points[q*2]   = r;
5590       points[q*2+1] = points[p*2+1];
5591       ++q;
5592     }
5593   }
5594   *numPoints = q;
5595   return 0;
5596 }
5597 
5598 /* Compressed closure does not apply closure permutation */
5599 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5600 {
5601   const PetscInt *cla = NULL;
5602   PetscInt       np, *pts = NULL;
5603 
5604   PetscFunctionBeginHot;
5605   CHKERRQ(PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints));
5606   if (*clPoints) {
5607     PetscInt dof, off;
5608 
5609     CHKERRQ(PetscSectionGetDof(*clSec, point, &dof));
5610     CHKERRQ(PetscSectionGetOffset(*clSec, point, &off));
5611     CHKERRQ(ISGetIndices(*clPoints, &cla));
5612     np   = dof/2;
5613     pts  = (PetscInt *) &cla[off];
5614   } else {
5615     CHKERRQ(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts));
5616     CHKERRQ(CompressPoints_Private(section, &np, pts));
5617   }
5618   *numPoints = np;
5619   *points    = pts;
5620   *clp       = cla;
5621   PetscFunctionReturn(0);
5622 }
5623 
5624 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5625 {
5626   PetscFunctionBeginHot;
5627   if (!*clPoints) {
5628     CHKERRQ(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points));
5629   } else {
5630     CHKERRQ(ISRestoreIndices(*clPoints, clp));
5631   }
5632   *numPoints = 0;
5633   *points    = NULL;
5634   *clSec     = NULL;
5635   *clPoints  = NULL;
5636   *clp       = NULL;
5637   PetscFunctionReturn(0);
5638 }
5639 
5640 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
5641 {
5642   PetscInt          offset = 0, p;
5643   const PetscInt    **perms = NULL;
5644   const PetscScalar **flips = NULL;
5645 
5646   PetscFunctionBeginHot;
5647   *size = 0;
5648   CHKERRQ(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips));
5649   for (p = 0; p < numPoints; p++) {
5650     const PetscInt    point = points[2*p];
5651     const PetscInt    *perm = perms ? perms[p] : NULL;
5652     const PetscScalar *flip = flips ? flips[p] : NULL;
5653     PetscInt          dof, off, d;
5654     const PetscScalar *varr;
5655 
5656     CHKERRQ(PetscSectionGetDof(section, point, &dof));
5657     CHKERRQ(PetscSectionGetOffset(section, point, &off));
5658     varr = &vArray[off];
5659     if (clperm) {
5660       if (perm) {
5661         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
5662       } else {
5663         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
5664       }
5665       if (flip) {
5666         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
5667       }
5668     } else {
5669       if (perm) {
5670         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
5671       } else {
5672         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
5673       }
5674       if (flip) {
5675         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
5676       }
5677     }
5678     offset += dof;
5679   }
5680   CHKERRQ(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips));
5681   *size = offset;
5682   PetscFunctionReturn(0);
5683 }
5684 
5685 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[])
5686 {
5687   PetscInt          offset = 0, f;
5688 
5689   PetscFunctionBeginHot;
5690   *size = 0;
5691   for (f = 0; f < numFields; ++f) {
5692     PetscInt          p;
5693     const PetscInt    **perms = NULL;
5694     const PetscScalar **flips = NULL;
5695 
5696     CHKERRQ(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips));
5697     for (p = 0; p < numPoints; p++) {
5698       const PetscInt    point = points[2*p];
5699       PetscInt          fdof, foff, b;
5700       const PetscScalar *varr;
5701       const PetscInt    *perm = perms ? perms[p] : NULL;
5702       const PetscScalar *flip = flips ? flips[p] : NULL;
5703 
5704       CHKERRQ(PetscSectionGetFieldDof(section, point, f, &fdof));
5705       CHKERRQ(PetscSectionGetFieldOffset(section, point, f, &foff));
5706       varr = &vArray[foff];
5707       if (clperm) {
5708         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
5709         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
5710         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
5711       } else {
5712         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
5713         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
5714         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
5715       }
5716       offset += fdof;
5717     }
5718     CHKERRQ(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips));
5719   }
5720   *size = offset;
5721   PetscFunctionReturn(0);
5722 }
5723 
5724 /*@C
5725   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
5726 
5727   Not collective
5728 
5729   Input Parameters:
5730 + dm - The DM
5731 . section - The section describing the layout in v, or NULL to use the default section
5732 . v - The local vector
5733 - point - The point in the DM
5734 
5735   Input/Output Parameters:
5736 + csize  - The size of the input values array, or NULL; on output the number of values in the closure
5737 - values - An array to use for the values, or NULL to have it allocated automatically;
5738            if the user provided NULL, it is a borrowed array and should not be freed
5739 
5740 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
5741 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
5742 $ assembly function, and a user may already have allocated storage for this operation.
5743 $
5744 $ A typical use could be
5745 $
5746 $  values = NULL;
5747 $  CHKERRQ(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
5748 $  for (cl = 0; cl < clSize; ++cl) {
5749 $    <Compute on closure>
5750 $  }
5751 $  CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values));
5752 $
5753 $ or
5754 $
5755 $  PetscMalloc1(clMaxSize, &values);
5756 $  for (p = pStart; p < pEnd; ++p) {
5757 $    clSize = clMaxSize;
5758 $    CHKERRQ(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
5759 $    for (cl = 0; cl < clSize; ++cl) {
5760 $      <Compute on closure>
5761 $    }
5762 $  }
5763 $  PetscFree(values);
5764 
5765   Fortran Notes:
5766   Since it returns an array, this routine is only available in Fortran 90, and you must
5767   include petsc.h90 in your code.
5768 
5769   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5770 
5771   Level: intermediate
5772 
5773 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5774 @*/
5775 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5776 {
5777   PetscSection       clSection;
5778   IS                 clPoints;
5779   PetscInt          *points = NULL;
5780   const PetscInt    *clp, *perm;
5781   PetscInt           depth, numFields, numPoints, asize;
5782 
5783   PetscFunctionBeginHot;
5784   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5785   if (!section) CHKERRQ(DMGetLocalSection(dm, &section));
5786   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5787   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5788   CHKERRQ(DMPlexGetDepth(dm, &depth));
5789   CHKERRQ(PetscSectionGetNumFields(section, &numFields));
5790   if (depth == 1 && numFields < 2) {
5791     CHKERRQ(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
5792     PetscFunctionReturn(0);
5793   }
5794   /* Get points */
5795   CHKERRQ(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
5796   /* Get sizes */
5797   asize = 0;
5798   for (PetscInt p = 0; p < numPoints*2; p += 2) {
5799     PetscInt dof;
5800     CHKERRQ(PetscSectionGetDof(section, points[p], &dof));
5801     asize += dof;
5802   }
5803   if (values) {
5804     const PetscScalar *vArray;
5805     PetscInt          size;
5806 
5807     if (*values) {
5808       PetscCheckFalse(*csize < asize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided array size %D not sufficient to hold closure size %D", *csize, asize);
5809     } else CHKERRQ(DMGetWorkArray(dm, asize, MPIU_SCALAR, values));
5810     CHKERRQ(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm));
5811     CHKERRQ(VecGetArrayRead(v, &vArray));
5812     /* Get values */
5813     if (numFields > 0) CHKERRQ(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values));
5814     else               CHKERRQ(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values));
5815     PetscCheckFalse(asize != size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %D does not match Vec closure size %D", asize, size);
5816     /* Cleanup array */
5817     CHKERRQ(VecRestoreArrayRead(v, &vArray));
5818   }
5819   if (csize) *csize = asize;
5820   /* Cleanup points */
5821   CHKERRQ(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
5822   PetscFunctionReturn(0);
5823 }
5824 
5825 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
5826 {
5827   DMLabel            depthLabel;
5828   PetscSection       clSection;
5829   IS                 clPoints;
5830   PetscScalar       *array;
5831   const PetscScalar *vArray;
5832   PetscInt          *points = NULL;
5833   const PetscInt    *clp, *perm = NULL;
5834   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;
5835 
5836   PetscFunctionBeginHot;
5837   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5838   if (!section) CHKERRQ(DMGetLocalSection(dm, &section));
5839   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5840   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5841   CHKERRQ(DMPlexGetDepth(dm, &mdepth));
5842   CHKERRQ(DMPlexGetDepthLabel(dm, &depthLabel));
5843   CHKERRQ(PetscSectionGetNumFields(section, &numFields));
5844   if (mdepth == 1 && numFields < 2) {
5845     CHKERRQ(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
5846     PetscFunctionReturn(0);
5847   }
5848   /* Get points */
5849   CHKERRQ(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
5850   for (clsize=0,p=0; p<Np; p++) {
5851     PetscInt dof;
5852     CHKERRQ(PetscSectionGetDof(section, points[2*p], &dof));
5853     clsize += dof;
5854   }
5855   CHKERRQ(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm));
5856   /* Filter points */
5857   for (p = 0; p < numPoints*2; p += 2) {
5858     PetscInt dep;
5859 
5860     CHKERRQ(DMLabelGetValue(depthLabel, points[p], &dep));
5861     if (dep != depth) continue;
5862     points[Np*2+0] = points[p];
5863     points[Np*2+1] = points[p+1];
5864     ++Np;
5865   }
5866   /* Get array */
5867   if (!values || !*values) {
5868     PetscInt asize = 0, dof;
5869 
5870     for (p = 0; p < Np*2; p += 2) {
5871       CHKERRQ(PetscSectionGetDof(section, points[p], &dof));
5872       asize += dof;
5873     }
5874     if (!values) {
5875       CHKERRQ(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
5876       if (csize) *csize = asize;
5877       PetscFunctionReturn(0);
5878     }
5879     CHKERRQ(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array));
5880   } else {
5881     array = *values;
5882   }
5883   CHKERRQ(VecGetArrayRead(v, &vArray));
5884   /* Get values */
5885   if (numFields > 0) CHKERRQ(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array));
5886   else               CHKERRQ(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array));
5887   /* Cleanup points */
5888   CHKERRQ(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
5889   /* Cleanup array */
5890   CHKERRQ(VecRestoreArrayRead(v, &vArray));
5891   if (!*values) {
5892     if (csize) *csize = size;
5893     *values = array;
5894   } else {
5895     PetscCheckFalse(size > *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
5896     *csize = size;
5897   }
5898   PetscFunctionReturn(0);
5899 }
5900 
5901 /*@C
5902   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
5903 
5904   Not collective
5905 
5906   Input Parameters:
5907 + dm - The DM
5908 . section - The section describing the layout in v, or NULL to use the default section
5909 . v - The local vector
5910 . point - The point in the DM
5911 . csize - The number of values in the closure, or NULL
5912 - values - The array of values, which is a borrowed array and should not be freed
5913 
5914   Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()
5915 
5916   Fortran Notes:
5917   Since it returns an array, this routine is only available in Fortran 90, and you must
5918   include petsc.h90 in your code.
5919 
5920   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5921 
5922   Level: intermediate
5923 
5924 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5925 @*/
5926 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5927 {
5928   PetscInt       size = 0;
5929 
5930   PetscFunctionBegin;
5931   /* Should work without recalculating size */
5932   CHKERRQ(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values));
5933   *values = NULL;
5934   PetscFunctionReturn(0);
5935 }
5936 
5937 static inline void add   (PetscScalar *x, PetscScalar y) {*x += y;}
5938 static inline void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
5939 
5940 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[])
5941 {
5942   PetscInt        cdof;   /* The number of constraints on this point */
5943   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5944   PetscScalar    *a;
5945   PetscInt        off, cind = 0, k;
5946 
5947   PetscFunctionBegin;
5948   CHKERRQ(PetscSectionGetConstraintDof(section, point, &cdof));
5949   CHKERRQ(PetscSectionGetOffset(section, point, &off));
5950   a    = &array[off];
5951   if (!cdof || setBC) {
5952     if (clperm) {
5953       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
5954       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
5955     } else {
5956       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
5957       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
5958     }
5959   } else {
5960     CHKERRQ(PetscSectionGetConstraintIndices(section, point, &cdofs));
5961     if (clperm) {
5962       if (perm) {for (k = 0; k < dof; ++k) {
5963           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5964           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
5965         }
5966       } else {
5967         for (k = 0; k < dof; ++k) {
5968           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5969           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
5970         }
5971       }
5972     } else {
5973       if (perm) {
5974         for (k = 0; k < dof; ++k) {
5975           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5976           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
5977         }
5978       } else {
5979         for (k = 0; k < dof; ++k) {
5980           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5981           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
5982         }
5983       }
5984     }
5985   }
5986   PetscFunctionReturn(0);
5987 }
5988 
5989 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[])
5990 {
5991   PetscInt        cdof;   /* The number of constraints on this point */
5992   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5993   PetscScalar    *a;
5994   PetscInt        off, cind = 0, k;
5995 
5996   PetscFunctionBegin;
5997   CHKERRQ(PetscSectionGetConstraintDof(section, point, &cdof));
5998   CHKERRQ(PetscSectionGetOffset(section, point, &off));
5999   a    = &array[off];
6000   if (cdof) {
6001     CHKERRQ(PetscSectionGetConstraintIndices(section, point, &cdofs));
6002     if (clperm) {
6003       if (perm) {
6004         for (k = 0; k < dof; ++k) {
6005           if ((cind < cdof) && (k == cdofs[cind])) {
6006             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
6007             cind++;
6008           }
6009         }
6010       } else {
6011         for (k = 0; k < dof; ++k) {
6012           if ((cind < cdof) && (k == cdofs[cind])) {
6013             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
6014             cind++;
6015           }
6016         }
6017       }
6018     } else {
6019       if (perm) {
6020         for (k = 0; k < dof; ++k) {
6021           if ((cind < cdof) && (k == cdofs[cind])) {
6022             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
6023             cind++;
6024           }
6025         }
6026       } else {
6027         for (k = 0; k < dof; ++k) {
6028           if ((cind < cdof) && (k == cdofs[cind])) {
6029             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
6030             cind++;
6031           }
6032         }
6033       }
6034     }
6035   }
6036   PetscFunctionReturn(0);
6037 }
6038 
6039 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[])
6040 {
6041   PetscScalar    *a;
6042   PetscInt        fdof, foff, fcdof, foffset = *offset;
6043   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6044   PetscInt        cind = 0, b;
6045 
6046   PetscFunctionBegin;
6047   CHKERRQ(PetscSectionGetFieldDof(section, point, f, &fdof));
6048   CHKERRQ(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
6049   CHKERRQ(PetscSectionGetFieldOffset(section, point, f, &foff));
6050   a    = &array[foff];
6051   if (!fcdof || setBC) {
6052     if (clperm) {
6053       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
6054       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
6055     } else {
6056       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
6057       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
6058     }
6059   } else {
6060     CHKERRQ(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
6061     if (clperm) {
6062       if (perm) {
6063         for (b = 0; b < fdof; b++) {
6064           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6065           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
6066         }
6067       } else {
6068         for (b = 0; b < fdof; b++) {
6069           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6070           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
6071         }
6072       }
6073     } else {
6074       if (perm) {
6075         for (b = 0; b < fdof; b++) {
6076           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6077           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
6078         }
6079       } else {
6080         for (b = 0; b < fdof; b++) {
6081           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6082           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
6083         }
6084       }
6085     }
6086   }
6087   *offset += fdof;
6088   PetscFunctionReturn(0);
6089 }
6090 
6091 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[])
6092 {
6093   PetscScalar    *a;
6094   PetscInt        fdof, foff, fcdof, foffset = *offset;
6095   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6096   PetscInt        Nc, cind = 0, ncind = 0, b;
6097   PetscBool       ncSet, fcSet;
6098 
6099   PetscFunctionBegin;
6100   CHKERRQ(PetscSectionGetFieldComponents(section, f, &Nc));
6101   CHKERRQ(PetscSectionGetFieldDof(section, point, f, &fdof));
6102   CHKERRQ(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
6103   CHKERRQ(PetscSectionGetFieldOffset(section, point, f, &foff));
6104   a    = &array[foff];
6105   if (fcdof) {
6106     /* We just override fcdof and fcdofs with Ncc and comps */
6107     CHKERRQ(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
6108     if (clperm) {
6109       if (perm) {
6110         if (comps) {
6111           for (b = 0; b < fdof; b++) {
6112             ncSet = fcSet = PETSC_FALSE;
6113             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6114             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6115             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
6116           }
6117         } else {
6118           for (b = 0; b < fdof; b++) {
6119             if ((cind < fcdof) && (b == fcdofs[cind])) {
6120               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
6121               ++cind;
6122             }
6123           }
6124         }
6125       } else {
6126         if (comps) {
6127           for (b = 0; b < fdof; b++) {
6128             ncSet = fcSet = PETSC_FALSE;
6129             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6130             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6131             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
6132           }
6133         } else {
6134           for (b = 0; b < fdof; b++) {
6135             if ((cind < fcdof) && (b == fcdofs[cind])) {
6136               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
6137               ++cind;
6138             }
6139           }
6140         }
6141       }
6142     } else {
6143       if (perm) {
6144         if (comps) {
6145           for (b = 0; b < fdof; b++) {
6146             ncSet = fcSet = PETSC_FALSE;
6147             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6148             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6149             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
6150           }
6151         } else {
6152           for (b = 0; b < fdof; b++) {
6153             if ((cind < fcdof) && (b == fcdofs[cind])) {
6154               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
6155               ++cind;
6156             }
6157           }
6158         }
6159       } else {
6160         if (comps) {
6161           for (b = 0; b < fdof; b++) {
6162             ncSet = fcSet = PETSC_FALSE;
6163             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6164             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6165             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
6166           }
6167         } else {
6168           for (b = 0; b < fdof; b++) {
6169             if ((cind < fcdof) && (b == fcdofs[cind])) {
6170               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
6171               ++cind;
6172             }
6173           }
6174         }
6175       }
6176     }
6177   }
6178   *offset += fdof;
6179   PetscFunctionReturn(0);
6180 }
6181 
6182 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6183 {
6184   PetscScalar    *array;
6185   const PetscInt *cone, *coneO;
6186   PetscInt        pStart, pEnd, p, numPoints, off, dof;
6187 
6188   PetscFunctionBeginHot;
6189   CHKERRQ(PetscSectionGetChart(section, &pStart, &pEnd));
6190   CHKERRQ(DMPlexGetConeSize(dm, point, &numPoints));
6191   CHKERRQ(DMPlexGetCone(dm, point, &cone));
6192   CHKERRQ(DMPlexGetConeOrientation(dm, point, &coneO));
6193   CHKERRQ(VecGetArray(v, &array));
6194   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
6195     const PetscInt cp = !p ? point : cone[p-1];
6196     const PetscInt o  = !p ? 0     : coneO[p-1];
6197 
6198     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
6199     CHKERRQ(PetscSectionGetDof(section, cp, &dof));
6200     /* ADD_VALUES */
6201     {
6202       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6203       PetscScalar    *a;
6204       PetscInt        cdof, coff, cind = 0, k;
6205 
6206       CHKERRQ(PetscSectionGetConstraintDof(section, cp, &cdof));
6207       CHKERRQ(PetscSectionGetOffset(section, cp, &coff));
6208       a    = &array[coff];
6209       if (!cdof) {
6210         if (o >= 0) {
6211           for (k = 0; k < dof; ++k) {
6212             a[k] += values[off+k];
6213           }
6214         } else {
6215           for (k = 0; k < dof; ++k) {
6216             a[k] += values[off+dof-k-1];
6217           }
6218         }
6219       } else {
6220         CHKERRQ(PetscSectionGetConstraintIndices(section, cp, &cdofs));
6221         if (o >= 0) {
6222           for (k = 0; k < dof; ++k) {
6223             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6224             a[k] += values[off+k];
6225           }
6226         } else {
6227           for (k = 0; k < dof; ++k) {
6228             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6229             a[k] += values[off+dof-k-1];
6230           }
6231         }
6232       }
6233     }
6234   }
6235   CHKERRQ(VecRestoreArray(v, &array));
6236   PetscFunctionReturn(0);
6237 }
6238 
6239 /*@C
6240   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
6241 
6242   Not collective
6243 
6244   Input Parameters:
6245 + dm - The DM
6246 . section - The section describing the layout in v, or NULL to use the default section
6247 . v - The local vector
6248 . point - The point in the DM
6249 . values - The array of values
6250 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
6251          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
6252 
6253   Fortran Notes:
6254   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
6255 
6256   Level: intermediate
6257 
6258 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
6259 @*/
6260 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6261 {
6262   PetscSection    clSection;
6263   IS              clPoints;
6264   PetscScalar    *array;
6265   PetscInt       *points = NULL;
6266   const PetscInt *clp, *clperm = NULL;
6267   PetscInt        depth, numFields, numPoints, p, clsize;
6268 
6269   PetscFunctionBeginHot;
6270   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6271   if (!section) CHKERRQ(DMGetLocalSection(dm, &section));
6272   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6273   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6274   CHKERRQ(DMPlexGetDepth(dm, &depth));
6275   CHKERRQ(PetscSectionGetNumFields(section, &numFields));
6276   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
6277     CHKERRQ(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode));
6278     PetscFunctionReturn(0);
6279   }
6280   /* Get points */
6281   CHKERRQ(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
6282   for (clsize=0,p=0; p<numPoints; p++) {
6283     PetscInt dof;
6284     CHKERRQ(PetscSectionGetDof(section, points[2*p], &dof));
6285     clsize += dof;
6286   }
6287   CHKERRQ(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm));
6288   /* Get array */
6289   CHKERRQ(VecGetArray(v, &array));
6290   /* Get values */
6291   if (numFields > 0) {
6292     PetscInt offset = 0, f;
6293     for (f = 0; f < numFields; ++f) {
6294       const PetscInt    **perms = NULL;
6295       const PetscScalar **flips = NULL;
6296 
6297       CHKERRQ(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips));
6298       switch (mode) {
6299       case INSERT_VALUES:
6300         for (p = 0; p < numPoints; p++) {
6301           const PetscInt    point = points[2*p];
6302           const PetscInt    *perm = perms ? perms[p] : NULL;
6303           const PetscScalar *flip = flips ? flips[p] : NULL;
6304           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
6305         } break;
6306       case INSERT_ALL_VALUES:
6307         for (p = 0; p < numPoints; p++) {
6308           const PetscInt    point = points[2*p];
6309           const PetscInt    *perm = perms ? perms[p] : NULL;
6310           const PetscScalar *flip = flips ? flips[p] : NULL;
6311           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
6312         } break;
6313       case INSERT_BC_VALUES:
6314         for (p = 0; p < numPoints; p++) {
6315           const PetscInt    point = points[2*p];
6316           const PetscInt    *perm = perms ? perms[p] : NULL;
6317           const PetscScalar *flip = flips ? flips[p] : NULL;
6318           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
6319         } break;
6320       case ADD_VALUES:
6321         for (p = 0; p < numPoints; p++) {
6322           const PetscInt    point = points[2*p];
6323           const PetscInt    *perm = perms ? perms[p] : NULL;
6324           const PetscScalar *flip = flips ? flips[p] : NULL;
6325           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
6326         } break;
6327       case ADD_ALL_VALUES:
6328         for (p = 0; p < numPoints; p++) {
6329           const PetscInt    point = points[2*p];
6330           const PetscInt    *perm = perms ? perms[p] : NULL;
6331           const PetscScalar *flip = flips ? flips[p] : NULL;
6332           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
6333         } break;
6334       case ADD_BC_VALUES:
6335         for (p = 0; p < numPoints; p++) {
6336           const PetscInt    point = points[2*p];
6337           const PetscInt    *perm = perms ? perms[p] : NULL;
6338           const PetscScalar *flip = flips ? flips[p] : NULL;
6339           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
6340         } break;
6341       default:
6342         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6343       }
6344       CHKERRQ(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips));
6345     }
6346   } else {
6347     PetscInt dof, off;
6348     const PetscInt    **perms = NULL;
6349     const PetscScalar **flips = NULL;
6350 
6351     CHKERRQ(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips));
6352     switch (mode) {
6353     case INSERT_VALUES:
6354       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6355         const PetscInt    point = points[2*p];
6356         const PetscInt    *perm = perms ? perms[p] : NULL;
6357         const PetscScalar *flip = flips ? flips[p] : NULL;
6358         CHKERRQ(PetscSectionGetDof(section, point, &dof));
6359         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
6360       } break;
6361     case INSERT_ALL_VALUES:
6362       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6363         const PetscInt    point = points[2*p];
6364         const PetscInt    *perm = perms ? perms[p] : NULL;
6365         const PetscScalar *flip = flips ? flips[p] : NULL;
6366         CHKERRQ(PetscSectionGetDof(section, point, &dof));
6367         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
6368       } break;
6369     case INSERT_BC_VALUES:
6370       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6371         const PetscInt    point = points[2*p];
6372         const PetscInt    *perm = perms ? perms[p] : NULL;
6373         const PetscScalar *flip = flips ? flips[p] : NULL;
6374         CHKERRQ(PetscSectionGetDof(section, point, &dof));
6375         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
6376       } break;
6377     case ADD_VALUES:
6378       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6379         const PetscInt    point = points[2*p];
6380         const PetscInt    *perm = perms ? perms[p] : NULL;
6381         const PetscScalar *flip = flips ? flips[p] : NULL;
6382         CHKERRQ(PetscSectionGetDof(section, point, &dof));
6383         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
6384       } break;
6385     case ADD_ALL_VALUES:
6386       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6387         const PetscInt    point = points[2*p];
6388         const PetscInt    *perm = perms ? perms[p] : NULL;
6389         const PetscScalar *flip = flips ? flips[p] : NULL;
6390         CHKERRQ(PetscSectionGetDof(section, point, &dof));
6391         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
6392       } break;
6393     case ADD_BC_VALUES:
6394       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6395         const PetscInt    point = points[2*p];
6396         const PetscInt    *perm = perms ? perms[p] : NULL;
6397         const PetscScalar *flip = flips ? flips[p] : NULL;
6398         CHKERRQ(PetscSectionGetDof(section, point, &dof));
6399         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
6400       } break;
6401     default:
6402       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6403     }
6404     CHKERRQ(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips));
6405   }
6406   /* Cleanup points */
6407   CHKERRQ(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
6408   /* Cleanup array */
6409   CHKERRQ(VecRestoreArray(v, &array));
6410   PetscFunctionReturn(0);
6411 }
6412 
6413 /* Check whether the given point is in the label. If not, update the offset to skip this point */
6414 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset)
6415 {
6416   PetscFunctionBegin;
6417   if (label) {
6418     PetscInt       val, fdof;
6419 
6420     /* There is a problem with this:
6421          Suppose we have two label values, defining surfaces, interecting along a line in 3D. When we add cells to the label, the cells that
6422        touch both surfaces must pick a label value. Thus we miss setting values for the surface with that other value intersecting that cell.
6423        Thus I am only going to check val != -1, not val != labelId
6424     */
6425     CHKERRQ(DMLabelGetValue(label, point, &val));
6426     if (val < 0) {
6427       CHKERRQ(PetscSectionGetFieldDof(section, point, f, &fdof));
6428       *offset += fdof;
6429       PetscFunctionReturn(1);
6430     }
6431   }
6432   PetscFunctionReturn(0);
6433 }
6434 
6435 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
6436 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)
6437 {
6438   PetscSection    clSection;
6439   IS              clPoints;
6440   PetscScalar    *array;
6441   PetscInt       *points = NULL;
6442   const PetscInt *clp;
6443   PetscInt        numFields, numPoints, p;
6444   PetscInt        offset = 0, f;
6445 
6446   PetscFunctionBeginHot;
6447   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6448   if (!section) CHKERRQ(DMGetLocalSection(dm, &section));
6449   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6450   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6451   CHKERRQ(PetscSectionGetNumFields(section, &numFields));
6452   /* Get points */
6453   CHKERRQ(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
6454   /* Get array */
6455   CHKERRQ(VecGetArray(v, &array));
6456   /* Get values */
6457   for (f = 0; f < numFields; ++f) {
6458     const PetscInt    **perms = NULL;
6459     const PetscScalar **flips = NULL;
6460 
6461     if (!fieldActive[f]) {
6462       for (p = 0; p < numPoints*2; p += 2) {
6463         PetscInt fdof;
6464         CHKERRQ(PetscSectionGetFieldDof(section, points[p], f, &fdof));
6465         offset += fdof;
6466       }
6467       continue;
6468     }
6469     CHKERRQ(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips));
6470     switch (mode) {
6471     case INSERT_VALUES:
6472       for (p = 0; p < numPoints; p++) {
6473         const PetscInt    point = points[2*p];
6474         const PetscInt    *perm = perms ? perms[p] : NULL;
6475         const PetscScalar *flip = flips ? flips[p] : NULL;
6476         if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue;
6477         CHKERRQ(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array));
6478       } break;
6479     case INSERT_ALL_VALUES:
6480       for (p = 0; p < numPoints; p++) {
6481         const PetscInt    point = points[2*p];
6482         const PetscInt    *perm = perms ? perms[p] : NULL;
6483         const PetscScalar *flip = flips ? flips[p] : NULL;
6484         if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue;
6485         CHKERRQ(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array));
6486       } break;
6487     case INSERT_BC_VALUES:
6488       for (p = 0; p < numPoints; p++) {
6489         const PetscInt    point = points[2*p];
6490         const PetscInt    *perm = perms ? perms[p] : NULL;
6491         const PetscScalar *flip = flips ? flips[p] : NULL;
6492         if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue;
6493         CHKERRQ(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array));
6494       } break;
6495     case ADD_VALUES:
6496       for (p = 0; p < numPoints; p++) {
6497         const PetscInt    point = points[2*p];
6498         const PetscInt    *perm = perms ? perms[p] : NULL;
6499         const PetscScalar *flip = flips ? flips[p] : NULL;
6500         if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue;
6501         CHKERRQ(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array));
6502       } break;
6503     case ADD_ALL_VALUES:
6504       for (p = 0; p < numPoints; p++) {
6505         const PetscInt    point = points[2*p];
6506         const PetscInt    *perm = perms ? perms[p] : NULL;
6507         const PetscScalar *flip = flips ? flips[p] : NULL;
6508         if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue;
6509         CHKERRQ(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array));
6510       } break;
6511     default:
6512       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6513     }
6514     CHKERRQ(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips));
6515   }
6516   /* Cleanup points */
6517   CHKERRQ(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
6518   /* Cleanup array */
6519   CHKERRQ(VecRestoreArray(v, &array));
6520   PetscFunctionReturn(0);
6521 }
6522 
6523 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
6524 {
6525   PetscMPIInt    rank;
6526   PetscInt       i, j;
6527 
6528   PetscFunctionBegin;
6529   CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
6530   CHKERRQ(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point));
6531   for (i = 0; i < numRIndices; i++) CHKERRQ(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]));
6532   for (i = 0; i < numCIndices; i++) CHKERRQ(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]));
6533   numCIndices = numCIndices ? numCIndices : numRIndices;
6534   if (!values) PetscFunctionReturn(0);
6535   for (i = 0; i < numRIndices; i++) {
6536     CHKERRQ(PetscViewerASCIIPrintf(viewer, "[%d]", rank));
6537     for (j = 0; j < numCIndices; j++) {
6538 #if defined(PETSC_USE_COMPLEX)
6539       CHKERRQ(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j])));
6540 #else
6541       CHKERRQ(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]));
6542 #endif
6543     }
6544     CHKERRQ(PetscViewerASCIIPrintf(viewer, "\n"));
6545   }
6546   PetscFunctionReturn(0);
6547 }
6548 
6549 /*
6550   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
6551 
6552   Input Parameters:
6553 + section - The section for this data layout
6554 . islocal - Is the section (and thus indices being requested) local or global?
6555 . point   - The point contributing dofs with these indices
6556 . off     - The global offset of this point
6557 . loff    - The local offset of each field
6558 . setBC   - The flag determining whether to include indices of boundary values
6559 . perm    - A permutation of the dofs on this point, or NULL
6560 - indperm - A permutation of the entire indices array, or NULL
6561 
6562   Output Parameter:
6563 . indices - Indices for dofs on this point
6564 
6565   Level: developer
6566 
6567   Note: The indices could be local or global, depending on the value of 'off'.
6568 */
6569 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
6570 {
6571   PetscInt        dof;   /* The number of unknowns on this point */
6572   PetscInt        cdof;  /* The number of constraints on this point */
6573   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6574   PetscInt        cind = 0, k;
6575 
6576   PetscFunctionBegin;
6577   PetscCheckFalse(!islocal && setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC");
6578   CHKERRQ(PetscSectionGetDof(section, point, &dof));
6579   CHKERRQ(PetscSectionGetConstraintDof(section, point, &cdof));
6580   if (!cdof || setBC) {
6581     for (k = 0; k < dof; ++k) {
6582       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
6583       const PetscInt ind    = indperm ? indperm[preind] : preind;
6584 
6585       indices[ind] = off + k;
6586     }
6587   } else {
6588     CHKERRQ(PetscSectionGetConstraintIndices(section, point, &cdofs));
6589     for (k = 0; k < dof; ++k) {
6590       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
6591       const PetscInt ind    = indperm ? indperm[preind] : preind;
6592 
6593       if ((cind < cdof) && (k == cdofs[cind])) {
6594         /* Insert check for returning constrained indices */
6595         indices[ind] = -(off+k+1);
6596         ++cind;
6597       } else {
6598         indices[ind] = off + k - (islocal ? 0 : cind);
6599       }
6600     }
6601   }
6602   *loff += dof;
6603   PetscFunctionReturn(0);
6604 }
6605 
6606 /*
6607  DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.
6608 
6609  Input Parameters:
6610 + section - a section (global or local)
6611 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global
6612 . point - point within section
6613 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
6614 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
6615 . setBC - identify constrained (boundary condition) points via involution.
6616 . perms - perms[f][permsoff][:] is a permutation of dofs within each field
6617 . permsoff - offset
6618 - indperm - index permutation
6619 
6620  Output Parameter:
6621 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
6622 . indices - array to hold indices (as defined by section) of each dof associated with point
6623 
6624  Notes:
6625  If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
6626  If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
6627  in the local vector.
6628 
6629  If section is global and setBC=false, the indices for constrained points are negative (and their value is not
6630  significant).  It is invalid to call with a global section and setBC=true.
6631 
6632  Developer Note:
6633  The section is only used for field layout, so islocal is technically a statement about the offset (off).  At some point
6634  in the future, global sections may have fields set, in which case we could pass the global section and obtain the
6635  offset could be obtained from the section instead of passing it explicitly as we do now.
6636 
6637  Example:
6638  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
6639  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
6640  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
6641  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.
6642 
6643  Level: developer
6644 */
6645 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[])
6646 {
6647   PetscInt       numFields, foff, f;
6648 
6649   PetscFunctionBegin;
6650   PetscCheckFalse(!islocal && setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC");
6651   CHKERRQ(PetscSectionGetNumFields(section, &numFields));
6652   for (f = 0, foff = 0; f < numFields; ++f) {
6653     PetscInt        fdof, cfdof;
6654     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6655     PetscInt        cind = 0, b;
6656     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
6657 
6658     CHKERRQ(PetscSectionGetFieldDof(section, point, f, &fdof));
6659     CHKERRQ(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
6660     if (!cfdof || setBC) {
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         indices[ind] = off+foff+b;
6666       }
6667     } else {
6668       CHKERRQ(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
6669       for (b = 0; b < fdof; ++b) {
6670         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6671         const PetscInt ind    = indperm ? indperm[preind] : preind;
6672 
6673         if ((cind < cfdof) && (b == fcdofs[cind])) {
6674           indices[ind] = -(off+foff+b+1);
6675           ++cind;
6676         } else {
6677           indices[ind] = off + foff + b - (islocal ? 0 : cind);
6678         }
6679       }
6680     }
6681     foff     += (setBC || islocal ? fdof : (fdof - cfdof));
6682     foffs[f] += fdof;
6683   }
6684   PetscFunctionReturn(0);
6685 }
6686 
6687 /*
6688   This version believes the globalSection offsets for each field, rather than just the point offset
6689 
6690  . foffs - The offset into 'indices' for each field, since it is segregated by field
6691 
6692  Notes:
6693  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
6694  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
6695 */
6696 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
6697 {
6698   PetscInt       numFields, foff, f;
6699 
6700   PetscFunctionBegin;
6701   CHKERRQ(PetscSectionGetNumFields(section, &numFields));
6702   for (f = 0; f < numFields; ++f) {
6703     PetscInt        fdof, cfdof;
6704     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6705     PetscInt        cind = 0, b;
6706     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
6707 
6708     CHKERRQ(PetscSectionGetFieldDof(section, point, f, &fdof));
6709     CHKERRQ(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
6710     CHKERRQ(PetscSectionGetFieldOffset(globalSection, point, f, &foff));
6711     if (!cfdof) {
6712       for (b = 0; b < fdof; ++b) {
6713         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6714         const PetscInt ind    = indperm ? indperm[preind] : preind;
6715 
6716         indices[ind] = foff+b;
6717       }
6718     } else {
6719       CHKERRQ(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
6720       for (b = 0; b < fdof; ++b) {
6721         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6722         const PetscInt ind    = indperm ? indperm[preind] : preind;
6723 
6724         if ((cind < cfdof) && (b == fcdofs[cind])) {
6725           indices[ind] = -(foff+b+1);
6726           ++cind;
6727         } else {
6728           indices[ind] = foff+b-cind;
6729         }
6730       }
6731     }
6732     foffs[f] += fdof;
6733   }
6734   PetscFunctionReturn(0);
6735 }
6736 
6737 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)
6738 {
6739   Mat             cMat;
6740   PetscSection    aSec, cSec;
6741   IS              aIS;
6742   PetscInt        aStart = -1, aEnd = -1;
6743   const PetscInt  *anchors;
6744   PetscInt        numFields, f, p, q, newP = 0;
6745   PetscInt        newNumPoints = 0, newNumIndices = 0;
6746   PetscInt        *newPoints, *indices, *newIndices;
6747   PetscInt        maxAnchor, maxDof;
6748   PetscInt        newOffsets[32];
6749   PetscInt        *pointMatOffsets[32];
6750   PetscInt        *newPointOffsets[32];
6751   PetscScalar     *pointMat[32];
6752   PetscScalar     *newValues=NULL,*tmpValues;
6753   PetscBool       anyConstrained = PETSC_FALSE;
6754 
6755   PetscFunctionBegin;
6756   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6757   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6758   CHKERRQ(PetscSectionGetNumFields(section, &numFields));
6759 
6760   CHKERRQ(DMPlexGetAnchors(dm,&aSec,&aIS));
6761   /* if there are point-to-point constraints */
6762   if (aSec) {
6763     CHKERRQ(PetscArrayzero(newOffsets, 32));
6764     CHKERRQ(ISGetIndices(aIS,&anchors));
6765     CHKERRQ(PetscSectionGetChart(aSec,&aStart,&aEnd));
6766     /* figure out how many points are going to be in the new element matrix
6767      * (we allow double counting, because it's all just going to be summed
6768      * into the global matrix anyway) */
6769     for (p = 0; p < 2*numPoints; p+=2) {
6770       PetscInt b    = points[p];
6771       PetscInt bDof = 0, bSecDof;
6772 
6773       CHKERRQ(PetscSectionGetDof(section,b,&bSecDof));
6774       if (!bSecDof) {
6775         continue;
6776       }
6777       if (b >= aStart && b < aEnd) {
6778         CHKERRQ(PetscSectionGetDof(aSec,b,&bDof));
6779       }
6780       if (bDof) {
6781         /* this point is constrained */
6782         /* it is going to be replaced by its anchors */
6783         PetscInt bOff, q;
6784 
6785         anyConstrained = PETSC_TRUE;
6786         newNumPoints  += bDof;
6787         CHKERRQ(PetscSectionGetOffset(aSec,b,&bOff));
6788         for (q = 0; q < bDof; q++) {
6789           PetscInt a = anchors[bOff + q];
6790           PetscInt aDof;
6791 
6792           CHKERRQ(PetscSectionGetDof(section,a,&aDof));
6793           newNumIndices += aDof;
6794           for (f = 0; f < numFields; ++f) {
6795             PetscInt fDof;
6796 
6797             CHKERRQ(PetscSectionGetFieldDof(section, a, f, &fDof));
6798             newOffsets[f+1] += fDof;
6799           }
6800         }
6801       }
6802       else {
6803         /* this point is not constrained */
6804         newNumPoints++;
6805         newNumIndices += bSecDof;
6806         for (f = 0; f < numFields; ++f) {
6807           PetscInt fDof;
6808 
6809           CHKERRQ(PetscSectionGetFieldDof(section, b, f, &fDof));
6810           newOffsets[f+1] += fDof;
6811         }
6812       }
6813     }
6814   }
6815   if (!anyConstrained) {
6816     if (outNumPoints)  *outNumPoints  = 0;
6817     if (outNumIndices) *outNumIndices = 0;
6818     if (outPoints)     *outPoints     = NULL;
6819     if (outValues)     *outValues     = NULL;
6820     if (aSec) CHKERRQ(ISRestoreIndices(aIS,&anchors));
6821     PetscFunctionReturn(0);
6822   }
6823 
6824   if (outNumPoints)  *outNumPoints  = newNumPoints;
6825   if (outNumIndices) *outNumIndices = newNumIndices;
6826 
6827   for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
6828 
6829   if (!outPoints && !outValues) {
6830     if (offsets) {
6831       for (f = 0; f <= numFields; f++) {
6832         offsets[f] = newOffsets[f];
6833       }
6834     }
6835     if (aSec) CHKERRQ(ISRestoreIndices(aIS,&anchors));
6836     PetscFunctionReturn(0);
6837   }
6838 
6839   PetscCheckFalse(numFields && newOffsets[numFields] != newNumIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
6840 
6841   CHKERRQ(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
6842 
6843   /* workspaces */
6844   if (numFields) {
6845     for (f = 0; f < numFields; f++) {
6846       CHKERRQ(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]));
6847       CHKERRQ(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]));
6848     }
6849   }
6850   else {
6851     CHKERRQ(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]));
6852     CHKERRQ(DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]));
6853   }
6854 
6855   /* get workspaces for the point-to-point matrices */
6856   if (numFields) {
6857     PetscInt totalOffset, totalMatOffset;
6858 
6859     for (p = 0; p < numPoints; p++) {
6860       PetscInt b    = points[2*p];
6861       PetscInt bDof = 0, bSecDof;
6862 
6863       CHKERRQ(PetscSectionGetDof(section,b,&bSecDof));
6864       if (!bSecDof) {
6865         for (f = 0; f < numFields; f++) {
6866           newPointOffsets[f][p + 1] = 0;
6867           pointMatOffsets[f][p + 1] = 0;
6868         }
6869         continue;
6870       }
6871       if (b >= aStart && b < aEnd) {
6872         CHKERRQ(PetscSectionGetDof(aSec, b, &bDof));
6873       }
6874       if (bDof) {
6875         for (f = 0; f < numFields; f++) {
6876           PetscInt fDof, q, bOff, allFDof = 0;
6877 
6878           CHKERRQ(PetscSectionGetFieldDof(section, b, f, &fDof));
6879           CHKERRQ(PetscSectionGetOffset(aSec, b, &bOff));
6880           for (q = 0; q < bDof; q++) {
6881             PetscInt a = anchors[bOff + q];
6882             PetscInt aFDof;
6883 
6884             CHKERRQ(PetscSectionGetFieldDof(section, a, f, &aFDof));
6885             allFDof += aFDof;
6886           }
6887           newPointOffsets[f][p+1] = allFDof;
6888           pointMatOffsets[f][p+1] = fDof * allFDof;
6889         }
6890       }
6891       else {
6892         for (f = 0; f < numFields; f++) {
6893           PetscInt fDof;
6894 
6895           CHKERRQ(PetscSectionGetFieldDof(section, b, f, &fDof));
6896           newPointOffsets[f][p+1] = fDof;
6897           pointMatOffsets[f][p+1] = 0;
6898         }
6899       }
6900     }
6901     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
6902       newPointOffsets[f][0] = totalOffset;
6903       pointMatOffsets[f][0] = totalMatOffset;
6904       for (p = 0; p < numPoints; p++) {
6905         newPointOffsets[f][p+1] += newPointOffsets[f][p];
6906         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
6907       }
6908       totalOffset    = newPointOffsets[f][numPoints];
6909       totalMatOffset = pointMatOffsets[f][numPoints];
6910       CHKERRQ(DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]));
6911     }
6912   }
6913   else {
6914     for (p = 0; p < numPoints; p++) {
6915       PetscInt b    = points[2*p];
6916       PetscInt bDof = 0, bSecDof;
6917 
6918       CHKERRQ(PetscSectionGetDof(section,b,&bSecDof));
6919       if (!bSecDof) {
6920         newPointOffsets[0][p + 1] = 0;
6921         pointMatOffsets[0][p + 1] = 0;
6922         continue;
6923       }
6924       if (b >= aStart && b < aEnd) {
6925         CHKERRQ(PetscSectionGetDof(aSec, b, &bDof));
6926       }
6927       if (bDof) {
6928         PetscInt bOff, q, allDof = 0;
6929 
6930         CHKERRQ(PetscSectionGetOffset(aSec, b, &bOff));
6931         for (q = 0; q < bDof; q++) {
6932           PetscInt a = anchors[bOff + q], aDof;
6933 
6934           CHKERRQ(PetscSectionGetDof(section, a, &aDof));
6935           allDof += aDof;
6936         }
6937         newPointOffsets[0][p+1] = allDof;
6938         pointMatOffsets[0][p+1] = bSecDof * allDof;
6939       }
6940       else {
6941         newPointOffsets[0][p+1] = bSecDof;
6942         pointMatOffsets[0][p+1] = 0;
6943       }
6944     }
6945     newPointOffsets[0][0] = 0;
6946     pointMatOffsets[0][0] = 0;
6947     for (p = 0; p < numPoints; p++) {
6948       newPointOffsets[0][p+1] += newPointOffsets[0][p];
6949       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
6950     }
6951     CHKERRQ(DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]));
6952   }
6953 
6954   /* output arrays */
6955   CHKERRQ(DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints));
6956 
6957   /* get the point-to-point matrices; construct newPoints */
6958   CHKERRQ(PetscSectionGetMaxDof(aSec, &maxAnchor));
6959   CHKERRQ(PetscSectionGetMaxDof(section, &maxDof));
6960   CHKERRQ(DMGetWorkArray(dm,maxDof,MPIU_INT,&indices));
6961   CHKERRQ(DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices));
6962   if (numFields) {
6963     for (p = 0, newP = 0; p < numPoints; p++) {
6964       PetscInt b    = points[2*p];
6965       PetscInt o    = points[2*p+1];
6966       PetscInt bDof = 0, bSecDof;
6967 
6968       CHKERRQ(PetscSectionGetDof(section, b, &bSecDof));
6969       if (!bSecDof) {
6970         continue;
6971       }
6972       if (b >= aStart && b < aEnd) {
6973         CHKERRQ(PetscSectionGetDof(aSec, b, &bDof));
6974       }
6975       if (bDof) {
6976         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
6977 
6978         fStart[0] = 0;
6979         fEnd[0]   = 0;
6980         for (f = 0; f < numFields; f++) {
6981           PetscInt fDof;
6982 
6983           CHKERRQ(PetscSectionGetFieldDof(cSec, b, f, &fDof));
6984           fStart[f+1] = fStart[f] + fDof;
6985           fEnd[f+1]   = fStart[f+1];
6986         }
6987         CHKERRQ(PetscSectionGetOffset(cSec, b, &bOff));
6988         CHKERRQ(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices));
6989 
6990         fAnchorStart[0] = 0;
6991         fAnchorEnd[0]   = 0;
6992         for (f = 0; f < numFields; f++) {
6993           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
6994 
6995           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
6996           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
6997         }
6998         CHKERRQ(PetscSectionGetOffset(aSec, b, &bOff));
6999         for (q = 0; q < bDof; q++) {
7000           PetscInt a = anchors[bOff + q], aOff;
7001 
7002           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
7003           newPoints[2*(newP + q)]     = a;
7004           newPoints[2*(newP + q) + 1] = 0;
7005           CHKERRQ(PetscSectionGetOffset(section, a, &aOff));
7006           CHKERRQ(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices));
7007         }
7008         newP += bDof;
7009 
7010         if (outValues) {
7011           /* get the point-to-point submatrix */
7012           for (f = 0; f < numFields; f++) {
7013             CHKERRQ(MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]));
7014           }
7015         }
7016       }
7017       else {
7018         newPoints[2 * newP]     = b;
7019         newPoints[2 * newP + 1] = o;
7020         newP++;
7021       }
7022     }
7023   } else {
7024     for (p = 0; p < numPoints; p++) {
7025       PetscInt b    = points[2*p];
7026       PetscInt o    = points[2*p+1];
7027       PetscInt bDof = 0, bSecDof;
7028 
7029       CHKERRQ(PetscSectionGetDof(section, b, &bSecDof));
7030       if (!bSecDof) {
7031         continue;
7032       }
7033       if (b >= aStart && b < aEnd) {
7034         CHKERRQ(PetscSectionGetDof(aSec, b, &bDof));
7035       }
7036       if (bDof) {
7037         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
7038 
7039         CHKERRQ(PetscSectionGetOffset(cSec, b, &bOff));
7040         CHKERRQ(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices));
7041 
7042         CHKERRQ(PetscSectionGetOffset (aSec, b, &bOff));
7043         for (q = 0; q < bDof; q++) {
7044           PetscInt a = anchors[bOff + q], aOff;
7045 
7046           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
7047 
7048           newPoints[2*(newP + q)]     = a;
7049           newPoints[2*(newP + q) + 1] = 0;
7050           CHKERRQ(PetscSectionGetOffset(section, a, &aOff));
7051           CHKERRQ(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices));
7052         }
7053         newP += bDof;
7054 
7055         /* get the point-to-point submatrix */
7056         if (outValues) {
7057           CHKERRQ(MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]));
7058         }
7059       }
7060       else {
7061         newPoints[2 * newP]     = b;
7062         newPoints[2 * newP + 1] = o;
7063         newP++;
7064       }
7065     }
7066   }
7067 
7068   if (outValues) {
7069     CHKERRQ(DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues));
7070     CHKERRQ(PetscArrayzero(tmpValues,newNumIndices*numIndices));
7071     /* multiply constraints on the right */
7072     if (numFields) {
7073       for (f = 0; f < numFields; f++) {
7074         PetscInt oldOff = offsets[f];
7075 
7076         for (p = 0; p < numPoints; p++) {
7077           PetscInt cStart = newPointOffsets[f][p];
7078           PetscInt b      = points[2 * p];
7079           PetscInt c, r, k;
7080           PetscInt dof;
7081 
7082           CHKERRQ(PetscSectionGetFieldDof(section,b,f,&dof));
7083           if (!dof) {
7084             continue;
7085           }
7086           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7087             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
7088             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
7089 
7090             for (r = 0; r < numIndices; r++) {
7091               for (c = 0; c < nCols; c++) {
7092                 for (k = 0; k < dof; k++) {
7093                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
7094                 }
7095               }
7096             }
7097           }
7098           else {
7099             /* copy this column as is */
7100             for (r = 0; r < numIndices; r++) {
7101               for (c = 0; c < dof; c++) {
7102                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7103               }
7104             }
7105           }
7106           oldOff += dof;
7107         }
7108       }
7109     }
7110     else {
7111       PetscInt oldOff = 0;
7112       for (p = 0; p < numPoints; p++) {
7113         PetscInt cStart = newPointOffsets[0][p];
7114         PetscInt b      = points[2 * p];
7115         PetscInt c, r, k;
7116         PetscInt dof;
7117 
7118         CHKERRQ(PetscSectionGetDof(section,b,&dof));
7119         if (!dof) {
7120           continue;
7121         }
7122         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7123           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
7124           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
7125 
7126           for (r = 0; r < numIndices; r++) {
7127             for (c = 0; c < nCols; c++) {
7128               for (k = 0; k < dof; k++) {
7129                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
7130               }
7131             }
7132           }
7133         }
7134         else {
7135           /* copy this column as is */
7136           for (r = 0; r < numIndices; r++) {
7137             for (c = 0; c < dof; c++) {
7138               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7139             }
7140           }
7141         }
7142         oldOff += dof;
7143       }
7144     }
7145 
7146     if (multiplyLeft) {
7147       CHKERRQ(DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues));
7148       CHKERRQ(PetscArrayzero(newValues,newNumIndices*newNumIndices));
7149       /* multiply constraints transpose on the left */
7150       if (numFields) {
7151         for (f = 0; f < numFields; f++) {
7152           PetscInt oldOff = offsets[f];
7153 
7154           for (p = 0; p < numPoints; p++) {
7155             PetscInt rStart = newPointOffsets[f][p];
7156             PetscInt b      = points[2 * p];
7157             PetscInt c, r, k;
7158             PetscInt dof;
7159 
7160             CHKERRQ(PetscSectionGetFieldDof(section,b,f,&dof));
7161             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7162               PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
7163               const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
7164 
7165               for (r = 0; r < nRows; r++) {
7166                 for (c = 0; c < newNumIndices; c++) {
7167                   for (k = 0; k < dof; k++) {
7168                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7169                   }
7170                 }
7171               }
7172             }
7173             else {
7174               /* copy this row as is */
7175               for (r = 0; r < dof; r++) {
7176                 for (c = 0; c < newNumIndices; c++) {
7177                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7178                 }
7179               }
7180             }
7181             oldOff += dof;
7182           }
7183         }
7184       }
7185       else {
7186         PetscInt oldOff = 0;
7187 
7188         for (p = 0; p < numPoints; p++) {
7189           PetscInt rStart = newPointOffsets[0][p];
7190           PetscInt b      = points[2 * p];
7191           PetscInt c, r, k;
7192           PetscInt dof;
7193 
7194           CHKERRQ(PetscSectionGetDof(section,b,&dof));
7195           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7196             PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
7197             const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
7198 
7199             for (r = 0; r < nRows; r++) {
7200               for (c = 0; c < newNumIndices; c++) {
7201                 for (k = 0; k < dof; k++) {
7202                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7203                 }
7204               }
7205             }
7206           }
7207           else {
7208             /* copy this row as is */
7209             for (r = 0; r < dof; r++) {
7210               for (c = 0; c < newNumIndices; c++) {
7211                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7212               }
7213             }
7214           }
7215           oldOff += dof;
7216         }
7217       }
7218 
7219       CHKERRQ(DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues));
7220     }
7221     else {
7222       newValues = tmpValues;
7223     }
7224   }
7225 
7226   /* clean up */
7227   CHKERRQ(DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices));
7228   CHKERRQ(DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices));
7229 
7230   if (numFields) {
7231     for (f = 0; f < numFields; f++) {
7232       CHKERRQ(DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]));
7233       CHKERRQ(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]));
7234       CHKERRQ(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]));
7235     }
7236   }
7237   else {
7238     CHKERRQ(DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]));
7239     CHKERRQ(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]));
7240     CHKERRQ(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]));
7241   }
7242   CHKERRQ(ISRestoreIndices(aIS,&anchors));
7243 
7244   /* output */
7245   if (outPoints) {
7246     *outPoints = newPoints;
7247   }
7248   else {
7249     CHKERRQ(DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints));
7250   }
7251   if (outValues) {
7252     *outValues = newValues;
7253   }
7254   for (f = 0; f <= numFields; f++) {
7255     offsets[f] = newOffsets[f];
7256   }
7257   PetscFunctionReturn(0);
7258 }
7259 
7260 /*@C
7261   DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.
7262 
7263   Not collective
7264 
7265   Input Parameters:
7266 + dm         - The DM
7267 . section    - The PetscSection describing the points (a local section)
7268 . idxSection - The PetscSection from which to obtain indices (may be local or global)
7269 . point      - The point defining the closure
7270 - useClPerm  - Use the closure point permutation if available
7271 
7272   Output Parameters:
7273 + numIndices - The number of dof indices in the closure of point with the input sections
7274 . indices    - The dof indices
7275 . outOffsets - Array to write the field offsets into, or NULL
7276 - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
7277 
7278   Notes:
7279   Must call DMPlexRestoreClosureIndices() to free allocated memory
7280 
7281   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
7282   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
7283   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
7284   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
7285   indices (with the above semantics) are implied.
7286 
7287   Level: advanced
7288 
7289 .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection()
7290 @*/
7291 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm,
7292                                        PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7293 {
7294   /* Closure ordering */
7295   PetscSection        clSection;
7296   IS                  clPoints;
7297   const PetscInt     *clp;
7298   PetscInt           *points;
7299   const PetscInt     *clperm = NULL;
7300   /* Dof permutation and sign flips */
7301   const PetscInt    **perms[32] = {NULL};
7302   const PetscScalar **flips[32] = {NULL};
7303   PetscScalar        *valCopy   = NULL;
7304   /* Hanging node constraints */
7305   PetscInt           *pointsC = NULL;
7306   PetscScalar        *valuesC = NULL;
7307   PetscInt            NclC, NiC;
7308 
7309   PetscInt           *idx;
7310   PetscInt            Nf, Ncl, Ni = 0, offsets[32], p, f;
7311   PetscBool           isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
7312 
7313   PetscFunctionBeginHot;
7314   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7315   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7316   PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3);
7317   if (numIndices) PetscValidIntPointer(numIndices, 6);
7318   if (indices)    PetscValidPointer(indices, 7);
7319   if (outOffsets) PetscValidIntPointer(outOffsets, 8);
7320   if (values)     PetscValidPointer(values, 9);
7321   CHKERRQ(PetscSectionGetNumFields(section, &Nf));
7322   PetscCheckFalse(Nf > 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
7323   CHKERRQ(PetscArrayzero(offsets, 32));
7324   /* 1) Get points in closure */
7325   CHKERRQ(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
7326   if (useClPerm) {
7327     PetscInt depth, clsize;
7328     CHKERRQ(DMPlexGetPointDepth(dm, point, &depth));
7329     for (clsize=0,p=0; p<Ncl; p++) {
7330       PetscInt dof;
7331       CHKERRQ(PetscSectionGetDof(section, points[2*p], &dof));
7332       clsize += dof;
7333     }
7334     CHKERRQ(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm));
7335   }
7336   /* 2) Get number of indices on these points and field offsets from section */
7337   for (p = 0; p < Ncl*2; p += 2) {
7338     PetscInt dof, fdof;
7339 
7340     CHKERRQ(PetscSectionGetDof(section, points[p], &dof));
7341     for (f = 0; f < Nf; ++f) {
7342       CHKERRQ(PetscSectionGetFieldDof(section, points[p], f, &fdof));
7343       offsets[f+1] += fdof;
7344     }
7345     Ni += dof;
7346   }
7347   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
7348   PetscCheckFalse(Nf && offsets[Nf] != Ni,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Ni);
7349   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
7350   for (f = 0; f < PetscMax(1, Nf); ++f) {
7351     if (Nf) CHKERRQ(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
7352     else    CHKERRQ(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]));
7353     /* may need to apply sign changes to the element matrix */
7354     if (values && flips[f]) {
7355       PetscInt foffset = offsets[f];
7356 
7357       for (p = 0; p < Ncl; ++p) {
7358         PetscInt           pnt  = points[2*p], fdof;
7359         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
7360 
7361         if (!Nf) CHKERRQ(PetscSectionGetDof(section, pnt, &fdof));
7362         else     CHKERRQ(PetscSectionGetFieldDof(section, pnt, f, &fdof));
7363         if (flip) {
7364           PetscInt i, j, k;
7365 
7366           if (!valCopy) {
7367             CHKERRQ(DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy));
7368             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
7369             *values = valCopy;
7370           }
7371           for (i = 0; i < fdof; ++i) {
7372             PetscScalar fval = flip[i];
7373 
7374             for (k = 0; k < Ni; ++k) {
7375               valCopy[Ni * (foffset + i) + k] *= fval;
7376               valCopy[Ni * k + (foffset + i)] *= fval;
7377             }
7378           }
7379         }
7380         foffset += fdof;
7381       }
7382     }
7383   }
7384   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
7385   CHKERRQ(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE));
7386   if (NclC) {
7387     if (valCopy) CHKERRQ(DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy));
7388     for (f = 0; f < PetscMax(1, Nf); ++f) {
7389       if (Nf) CHKERRQ(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
7390       else    CHKERRQ(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
7391     }
7392     for (f = 0; f < PetscMax(1, Nf); ++f) {
7393       if (Nf) CHKERRQ(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]));
7394       else    CHKERRQ(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]));
7395     }
7396     CHKERRQ(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
7397     Ncl     = NclC;
7398     Ni      = NiC;
7399     points  = pointsC;
7400     if (values) *values = valuesC;
7401   }
7402   /* 5) Calculate indices */
7403   CHKERRQ(DMGetWorkArray(dm, Ni, MPIU_INT, &idx));
7404   if (Nf) {
7405     PetscInt  idxOff;
7406     PetscBool useFieldOffsets;
7407 
7408     if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];}
7409     CHKERRQ(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets));
7410     if (useFieldOffsets) {
7411       for (p = 0; p < Ncl; ++p) {
7412         const PetscInt pnt = points[p*2];
7413 
7414         CHKERRQ(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx));
7415       }
7416     } else {
7417       for (p = 0; p < Ncl; ++p) {
7418         const PetscInt pnt = points[p*2];
7419 
7420         CHKERRQ(PetscSectionGetOffset(idxSection, pnt, &idxOff));
7421         /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
7422          * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
7423          * global section. */
7424         CHKERRQ(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx));
7425       }
7426     }
7427   } else {
7428     PetscInt off = 0, idxOff;
7429 
7430     for (p = 0; p < Ncl; ++p) {
7431       const PetscInt  pnt  = points[p*2];
7432       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
7433 
7434       CHKERRQ(PetscSectionGetOffset(idxSection, pnt, &idxOff));
7435       /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
7436        * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
7437       CHKERRQ(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx));
7438     }
7439   }
7440   /* 6) Cleanup */
7441   for (f = 0; f < PetscMax(1, Nf); ++f) {
7442     if (Nf) CHKERRQ(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
7443     else    CHKERRQ(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
7444   }
7445   if (NclC) {
7446     CHKERRQ(DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC));
7447   } else {
7448     CHKERRQ(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
7449   }
7450 
7451   if (numIndices) *numIndices = Ni;
7452   if (indices)    *indices    = idx;
7453   PetscFunctionReturn(0);
7454 }
7455 
7456 /*@C
7457   DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.
7458 
7459   Not collective
7460 
7461   Input Parameters:
7462 + dm         - The DM
7463 . section    - The PetscSection describing the points (a local section)
7464 . idxSection - The PetscSection from which to obtain indices (may be local or global)
7465 . point      - The point defining the closure
7466 - useClPerm  - Use the closure point permutation if available
7467 
7468   Output Parameters:
7469 + numIndices - The number of dof indices in the closure of point with the input sections
7470 . indices    - The dof indices
7471 . outOffsets - Array to write the field offsets into, or NULL
7472 - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
7473 
7474   Notes:
7475   If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values).
7476 
7477   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
7478   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
7479   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
7480   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
7481   indices (with the above semantics) are implied.
7482 
7483   Level: advanced
7484 
7485 .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection()
7486 @*/
7487 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm,
7488                                            PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7489 {
7490   PetscFunctionBegin;
7491   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7492   PetscValidPointer(indices, 7);
7493   CHKERRQ(DMRestoreWorkArray(dm, 0, MPIU_INT, indices));
7494   PetscFunctionReturn(0);
7495 }
7496 
7497 /*@C
7498   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
7499 
7500   Not collective
7501 
7502   Input Parameters:
7503 + dm - The DM
7504 . section - The section describing the layout in v, or NULL to use the default section
7505 . globalSection - The section describing the layout in v, or NULL to use the default global section
7506 . A - The matrix
7507 . point - The point in the DM
7508 . values - The array of values
7509 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7510 
7511   Fortran Notes:
7512   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
7513 
7514   Level: intermediate
7515 
7516 .seealso DMPlexMatSetClosureGeneral(), DMPlexVecGetClosure(), DMPlexVecSetClosure()
7517 @*/
7518 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7519 {
7520   DM_Plex           *mesh = (DM_Plex*) dm->data;
7521   PetscInt          *indices;
7522   PetscInt           numIndices;
7523   const PetscScalar *valuesOrig = values;
7524   PetscErrorCode     ierr;
7525 
7526   PetscFunctionBegin;
7527   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7528   if (!section) CHKERRQ(DMGetLocalSection(dm, &section));
7529   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7530   if (!globalSection) CHKERRQ(DMGetGlobalSection(dm, &globalSection));
7531   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
7532   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
7533 
7534   CHKERRQ(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values));
7535 
7536   if (mesh->printSetValues) CHKERRQ(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values));
7537   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7538   if (ierr) {
7539     PetscMPIInt    rank;
7540 
7541     CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
7542     CHKERRQ((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
7543     CHKERRQ(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values));
7544     CHKERRQ(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values));
7545     if (values != valuesOrig) CHKERRQ(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
7546     SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values");
7547   }
7548   if (mesh->printFEM > 1) {
7549     PetscInt i;
7550     CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "  Indices:"));
7551     for (i = 0; i < numIndices; ++i) CHKERRQ(PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]));
7552     CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "\n"));
7553   }
7554 
7555   CHKERRQ(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values));
7556   if (values != valuesOrig) CHKERRQ(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
7557   PetscFunctionReturn(0);
7558 }
7559 
7560 /*@C
7561   DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section
7562 
7563   Not collective
7564 
7565   Input Parameters:
7566 + dmRow - The DM for the row fields
7567 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow
7568 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow
7569 . dmCol - The DM for the column fields
7570 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol
7571 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol
7572 . A - The matrix
7573 . point - The point in the DMs
7574 . values - The array of values
7575 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7576 
7577   Level: intermediate
7578 
7579 .seealso DMPlexMatSetClosure(), DMPlexVecGetClosure(), DMPlexVecSetClosure()
7580 @*/
7581 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7582 {
7583   DM_Plex           *mesh = (DM_Plex*) dmRow->data;
7584   PetscInt          *indicesRow, *indicesCol;
7585   PetscInt           numIndicesRow, numIndicesCol;
7586   const PetscScalar *valuesOrig = values;
7587   PetscErrorCode     ierr;
7588 
7589   PetscFunctionBegin;
7590   PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1);
7591   if (!sectionRow) CHKERRQ(DMGetLocalSection(dmRow, &sectionRow));
7592   PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2);
7593   if (!globalSectionRow) CHKERRQ(DMGetGlobalSection(dmRow, &globalSectionRow));
7594   PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3);
7595   PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4);
7596   if (!sectionCol) CHKERRQ(DMGetLocalSection(dmCol, &sectionCol));
7597   PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5);
7598   if (!globalSectionCol) CHKERRQ(DMGetGlobalSection(dmCol, &globalSectionCol));
7599   PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6);
7600   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
7601 
7602   CHKERRQ(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values));
7603   CHKERRQ(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values));
7604 
7605   if (mesh->printSetValues) CHKERRQ(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
7606   ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode);
7607   if (ierr) {
7608     PetscMPIInt    rank;
7609 
7610     CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
7611     CHKERRQ((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
7612     CHKERRQ(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
7613     CHKERRQ(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values));
7614     CHKERRQ(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values));
7615     if (values != valuesOrig) CHKERRQ(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values));
7616     CHKERRQ(ierr);
7617   }
7618 
7619   CHKERRQ(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values));
7620   CHKERRQ(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values));
7621   if (values != valuesOrig) CHKERRQ(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values));
7622   PetscFunctionReturn(0);
7623 }
7624 
7625 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7626 {
7627   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
7628   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
7629   PetscInt       *cpoints = NULL;
7630   PetscInt       *findices, *cindices;
7631   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7632   PetscInt        foffsets[32], coffsets[32];
7633   DMPolytopeType  ct;
7634   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
7635   PetscErrorCode  ierr;
7636 
7637   PetscFunctionBegin;
7638   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
7639   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
7640   if (!fsection) CHKERRQ(DMGetLocalSection(dmf, &fsection));
7641   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
7642   if (!csection) CHKERRQ(DMGetLocalSection(dmc, &csection));
7643   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
7644   if (!globalFSection) CHKERRQ(DMGetGlobalSection(dmf, &globalFSection));
7645   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
7646   if (!globalCSection) CHKERRQ(DMGetGlobalSection(dmc, &globalCSection));
7647   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
7648   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
7649   CHKERRQ(PetscSectionGetNumFields(fsection, &numFields));
7650   PetscCheckFalse(numFields > 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7651   CHKERRQ(PetscArrayzero(foffsets, 32));
7652   CHKERRQ(PetscArrayzero(coffsets, 32));
7653   /* Column indices */
7654   CHKERRQ(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
7655   maxFPoints = numCPoints;
7656   /* Compress out points not in the section */
7657   /*   TODO: Squeeze out points with 0 dof as well */
7658   CHKERRQ(PetscSectionGetChart(csection, &pStart, &pEnd));
7659   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
7660     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
7661       cpoints[q*2]   = cpoints[p];
7662       cpoints[q*2+1] = cpoints[p+1];
7663       ++q;
7664     }
7665   }
7666   numCPoints = q;
7667   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
7668     PetscInt fdof;
7669 
7670     CHKERRQ(PetscSectionGetDof(csection, cpoints[p], &dof));
7671     if (!dof) continue;
7672     for (f = 0; f < numFields; ++f) {
7673       CHKERRQ(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
7674       coffsets[f+1] += fdof;
7675     }
7676     numCIndices += dof;
7677   }
7678   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
7679   /* Row indices */
7680   CHKERRQ(DMPlexGetCellType(dmc, point, &ct));
7681   {
7682     DMPlexTransform tr;
7683     DMPolytopeType *rct;
7684     PetscInt       *rsize, *rcone, *rornt, Nt;
7685 
7686     CHKERRQ(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
7687     CHKERRQ(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
7688     CHKERRQ(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
7689     numSubcells = rsize[Nt-1];
7690     CHKERRQ(DMPlexTransformDestroy(&tr));
7691   }
7692   CHKERRQ(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints));
7693   for (r = 0, q = 0; r < numSubcells; ++r) {
7694     /* TODO Map from coarse to fine cells */
7695     CHKERRQ(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
7696     /* Compress out points not in the section */
7697     CHKERRQ(PetscSectionGetChart(fsection, &pStart, &pEnd));
7698     for (p = 0; p < numFPoints*2; p += 2) {
7699       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
7700         CHKERRQ(PetscSectionGetDof(fsection, fpoints[p], &dof));
7701         if (!dof) continue;
7702         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
7703         if (s < q) continue;
7704         ftotpoints[q*2]   = fpoints[p];
7705         ftotpoints[q*2+1] = fpoints[p+1];
7706         ++q;
7707       }
7708     }
7709     CHKERRQ(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
7710   }
7711   numFPoints = q;
7712   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
7713     PetscInt fdof;
7714 
7715     CHKERRQ(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
7716     if (!dof) continue;
7717     for (f = 0; f < numFields; ++f) {
7718       CHKERRQ(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
7719       foffsets[f+1] += fdof;
7720     }
7721     numFIndices += dof;
7722   }
7723   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
7724 
7725   PetscCheckFalse(numFields && foffsets[numFields] != numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
7726   PetscCheckFalse(numFields && coffsets[numFields] != numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
7727   CHKERRQ(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices));
7728   CHKERRQ(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
7729   if (numFields) {
7730     const PetscInt **permsF[32] = {NULL};
7731     const PetscInt **permsC[32] = {NULL};
7732 
7733     for (f = 0; f < numFields; f++) {
7734       CHKERRQ(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL));
7735       CHKERRQ(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL));
7736     }
7737     for (p = 0; p < numFPoints; p++) {
7738       CHKERRQ(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff));
7739       CHKERRQ(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
7740     }
7741     for (p = 0; p < numCPoints; p++) {
7742       CHKERRQ(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff));
7743       CHKERRQ(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
7744     }
7745     for (f = 0; f < numFields; f++) {
7746       CHKERRQ(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL));
7747       CHKERRQ(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL));
7748     }
7749   } else {
7750     const PetscInt **permsF = NULL;
7751     const PetscInt **permsC = NULL;
7752 
7753     CHKERRQ(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL));
7754     CHKERRQ(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL));
7755     for (p = 0, off = 0; p < numFPoints; p++) {
7756       const PetscInt *perm = permsF ? permsF[p] : NULL;
7757 
7758       CHKERRQ(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff));
7759       CHKERRQ(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
7760     }
7761     for (p = 0, off = 0; p < numCPoints; p++) {
7762       const PetscInt *perm = permsC ? permsC[p] : NULL;
7763 
7764       CHKERRQ(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff));
7765       CHKERRQ(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
7766     }
7767     CHKERRQ(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL));
7768     CHKERRQ(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL));
7769   }
7770   if (mesh->printSetValues) CHKERRQ(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
7771   /* TODO: flips */
7772   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
7773   if (ierr) {
7774     PetscMPIInt    rank;
7775 
7776     CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
7777     CHKERRQ((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
7778     CHKERRQ(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
7779     CHKERRQ(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
7780     CHKERRQ(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
7781     CHKERRQ(ierr);
7782   }
7783   CHKERRQ(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints));
7784   CHKERRQ(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
7785   CHKERRQ(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
7786   CHKERRQ(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
7787   PetscFunctionReturn(0);
7788 }
7789 
7790 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
7791 {
7792   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
7793   PetscInt      *cpoints = NULL;
7794   PetscInt       foffsets[32], coffsets[32];
7795   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7796   DMPolytopeType ct;
7797   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
7798 
7799   PetscFunctionBegin;
7800   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
7801   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
7802   if (!fsection) CHKERRQ(DMGetLocalSection(dmf, &fsection));
7803   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
7804   if (!csection) CHKERRQ(DMGetLocalSection(dmc, &csection));
7805   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
7806   if (!globalFSection) CHKERRQ(DMGetGlobalSection(dmf, &globalFSection));
7807   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
7808   if (!globalCSection) CHKERRQ(DMGetGlobalSection(dmc, &globalCSection));
7809   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
7810   CHKERRQ(PetscSectionGetNumFields(fsection, &numFields));
7811   PetscCheckFalse(numFields > 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7812   CHKERRQ(PetscArrayzero(foffsets, 32));
7813   CHKERRQ(PetscArrayzero(coffsets, 32));
7814   /* Column indices */
7815   CHKERRQ(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
7816   maxFPoints = numCPoints;
7817   /* Compress out points not in the section */
7818   /*   TODO: Squeeze out points with 0 dof as well */
7819   CHKERRQ(PetscSectionGetChart(csection, &pStart, &pEnd));
7820   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
7821     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
7822       cpoints[q*2]   = cpoints[p];
7823       cpoints[q*2+1] = cpoints[p+1];
7824       ++q;
7825     }
7826   }
7827   numCPoints = q;
7828   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
7829     PetscInt fdof;
7830 
7831     CHKERRQ(PetscSectionGetDof(csection, cpoints[p], &dof));
7832     if (!dof) continue;
7833     for (f = 0; f < numFields; ++f) {
7834       CHKERRQ(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
7835       coffsets[f+1] += fdof;
7836     }
7837     numCIndices += dof;
7838   }
7839   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
7840   /* Row indices */
7841   CHKERRQ(DMPlexGetCellType(dmc, point, &ct));
7842   {
7843     DMPlexTransform tr;
7844     DMPolytopeType *rct;
7845     PetscInt       *rsize, *rcone, *rornt, Nt;
7846 
7847     CHKERRQ(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
7848     CHKERRQ(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
7849     CHKERRQ(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
7850     numSubcells = rsize[Nt-1];
7851     CHKERRQ(DMPlexTransformDestroy(&tr));
7852   }
7853   CHKERRQ(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints));
7854   for (r = 0, q = 0; r < numSubcells; ++r) {
7855     /* TODO Map from coarse to fine cells */
7856     CHKERRQ(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
7857     /* Compress out points not in the section */
7858     CHKERRQ(PetscSectionGetChart(fsection, &pStart, &pEnd));
7859     for (p = 0; p < numFPoints*2; p += 2) {
7860       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
7861         CHKERRQ(PetscSectionGetDof(fsection, fpoints[p], &dof));
7862         if (!dof) continue;
7863         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
7864         if (s < q) continue;
7865         ftotpoints[q*2]   = fpoints[p];
7866         ftotpoints[q*2+1] = fpoints[p+1];
7867         ++q;
7868       }
7869     }
7870     CHKERRQ(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
7871   }
7872   numFPoints = q;
7873   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
7874     PetscInt fdof;
7875 
7876     CHKERRQ(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
7877     if (!dof) continue;
7878     for (f = 0; f < numFields; ++f) {
7879       CHKERRQ(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
7880       foffsets[f+1] += fdof;
7881     }
7882     numFIndices += dof;
7883   }
7884   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
7885 
7886   PetscCheckFalse(numFields && foffsets[numFields] != numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
7887   PetscCheckFalse(numFields && coffsets[numFields] != numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
7888   if (numFields) {
7889     const PetscInt **permsF[32] = {NULL};
7890     const PetscInt **permsC[32] = {NULL};
7891 
7892     for (f = 0; f < numFields; f++) {
7893       CHKERRQ(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL));
7894       CHKERRQ(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL));
7895     }
7896     for (p = 0; p < numFPoints; p++) {
7897       CHKERRQ(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff));
7898       CHKERRQ(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
7899     }
7900     for (p = 0; p < numCPoints; p++) {
7901       CHKERRQ(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff));
7902       CHKERRQ(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
7903     }
7904     for (f = 0; f < numFields; f++) {
7905       CHKERRQ(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL));
7906       CHKERRQ(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL));
7907     }
7908   } else {
7909     const PetscInt **permsF = NULL;
7910     const PetscInt **permsC = NULL;
7911 
7912     CHKERRQ(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL));
7913     CHKERRQ(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL));
7914     for (p = 0, off = 0; p < numFPoints; p++) {
7915       const PetscInt *perm = permsF ? permsF[p] : NULL;
7916 
7917       CHKERRQ(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff));
7918       CHKERRQ(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
7919     }
7920     for (p = 0, off = 0; p < numCPoints; p++) {
7921       const PetscInt *perm = permsC ? permsC[p] : NULL;
7922 
7923       CHKERRQ(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff));
7924       CHKERRQ(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
7925     }
7926     CHKERRQ(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL));
7927     CHKERRQ(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL));
7928   }
7929   CHKERRQ(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints));
7930   CHKERRQ(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
7931   PetscFunctionReturn(0);
7932 }
7933 
7934 /*@C
7935   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
7936 
7937   Input Parameter:
7938 . dm   - The DMPlex object
7939 
7940   Output Parameter:
7941 . cellHeight - The height of a cell
7942 
7943   Level: developer
7944 
7945 .seealso DMPlexSetVTKCellHeight()
7946 @*/
7947 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
7948 {
7949   DM_Plex *mesh = (DM_Plex*) dm->data;
7950 
7951   PetscFunctionBegin;
7952   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7953   PetscValidIntPointer(cellHeight, 2);
7954   *cellHeight = mesh->vtkCellHeight;
7955   PetscFunctionReturn(0);
7956 }
7957 
7958 /*@C
7959   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
7960 
7961   Input Parameters:
7962 + dm   - The DMPlex object
7963 - cellHeight - The height of a cell
7964 
7965   Level: developer
7966 
7967 .seealso DMPlexGetVTKCellHeight()
7968 @*/
7969 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
7970 {
7971   DM_Plex *mesh = (DM_Plex*) dm->data;
7972 
7973   PetscFunctionBegin;
7974   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7975   mesh->vtkCellHeight = cellHeight;
7976   PetscFunctionReturn(0);
7977 }
7978 
7979 /*@
7980   DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions
7981 
7982   Input Parameter:
7983 . dm - The DMPlex object
7984 
7985   Output Parameters:
7986 + gcStart - The first ghost cell, or NULL
7987 - gcEnd   - The upper bound on ghost cells, or NULL
7988 
7989   Level: advanced
7990 
7991 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum()
7992 @*/
7993 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd)
7994 {
7995   DMLabel        ctLabel;
7996 
7997   PetscFunctionBegin;
7998   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7999   CHKERRQ(DMPlexGetCellTypeLabel(dm, &ctLabel));
8000   CHKERRQ(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd));
8001   PetscFunctionReturn(0);
8002 }
8003 
8004 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
8005 {
8006   PetscSection   section, globalSection;
8007   PetscInt      *numbers, p;
8008 
8009   PetscFunctionBegin;
8010   CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
8011   CHKERRQ(PetscSectionSetChart(section, pStart, pEnd));
8012   for (p = pStart; p < pEnd; ++p) {
8013     CHKERRQ(PetscSectionSetDof(section, p, 1));
8014   }
8015   CHKERRQ(PetscSectionSetUp(section));
8016   CHKERRQ(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection));
8017   CHKERRQ(PetscMalloc1(pEnd - pStart, &numbers));
8018   for (p = pStart; p < pEnd; ++p) {
8019     CHKERRQ(PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]));
8020     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
8021     else                       numbers[p-pStart] += shift;
8022   }
8023   CHKERRQ(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering));
8024   if (globalSize) {
8025     PetscLayout layout;
8026     CHKERRQ(PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout));
8027     CHKERRQ(PetscLayoutGetSize(layout, globalSize));
8028     CHKERRQ(PetscLayoutDestroy(&layout));
8029   }
8030   CHKERRQ(PetscSectionDestroy(&section));
8031   CHKERRQ(PetscSectionDestroy(&globalSection));
8032   PetscFunctionReturn(0);
8033 }
8034 
8035 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
8036 {
8037   PetscInt       cellHeight, cStart, cEnd;
8038 
8039   PetscFunctionBegin;
8040   CHKERRQ(DMPlexGetVTKCellHeight(dm, &cellHeight));
8041   if (includeHybrid) CHKERRQ(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
8042   else               CHKERRQ(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
8043   CHKERRQ(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers));
8044   PetscFunctionReturn(0);
8045 }
8046 
8047 /*@
8048   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
8049 
8050   Input Parameter:
8051 . dm   - The DMPlex object
8052 
8053   Output Parameter:
8054 . globalCellNumbers - Global cell numbers for all cells on this process
8055 
8056   Level: developer
8057 
8058 .seealso DMPlexGetVertexNumbering()
8059 @*/
8060 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
8061 {
8062   DM_Plex       *mesh = (DM_Plex*) dm->data;
8063 
8064   PetscFunctionBegin;
8065   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8066   if (!mesh->globalCellNumbers) CHKERRQ(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers));
8067   *globalCellNumbers = mesh->globalCellNumbers;
8068   PetscFunctionReturn(0);
8069 }
8070 
8071 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
8072 {
8073   PetscInt       vStart, vEnd;
8074 
8075   PetscFunctionBegin;
8076   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8077   CHKERRQ(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
8078   CHKERRQ(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers));
8079   PetscFunctionReturn(0);
8080 }
8081 
8082 /*@
8083   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
8084 
8085   Input Parameter:
8086 . dm   - The DMPlex object
8087 
8088   Output Parameter:
8089 . globalVertexNumbers - Global vertex numbers for all vertices on this process
8090 
8091   Level: developer
8092 
8093 .seealso DMPlexGetCellNumbering()
8094 @*/
8095 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
8096 {
8097   DM_Plex       *mesh = (DM_Plex*) dm->data;
8098 
8099   PetscFunctionBegin;
8100   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8101   if (!mesh->globalVertexNumbers) CHKERRQ(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers));
8102   *globalVertexNumbers = mesh->globalVertexNumbers;
8103   PetscFunctionReturn(0);
8104 }
8105 
8106 /*@
8107   DMPlexCreatePointNumbering - Create a global numbering for all points on this process
8108 
8109   Input Parameter:
8110 . dm   - The DMPlex object
8111 
8112   Output Parameter:
8113 . globalPointNumbers - Global numbers for all points on this process
8114 
8115   Level: developer
8116 
8117 .seealso DMPlexGetCellNumbering()
8118 @*/
8119 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
8120 {
8121   IS             nums[4];
8122   PetscInt       depths[4], gdepths[4], starts[4];
8123   PetscInt       depth, d, shift = 0;
8124 
8125   PetscFunctionBegin;
8126   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8127   CHKERRQ(DMPlexGetDepth(dm, &depth));
8128   /* For unstratified meshes use dim instead of depth */
8129   if (depth < 0) CHKERRQ(DMGetDimension(dm, &depth));
8130   for (d = 0; d <= depth; ++d) {
8131     PetscInt end;
8132 
8133     depths[d] = depth-d;
8134     CHKERRQ(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end));
8135     if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
8136   }
8137   CHKERRQ(PetscSortIntWithArray(depth+1, starts, depths));
8138   CHKERRMPI(MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm)));
8139   for (d = 0; d <= depth; ++d) {
8140     PetscCheckFalse(starts[d] >= 0 && depths[d] != gdepths[d],PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
8141   }
8142   for (d = 0; d <= depth; ++d) {
8143     PetscInt pStart, pEnd, gsize;
8144 
8145     CHKERRQ(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd));
8146     CHKERRQ(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]));
8147     shift += gsize;
8148   }
8149   CHKERRQ(ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers));
8150   for (d = 0; d <= depth; ++d) CHKERRQ(ISDestroy(&nums[d]));
8151   PetscFunctionReturn(0);
8152 }
8153 
8154 /*@
8155   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
8156 
8157   Input Parameter:
8158 . dm - The DMPlex object
8159 
8160   Output Parameter:
8161 . ranks - The rank field
8162 
8163   Options Database Keys:
8164 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
8165 
8166   Level: intermediate
8167 
8168 .seealso: DMView()
8169 @*/
8170 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
8171 {
8172   DM             rdm;
8173   PetscFE        fe;
8174   PetscScalar   *r;
8175   PetscMPIInt    rank;
8176   DMPolytopeType ct;
8177   PetscInt       dim, cStart, cEnd, c;
8178   PetscBool      simplex;
8179 
8180   PetscFunctionBeginUser;
8181   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8182   PetscValidPointer(ranks, 2);
8183   CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
8184   CHKERRQ(DMClone(dm, &rdm));
8185   CHKERRQ(DMGetDimension(rdm, &dim));
8186   CHKERRQ(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd));
8187   CHKERRQ(DMPlexGetCellType(dm, cStart, &ct));
8188   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
8189   CHKERRQ(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe));
8190   CHKERRQ(PetscObjectSetName((PetscObject) fe, "rank"));
8191   CHKERRQ(DMSetField(rdm, 0, NULL, (PetscObject) fe));
8192   CHKERRQ(PetscFEDestroy(&fe));
8193   CHKERRQ(DMCreateDS(rdm));
8194   CHKERRQ(DMCreateGlobalVector(rdm, ranks));
8195   CHKERRQ(PetscObjectSetName((PetscObject) *ranks, "partition"));
8196   CHKERRQ(VecGetArray(*ranks, &r));
8197   for (c = cStart; c < cEnd; ++c) {
8198     PetscScalar *lr;
8199 
8200     CHKERRQ(DMPlexPointGlobalRef(rdm, c, r, &lr));
8201     if (lr) *lr = rank;
8202   }
8203   CHKERRQ(VecRestoreArray(*ranks, &r));
8204   CHKERRQ(DMDestroy(&rdm));
8205   PetscFunctionReturn(0);
8206 }
8207 
8208 /*@
8209   DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
8210 
8211   Input Parameters:
8212 + dm    - The DMPlex
8213 - label - The DMLabel
8214 
8215   Output Parameter:
8216 . val - The label value field
8217 
8218   Options Database Keys:
8219 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer
8220 
8221   Level: intermediate
8222 
8223 .seealso: DMView()
8224 @*/
8225 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
8226 {
8227   DM             rdm;
8228   PetscFE        fe;
8229   PetscScalar   *v;
8230   PetscInt       dim, cStart, cEnd, c;
8231 
8232   PetscFunctionBeginUser;
8233   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8234   PetscValidPointer(label, 2);
8235   PetscValidPointer(val, 3);
8236   CHKERRQ(DMClone(dm, &rdm));
8237   CHKERRQ(DMGetDimension(rdm, &dim));
8238   CHKERRQ(PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe));
8239   CHKERRQ(PetscObjectSetName((PetscObject) fe, "label_value"));
8240   CHKERRQ(DMSetField(rdm, 0, NULL, (PetscObject) fe));
8241   CHKERRQ(PetscFEDestroy(&fe));
8242   CHKERRQ(DMCreateDS(rdm));
8243   CHKERRQ(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd));
8244   CHKERRQ(DMCreateGlobalVector(rdm, val));
8245   CHKERRQ(PetscObjectSetName((PetscObject) *val, "label_value"));
8246   CHKERRQ(VecGetArray(*val, &v));
8247   for (c = cStart; c < cEnd; ++c) {
8248     PetscScalar *lv;
8249     PetscInt     cval;
8250 
8251     CHKERRQ(DMPlexPointGlobalRef(rdm, c, v, &lv));
8252     CHKERRQ(DMLabelGetValue(label, c, &cval));
8253     *lv = cval;
8254   }
8255   CHKERRQ(VecRestoreArray(*val, &v));
8256   CHKERRQ(DMDestroy(&rdm));
8257   PetscFunctionReturn(0);
8258 }
8259 
8260 /*@
8261   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
8262 
8263   Input Parameter:
8264 . dm - The DMPlex object
8265 
8266   Notes:
8267   This is a useful diagnostic when creating meshes programmatically.
8268 
8269   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8270 
8271   Level: developer
8272 
8273 .seealso: DMCreate(), DMSetFromOptions()
8274 @*/
8275 PetscErrorCode DMPlexCheckSymmetry(DM dm)
8276 {
8277   PetscSection    coneSection, supportSection;
8278   const PetscInt *cone, *support;
8279   PetscInt        coneSize, c, supportSize, s;
8280   PetscInt        pStart, pEnd, p, pp, csize, ssize;
8281   PetscBool       storagecheck = PETSC_TRUE;
8282 
8283   PetscFunctionBegin;
8284   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8285   CHKERRQ(DMViewFromOptions(dm, NULL, "-sym_dm_view"));
8286   CHKERRQ(DMPlexGetConeSection(dm, &coneSection));
8287   CHKERRQ(DMPlexGetSupportSection(dm, &supportSection));
8288   /* Check that point p is found in the support of its cone points, and vice versa */
8289   CHKERRQ(DMPlexGetChart(dm, &pStart, &pEnd));
8290   for (p = pStart; p < pEnd; ++p) {
8291     CHKERRQ(DMPlexGetConeSize(dm, p, &coneSize));
8292     CHKERRQ(DMPlexGetCone(dm, p, &cone));
8293     for (c = 0; c < coneSize; ++c) {
8294       PetscBool dup = PETSC_FALSE;
8295       PetscInt  d;
8296       for (d = c-1; d >= 0; --d) {
8297         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
8298       }
8299       CHKERRQ(DMPlexGetSupportSize(dm, cone[c], &supportSize));
8300       CHKERRQ(DMPlexGetSupport(dm, cone[c], &support));
8301       for (s = 0; s < supportSize; ++s) {
8302         if (support[s] == p) break;
8303       }
8304       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
8305         CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p));
8306         for (s = 0; s < coneSize; ++s) {
8307           CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]));
8308         }
8309         CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "\n"));
8310         CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]));
8311         for (s = 0; s < supportSize; ++s) {
8312           CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]));
8313         }
8314         CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "\n"));
8315         PetscCheck(!dup,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
8316         else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
8317       }
8318     }
8319     CHKERRQ(DMPlexGetTreeParent(dm, p, &pp, NULL));
8320     if (p != pp) { storagecheck = PETSC_FALSE; continue; }
8321     CHKERRQ(DMPlexGetSupportSize(dm, p, &supportSize));
8322     CHKERRQ(DMPlexGetSupport(dm, p, &support));
8323     for (s = 0; s < supportSize; ++s) {
8324       CHKERRQ(DMPlexGetConeSize(dm, support[s], &coneSize));
8325       CHKERRQ(DMPlexGetCone(dm, support[s], &cone));
8326       for (c = 0; c < coneSize; ++c) {
8327         CHKERRQ(DMPlexGetTreeParent(dm, cone[c], &pp, NULL));
8328         if (cone[c] != pp) { c = 0; break; }
8329         if (cone[c] == p) break;
8330       }
8331       if (c >= coneSize) {
8332         CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p));
8333         for (c = 0; c < supportSize; ++c) {
8334           CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]));
8335         }
8336         CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "\n"));
8337         CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]));
8338         for (c = 0; c < coneSize; ++c) {
8339           CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]));
8340         }
8341         CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "\n"));
8342         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
8343       }
8344     }
8345   }
8346   if (storagecheck) {
8347     CHKERRQ(PetscSectionGetStorageSize(coneSection, &csize));
8348     CHKERRQ(PetscSectionGetStorageSize(supportSection, &ssize));
8349     PetscCheckFalse(csize != ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
8350   }
8351   PetscFunctionReturn(0);
8352 }
8353 
8354 /*
8355   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.
8356 */
8357 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit)
8358 {
8359   DMPolytopeType  cct;
8360   PetscInt        ptpoints[4];
8361   const PetscInt *cone, *ccone, *ptcone;
8362   PetscInt        coneSize, cp, cconeSize, ccp, npt = 0, pt;
8363 
8364   PetscFunctionBegin;
8365   *unsplit = 0;
8366   switch (ct) {
8367     case DM_POLYTOPE_POINT_PRISM_TENSOR:
8368       ptpoints[npt++] = c;
8369       break;
8370     case DM_POLYTOPE_SEG_PRISM_TENSOR:
8371       CHKERRQ(DMPlexGetCone(dm, c, &cone));
8372       CHKERRQ(DMPlexGetConeSize(dm, c, &coneSize));
8373       for (cp = 0; cp < coneSize; ++cp) {
8374         CHKERRQ(DMPlexGetCellType(dm, cone[cp], &cct));
8375         if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp];
8376       }
8377       break;
8378     case DM_POLYTOPE_TRI_PRISM_TENSOR:
8379     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8380       CHKERRQ(DMPlexGetCone(dm, c, &cone));
8381       CHKERRQ(DMPlexGetConeSize(dm, c, &coneSize));
8382       for (cp = 0; cp < coneSize; ++cp) {
8383         CHKERRQ(DMPlexGetCone(dm, cone[cp], &ccone));
8384         CHKERRQ(DMPlexGetConeSize(dm, cone[cp], &cconeSize));
8385         for (ccp = 0; ccp < cconeSize; ++ccp) {
8386           CHKERRQ(DMPlexGetCellType(dm, ccone[ccp], &cct));
8387           if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) {
8388             PetscInt p;
8389             for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break;
8390             if (p == npt) ptpoints[npt++] = ccone[ccp];
8391           }
8392         }
8393       }
8394       break;
8395     default: break;
8396   }
8397   for (pt = 0; pt < npt; ++pt) {
8398     CHKERRQ(DMPlexGetCone(dm, ptpoints[pt], &ptcone));
8399     if (ptcone[0] == ptcone[1]) ++(*unsplit);
8400   }
8401   PetscFunctionReturn(0);
8402 }
8403 
8404 /*@
8405   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
8406 
8407   Input Parameters:
8408 + dm - The DMPlex object
8409 - cellHeight - Normally 0
8410 
8411   Notes:
8412   This is a useful diagnostic when creating meshes programmatically.
8413   Currently applicable only to homogeneous simplex or tensor meshes.
8414 
8415   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8416 
8417   Level: developer
8418 
8419 .seealso: DMCreate(), DMSetFromOptions()
8420 @*/
8421 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
8422 {
8423   DMPlexInterpolatedFlag interp;
8424   DMPolytopeType         ct;
8425   PetscInt               vStart, vEnd, cStart, cEnd, c;
8426 
8427   PetscFunctionBegin;
8428   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8429   CHKERRQ(DMPlexIsInterpolated(dm, &interp));
8430   CHKERRQ(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
8431   CHKERRQ(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
8432   for (c = cStart; c < cEnd; ++c) {
8433     PetscInt *closure = NULL;
8434     PetscInt  coneSize, closureSize, cl, Nv = 0;
8435 
8436     CHKERRQ(DMPlexGetCellType(dm, c, &ct));
8437     PetscCheckFalse((PetscInt) ct < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has no cell type", c);
8438     if (ct == DM_POLYTOPE_UNKNOWN) continue;
8439     if (interp == DMPLEX_INTERPOLATED_FULL) {
8440       CHKERRQ(DMPlexGetConeSize(dm, c, &coneSize));
8441       PetscCheckFalse(coneSize != DMPolytopeTypeGetConeSize(ct),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D of type %s has cone size %D != %D", c, DMPolytopeTypes[ct], coneSize, DMPolytopeTypeGetConeSize(ct));
8442     }
8443     CHKERRQ(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
8444     for (cl = 0; cl < closureSize*2; cl += 2) {
8445       const PetscInt p = closure[cl];
8446       if ((p >= vStart) && (p < vEnd)) ++Nv;
8447     }
8448     CHKERRQ(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
8449     /* Special Case: Tensor faces with identified vertices */
8450     if (Nv < DMPolytopeTypeGetNumVertices(ct)) {
8451       PetscInt unsplit;
8452 
8453       CHKERRQ(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
8454       if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue;
8455     }
8456     PetscCheckFalse(Nv != DMPolytopeTypeGetNumVertices(ct),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D of type %s has %D vertices != %D", c, DMPolytopeTypes[ct], Nv, DMPolytopeTypeGetNumVertices(ct));
8457   }
8458   PetscFunctionReturn(0);
8459 }
8460 
8461 /*@
8462   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
8463 
8464   Not Collective
8465 
8466   Input Parameters:
8467 + dm - The DMPlex object
8468 - cellHeight - Normally 0
8469 
8470   Notes:
8471   This is a useful diagnostic when creating meshes programmatically.
8472   This routine is only relevant for meshes that are fully interpolated across all ranks.
8473   It will error out if a partially interpolated mesh is given on some rank.
8474   It will do nothing for locally uninterpolated mesh (as there is nothing to check).
8475 
8476   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8477 
8478   Level: developer
8479 
8480 .seealso: DMCreate(), DMPlexGetVTKCellHeight(), DMSetFromOptions()
8481 @*/
8482 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
8483 {
8484   PetscInt       dim, depth, vStart, vEnd, cStart, cEnd, c, h;
8485   DMPlexInterpolatedFlag interpEnum;
8486 
8487   PetscFunctionBegin;
8488   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8489   CHKERRQ(DMPlexIsInterpolated(dm, &interpEnum));
8490   if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0);
8491   if (interpEnum == DMPLEX_INTERPOLATED_PARTIAL) {
8492     PetscMPIInt rank;
8493     MPI_Comm    comm;
8494 
8495     CHKERRQ(PetscObjectGetComm((PetscObject) dm, &comm));
8496     CHKERRMPI(MPI_Comm_rank(comm, &rank));
8497     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Mesh is only partially interpolated on rank %d, this is currently not supported", rank);
8498   }
8499 
8500   CHKERRQ(DMGetDimension(dm, &dim));
8501   CHKERRQ(DMPlexGetDepth(dm, &depth));
8502   CHKERRQ(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
8503   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
8504     CHKERRQ(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd));
8505     for (c = cStart; c < cEnd; ++c) {
8506       const PetscInt      *cone, *ornt, *faceSizes, *faces;
8507       const DMPolytopeType *faceTypes;
8508       DMPolytopeType        ct;
8509       PetscInt              numFaces, coneSize, f;
8510       PetscInt             *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit;
8511 
8512       CHKERRQ(DMPlexGetCellType(dm, c, &ct));
8513       CHKERRQ(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
8514       if (unsplit) continue;
8515       CHKERRQ(DMPlexGetConeSize(dm, c, &coneSize));
8516       CHKERRQ(DMPlexGetCone(dm, c, &cone));
8517       CHKERRQ(DMPlexGetConeOrientation(dm, c, &ornt));
8518       CHKERRQ(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
8519       for (cl = 0; cl < closureSize*2; cl += 2) {
8520         const PetscInt p = closure[cl];
8521         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
8522       }
8523       CHKERRQ(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
8524       PetscCheckFalse(coneSize != numFaces,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D of type %s has %D faces but should have %D", c, DMPolytopeTypes[ct], coneSize, numFaces);
8525       for (f = 0; f < numFaces; ++f) {
8526         DMPolytopeType fct;
8527         PetscInt       *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
8528 
8529         CHKERRQ(DMPlexGetCellType(dm, cone[f], &fct));
8530         CHKERRQ(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure));
8531         for (cl = 0; cl < fclosureSize*2; cl += 2) {
8532           const PetscInt p = fclosure[cl];
8533           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
8534         }
8535         PetscCheckFalse(fnumCorners != faceSizes[f],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]);
8536         for (v = 0; v < fnumCorners; ++v) {
8537           if (fclosure[v] != faces[fOff+v]) {
8538             PetscInt v1;
8539 
8540             CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "face closure:"));
8541             for (v1 = 0; v1 < fnumCorners; ++v1) CHKERRQ(PetscPrintf(PETSC_COMM_SELF, " %D", fclosure[v1]));
8542             CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "\ncell face:"));
8543             for (v1 = 0; v1 < fnumCorners; ++v1) CHKERRQ(PetscPrintf(PETSC_COMM_SELF, " %D", faces[fOff+v1]));
8544             CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "\n"));
8545             SETERRQ(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]);
8546           }
8547         }
8548         CHKERRQ(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure));
8549         fOff += faceSizes[f];
8550       }
8551       CHKERRQ(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
8552       CHKERRQ(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
8553     }
8554   }
8555   PetscFunctionReturn(0);
8556 }
8557 
8558 /*@
8559   DMPlexCheckGeometry - Check the geometry of mesh cells
8560 
8561   Input Parameter:
8562 . dm - The DMPlex object
8563 
8564   Notes:
8565   This is a useful diagnostic when creating meshes programmatically.
8566 
8567   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8568 
8569   Level: developer
8570 
8571 .seealso: DMCreate(), DMSetFromOptions()
8572 @*/
8573 PetscErrorCode DMPlexCheckGeometry(DM dm)
8574 {
8575   Vec            coordinates;
8576   PetscReal      detJ, J[9], refVol = 1.0;
8577   PetscReal      vol;
8578   PetscBool      periodic;
8579   PetscInt       dim, depth, dE, d, cStart, cEnd, c;
8580 
8581   PetscFunctionBegin;
8582   CHKERRQ(DMGetDimension(dm, &dim));
8583   CHKERRQ(DMGetCoordinateDim(dm, &dE));
8584   if (dim != dE) PetscFunctionReturn(0);
8585   CHKERRQ(DMPlexGetDepth(dm, &depth));
8586   CHKERRQ(DMGetPeriodicity(dm, &periodic, NULL, NULL, NULL));
8587   for (d = 0; d < dim; ++d) refVol *= 2.0;
8588   CHKERRQ(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
8589   /* Make sure local coordinates are created, because that step is collective */
8590   CHKERRQ(DMGetCoordinatesLocal(dm, &coordinates));
8591   for (c = cStart; c < cEnd; ++c) {
8592     DMPolytopeType ct;
8593     PetscInt       unsplit;
8594     PetscBool      ignoreZeroVol = PETSC_FALSE;
8595 
8596     CHKERRQ(DMPlexGetCellType(dm, c, &ct));
8597     switch (ct) {
8598       case DM_POLYTOPE_SEG_PRISM_TENSOR:
8599       case DM_POLYTOPE_TRI_PRISM_TENSOR:
8600       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8601         ignoreZeroVol = PETSC_TRUE; break;
8602       default: break;
8603     }
8604     switch (ct) {
8605       case DM_POLYTOPE_TRI_PRISM:
8606       case DM_POLYTOPE_TRI_PRISM_TENSOR:
8607       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8608       case DM_POLYTOPE_PYRAMID:
8609         continue;
8610       default: break;
8611     }
8612     CHKERRQ(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
8613     if (unsplit) continue;
8614     CHKERRQ(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ));
8615     PetscCheckFalse(detJ < -PETSC_SMALL || (detJ <= 0.0 && !ignoreZeroVol),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D of type %s is inverted, |J| = %g", c, DMPolytopeTypes[ct], (double) detJ);
8616     CHKERRQ(PetscInfo(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol));
8617     if (depth > 1 && !periodic) {
8618       CHKERRQ(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL));
8619       PetscCheckFalse(vol < -PETSC_SMALL || (vol <= 0.0 && !ignoreZeroVol),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D of type %s is inverted, vol = %g", c, DMPolytopeTypes[ct], (double) vol);
8620       CHKERRQ(PetscInfo(dm, "Cell %D FVM Volume %g\n", c, (double) vol));
8621     }
8622   }
8623   PetscFunctionReturn(0);
8624 }
8625 
8626 /*@
8627   DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex.
8628 
8629   Input Parameters:
8630 . dm - The DMPlex object
8631 
8632   Notes:
8633   This is mainly intended for debugging/testing purposes.
8634   It currently checks only meshes with no partition overlapping.
8635 
8636   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8637 
8638   Level: developer
8639 
8640 .seealso: DMGetPointSF(), DMSetFromOptions()
8641 @*/
8642 PetscErrorCode DMPlexCheckPointSF(DM dm)
8643 {
8644   PetscSF         pointSF;
8645   PetscInt        cellHeight, cStart, cEnd, l, nleaves, nroots, overlap;
8646   const PetscInt *locals, *rootdegree;
8647   PetscBool       distributed;
8648 
8649   PetscFunctionBegin;
8650   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8651   CHKERRQ(DMGetPointSF(dm, &pointSF));
8652   CHKERRQ(DMPlexIsDistributed(dm, &distributed));
8653   if (!distributed) PetscFunctionReturn(0);
8654   CHKERRQ(DMPlexGetOverlap(dm, &overlap));
8655   if (overlap) {
8656     CHKERRQ(PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping"));
8657     PetscFunctionReturn(0);
8658   }
8659   PetscCheck(pointSF,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but does not have PointSF attached");
8660   CHKERRQ(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, NULL));
8661   PetscCheckFalse(nroots < 0,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set");
8662   CHKERRQ(PetscSFComputeDegreeBegin(pointSF, &rootdegree));
8663   CHKERRQ(PetscSFComputeDegreeEnd(pointSF, &rootdegree));
8664 
8665   /* 1) check there are no faces in 2D, cells in 3D, in interface */
8666   CHKERRQ(DMPlexGetVTKCellHeight(dm, &cellHeight));
8667   CHKERRQ(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
8668   for (l = 0; l < nleaves; ++l) {
8669     const PetscInt point = locals[l];
8670 
8671     PetscCheckFalse(point >= cStart && point < cEnd,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D which is a cell", point);
8672   }
8673 
8674   /* 2) if some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
8675   for (l = 0; l < nleaves; ++l) {
8676     const PetscInt  point = locals[l];
8677     const PetscInt *cone;
8678     PetscInt        coneSize, c, idx;
8679 
8680     CHKERRQ(DMPlexGetConeSize(dm, point, &coneSize));
8681     CHKERRQ(DMPlexGetCone(dm, point, &cone));
8682     for (c = 0; c < coneSize; ++c) {
8683       if (!rootdegree[cone[c]]) {
8684         CHKERRQ(PetscFindInt(cone[c], nleaves, locals, &idx));
8685         PetscCheckFalse(idx < 0,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D but not %D from its cone", point, cone[c]);
8686       }
8687     }
8688   }
8689   PetscFunctionReturn(0);
8690 }
8691 
8692 PetscErrorCode DMPlexCheckAll_Internal(DM dm, PetscInt cellHeight)
8693 {
8694   PetscFunctionBegin;
8695   CHKERRQ(DMPlexCheckSymmetry(dm));
8696   CHKERRQ(DMPlexCheckSkeleton(dm, cellHeight));
8697   CHKERRQ(DMPlexCheckFaces(dm, cellHeight));
8698   CHKERRQ(DMPlexCheckGeometry(dm));
8699   CHKERRQ(DMPlexCheckPointSF(dm));
8700   CHKERRQ(DMPlexCheckInterfaceCones(dm));
8701   PetscFunctionReturn(0);
8702 }
8703 
8704 typedef struct cell_stats
8705 {
8706   PetscReal min, max, sum, squaresum;
8707   PetscInt  count;
8708 } cell_stats_t;
8709 
8710 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
8711 {
8712   PetscInt i, N = *len;
8713 
8714   for (i = 0; i < N; i++) {
8715     cell_stats_t *A = (cell_stats_t *) a;
8716     cell_stats_t *B = (cell_stats_t *) b;
8717 
8718     B->min = PetscMin(A->min,B->min);
8719     B->max = PetscMax(A->max,B->max);
8720     B->sum += A->sum;
8721     B->squaresum += A->squaresum;
8722     B->count += A->count;
8723   }
8724 }
8725 
8726 /*@
8727   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
8728 
8729   Collective on dm
8730 
8731   Input Parameters:
8732 + dm        - The DMPlex object
8733 . output    - If true, statistics will be displayed on stdout
8734 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output
8735 
8736   Notes:
8737   This is mainly intended for debugging/testing purposes.
8738 
8739   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8740 
8741   Level: developer
8742 
8743 .seealso: DMSetFromOptions(), DMPlexComputeOrthogonalQuality()
8744 @*/
8745 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
8746 {
8747   DM             dmCoarse;
8748   cell_stats_t   stats, globalStats;
8749   MPI_Comm       comm = PetscObjectComm((PetscObject)dm);
8750   PetscReal      *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
8751   PetscReal      limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
8752   PetscInt       cdim, cStart, cEnd, c, eStart, eEnd, count = 0;
8753   PetscMPIInt    rank,size;
8754 
8755   PetscFunctionBegin;
8756   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8757   stats.min   = PETSC_MAX_REAL;
8758   stats.max   = PETSC_MIN_REAL;
8759   stats.sum   = stats.squaresum = 0.;
8760   stats.count = 0;
8761 
8762   CHKERRMPI(MPI_Comm_size(comm, &size));
8763   CHKERRMPI(MPI_Comm_rank(comm, &rank));
8764   CHKERRQ(DMGetCoordinateDim(dm,&cdim));
8765   CHKERRQ(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ));
8766   CHKERRQ(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd));
8767   CHKERRQ(DMPlexGetDepthStratum(dm,1,&eStart,&eEnd));
8768   for (c = cStart; c < cEnd; c++) {
8769     PetscInt  i;
8770     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
8771 
8772     CHKERRQ(DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ));
8773     PetscCheckFalse(detJ < 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
8774     for (i = 0; i < PetscSqr(cdim); ++i) {
8775       frobJ    += J[i] * J[i];
8776       frobInvJ += invJ[i] * invJ[i];
8777     }
8778     cond2 = frobJ * frobInvJ;
8779     cond  = PetscSqrtReal(cond2);
8780 
8781     stats.min        = PetscMin(stats.min,cond);
8782     stats.max        = PetscMax(stats.max,cond);
8783     stats.sum       += cond;
8784     stats.squaresum += cond2;
8785     stats.count++;
8786     if (output && cond > limit) {
8787       PetscSection coordSection;
8788       Vec          coordsLocal;
8789       PetscScalar *coords = NULL;
8790       PetscInt     Nv, d, clSize, cl, *closure = NULL;
8791 
8792       CHKERRQ(DMGetCoordinatesLocal(dm, &coordsLocal));
8793       CHKERRQ(DMGetCoordinateSection(dm, &coordSection));
8794       CHKERRQ(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
8795       CHKERRQ(PetscSynchronizedPrintf(comm, "[%d] Cell %D cond %g\n", rank, c, (double) cond));
8796       for (i = 0; i < Nv/cdim; ++i) {
8797         CHKERRQ(PetscSynchronizedPrintf(comm, "  Vertex %D: (", i));
8798         for (d = 0; d < cdim; ++d) {
8799           if (d > 0) CHKERRQ(PetscSynchronizedPrintf(comm, ", "));
8800           CHKERRQ(PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d])));
8801         }
8802         CHKERRQ(PetscSynchronizedPrintf(comm, ")\n"));
8803       }
8804       CHKERRQ(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
8805       for (cl = 0; cl < clSize*2; cl += 2) {
8806         const PetscInt edge = closure[cl];
8807 
8808         if ((edge >= eStart) && (edge < eEnd)) {
8809           PetscReal len;
8810 
8811           CHKERRQ(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL));
8812           CHKERRQ(PetscSynchronizedPrintf(comm, "  Edge %D: length %g\n", edge, (double) len));
8813         }
8814       }
8815       CHKERRQ(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
8816       CHKERRQ(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
8817     }
8818   }
8819   if (output) CHKERRQ(PetscSynchronizedFlush(comm, NULL));
8820 
8821   if (size > 1) {
8822     PetscMPIInt   blockLengths[2] = {4,1};
8823     MPI_Aint      blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
8824     MPI_Datatype  blockTypes[2]   = {MPIU_REAL,MPIU_INT}, statType;
8825     MPI_Op        statReduce;
8826 
8827     CHKERRMPI(MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType));
8828     CHKERRMPI(MPI_Type_commit(&statType));
8829     CHKERRMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce));
8830     CHKERRMPI(MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm));
8831     CHKERRMPI(MPI_Op_free(&statReduce));
8832     CHKERRMPI(MPI_Type_free(&statType));
8833   } else {
8834     CHKERRQ(PetscArraycpy(&globalStats,&stats,1));
8835   }
8836   if (rank == 0) {
8837     count = globalStats.count;
8838     min   = globalStats.min;
8839     max   = globalStats.max;
8840     mean  = globalStats.sum / globalStats.count;
8841     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
8842   }
8843 
8844   if (output) {
8845     CHKERRQ(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));
8846   }
8847   CHKERRQ(PetscFree2(J,invJ));
8848 
8849   CHKERRQ(DMGetCoarseDM(dm,&dmCoarse));
8850   if (dmCoarse) {
8851     PetscBool isplex;
8852 
8853     CHKERRQ(PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex));
8854     if (isplex) {
8855       CHKERRQ(DMPlexCheckCellShape(dmCoarse,output,condLimit));
8856     }
8857   }
8858   PetscFunctionReturn(0);
8859 }
8860 
8861 /*@
8862   DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with
8863   orthogonal quality below given tolerance.
8864 
8865   Collective on dm
8866 
8867   Input Parameters:
8868 + dm   - The DMPlex object
8869 . fv   - Optional PetscFV object for pre-computed cell/face centroid information
8870 - atol - [0, 1] Absolute tolerance for tagging cells.
8871 
8872   Output Parameters:
8873 + OrthQual      - Vec containing orthogonal quality per cell
8874 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE
8875 
8876   Options Database Keys:
8877 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is
8878 supported.
8879 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector.
8880 
8881   Notes:
8882   Orthogonal quality is given by the following formula:
8883 
8884   \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]
8885 
8886   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
8887   is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the
8888   current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by
8889   calculating the cosine of the angle between these vectors.
8890 
8891   Orthogonal quality ranges from 1 (best) to 0 (worst).
8892 
8893   This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for
8894   pre-computed FVM cell data, but if it is not passed in then this data will be computed.
8895 
8896   Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance.
8897 
8898   Level: intermediate
8899 
8900 .seealso: DMPlexCheckCellShape(), DMCreateLabel()
8901 @*/
8902 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel)
8903 {
8904   PetscInt                nc, cellHeight, cStart, cEnd, cell, cellIter = 0;
8905   PetscInt                *idx;
8906   PetscScalar             *oqVals;
8907   const PetscScalar       *cellGeomArr, *faceGeomArr;
8908   PetscReal               *ci, *fi, *Ai;
8909   MPI_Comm                comm;
8910   Vec                     cellgeom, facegeom;
8911   DM                      dmFace, dmCell;
8912   IS                      glob;
8913   ISLocalToGlobalMapping  ltog;
8914   PetscViewer             vwr;
8915 
8916   PetscFunctionBegin;
8917   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8918   if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);}
8919   PetscValidPointer(OrthQual, 4);
8920   PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol);
8921   CHKERRQ(PetscObjectGetComm((PetscObject) dm, &comm));
8922   CHKERRQ(DMGetDimension(dm, &nc));
8923   PetscCheckFalse(nc < 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %D)", nc);
8924   {
8925     DMPlexInterpolatedFlag interpFlag;
8926 
8927     CHKERRQ(DMPlexIsInterpolated(dm, &interpFlag));
8928     if (interpFlag != DMPLEX_INTERPOLATED_FULL) {
8929       PetscMPIInt rank;
8930 
8931       CHKERRMPI(MPI_Comm_rank(comm, &rank));
8932       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank);
8933     }
8934   }
8935   if (OrthQualLabel) {
8936     PetscValidPointer(OrthQualLabel, 5);
8937     CHKERRQ(DMCreateLabel(dm, "Orthogonal_Quality"));
8938     CHKERRQ(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel));
8939   } else {*OrthQualLabel = NULL;}
8940   CHKERRQ(DMPlexGetVTKCellHeight(dm, &cellHeight));
8941   CHKERRQ(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
8942   CHKERRQ(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob));
8943   CHKERRQ(ISLocalToGlobalMappingCreateIS(glob, &ltog));
8944   CHKERRQ(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH));
8945   CHKERRQ(VecCreate(comm, OrthQual));
8946   CHKERRQ(VecSetType(*OrthQual, VECSTANDARD));
8947   CHKERRQ(VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE));
8948   CHKERRQ(VecSetLocalToGlobalMapping(*OrthQual, ltog));
8949   CHKERRQ(VecSetUp(*OrthQual));
8950   CHKERRQ(ISDestroy(&glob));
8951   CHKERRQ(ISLocalToGlobalMappingDestroy(&ltog));
8952   CHKERRQ(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL));
8953   CHKERRQ(VecGetArrayRead(cellgeom, &cellGeomArr));
8954   CHKERRQ(VecGetArrayRead(facegeom, &faceGeomArr));
8955   CHKERRQ(VecGetDM(cellgeom, &dmCell));
8956   CHKERRQ(VecGetDM(facegeom, &dmFace));
8957   CHKERRQ(PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai));
8958   for (cell = cStart; cell < cEnd; cellIter++,cell++) {
8959     PetscInt           cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE;
8960     PetscInt           cellarr[2], *adj = NULL;
8961     PetscScalar        *cArr, *fArr;
8962     PetscReal          minvalc = 1.0, minvalf = 1.0;
8963     PetscFVCellGeom    *cg;
8964 
8965     idx[cellIter] = cell-cStart;
8966     cellarr[0] = cell;
8967     /* Make indexing into cellGeom easier */
8968     CHKERRQ(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg));
8969     CHKERRQ(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj));
8970     /* Technically 1 too big, but easier than fiddling with empty adjacency array */
8971     CHKERRQ(PetscCalloc2(adjSize, &cArr, adjSize, &fArr));
8972     for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) {
8973       PetscInt         i;
8974       const PetscInt   neigh = adj[cellneigh];
8975       PetscReal        normci = 0, normfi = 0, normai = 0;
8976       PetscFVCellGeom  *cgneigh;
8977       PetscFVFaceGeom  *fg;
8978 
8979       /* Don't count ourselves in the neighbor list */
8980       if (neigh == cell) continue;
8981       CHKERRQ(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh));
8982       cellarr[1] = neigh;
8983       {
8984         PetscInt       numcovpts;
8985         const PetscInt *covpts;
8986 
8987         CHKERRQ(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts));
8988         CHKERRQ(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg));
8989         CHKERRQ(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts));
8990       }
8991 
8992       /* Compute c_i, f_i and their norms */
8993       for (i = 0; i < nc; i++) {
8994         ci[i] = cgneigh->centroid[i] - cg->centroid[i];
8995         fi[i] = fg->centroid[i] - cg->centroid[i];
8996         Ai[i] = fg->normal[i];
8997         normci += PetscPowReal(ci[i], 2);
8998         normfi += PetscPowReal(fi[i], 2);
8999         normai += PetscPowReal(Ai[i], 2);
9000       }
9001       normci = PetscSqrtReal(normci);
9002       normfi = PetscSqrtReal(normfi);
9003       normai = PetscSqrtReal(normai);
9004 
9005       /* Normalize and compute for each face-cell-normal pair */
9006       for (i = 0; i < nc; i++) {
9007         ci[i] = ci[i]/normci;
9008         fi[i] = fi[i]/normfi;
9009         Ai[i] = Ai[i]/normai;
9010         /* PetscAbs because I don't know if normals are guaranteed to point out */
9011         cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]);
9012         fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]);
9013       }
9014       if (PetscRealPart(cArr[cellneighiter]) < minvalc) {
9015         minvalc = PetscRealPart(cArr[cellneighiter]);
9016       }
9017       if (PetscRealPart(fArr[cellneighiter]) < minvalf) {
9018         minvalf = PetscRealPart(fArr[cellneighiter]);
9019       }
9020     }
9021     CHKERRQ(PetscFree(adj));
9022     CHKERRQ(PetscFree2(cArr, fArr));
9023     /* Defer to cell if they're equal */
9024     oqVals[cellIter] = PetscMin(minvalf, minvalc);
9025     if (OrthQualLabel) {
9026       if (PetscRealPart(oqVals[cellIter]) <= atol) CHKERRQ(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE));
9027     }
9028   }
9029   CHKERRQ(VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES));
9030   CHKERRQ(VecAssemblyBegin(*OrthQual));
9031   CHKERRQ(VecAssemblyEnd(*OrthQual));
9032   CHKERRQ(VecRestoreArrayRead(cellgeom, &cellGeomArr));
9033   CHKERRQ(VecRestoreArrayRead(facegeom, &faceGeomArr));
9034   CHKERRQ(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL));
9035   if (OrthQualLabel) {
9036     if (vwr) CHKERRQ(DMLabelView(*OrthQualLabel, vwr));
9037   }
9038   CHKERRQ(PetscFree5(idx, oqVals, ci, fi, Ai));
9039   CHKERRQ(PetscViewerDestroy(&vwr));
9040   CHKERRQ(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view"));
9041   PetscFunctionReturn(0);
9042 }
9043 
9044 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect
9045  * interpolator construction */
9046 static PetscErrorCode DMGetFullDM(DM dm, DM *odm)
9047 {
9048   PetscSection   section, newSection, gsection;
9049   PetscSF        sf;
9050   PetscBool      hasConstraints, ghasConstraints;
9051 
9052   PetscFunctionBegin;
9053   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9054   PetscValidPointer(odm,2);
9055   CHKERRQ(DMGetLocalSection(dm, &section));
9056   CHKERRQ(PetscSectionHasConstraints(section, &hasConstraints));
9057   CHKERRMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm)));
9058   if (!ghasConstraints) {
9059     CHKERRQ(PetscObjectReference((PetscObject)dm));
9060     *odm = dm;
9061     PetscFunctionReturn(0);
9062   }
9063   CHKERRQ(DMClone(dm, odm));
9064   CHKERRQ(DMCopyFields(dm, *odm));
9065   CHKERRQ(DMGetLocalSection(*odm, &newSection));
9066   CHKERRQ(DMGetPointSF(*odm, &sf));
9067   CHKERRQ(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection));
9068   CHKERRQ(DMSetGlobalSection(*odm, gsection));
9069   CHKERRQ(PetscSectionDestroy(&gsection));
9070   PetscFunctionReturn(0);
9071 }
9072 
9073 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift)
9074 {
9075   DM             dmco, dmfo;
9076   Mat            interpo;
9077   Vec            rscale;
9078   Vec            cglobalo, clocal;
9079   Vec            fglobal, fglobalo, flocal;
9080   PetscBool      regular;
9081 
9082   PetscFunctionBegin;
9083   CHKERRQ(DMGetFullDM(dmc, &dmco));
9084   CHKERRQ(DMGetFullDM(dmf, &dmfo));
9085   CHKERRQ(DMSetCoarseDM(dmfo, dmco));
9086   CHKERRQ(DMPlexGetRegularRefinement(dmf, &regular));
9087   CHKERRQ(DMPlexSetRegularRefinement(dmfo, regular));
9088   CHKERRQ(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale));
9089   CHKERRQ(DMCreateGlobalVector(dmco, &cglobalo));
9090   CHKERRQ(DMCreateLocalVector(dmc, &clocal));
9091   CHKERRQ(VecSet(cglobalo, 0.));
9092   CHKERRQ(VecSet(clocal, 0.));
9093   CHKERRQ(DMCreateGlobalVector(dmf, &fglobal));
9094   CHKERRQ(DMCreateGlobalVector(dmfo, &fglobalo));
9095   CHKERRQ(DMCreateLocalVector(dmf, &flocal));
9096   CHKERRQ(VecSet(fglobal, 0.));
9097   CHKERRQ(VecSet(fglobalo, 0.));
9098   CHKERRQ(VecSet(flocal, 0.));
9099   CHKERRQ(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL));
9100   CHKERRQ(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo));
9101   CHKERRQ(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo));
9102   CHKERRQ(MatMult(interpo, cglobalo, fglobalo));
9103   CHKERRQ(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal));
9104   CHKERRQ(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal));
9105   CHKERRQ(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal));
9106   CHKERRQ(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal));
9107   *shift = fglobal;
9108   CHKERRQ(VecDestroy(&flocal));
9109   CHKERRQ(VecDestroy(&fglobalo));
9110   CHKERRQ(VecDestroy(&clocal));
9111   CHKERRQ(VecDestroy(&cglobalo));
9112   CHKERRQ(VecDestroy(&rscale));
9113   CHKERRQ(MatDestroy(&interpo));
9114   CHKERRQ(DMDestroy(&dmfo));
9115   CHKERRQ(DMDestroy(&dmco));
9116   PetscFunctionReturn(0);
9117 }
9118 
9119 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
9120 {
9121   PetscObject    shifto;
9122   Vec            shift;
9123 
9124   PetscFunctionBegin;
9125   if (!interp) {
9126     Vec rscale;
9127 
9128     CHKERRQ(DMCreateInterpolation(coarse, fine, &interp, &rscale));
9129     CHKERRQ(VecDestroy(&rscale));
9130   } else {
9131     CHKERRQ(PetscObjectReference((PetscObject)interp));
9132   }
9133   CHKERRQ(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto));
9134   if (!shifto) {
9135     CHKERRQ(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift));
9136     CHKERRQ(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift));
9137     shifto = (PetscObject) shift;
9138     CHKERRQ(VecDestroy(&shift));
9139   }
9140   shift = (Vec) shifto;
9141   CHKERRQ(MatInterpolate(interp, coarseSol, fineSol));
9142   CHKERRQ(VecAXPY(fineSol, 1.0, shift));
9143   CHKERRQ(MatDestroy(&interp));
9144   PetscFunctionReturn(0);
9145 }
9146 
9147 /* Pointwise interpolation
9148      Just code FEM for now
9149      u^f = I u^c
9150      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
9151      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
9152      I_{ij} = psi^f_i phi^c_j
9153 */
9154 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
9155 {
9156   PetscSection   gsc, gsf;
9157   PetscInt       m, n;
9158   void          *ctx;
9159   DM             cdm;
9160   PetscBool      regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE;
9161 
9162   PetscFunctionBegin;
9163   CHKERRQ(DMGetGlobalSection(dmFine, &gsf));
9164   CHKERRQ(PetscSectionGetConstrainedStorageSize(gsf, &m));
9165   CHKERRQ(DMGetGlobalSection(dmCoarse, &gsc));
9166   CHKERRQ(PetscSectionGetConstrainedStorageSize(gsc, &n));
9167 
9168   CHKERRQ(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis));
9169   CHKERRQ(MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation));
9170   CHKERRQ(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
9171   CHKERRQ(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype));
9172   CHKERRQ(DMGetApplicationContext(dmFine, &ctx));
9173 
9174   CHKERRQ(DMGetCoarseDM(dmFine, &cdm));
9175   CHKERRQ(DMPlexGetRegularRefinement(dmFine, &regular));
9176   if (!isRefined || (regular && cdm == dmCoarse)) CHKERRQ(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx));
9177   else                                            CHKERRQ(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx));
9178   CHKERRQ(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
9179   if (scaling) {
9180     /* Use naive scaling */
9181     CHKERRQ(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
9182   }
9183   PetscFunctionReturn(0);
9184 }
9185 
9186 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
9187 {
9188   VecScatter     ctx;
9189 
9190   PetscFunctionBegin;
9191   CHKERRQ(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL));
9192   CHKERRQ(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat));
9193   CHKERRQ(VecScatterDestroy(&ctx));
9194   PetscFunctionReturn(0);
9195 }
9196 
9197 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux,
9198                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
9199                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
9200                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
9201 {
9202   const PetscInt Nc = uOff[1] - uOff[0];
9203   PetscInt       c;
9204   for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0;
9205 }
9206 
9207 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass)
9208 {
9209   DM             dmc;
9210   PetscDS        ds;
9211   Vec            ones, locmass;
9212   IS             cellIS;
9213   PetscFormKey   key;
9214   PetscInt       depth;
9215 
9216   PetscFunctionBegin;
9217   CHKERRQ(DMClone(dm, &dmc));
9218   CHKERRQ(DMCopyDisc(dm, dmc));
9219   CHKERRQ(DMGetDS(dmc, &ds));
9220   CHKERRQ(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL));
9221   CHKERRQ(DMCreateGlobalVector(dmc, mass));
9222   CHKERRQ(DMGetLocalVector(dmc, &ones));
9223   CHKERRQ(DMGetLocalVector(dmc, &locmass));
9224   CHKERRQ(DMPlexGetDepth(dmc, &depth));
9225   CHKERRQ(DMGetStratumIS(dmc, "depth", depth, &cellIS));
9226   CHKERRQ(VecSet(locmass, 0.0));
9227   CHKERRQ(VecSet(ones, 1.0));
9228   key.label = NULL;
9229   key.value = 0;
9230   key.field = 0;
9231   key.part  = 0;
9232   CHKERRQ(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL));
9233   CHKERRQ(ISDestroy(&cellIS));
9234   CHKERRQ(VecSet(*mass, 0.0));
9235   CHKERRQ(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass));
9236   CHKERRQ(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass));
9237   CHKERRQ(DMRestoreLocalVector(dmc, &ones));
9238   CHKERRQ(DMRestoreLocalVector(dmc, &locmass));
9239   CHKERRQ(DMDestroy(&dmc));
9240   PetscFunctionReturn(0);
9241 }
9242 
9243 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
9244 {
9245   PetscSection   gsc, gsf;
9246   PetscInt       m, n;
9247   void          *ctx;
9248   DM             cdm;
9249   PetscBool      regular;
9250 
9251   PetscFunctionBegin;
9252   if (dmFine == dmCoarse) {
9253     DM            dmc;
9254     PetscDS       ds;
9255     PetscWeakForm wf;
9256     Vec           u;
9257     IS            cellIS;
9258     PetscFormKey  key;
9259     PetscInt      depth;
9260 
9261     CHKERRQ(DMClone(dmFine, &dmc));
9262     CHKERRQ(DMCopyDisc(dmFine, dmc));
9263     CHKERRQ(DMGetDS(dmc, &ds));
9264     CHKERRQ(PetscDSGetWeakForm(ds, &wf));
9265     CHKERRQ(PetscWeakFormClear(wf));
9266     CHKERRQ(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL));
9267     CHKERRQ(DMCreateMatrix(dmc, mass));
9268     CHKERRQ(DMGetGlobalVector(dmc, &u));
9269     CHKERRQ(DMPlexGetDepth(dmc, &depth));
9270     CHKERRQ(DMGetStratumIS(dmc, "depth", depth, &cellIS));
9271     CHKERRQ(MatZeroEntries(*mass));
9272     key.label = NULL;
9273     key.value = 0;
9274     key.field = 0;
9275     key.part  = 0;
9276     CHKERRQ(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL));
9277     CHKERRQ(ISDestroy(&cellIS));
9278     CHKERRQ(DMRestoreGlobalVector(dmc, &u));
9279     CHKERRQ(DMDestroy(&dmc));
9280   } else {
9281     CHKERRQ(DMGetGlobalSection(dmFine, &gsf));
9282     CHKERRQ(PetscSectionGetConstrainedStorageSize(gsf, &m));
9283     CHKERRQ(DMGetGlobalSection(dmCoarse, &gsc));
9284     CHKERRQ(PetscSectionGetConstrainedStorageSize(gsc, &n));
9285 
9286     CHKERRQ(MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass));
9287     CHKERRQ(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
9288     CHKERRQ(MatSetType(*mass, dmCoarse->mattype));
9289     CHKERRQ(DMGetApplicationContext(dmFine, &ctx));
9290 
9291     CHKERRQ(DMGetCoarseDM(dmFine, &cdm));
9292     CHKERRQ(DMPlexGetRegularRefinement(dmFine, &regular));
9293     if (regular && cdm == dmCoarse) CHKERRQ(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx));
9294     else                            CHKERRQ(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx));
9295   }
9296   CHKERRQ(MatViewFromOptions(*mass, NULL, "-mass_mat_view"));
9297   PetscFunctionReturn(0);
9298 }
9299 
9300 /*@
9301   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
9302 
9303   Input Parameter:
9304 . dm - The DMPlex object
9305 
9306   Output Parameter:
9307 . regular - The flag
9308 
9309   Level: intermediate
9310 
9311 .seealso: DMPlexSetRegularRefinement()
9312 @*/
9313 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
9314 {
9315   PetscFunctionBegin;
9316   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9317   PetscValidBoolPointer(regular, 2);
9318   *regular = ((DM_Plex *) dm->data)->regularRefinement;
9319   PetscFunctionReturn(0);
9320 }
9321 
9322 /*@
9323   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
9324 
9325   Input Parameters:
9326 + dm - The DMPlex object
9327 - regular - The flag
9328 
9329   Level: intermediate
9330 
9331 .seealso: DMPlexGetRegularRefinement()
9332 @*/
9333 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
9334 {
9335   PetscFunctionBegin;
9336   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9337   ((DM_Plex *) dm->data)->regularRefinement = regular;
9338   PetscFunctionReturn(0);
9339 }
9340 
9341 /* anchors */
9342 /*@
9343   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
9344   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints().
9345 
9346   not collective
9347 
9348   Input Parameter:
9349 . dm - The DMPlex object
9350 
9351   Output Parameters:
9352 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
9353 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
9354 
9355   Level: intermediate
9356 
9357 .seealso: DMPlexSetAnchors(), DMGetDefaultConstraints(), DMSetDefaultConstraints()
9358 @*/
9359 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
9360 {
9361   DM_Plex *plex = (DM_Plex *)dm->data;
9362 
9363   PetscFunctionBegin;
9364   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9365   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) CHKERRQ((*plex->createanchors)(dm));
9366   if (anchorSection) *anchorSection = plex->anchorSection;
9367   if (anchorIS) *anchorIS = plex->anchorIS;
9368   PetscFunctionReturn(0);
9369 }
9370 
9371 /*@
9372   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
9373   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
9374   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
9375 
9376   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
9377   DMGetDefaultConstraints() and filling in the entries in the constraint matrix.
9378 
9379   collective on dm
9380 
9381   Input Parameters:
9382 + dm - The DMPlex object
9383 . 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).
9384 - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
9385 
9386   The reference counts of anchorSection and anchorIS are incremented.
9387 
9388   Level: intermediate
9389 
9390 .seealso: DMPlexGetAnchors(), DMGetDefaultConstraints(), DMSetDefaultConstraints()
9391 @*/
9392 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
9393 {
9394   DM_Plex        *plex = (DM_Plex *)dm->data;
9395   PetscMPIInt    result;
9396 
9397   PetscFunctionBegin;
9398   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9399   if (anchorSection) {
9400     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
9401     CHKERRMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result));
9402     PetscCheckFalse(result != MPI_CONGRUENT && result != MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
9403   }
9404   if (anchorIS) {
9405     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
9406     CHKERRMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result));
9407     PetscCheckFalse(result != MPI_CONGRUENT && result != MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
9408   }
9409 
9410   CHKERRQ(PetscObjectReference((PetscObject)anchorSection));
9411   CHKERRQ(PetscSectionDestroy(&plex->anchorSection));
9412   plex->anchorSection = anchorSection;
9413 
9414   CHKERRQ(PetscObjectReference((PetscObject)anchorIS));
9415   CHKERRQ(ISDestroy(&plex->anchorIS));
9416   plex->anchorIS = anchorIS;
9417 
9418   if (PetscUnlikelyDebug(anchorIS && anchorSection)) {
9419     PetscInt size, a, pStart, pEnd;
9420     const PetscInt *anchors;
9421 
9422     CHKERRQ(PetscSectionGetChart(anchorSection,&pStart,&pEnd));
9423     CHKERRQ(ISGetLocalSize(anchorIS,&size));
9424     CHKERRQ(ISGetIndices(anchorIS,&anchors));
9425     for (a = 0; a < size; a++) {
9426       PetscInt p;
9427 
9428       p = anchors[a];
9429       if (p >= pStart && p < pEnd) {
9430         PetscInt dof;
9431 
9432         CHKERRQ(PetscSectionGetDof(anchorSection,p,&dof));
9433         if (dof) {
9434 
9435           CHKERRQ(ISRestoreIndices(anchorIS,&anchors));
9436           SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
9437         }
9438       }
9439     }
9440     CHKERRQ(ISRestoreIndices(anchorIS,&anchors));
9441   }
9442   /* reset the generic constraints */
9443   CHKERRQ(DMSetDefaultConstraints(dm,NULL,NULL,NULL));
9444   PetscFunctionReturn(0);
9445 }
9446 
9447 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
9448 {
9449   PetscSection anchorSection;
9450   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
9451 
9452   PetscFunctionBegin;
9453   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9454   CHKERRQ(DMPlexGetAnchors(dm,&anchorSection,NULL));
9455   CHKERRQ(PetscSectionCreate(PETSC_COMM_SELF,cSec));
9456   CHKERRQ(PetscSectionGetNumFields(section,&numFields));
9457   if (numFields) {
9458     PetscInt f;
9459     CHKERRQ(PetscSectionSetNumFields(*cSec,numFields));
9460 
9461     for (f = 0; f < numFields; f++) {
9462       PetscInt numComp;
9463 
9464       CHKERRQ(PetscSectionGetFieldComponents(section,f,&numComp));
9465       CHKERRQ(PetscSectionSetFieldComponents(*cSec,f,numComp));
9466     }
9467   }
9468   CHKERRQ(PetscSectionGetChart(anchorSection,&pStart,&pEnd));
9469   CHKERRQ(PetscSectionGetChart(section,&sStart,&sEnd));
9470   pStart = PetscMax(pStart,sStart);
9471   pEnd   = PetscMin(pEnd,sEnd);
9472   pEnd   = PetscMax(pStart,pEnd);
9473   CHKERRQ(PetscSectionSetChart(*cSec,pStart,pEnd));
9474   for (p = pStart; p < pEnd; p++) {
9475     CHKERRQ(PetscSectionGetDof(anchorSection,p,&dof));
9476     if (dof) {
9477       CHKERRQ(PetscSectionGetDof(section,p,&dof));
9478       CHKERRQ(PetscSectionSetDof(*cSec,p,dof));
9479       for (f = 0; f < numFields; f++) {
9480         CHKERRQ(PetscSectionGetFieldDof(section,p,f,&dof));
9481         CHKERRQ(PetscSectionSetFieldDof(*cSec,p,f,dof));
9482       }
9483     }
9484   }
9485   CHKERRQ(PetscSectionSetUp(*cSec));
9486   CHKERRQ(PetscObjectSetName((PetscObject) *cSec, "Constraint Section"));
9487   PetscFunctionReturn(0);
9488 }
9489 
9490 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
9491 {
9492   PetscSection   aSec;
9493   PetscInt       pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
9494   const PetscInt *anchors;
9495   PetscInt       numFields, f;
9496   IS             aIS;
9497   MatType        mtype;
9498   PetscBool      iscuda,iskokkos;
9499 
9500   PetscFunctionBegin;
9501   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9502   CHKERRQ(PetscSectionGetStorageSize(cSec, &m));
9503   CHKERRQ(PetscSectionGetStorageSize(section, &n));
9504   CHKERRQ(MatCreate(PETSC_COMM_SELF,cMat));
9505   CHKERRQ(MatSetSizes(*cMat,m,n,m,n));
9506   CHKERRQ(PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda));
9507   if (!iscuda) CHKERRQ(PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda));
9508   CHKERRQ(PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos));
9509   if (!iskokkos) CHKERRQ(PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos));
9510   if (iscuda) mtype = MATSEQAIJCUSPARSE;
9511   else if (iskokkos) mtype = MATSEQAIJKOKKOS;
9512   else mtype = MATSEQAIJ;
9513   CHKERRQ(MatSetType(*cMat,mtype));
9514   CHKERRQ(DMPlexGetAnchors(dm,&aSec,&aIS));
9515   CHKERRQ(ISGetIndices(aIS,&anchors));
9516   /* cSec will be a subset of aSec and section */
9517   CHKERRQ(PetscSectionGetChart(cSec,&pStart,&pEnd));
9518   CHKERRQ(PetscSectionGetChart(section,&sStart,&sEnd));
9519   CHKERRQ(PetscMalloc1(m+1,&i));
9520   i[0] = 0;
9521   CHKERRQ(PetscSectionGetNumFields(section,&numFields));
9522   for (p = pStart; p < pEnd; p++) {
9523     PetscInt rDof, rOff, r;
9524 
9525     CHKERRQ(PetscSectionGetDof(aSec,p,&rDof));
9526     if (!rDof) continue;
9527     CHKERRQ(PetscSectionGetOffset(aSec,p,&rOff));
9528     if (numFields) {
9529       for (f = 0; f < numFields; f++) {
9530         annz = 0;
9531         for (r = 0; r < rDof; r++) {
9532           a = anchors[rOff + r];
9533           if (a < sStart || a >= sEnd) continue;
9534           CHKERRQ(PetscSectionGetFieldDof(section,a,f,&aDof));
9535           annz += aDof;
9536         }
9537         CHKERRQ(PetscSectionGetFieldDof(cSec,p,f,&dof));
9538         CHKERRQ(PetscSectionGetFieldOffset(cSec,p,f,&off));
9539         for (q = 0; q < dof; q++) {
9540           i[off + q + 1] = i[off + q] + annz;
9541         }
9542       }
9543     } else {
9544       annz = 0;
9545       CHKERRQ(PetscSectionGetDof(cSec,p,&dof));
9546       for (q = 0; q < dof; q++) {
9547         a = anchors[rOff + q];
9548         if (a < sStart || a >= sEnd) continue;
9549         CHKERRQ(PetscSectionGetDof(section,a,&aDof));
9550         annz += aDof;
9551       }
9552       CHKERRQ(PetscSectionGetDof(cSec,p,&dof));
9553       CHKERRQ(PetscSectionGetOffset(cSec,p,&off));
9554       for (q = 0; q < dof; q++) {
9555         i[off + q + 1] = i[off + q] + annz;
9556       }
9557     }
9558   }
9559   nnz = i[m];
9560   CHKERRQ(PetscMalloc1(nnz,&j));
9561   offset = 0;
9562   for (p = pStart; p < pEnd; p++) {
9563     if (numFields) {
9564       for (f = 0; f < numFields; f++) {
9565         CHKERRQ(PetscSectionGetFieldDof(cSec,p,f,&dof));
9566         for (q = 0; q < dof; q++) {
9567           PetscInt rDof, rOff, r;
9568           CHKERRQ(PetscSectionGetDof(aSec,p,&rDof));
9569           CHKERRQ(PetscSectionGetOffset(aSec,p,&rOff));
9570           for (r = 0; r < rDof; r++) {
9571             PetscInt s;
9572 
9573             a = anchors[rOff + r];
9574             if (a < sStart || a >= sEnd) continue;
9575             CHKERRQ(PetscSectionGetFieldDof(section,a,f,&aDof));
9576             CHKERRQ(PetscSectionGetFieldOffset(section,a,f,&aOff));
9577             for (s = 0; s < aDof; s++) {
9578               j[offset++] = aOff + s;
9579             }
9580           }
9581         }
9582       }
9583     } else {
9584       CHKERRQ(PetscSectionGetDof(cSec,p,&dof));
9585       for (q = 0; q < dof; q++) {
9586         PetscInt rDof, rOff, r;
9587         CHKERRQ(PetscSectionGetDof(aSec,p,&rDof));
9588         CHKERRQ(PetscSectionGetOffset(aSec,p,&rOff));
9589         for (r = 0; r < rDof; r++) {
9590           PetscInt s;
9591 
9592           a = anchors[rOff + r];
9593           if (a < sStart || a >= sEnd) continue;
9594           CHKERRQ(PetscSectionGetDof(section,a,&aDof));
9595           CHKERRQ(PetscSectionGetOffset(section,a,&aOff));
9596           for (s = 0; s < aDof; s++) {
9597             j[offset++] = aOff + s;
9598           }
9599         }
9600       }
9601     }
9602   }
9603   CHKERRQ(MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL));
9604   CHKERRQ(PetscFree(i));
9605   CHKERRQ(PetscFree(j));
9606   CHKERRQ(ISRestoreIndices(aIS,&anchors));
9607   PetscFunctionReturn(0);
9608 }
9609 
9610 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
9611 {
9612   DM_Plex        *plex = (DM_Plex *)dm->data;
9613   PetscSection   anchorSection, section, cSec;
9614   Mat            cMat;
9615 
9616   PetscFunctionBegin;
9617   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9618   CHKERRQ(DMPlexGetAnchors(dm,&anchorSection,NULL));
9619   if (anchorSection) {
9620     PetscInt Nf;
9621 
9622     CHKERRQ(DMGetLocalSection(dm,&section));
9623     CHKERRQ(DMPlexCreateConstraintSection_Anchors(dm,section,&cSec));
9624     CHKERRQ(DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat));
9625     CHKERRQ(DMGetNumFields(dm,&Nf));
9626     if (Nf && plex->computeanchormatrix) CHKERRQ((*plex->computeanchormatrix)(dm,section,cSec,cMat));
9627     CHKERRQ(DMSetDefaultConstraints(dm,cSec,cMat,NULL));
9628     CHKERRQ(PetscSectionDestroy(&cSec));
9629     CHKERRQ(MatDestroy(&cMat));
9630   }
9631   PetscFunctionReturn(0);
9632 }
9633 
9634 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
9635 {
9636   IS             subis;
9637   PetscSection   section, subsection;
9638 
9639   PetscFunctionBegin;
9640   CHKERRQ(DMGetLocalSection(dm, &section));
9641   PetscCheck(section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
9642   PetscCheck(subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
9643   /* Create subdomain */
9644   CHKERRQ(DMPlexFilter(dm, label, value, subdm));
9645   /* Create submodel */
9646   CHKERRQ(DMPlexGetSubpointIS(*subdm, &subis));
9647   CHKERRQ(PetscSectionCreateSubmeshSection(section, subis, &subsection));
9648   CHKERRQ(DMSetLocalSection(*subdm, subsection));
9649   CHKERRQ(PetscSectionDestroy(&subsection));
9650   CHKERRQ(DMCopyDisc(dm, *subdm));
9651   /* Create map from submodel to global model */
9652   if (is) {
9653     PetscSection    sectionGlobal, subsectionGlobal;
9654     IS              spIS;
9655     const PetscInt *spmap;
9656     PetscInt       *subIndices;
9657     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
9658     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
9659 
9660     CHKERRQ(DMPlexGetSubpointIS(*subdm, &spIS));
9661     CHKERRQ(ISGetIndices(spIS, &spmap));
9662     CHKERRQ(PetscSectionGetNumFields(section, &Nf));
9663     CHKERRQ(DMGetGlobalSection(dm, &sectionGlobal));
9664     CHKERRQ(DMGetGlobalSection(*subdm, &subsectionGlobal));
9665     CHKERRQ(PetscSectionGetChart(subsection, &pStart, &pEnd));
9666     for (p = pStart; p < pEnd; ++p) {
9667       PetscInt gdof, pSubSize  = 0;
9668 
9669       CHKERRQ(PetscSectionGetDof(sectionGlobal, p, &gdof));
9670       if (gdof > 0) {
9671         for (f = 0; f < Nf; ++f) {
9672           PetscInt fdof, fcdof;
9673 
9674           CHKERRQ(PetscSectionGetFieldDof(subsection, p, f, &fdof));
9675           CHKERRQ(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof));
9676           pSubSize += fdof-fcdof;
9677         }
9678         subSize += pSubSize;
9679         if (pSubSize) {
9680           if (bs < 0) {
9681             bs = pSubSize;
9682           } else if (bs != pSubSize) {
9683             /* Layout does not admit a pointwise block size */
9684             bs = 1;
9685           }
9686         }
9687       }
9688     }
9689     /* Must have same blocksize on all procs (some might have no points) */
9690     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
9691     CHKERRQ(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax));
9692     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
9693     else                            {bs = bsMinMax[0];}
9694     CHKERRQ(PetscMalloc1(subSize, &subIndices));
9695     for (p = pStart; p < pEnd; ++p) {
9696       PetscInt gdof, goff;
9697 
9698       CHKERRQ(PetscSectionGetDof(subsectionGlobal, p, &gdof));
9699       if (gdof > 0) {
9700         const PetscInt point = spmap[p];
9701 
9702         CHKERRQ(PetscSectionGetOffset(sectionGlobal, point, &goff));
9703         for (f = 0; f < Nf; ++f) {
9704           PetscInt fdof, fcdof, fc, f2, poff = 0;
9705 
9706           /* Can get rid of this loop by storing field information in the global section */
9707           for (f2 = 0; f2 < f; ++f2) {
9708             CHKERRQ(PetscSectionGetFieldDof(section, p, f2, &fdof));
9709             CHKERRQ(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof));
9710             poff += fdof-fcdof;
9711           }
9712           CHKERRQ(PetscSectionGetFieldDof(section, p, f, &fdof));
9713           CHKERRQ(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
9714           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
9715             subIndices[subOff] = goff+poff+fc;
9716           }
9717         }
9718       }
9719     }
9720     CHKERRQ(ISRestoreIndices(spIS, &spmap));
9721     CHKERRQ(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is));
9722     if (bs > 1) {
9723       /* We need to check that the block size does not come from non-contiguous fields */
9724       PetscInt i, j, set = 1;
9725       for (i = 0; i < subSize; i += bs) {
9726         for (j = 0; j < bs; ++j) {
9727           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
9728         }
9729       }
9730       if (set) CHKERRQ(ISSetBlockSize(*is, bs));
9731     }
9732     /* Attach nullspace */
9733     for (f = 0; f < Nf; ++f) {
9734       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
9735       if ((*subdm)->nullspaceConstructors[f]) break;
9736     }
9737     if (f < Nf) {
9738       MatNullSpace nullSpace;
9739       CHKERRQ((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace));
9740 
9741       CHKERRQ(PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace));
9742       CHKERRQ(MatNullSpaceDestroy(&nullSpace));
9743     }
9744   }
9745   PetscFunctionReturn(0);
9746 }
9747 
9748 /*@
9749   DMPlexMonitorThroughput - Report the cell throughput of FE integration
9750 
9751   Input Parameter:
9752 - dm - The DM
9753 
9754   Level: developer
9755 
9756   Options Database Keys:
9757 . -dm_plex_monitor_throughput - Activate the monitor
9758 
9759 .seealso: DMSetFromOptions(), DMPlexCreate()
9760 @*/
9761 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy)
9762 {
9763 #if defined(PETSC_USE_LOG)
9764   PetscStageLog      stageLog;
9765   PetscLogEvent      event;
9766   PetscLogStage      stage;
9767   PetscEventPerfInfo eventInfo;
9768   PetscReal          cellRate, flopRate;
9769   PetscInt           cStart, cEnd, Nf, N;
9770   const char        *name;
9771 #endif
9772 
9773   PetscFunctionBegin;
9774   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9775 #if defined(PETSC_USE_LOG)
9776   CHKERRQ(PetscObjectGetName((PetscObject) dm, &name));
9777   CHKERRQ(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
9778   CHKERRQ(DMGetNumFields(dm, &Nf));
9779   CHKERRQ(PetscLogGetStageLog(&stageLog));
9780   CHKERRQ(PetscStageLogGetCurrent(stageLog, &stage));
9781   CHKERRQ(PetscLogEventGetId("DMPlexResidualFE", &event));
9782   CHKERRQ(PetscLogEventGetPerfInfo(stage, event, &eventInfo));
9783   N        = (cEnd - cStart)*Nf*eventInfo.count;
9784   flopRate = eventInfo.flops/eventInfo.time;
9785   cellRate = N/eventInfo.time;
9786   CHKERRQ(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)));
9787 #else
9788   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log.");
9789 #endif
9790   PetscFunctionReturn(0);
9791 }
9792