xref: /petsc/src/dm/impls/plex/plex.c (revision ae1ee55146a7ad071171b861759b85940c7e5c67)
1 #include <petsc/private/dmpleximpl.h> /*I      "petscdmplex.h"   I*/
2 #include <petsc/private/dmlabelimpl.h>
3 #include <petsc/private/isimpl.h>
4 #include <petsc/private/vecimpl.h>
5 #include <petsc/private/glvisvecimpl.h>
6 #include <petscsf.h>
7 #include <petscds.h>
8 #include <petscdraw.h>
9 #include <petscdmfield.h>
10 #include <petscdmplextransform.h>
11 #include <petscblaslapack.h>
12 
13 /* Logging support */
14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeMultistage, 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_CreateBoxSFC, 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;
15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate;
16 PetscLogEvent DMPLEX_DistributionView, DMPLEX_DistributionLoad;
17 
18 PetscBool  Plexcite       = PETSC_FALSE;
19 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n"
20                             "title     = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n"
21                             "author    = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n"
22                             "journal   = {SIAM Journal on Scientific Computing},\n"
23                             "volume    = {38},\n"
24                             "number    = {5},\n"
25                             "pages     = {S143--S155},\n"
26                             "eprint    = {http://arxiv.org/abs/1506.07749},\n"
27                             "doi       = {10.1137/15M1026092},\n"
28                             "year      = {2016},\n"
29                             "petsc_uses={DMPlex},\n}\n";
30 
31 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
32 
33 /*@
34   DMPlexIsSimplex - Is the first cell in this mesh a simplex?
35 
36   Input Parameter:
37 . dm - The `DMPLEX` object
38 
39   Output Parameter:
40 . simplex - Flag checking for a simplex
41 
42   Level: intermediate
43 
44   Note:
45   This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
46   If the mesh has no cells, this returns `PETSC_FALSE`.
47 
48 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()`
49 @*/
DMPlexIsSimplex(DM dm,PetscBool * simplex)50 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex)
51 {
52   DMPolytopeType ct;
53   PetscInt       cStart, cEnd;
54 
55   PetscFunctionBegin;
56   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
57   if (cEnd <= cStart) {
58     *simplex = PETSC_FALSE;
59     PetscFunctionReturn(PETSC_SUCCESS);
60   }
61   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
62   *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
63   PetscFunctionReturn(PETSC_SUCCESS);
64 }
65 
66 /*@
67   DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells
68 
69   Input Parameters:
70 + dm     - The `DMPLEX` object
71 - height - The cell height in the Plex, 0 is the default
72 
73   Output Parameters:
74 + cStart - The first "normal" cell, pass `NULL` if not needed
75 - cEnd   - The upper bound on "normal" cells, pass `NULL` if not needed
76 
77   Level: developer
78 
79   Note:
80   This function requires that tensor cells are ordered last.
81 
82 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()`
83 @*/
DMPlexGetSimplexOrBoxCells(DM dm,PetscInt height,PeOp PetscInt * cStart,PeOp PetscInt * cEnd)84 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PeOp PetscInt *cStart, PeOp PetscInt *cEnd)
85 {
86   DMLabel         ctLabel;
87   IS              valueIS;
88   const PetscInt *ctypes;
89   PetscBool       found = PETSC_FALSE;
90   PetscInt        Nct, cS = PETSC_INT_MAX, cE = 0;
91 
92   PetscFunctionBegin;
93   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
94   PetscCall(DMLabelGetValueIS(ctLabel, &valueIS));
95   PetscCall(ISGetLocalSize(valueIS, &Nct));
96   PetscCall(ISGetIndices(valueIS, &ctypes));
97   for (PetscInt t = 0; t < Nct; ++t) {
98     const DMPolytopeType ct = (DMPolytopeType)ctypes[t];
99     PetscInt             ctS, ctE, ht;
100 
101     if (ct == DM_POLYTOPE_UNKNOWN) {
102       // If any cells are not typed, just use all cells
103       PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd));
104       break;
105     }
106     if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue;
107     PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE));
108     if (ctS >= ctE) continue;
109     // Check that a point has the right height
110     PetscCall(DMPlexGetPointHeight(dm, ctS, &ht));
111     if (ht != height) continue;
112     cS    = PetscMin(cS, ctS);
113     cE    = PetscMax(cE, ctE);
114     found = PETSC_TRUE;
115   }
116   if (!Nct || !found) cS = cE = 0;
117   PetscCall(ISDestroy(&valueIS));
118   // Reset label for fast lookup
119   PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel));
120   if (cStart) *cStart = cS;
121   if (cEnd) *cEnd = cE;
122   PetscFunctionReturn(PETSC_SUCCESS);
123 }
124 
DMPlexGetFieldTypes_Internal(DM dm,PetscSection section,PetscInt field,PetscInt * types,PetscInt ** ssStart,PetscInt ** ssEnd,PetscViewerVTKFieldType ** sft)125 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft)
126 {
127   PetscInt                 cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t;
128   PetscInt                *sStart, *sEnd;
129   PetscViewerVTKFieldType *ft;
130   PetscInt                 vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1];
131   DMLabel                  depthLabel, ctLabel;
132 
133   PetscFunctionBegin;
134   /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */
135   PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1));
136   PetscCall(DMGetCoordinateDim(dm, &cdim));
137   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
138   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
139   if (field >= 0) {
140     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES]));
141   } else {
142     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES]));
143   }
144 
145   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
146   PetscCall(DMPlexGetDepth(dm, &depth));
147   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
148   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
149   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
150     const DMPolytopeType ict = (DMPolytopeType)c;
151     PetscInt             dep;
152 
153     if (ict == DM_POLYTOPE_FV_GHOST) continue;
154     PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd));
155     if (pStart >= 0) {
156       PetscCall(DMLabelGetValue(depthLabel, cStart, &dep));
157       if (dep != depth - cellHeight) continue;
158     }
159     if (field >= 0) {
160       if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c]));
161     } else {
162       if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c]));
163     }
164   }
165 
166   PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
167   *types = 0;
168 
169   for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) {
170     if (globalvcdof[c]) ++(*types);
171   }
172 
173   PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft));
174   t = 0;
175   if (globalvcdof[DM_NUM_POLYTOPES]) {
176     sStart[t] = vStart;
177     sEnd[t]   = vEnd;
178     ft[t]     = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
179     ++t;
180   }
181 
182   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
183     if (globalvcdof[c]) {
184       const DMPolytopeType ict = (DMPolytopeType)c;
185 
186       PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd));
187       sStart[t] = cStart;
188       sEnd[t]   = cEnd;
189       ft[t]     = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD;
190       ++t;
191     }
192   }
193 
194   if (!*types) {
195     if (field >= 0) {
196       const char *fieldname;
197 
198       PetscCall(PetscSectionGetFieldName(section, field, &fieldname));
199       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname));
200     } else {
201       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n"));
202     }
203   }
204 
205   *ssStart = sStart;
206   *ssEnd   = sEnd;
207   *sft     = ft;
208   PetscFunctionReturn(PETSC_SUCCESS);
209 }
210 
DMPlexRestoreFieldTypes_Internal(DM dm,PetscSection section,PetscInt field,PetscInt * types,PetscInt ** sStart,PetscInt ** sEnd,PetscViewerVTKFieldType ** ft)211 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft)
212 {
213   PetscFunctionBegin;
214   PetscCall(PetscFree3(*sStart, *sEnd, *ft));
215   PetscFunctionReturn(PETSC_SUCCESS);
216 }
217 
DMPlexGetFieldType_Internal(DM dm,PetscSection section,PetscInt field,PetscInt * sStart,PetscInt * sEnd,PetscViewerVTKFieldType * ft)218 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
219 {
220   PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd;
221   PetscInt vcdof[2] = {0, 0}, globalvcdof[2];
222 
223   PetscFunctionBegin;
224   *ft = PETSC_VTK_INVALID;
225   PetscCall(DMGetCoordinateDim(dm, &cdim));
226   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
227   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
228   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
229   if (field >= 0) {
230     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]));
231     if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]));
232   } else {
233     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0]));
234     if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1]));
235   }
236   PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
237   if (globalvcdof[0]) {
238     *sStart = vStart;
239     *sEnd   = vEnd;
240     if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
241     else *ft = PETSC_VTK_POINT_FIELD;
242   } else if (globalvcdof[1]) {
243     *sStart = cStart;
244     *sEnd   = cEnd;
245     if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
246     else *ft = PETSC_VTK_CELL_FIELD;
247   } else {
248     if (field >= 0) {
249       const char *fieldname;
250 
251       PetscCall(PetscSectionGetFieldName(section, field, &fieldname));
252       PetscCall(PetscInfo(dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname));
253     } else {
254       PetscCall(PetscInfo(dm, "Could not classify VTK output type of section\n"));
255     }
256   }
257   PetscFunctionReturn(PETSC_SUCCESS);
258 }
259 
260 /*@
261   DMPlexVecView1D - Plot many 1D solutions on the same line graph
262 
263   Collective
264 
265   Input Parameters:
266 + dm     - The `DMPLEX` object
267 . n      - The number of vectors
268 . u      - The array of local vectors
269 - viewer - The `PetscViewer`
270 
271   Level: advanced
272 
273 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()`
274 @*/
DMPlexVecView1D(DM dm,PetscInt n,Vec u[],PetscViewer viewer)275 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer)
276 {
277   DM                 cdm;
278   PetscDS            ds;
279   PetscDraw          draw = NULL;
280   PetscDrawLG        lg;
281   Vec                coordinates;
282   const PetscScalar *coords, **sol;
283   PetscReal         *vals;
284   PetscInt          *Nc;
285   PetscInt           Nf, Nl, vStart, vEnd, eStart, eEnd;
286   char             **names;
287 
288   PetscFunctionBegin;
289   PetscCall(DMGetCoordinateDM(dm, &cdm));
290   PetscCall(DMGetDS(dm, &ds));
291   PetscCall(PetscDSGetNumFields(ds, &Nf));
292   PetscCall(PetscDSGetTotalComponents(ds, &Nl));
293   PetscCall(PetscDSGetComponents(ds, &Nc));
294 
295   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
296   if (!draw) PetscFunctionReturn(PETSC_SUCCESS);
297   PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg));
298 
299   PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals));
300   for (PetscInt i = 0, l = 0; i < n; ++i) {
301     const char *vname;
302 
303     PetscCall(PetscObjectGetName((PetscObject)u[i], &vname));
304     for (PetscInt f = 0; f < Nf; ++f) {
305       PetscObject disc;
306       const char *fname;
307       char        tmpname[PETSC_MAX_PATH_LEN];
308 
309       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
310       /* TODO Create names for components */
311       for (PetscInt c = 0; c < Nc[f]; ++c, ++l) {
312         PetscCall(PetscObjectGetName(disc, &fname));
313         PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname)));
314         PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname)));
315         PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname)));
316         PetscCall(PetscStrallocpy(tmpname, &names[l]));
317       }
318     }
319   }
320   PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names));
321   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
322   PetscCall(VecGetArrayRead(coordinates, &coords));
323   for (PetscInt i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i]));
324   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
325   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
326   PetscSection s;
327   PetscInt     cdof, vdof;
328 
329   PetscCall(DMGetLocalSection(dm, &s));
330   PetscCall(PetscSectionGetDof(s, eStart, &cdof));
331   PetscCall(PetscSectionGetDof(s, vStart, &vdof));
332   if (cdof) {
333     if (vdof) {
334       // P_2
335       PetscInt vFirst = -1;
336 
337       for (PetscInt e = eStart; e < eEnd; ++e) {
338         PetscScalar    *xa, *xb, *svals;
339         const PetscInt *cone;
340 
341         PetscCall(DMPlexGetCone(dm, e, &cone));
342         PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa));
343         PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb));
344         if (e == eStart) vFirst = cone[0];
345         for (PetscInt i = 0; i < n; ++i) {
346           PetscCall(DMPlexPointLocalRead(dm, cone[0], sol[i], &svals));
347           for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]);
348         }
349         PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xa[0]), vals));
350         if (e == eEnd - 1 && cone[1] != vFirst) {
351           for (PetscInt i = 0; i < n; ++i) {
352             PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals));
353             for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]);
354           }
355           PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals));
356           for (PetscInt i = 0; i < n; ++i) {
357             PetscCall(DMPlexPointLocalRead(dm, cone[1], sol[i], &svals));
358             for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]);
359           }
360           PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xb[0]), vals));
361         }
362       }
363     } else {
364       // P_0
365       for (PetscInt e = eStart; e < eEnd; ++e) {
366         PetscScalar    *xa, *xb, *svals;
367         const PetscInt *cone;
368 
369         PetscCall(DMPlexGetCone(dm, e, &cone));
370         PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa));
371         PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb));
372         for (PetscInt i = 0; i < n; ++i) {
373           PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals));
374           for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]);
375         }
376         PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals));
377       }
378     }
379   } else if (vdof) {
380     // P_1
381     for (PetscInt v = vStart; v < vEnd; ++v) {
382       PetscScalar *x, *svals;
383 
384       PetscCall(DMPlexPointLocalRead(cdm, v, coords, &x));
385       for (PetscInt i = 0; i < n; ++i) {
386         PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals));
387         for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]);
388       }
389       PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals));
390     }
391   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Discretization not supported");
392   PetscCall(VecRestoreArrayRead(coordinates, &coords));
393   for (PetscInt i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i]));
394   for (PetscInt l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l]));
395   PetscCall(PetscFree3(sol, names, vals));
396 
397   PetscCall(PetscDrawLGDraw(lg));
398   PetscCall(PetscDrawLGDestroy(&lg));
399   PetscFunctionReturn(PETSC_SUCCESS);
400 }
401 
VecView_Plex_Local_Draw_1D(Vec u,PetscViewer viewer)402 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer)
403 {
404   DM dm;
405 
406   PetscFunctionBegin;
407   PetscCall(VecGetDM(u, &dm));
408   PetscCall(DMPlexVecView1D(dm, 1, &u, viewer));
409   PetscFunctionReturn(PETSC_SUCCESS);
410 }
411 
VecView_Plex_Local_Draw_2D(Vec v,PetscViewer viewer)412 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer)
413 {
414   DM                 dm;
415   PetscSection       s;
416   PetscDraw          draw, popup;
417   DM                 cdm;
418   PetscSection       coordSection;
419   Vec                coordinates;
420   const PetscScalar *array;
421   PetscReal          lbound[3], ubound[3];
422   PetscReal          vbound[2], time;
423   PetscBool          flg;
424   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
425   const char        *name;
426   char               title[PETSC_MAX_PATH_LEN];
427 
428   PetscFunctionBegin;
429   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
430   PetscCall(VecGetDM(v, &dm));
431   PetscCall(DMGetCoordinateDim(dm, &dim));
432   PetscCall(DMGetLocalSection(dm, &s));
433   PetscCall(PetscSectionGetNumFields(s, &Nf));
434   PetscCall(DMGetCoarsenLevel(dm, &level));
435   PetscCall(DMGetCoordinateDM(dm, &cdm));
436   PetscCall(DMGetLocalSection(cdm, &coordSection));
437   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
438   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
439   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
440 
441   PetscCall(PetscObjectGetName((PetscObject)v, &name));
442   PetscCall(DMGetOutputSequenceNumber(dm, &step, &time));
443 
444   PetscCall(VecGetLocalSize(coordinates, &N));
445   PetscCall(DMGetBoundingBox(dm, lbound, ubound));
446   PetscCall(PetscDrawClear(draw));
447 
448   /* Could implement something like DMDASelectFields() */
449   for (f = 0; f < Nf; ++f) {
450     DM          fdm = dm;
451     Vec         fv  = v;
452     IS          fis;
453     char        prefix[PETSC_MAX_PATH_LEN];
454     const char *fname;
455 
456     PetscCall(PetscSectionGetFieldComponents(s, f, &Nc));
457     PetscCall(PetscSectionGetFieldName(s, f, &fname));
458 
459     if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix)));
460     else prefix[0] = '\0';
461     if (Nf > 1) {
462       PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm));
463       PetscCall(VecGetSubVector(v, fis, &fv));
464       PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix)));
465       PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix)));
466     }
467     for (comp = 0; comp < Nc; ++comp, ++w) {
468       PetscInt nmax = 2;
469 
470       PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw));
471       if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time));
472       else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time));
473       PetscCall(PetscDrawSetTitle(draw, title));
474 
475       /* TODO Get max and min only for this component */
476       PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg));
477       if (!flg) {
478         PetscCall(VecMin(fv, NULL, &vbound[0]));
479         PetscCall(VecMax(fv, NULL, &vbound[1]));
480         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
481       }
482 
483       PetscCall(PetscDrawGetPopup(draw, &popup));
484       PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1]));
485       PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1]));
486       PetscCall(VecGetArrayRead(fv, &array));
487       for (c = cStart; c < cEnd; ++c) {
488         DMPolytopeType     ct;
489         PetscScalar       *coords = NULL, *a = NULL;
490         const PetscScalar *coords_arr;
491         PetscBool          isDG;
492         PetscInt           numCoords;
493         int                color[4] = {-1, -1, -1, -1};
494 
495         PetscCall(DMPlexGetCellType(dm, c, &ct));
496         PetscCall(DMPlexPointLocalRead(fdm, c, array, &a));
497         if (a) {
498           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
499           color[1] = color[2] = color[3] = color[0];
500         } else {
501           PetscScalar *vals = NULL;
502           PetscInt     numVals, va;
503 
504           PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals));
505           if (!numVals) {
506             PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals));
507             continue;
508           }
509           PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals);
510           switch (numVals / Nc) {
511           case 1: /* P1 Clamped Segment Prism */
512           case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */
513             PetscCheck(ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a tensor segment, but it is a %s", DMPolytopeTypes[ct]);
514             for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]);
515             break;
516           case 3: /* P1 Triangle */
517           case 4: /* P1 Quadrangle */
518             PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]);
519             for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]);
520             break;
521           case 6: /* P2 Triangle */
522           case 8: /* P2 Quadrangle */
523             PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]);
524             for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]);
525             break;
526           default:
527             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc);
528           }
529           PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals));
530         }
531         PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
532         switch (numCoords) {
533         case 6:
534         case 12: /* Localized triangle */
535           PetscCall(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]));
536           break;
537         case 8:
538         case 16: /* Localized quadrilateral */
539           if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) {
540             PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1])));
541           } else {
542             PetscCall(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]));
543             PetscCall(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]));
544           }
545           break;
546         default:
547           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords);
548         }
549         PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
550       }
551       PetscCall(VecRestoreArrayRead(fv, &array));
552       PetscCall(PetscDrawFlush(draw));
553       PetscCall(PetscDrawPause(draw));
554       PetscCall(PetscDrawSave(draw));
555     }
556     if (Nf > 1) {
557       PetscCall(VecRestoreSubVector(v, fis, &fv));
558       PetscCall(ISDestroy(&fis));
559       PetscCall(DMDestroy(&fdm));
560     }
561   }
562   PetscFunctionReturn(PETSC_SUCCESS);
563 }
564 
VecView_Plex_Local_Draw(Vec v,PetscViewer viewer)565 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
566 {
567   DM        dm;
568   PetscDraw draw;
569   PetscInt  dim;
570   PetscBool isnull;
571 
572   PetscFunctionBegin;
573   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
574   PetscCall(PetscDrawIsNull(draw, &isnull));
575   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
576 
577   PetscCall(VecGetDM(v, &dm));
578   PetscCall(DMGetCoordinateDim(dm, &dim));
579   switch (dim) {
580   case 1:
581     PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));
582     break;
583   case 2:
584     PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));
585     break;
586   default:
587     SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim);
588   }
589   PetscFunctionReturn(PETSC_SUCCESS);
590 }
591 
VecView_Plex_Local_VTK(Vec v,PetscViewer viewer)592 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
593 {
594   DM                      dm;
595   Vec                     locv;
596   const char             *name;
597   PetscSection            section;
598   PetscInt                pStart, pEnd;
599   PetscInt                numFields;
600   PetscViewerVTKFieldType ft;
601 
602   PetscFunctionBegin;
603   PetscCall(VecGetDM(v, &dm));
604   PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */
605   PetscCall(PetscObjectGetName((PetscObject)v, &name));
606   PetscCall(PetscObjectSetName((PetscObject)locv, name));
607   PetscCall(VecCopy(v, locv));
608   PetscCall(DMGetLocalSection(dm, &section));
609   PetscCall(PetscSectionGetNumFields(section, &numFields));
610   if (!numFields) {
611     PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft));
612     PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv));
613   } else {
614     PetscInt f;
615 
616     for (f = 0; f < numFields; f++) {
617       PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft));
618       if (ft == PETSC_VTK_INVALID) continue;
619       PetscCall(PetscObjectReference((PetscObject)locv));
620       PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv));
621     }
622     PetscCall(VecDestroy(&locv));
623   }
624   PetscFunctionReturn(PETSC_SUCCESS);
625 }
626 
VecView_Plex_Local(Vec v,PetscViewer viewer)627 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
628 {
629   DM        dm;
630   PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns, ispython;
631 
632   PetscFunctionBegin;
633   PetscCall(VecGetDM(v, &dm));
634   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
635   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
636   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
637   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
638   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
639   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
640   PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython));
641   if (isvtk || ishdf5 || isdraw || isglvis || iscgns || ispython) {
642     PetscInt    i, numFields;
643     PetscObject fe;
644     PetscBool   fem  = PETSC_FALSE;
645     Vec         locv = v;
646     const char *name;
647     PetscInt    step;
648     PetscReal   time;
649 
650     PetscCall(DMGetNumFields(dm, &numFields));
651     for (i = 0; i < numFields; i++) {
652       PetscCall(DMGetField(dm, i, NULL, &fe));
653       if (fe->classid == PETSCFE_CLASSID) {
654         fem = PETSC_TRUE;
655         break;
656       }
657     }
658     if (fem) {
659       PetscObject isZero;
660 
661       PetscCall(DMGetLocalVector(dm, &locv));
662       PetscCall(PetscObjectGetName((PetscObject)v, &name));
663       PetscCall(PetscObjectSetName((PetscObject)locv, name));
664       PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
665       PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
666       PetscCall(VecCopy(v, locv));
667       PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
668       PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL));
669     }
670     if (isvtk) {
671       PetscCall(VecView_Plex_Local_VTK(locv, viewer));
672     } else if (ishdf5) {
673 #if defined(PETSC_HAVE_HDF5)
674       PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer));
675 #else
676       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
677 #endif
678     } else if (isdraw) {
679       PetscCall(VecView_Plex_Local_Draw(locv, viewer));
680     } else if (ispython) {
681       PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)locv));
682     } else if (isglvis) {
683       PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL));
684       PetscCall(PetscViewerGLVisSetSnapId(viewer, step));
685       PetscCall(VecView_GLVis(locv, viewer));
686     } else if (iscgns) {
687 #if defined(PETSC_HAVE_CGNS)
688       PetscCall(VecView_Plex_Local_CGNS(locv, viewer));
689 #else
690       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns");
691 #endif
692     }
693     if (fem) {
694       PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
695       PetscCall(DMRestoreLocalVector(dm, &locv));
696     }
697   } else {
698     PetscBool isseq;
699 
700     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
701     if (isseq) PetscCall(VecView_Seq(v, viewer));
702     else PetscCall(VecView_MPI(v, viewer));
703   }
704   PetscFunctionReturn(PETSC_SUCCESS);
705 }
706 
VecView_Plex(Vec v,PetscViewer viewer)707 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
708 {
709   DM        dm;
710   PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns, ispython;
711 
712   PetscFunctionBegin;
713   PetscCall(VecGetDM(v, &dm));
714   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
715   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
716   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
717   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
718   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
719   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
720   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii));
721   PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython));
722   if (isvtk || isdraw || isglvis || iscgns || ispython) {
723     Vec         locv;
724     PetscObject isZero;
725     const char *name;
726 
727     PetscCall(DMGetLocalVector(dm, &locv));
728     PetscCall(PetscObjectGetName((PetscObject)v, &name));
729     PetscCall(PetscObjectSetName((PetscObject)locv, name));
730     PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv));
731     PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv));
732     PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
733     PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
734     PetscCall(VecView_Plex_Local(locv, viewer));
735     PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
736     PetscCall(DMRestoreLocalVector(dm, &locv));
737   } else if (ishdf5) {
738 #if defined(PETSC_HAVE_HDF5)
739     PetscCall(VecView_Plex_HDF5_Internal(v, viewer));
740 #else
741     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
742 #endif
743   } else if (isexodusii) {
744 #if defined(PETSC_HAVE_EXODUSII)
745     PetscCall(VecView_PlexExodusII_Internal(v, viewer));
746 #else
747     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
748 #endif
749   } else {
750     PetscBool isseq;
751 
752     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
753     if (isseq) PetscCall(VecView_Seq(v, viewer));
754     else PetscCall(VecView_MPI(v, viewer));
755   }
756   PetscFunctionReturn(PETSC_SUCCESS);
757 }
758 
VecView_Plex_Native(Vec originalv,PetscViewer viewer)759 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
760 {
761   DM                dm;
762   MPI_Comm          comm;
763   PetscViewerFormat format;
764   Vec               v;
765   PetscBool         isvtk, ishdf5;
766 
767   PetscFunctionBegin;
768   PetscCall(VecGetDM(originalv, &dm));
769   PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm));
770   PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
771   PetscCall(PetscViewerGetFormat(viewer, &format));
772   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
773   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
774   if (format == PETSC_VIEWER_NATIVE) {
775     /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
776     /* this need a better fix */
777     if (dm->useNatural) {
778       const char *vecname;
779       PetscInt    n, nroots;
780 
781       PetscCheck(dm->sfNatural, comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
782       PetscCall(VecGetLocalSize(originalv, &n));
783       PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL));
784       PetscCheck(n == nroots, comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
785       PetscCall(DMPlexCreateNaturalVector(dm, &v));
786       PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v));
787       PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v));
788       PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname));
789       PetscCall(PetscObjectSetName((PetscObject)v, vecname));
790     } else v = originalv;
791   } else v = originalv;
792 
793   if (ishdf5) {
794 #if defined(PETSC_HAVE_HDF5)
795     PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer));
796 #else
797     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
798 #endif
799   } else if (isvtk) {
800     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
801   } else {
802     PetscBool isseq;
803 
804     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
805     if (isseq) PetscCall(VecView_Seq(v, viewer));
806     else PetscCall(VecView_MPI(v, viewer));
807   }
808   if (v != originalv) PetscCall(VecDestroy(&v));
809   PetscFunctionReturn(PETSC_SUCCESS);
810 }
811 
VecLoad_Plex_Local(Vec v,PetscViewer viewer)812 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
813 {
814   DM        dm;
815   PetscBool ishdf5;
816 
817   PetscFunctionBegin;
818   PetscCall(VecGetDM(v, &dm));
819   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
820   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
821   if (ishdf5) {
822     DM          dmBC;
823     Vec         gv;
824     const char *name;
825 
826     PetscCall(DMGetOutputDM(dm, &dmBC));
827     PetscCall(DMGetGlobalVector(dmBC, &gv));
828     PetscCall(PetscObjectGetName((PetscObject)v, &name));
829     PetscCall(PetscObjectSetName((PetscObject)gv, name));
830     PetscCall(VecLoad_Default(gv, viewer));
831     PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v));
832     PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v));
833     PetscCall(DMRestoreGlobalVector(dmBC, &gv));
834   } else PetscCall(VecLoad_Default(v, viewer));
835   PetscFunctionReturn(PETSC_SUCCESS);
836 }
837 
VecLoad_Plex(Vec v,PetscViewer viewer)838 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
839 {
840   DM        dm;
841   PetscBool ishdf5, isexodusii, iscgns;
842 
843   PetscFunctionBegin;
844   PetscCall(VecGetDM(v, &dm));
845   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
846   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
847   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii));
848   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
849   if (ishdf5) {
850 #if defined(PETSC_HAVE_HDF5)
851     PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer));
852 #else
853     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
854 #endif
855   } else if (isexodusii) {
856 #if defined(PETSC_HAVE_EXODUSII)
857     PetscCall(VecLoad_PlexExodusII_Internal(v, viewer));
858 #else
859     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
860 #endif
861   } else if (iscgns) {
862 #if defined(PETSC_HAVE_CGNS)
863     PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer));
864 #else
865     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns");
866 #endif
867   } else PetscCall(VecLoad_Default(v, viewer));
868   PetscFunctionReturn(PETSC_SUCCESS);
869 }
870 
VecLoad_Plex_Native(Vec originalv,PetscViewer viewer)871 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
872 {
873   DM                dm;
874   PetscViewerFormat format;
875   PetscBool         ishdf5;
876 
877   PetscFunctionBegin;
878   PetscCall(VecGetDM(originalv, &dm));
879   PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
880   PetscCall(PetscViewerGetFormat(viewer, &format));
881   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
882   if (format == PETSC_VIEWER_NATIVE) {
883     if (dm->useNatural) {
884       if (dm->sfNatural) {
885         if (ishdf5) {
886 #if defined(PETSC_HAVE_HDF5)
887           Vec         v;
888           const char *vecname;
889 
890           PetscCall(DMPlexCreateNaturalVector(dm, &v));
891           PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname));
892           PetscCall(PetscObjectSetName((PetscObject)v, vecname));
893           PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer));
894           PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv));
895           PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv));
896           PetscCall(VecDestroy(&v));
897 #else
898           SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
899 #endif
900         } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
901       }
902     } else PetscCall(VecLoad_Default(originalv, viewer));
903   }
904   PetscFunctionReturn(PETSC_SUCCESS);
905 }
906 
DMPlexView_Ascii_Geometry(DM dm,PetscViewer viewer)907 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
908 {
909   PetscSection       coordSection;
910   Vec                coordinates;
911   DMLabel            depthLabel, celltypeLabel;
912   const char        *name[4];
913   const PetscScalar *a;
914   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
915 
916   PetscFunctionBegin;
917   PetscCall(DMGetDimension(dm, &dim));
918   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
919   PetscCall(DMGetCoordinateSection(dm, &coordSection));
920   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
921   PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel));
922   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
923   PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd));
924   PetscCall(VecGetArrayRead(coordinates, &a));
925   name[0]       = "vertex";
926   name[1]       = "edge";
927   name[dim - 1] = "face";
928   name[dim]     = "cell";
929   for (c = cStart; c < cEnd; ++c) {
930     PetscInt *closure = NULL;
931     PetscInt  closureSize, cl, ct;
932 
933     PetscCall(DMLabelGetValue(celltypeLabel, c, &ct));
934     PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct]));
935     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
936     PetscCall(PetscViewerASCIIPushTab(viewer));
937     for (cl = 0; cl < closureSize * 2; cl += 2) {
938       PetscInt point = closure[cl], depth, dof, off, d, p;
939 
940       if ((point < pStart) || (point >= pEnd)) continue;
941       PetscCall(PetscSectionGetDof(coordSection, point, &dof));
942       if (!dof) continue;
943       PetscCall(DMLabelGetValue(depthLabel, point, &depth));
944       PetscCall(PetscSectionGetOffset(coordSection, point, &off));
945       PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point));
946       for (p = 0; p < dof / dim; ++p) {
947         PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
948         for (d = 0; d < dim; ++d) {
949           if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
950           PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d])));
951         }
952         PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
953       }
954       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
955     }
956     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
957     PetscCall(PetscViewerASCIIPopTab(viewer));
958   }
959   PetscCall(VecRestoreArrayRead(coordinates, &a));
960   PetscFunctionReturn(PETSC_SUCCESS);
961 }
962 
963 typedef enum {
964   CS_CARTESIAN,
965   CS_POLAR,
966   CS_CYLINDRICAL,
967   CS_SPHERICAL
968 } CoordSystem;
969 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL};
970 
DMPlexView_Ascii_Coordinates(PetscViewer viewer,CoordSystem cs,PetscInt dim,const PetscScalar x[])971 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[])
972 {
973   PetscInt i;
974 
975   PetscFunctionBegin;
976   if (dim > 3) {
977     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i])));
978   } else {
979     PetscReal coords[3], trcoords[3] = {0., 0., 0.};
980 
981     for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]);
982     switch (cs) {
983     case CS_CARTESIAN:
984       for (i = 0; i < dim; ++i) trcoords[i] = coords[i];
985       break;
986     case CS_POLAR:
987       PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim);
988       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
989       trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
990       break;
991     case CS_CYLINDRICAL:
992       PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
993       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
994       trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
995       trcoords[2] = coords[2];
996       break;
997     case CS_SPHERICAL:
998       PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
999       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2]));
1000       trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]);
1001       trcoords[2] = PetscAtan2Real(coords[1], coords[0]);
1002       break;
1003     }
1004     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i]));
1005   }
1006   PetscFunctionReturn(PETSC_SUCCESS);
1007 }
1008 
DMPlexView_Ascii(DM dm,PetscViewer viewer)1009 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
1010 {
1011   DM_Plex          *mesh = (DM_Plex *)dm->data;
1012   DM                cdm, cdmCell;
1013   PetscSection      coordSection, coordSectionCell;
1014   Vec               coordinates, coordinatesCell;
1015   PetscViewerFormat format;
1016 
1017   PetscFunctionBegin;
1018   PetscCall(PetscViewerGetFormat(viewer, &format));
1019   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1020     const char *name;
1021     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
1022     PetscInt    pStart, pEnd, p, numLabels, l;
1023     PetscMPIInt rank, size;
1024 
1025     PetscCall(DMGetCoordinateDM(dm, &cdm));
1026     PetscCall(DMGetCoordinateSection(dm, &coordSection));
1027     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
1028     PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
1029     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
1030     PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
1031     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1032     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
1033     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
1034     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1035     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
1036     PetscCall(DMGetDimension(dm, &dim));
1037     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
1038     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
1039     else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
1040     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
1041     PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n"));
1042     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
1043     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize));
1044     for (p = pStart; p < pEnd; ++p) {
1045       PetscInt dof, off, s;
1046 
1047       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
1048       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
1049       for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s]));
1050     }
1051     PetscCall(PetscViewerFlush(viewer));
1052     PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n"));
1053     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize));
1054     for (p = pStart; p < pEnd; ++p) {
1055       PetscInt dof, off, c;
1056 
1057       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
1058       PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
1059       for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]));
1060     }
1061     PetscCall(PetscViewerFlush(viewer));
1062     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
1063     if (coordSection && coordinates) {
1064       CoordSystem        cs = CS_CARTESIAN;
1065       const PetscScalar *array, *arrayCell = NULL;
1066       PetscInt           Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p;
1067       PetscMPIInt        rank;
1068       const char        *name;
1069 
1070       PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL));
1071       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
1072       PetscCall(PetscSectionGetNumFields(coordSection, &Nf));
1073       PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf);
1074       PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc));
1075       PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd));
1076       if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd));
1077       pStart = PetscMin(pvStart, pcStart);
1078       pEnd   = PetscMax(pvEnd, pcEnd);
1079       PetscCall(PetscObjectGetName((PetscObject)coordinates, &name));
1080       PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf));
1081       PetscCall(PetscViewerASCIIPrintf(viewer, "  field 0 with %" PetscInt_FMT " components\n", Nc));
1082       if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, "  output coordinate system: %s\n", CoordSystems[cs]));
1083 
1084       PetscCall(VecGetArrayRead(coordinates, &array));
1085       if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell));
1086       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
1087       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank));
1088       for (p = pStart; p < pEnd; ++p) {
1089         PetscInt dof, off;
1090 
1091         if (p >= pvStart && p < pvEnd) {
1092           PetscCall(PetscSectionGetDof(coordSection, p, &dof));
1093           PetscCall(PetscSectionGetOffset(coordSection, p, &off));
1094           if (dof) {
1095             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
1096             PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off]));
1097             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
1098           }
1099         }
1100         if (cdmCell && p >= pcStart && p < pcEnd) {
1101           PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof));
1102           PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off));
1103           if (dof) {
1104             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
1105             PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off]));
1106             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
1107           }
1108         }
1109       }
1110       PetscCall(PetscViewerFlush(viewer));
1111       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
1112       PetscCall(VecRestoreArrayRead(coordinates, &array));
1113       if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell));
1114     }
1115     PetscCall(DMGetNumLabels(dm, &numLabels));
1116     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
1117     for (l = 0; l < numLabels; ++l) {
1118       DMLabel     label;
1119       PetscBool   isdepth;
1120       const char *name;
1121 
1122       PetscCall(DMGetLabelName(dm, l, &name));
1123       PetscCall(PetscStrcmp(name, "depth", &isdepth));
1124       if (isdepth) continue;
1125       PetscCall(DMGetLabel(dm, name, &label));
1126       PetscCall(DMLabelView(label, viewer));
1127     }
1128     if (size > 1) {
1129       PetscSF sf;
1130 
1131       PetscCall(DMGetPointSF(dm, &sf));
1132       PetscCall(PetscSFView(sf, viewer));
1133     }
1134     if (mesh->periodic.face_sfs)
1135       for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer));
1136     PetscCall(PetscViewerFlush(viewer));
1137   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
1138     const char  *name, *color;
1139     const char  *defcolors[3]  = {"gray", "orange", "green"};
1140     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
1141     char         lname[PETSC_MAX_PATH_LEN];
1142     PetscReal    scale      = 2.0;
1143     PetscReal    tikzscale  = 1.0;
1144     PetscBool    useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE;
1145     double       tcoords[3];
1146     PetscScalar *coords;
1147     PetscInt     numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, fStart = 0, fEnd = 0, e, p, n;
1148     PetscMPIInt  rank, size;
1149     char       **names, **colors, **lcolors;
1150     PetscBool    flg, lflg;
1151     PetscBT      wp = NULL;
1152     PetscInt     pEnd, pStart;
1153 
1154     PetscCall(DMGetCoordinateDM(dm, &cdm));
1155     PetscCall(DMGetCoordinateSection(dm, &coordSection));
1156     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
1157     PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
1158     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
1159     PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
1160     PetscCall(DMGetDimension(dm, &dim));
1161     PetscCall(DMPlexGetDepth(dm, &depth));
1162     PetscCall(DMGetNumLabels(dm, &numLabels));
1163     numLabels  = PetscMax(numLabels, 10);
1164     numColors  = 10;
1165     numLColors = 10;
1166     PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors));
1167     PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL));
1168     PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL));
1169     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL));
1170     for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers;
1171     for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE;
1172     n = 4;
1173     PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg));
1174     PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1);
1175     n = 4;
1176     PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg));
1177     PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1);
1178     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels));
1179     if (!useLabels) numLabels = 0;
1180     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors));
1181     if (!useColors) {
1182       numColors = 3;
1183       for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c]));
1184     }
1185     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors));
1186     if (!useColors) {
1187       numLColors = 4;
1188       for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c]));
1189     }
1190     PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg));
1191     plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3);
1192     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg));
1193     PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated");
1194     if (depth < dim) plotEdges = PETSC_FALSE;
1195     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL));
1196 
1197     /* filter points with labelvalue != labeldefaultvalue */
1198     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1199     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1200     PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
1201     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1202     PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
1203     if (lflg) {
1204       DMLabel lbl;
1205 
1206       PetscCall(DMGetLabel(dm, lname, &lbl));
1207       if (lbl) {
1208         PetscInt val, defval;
1209 
1210         PetscCall(DMLabelGetDefaultValue(lbl, &defval));
1211         PetscCall(PetscBTCreate(pEnd - pStart, &wp));
1212         for (c = pStart; c < pEnd; c++) {
1213           PetscInt *closure = NULL;
1214           PetscInt  closureSize;
1215 
1216           PetscCall(DMLabelGetValue(lbl, c, &val));
1217           if (val == defval) continue;
1218 
1219           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1220           for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart));
1221           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1222         }
1223       }
1224     }
1225 
1226     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1227     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
1228     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
1229     PetscCall(PetscViewerASCIIPrintf(viewer, "\
1230 \\documentclass[tikz]{standalone}\n\n\
1231 \\usepackage{pgflibraryshapes}\n\
1232 \\usetikzlibrary{backgrounds}\n\
1233 \\usetikzlibrary{arrows}\n\
1234 \\begin{document}\n"));
1235     if (size > 1) {
1236       PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name));
1237       for (p = 0; p < size; ++p) {
1238         if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", "));
1239         PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p));
1240       }
1241       PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n"));
1242     }
1243     if (drawHasse) {
1244       PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart)));
1245 
1246       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart));
1247       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1));
1248       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart));
1249       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.));
1250       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart));
1251       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1));
1252       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.));
1253       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart));
1254       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart));
1255       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1));
1256       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.));
1257       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart));
1258       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart));
1259       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1));
1260       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart));
1261       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.));
1262     }
1263     PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale));
1264 
1265     /* Plot vertices */
1266     PetscCall(VecGetArray(coordinates, &coords));
1267     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
1268     for (v = vStart; v < vEnd; ++v) {
1269       PetscInt  off, dof, d;
1270       PetscBool isLabeled = PETSC_FALSE;
1271 
1272       if (wp && !PetscBTLookup(wp, v - pStart)) continue;
1273       PetscCall(PetscSectionGetDof(coordSection, v, &dof));
1274       PetscCall(PetscSectionGetOffset(coordSection, v, &off));
1275       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
1276       PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof);
1277       for (d = 0; d < dof; ++d) {
1278         tcoords[d] = (double)(scale * PetscRealPart(coords[off + d]));
1279         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1280       }
1281       /* Rotate coordinates since PGF makes z point out of the page instead of up */
1282       if (dim == 3) {
1283         PetscReal tmp = tcoords[1];
1284         tcoords[1]    = tcoords[2];
1285         tcoords[2]    = -tmp;
1286       }
1287       for (d = 0; d < dof; ++d) {
1288         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
1289         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]));
1290       }
1291       if (drawHasse) color = colors[0 % numColors];
1292       else color = colors[rank % numColors];
1293       for (l = 0; l < numLabels; ++l) {
1294         PetscInt val;
1295         PetscCall(DMGetLabelValue(dm, names[l], v, &val));
1296         if (val >= 0) {
1297           color     = lcolors[l % numLColors];
1298           isLabeled = PETSC_TRUE;
1299           break;
1300         }
1301       }
1302       if (drawNumbers[0]) {
1303         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v));
1304       } else if (drawColors[0]) {
1305         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color));
1306       } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank));
1307     }
1308     PetscCall(VecRestoreArray(coordinates, &coords));
1309     PetscCall(PetscViewerFlush(viewer));
1310     /* Plot edges */
1311     if (plotEdges) {
1312       PetscCall(VecGetArray(coordinates, &coords));
1313       PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n"));
1314       for (e = eStart; e < eEnd; ++e) {
1315         const PetscInt *cone;
1316         PetscInt        coneSize, offA, offB, dof, d;
1317 
1318         if (wp && !PetscBTLookup(wp, e - pStart)) continue;
1319         PetscCall(DMPlexGetConeSize(dm, e, &coneSize));
1320         PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize);
1321         PetscCall(DMPlexGetCone(dm, e, &cone));
1322         PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof));
1323         PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA));
1324         PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB));
1325         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "("));
1326         for (d = 0; d < dof; ++d) {
1327           tcoords[d] = (double)(scale * PetscRealPart(coords[offA + d] + coords[offB + d]) / 2);
1328           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1329         }
1330         /* Rotate coordinates since PGF makes z point out of the page instead of up */
1331         if (dim == 3) {
1332           PetscReal tmp = tcoords[1];
1333           tcoords[1]    = tcoords[2];
1334           tcoords[2]    = -tmp;
1335         }
1336         for (d = 0; d < dof; ++d) {
1337           if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
1338           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]));
1339         }
1340         if (drawHasse) color = colors[1 % numColors];
1341         else color = colors[rank % numColors];
1342         for (l = 0; l < numLabels; ++l) {
1343           PetscInt val;
1344           PetscCall(DMGetLabelValue(dm, names[l], e, &val));
1345           if (val >= 0) {
1346             color = lcolors[l % numLColors];
1347             break;
1348           }
1349         }
1350         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e));
1351       }
1352       PetscCall(VecRestoreArray(coordinates, &coords));
1353       PetscCall(PetscViewerFlush(viewer));
1354       PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n"));
1355     }
1356     /* Plot cells */
1357     if (dim == 3 || !drawNumbers[1]) {
1358       for (e = eStart; e < eEnd; ++e) {
1359         const PetscInt *cone;
1360 
1361         if (wp && !PetscBTLookup(wp, e - pStart)) continue;
1362         color = colors[rank % numColors];
1363         for (l = 0; l < numLabels; ++l) {
1364           PetscInt val;
1365           PetscCall(DMGetLabelValue(dm, names[l], e, &val));
1366           if (val >= 0) {
1367             color = lcolors[l % numLColors];
1368             break;
1369           }
1370         }
1371         PetscCall(DMPlexGetCone(dm, e, &cone));
1372         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank));
1373       }
1374     } else {
1375       DMPolytopeType ct;
1376 
1377       /* Drawing a 2D polygon */
1378       for (c = cStart; c < cEnd; ++c) {
1379         if (wp && !PetscBTLookup(wp, c - pStart)) continue;
1380         PetscCall(DMPlexGetCellType(dm, c, &ct));
1381         if (DMPolytopeTypeIsHybrid(ct)) {
1382           const PetscInt *cone;
1383           PetscInt        coneSize, e;
1384 
1385           PetscCall(DMPlexGetCone(dm, c, &cone));
1386           PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
1387           for (e = 0; e < coneSize; ++e) {
1388             const PetscInt *econe;
1389 
1390             PetscCall(DMPlexGetCone(dm, cone[e], &econe));
1391             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank));
1392           }
1393         } else {
1394           PetscInt *closure = NULL;
1395           PetscInt  closureSize, Nv = 0, v;
1396 
1397           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1398           for (p = 0; p < closureSize * 2; p += 2) {
1399             const PetscInt point = closure[p];
1400 
1401             if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point;
1402           }
1403           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors]));
1404           for (v = 0; v <= Nv; ++v) {
1405             const PetscInt vertex = closure[v % Nv];
1406 
1407             if (v > 0) {
1408               if (plotEdges) {
1409                 const PetscInt *edge;
1410                 PetscInt        endpoints[2], ne;
1411 
1412                 endpoints[0] = closure[v - 1];
1413                 endpoints[1] = vertex;
1414                 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge));
1415                 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]);
1416                 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank));
1417                 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge));
1418               } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- "));
1419             }
1420             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank));
1421           }
1422           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n"));
1423           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1424         }
1425       }
1426     }
1427     for (c = cStart; c < cEnd; ++c) {
1428       double             ccoords[3] = {0.0, 0.0, 0.0};
1429       PetscBool          isLabeled  = PETSC_FALSE;
1430       PetscScalar       *cellCoords = NULL;
1431       const PetscScalar *array;
1432       PetscInt           numCoords, cdim, d;
1433       PetscBool          isDG;
1434 
1435       if (wp && !PetscBTLookup(wp, c - pStart)) continue;
1436       PetscCall(DMGetCoordinateDim(dm, &cdim));
1437       PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords));
1438       PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords);
1439       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
1440       for (p = 0; p < numCoords / cdim; ++p) {
1441         for (d = 0; d < cdim; ++d) {
1442           tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d]));
1443           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1444         }
1445         /* Rotate coordinates since PGF makes z point out of the page instead of up */
1446         if (cdim == 3) {
1447           PetscReal tmp = tcoords[1];
1448           tcoords[1]    = tcoords[2];
1449           tcoords[2]    = -tmp;
1450         }
1451         for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d];
1452       }
1453       for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim);
1454       PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords));
1455       for (d = 0; d < cdim; ++d) {
1456         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
1457         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d]));
1458       }
1459       if (drawHasse) color = colors[depth % numColors];
1460       else color = colors[rank % numColors];
1461       for (l = 0; l < numLabels; ++l) {
1462         PetscInt val;
1463         PetscCall(DMGetLabelValue(dm, names[l], c, &val));
1464         if (val >= 0) {
1465           color     = lcolors[l % numLColors];
1466           isLabeled = PETSC_TRUE;
1467           break;
1468         }
1469       }
1470       if (drawNumbers[dim]) {
1471         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c));
1472       } else if (drawColors[dim]) {
1473         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color));
1474       } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank));
1475     }
1476     if (drawHasse) {
1477       int height = 0;
1478 
1479       color = colors[depth % numColors];
1480       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n"));
1481       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n"));
1482       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1483       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++));
1484       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1485 
1486       if (depth > 2) {
1487         color = colors[1 % numColors];
1488         PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n"));
1489         PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n"));
1490         PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1491         PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++));
1492         PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1493       }
1494 
1495       color = colors[1 % numColors];
1496       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n"));
1497       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n"));
1498       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1499       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++));
1500       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1501 
1502       color = colors[0 % numColors];
1503       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n"));
1504       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n"));
1505       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1506       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++));
1507       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1508 
1509       for (p = pStart; p < pEnd; ++p) {
1510         const PetscInt *cone;
1511         PetscInt        coneSize, cp;
1512 
1513         PetscCall(DMPlexGetCone(dm, p, &cone));
1514         PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
1515         for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank));
1516       }
1517     }
1518     PetscCall(PetscViewerFlush(viewer));
1519     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
1520     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n"));
1521     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n"));
1522     for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l]));
1523     for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c]));
1524     for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c]));
1525     PetscCall(PetscFree3(names, colors, lcolors));
1526     PetscCall(PetscBTDestroy(&wp));
1527   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
1528     Vec                    cown, acown;
1529     VecScatter             sct;
1530     ISLocalToGlobalMapping g2l;
1531     IS                     gid, acis;
1532     MPI_Comm               comm, ncomm = MPI_COMM_NULL;
1533     MPI_Group              ggroup, ngroup;
1534     PetscScalar           *array, nid;
1535     const PetscInt        *idxs;
1536     PetscInt              *idxs2, *start, *adjacency, *work;
1537     PetscInt64             lm[3], gm[3];
1538     PetscInt               i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight;
1539     PetscMPIInt            d1, d2, rank;
1540 
1541     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1542     PetscCallMPI(MPI_Comm_rank(comm, &rank));
1543 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1544     PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm));
1545 #endif
1546     if (ncomm != MPI_COMM_NULL) {
1547       PetscCallMPI(MPI_Comm_group(comm, &ggroup));
1548       PetscCallMPI(MPI_Comm_group(ncomm, &ngroup));
1549       d1 = 0;
1550       PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2));
1551       nid = d2;
1552       PetscCallMPI(MPI_Group_free(&ggroup));
1553       PetscCallMPI(MPI_Group_free(&ngroup));
1554       PetscCallMPI(MPI_Comm_free(&ncomm));
1555     } else nid = 0.0;
1556 
1557     /* Get connectivity */
1558     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
1559     PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid));
1560 
1561     /* filter overlapped local cells */
1562     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
1563     PetscCall(ISGetIndices(gid, &idxs));
1564     PetscCall(ISGetLocalSize(gid, &cum));
1565     PetscCall(PetscMalloc1(cum, &idxs2));
1566     for (c = cStart, cum = 0; c < cEnd; c++) {
1567       if (idxs[c - cStart] < 0) continue;
1568       idxs2[cum++] = idxs[c - cStart];
1569     }
1570     PetscCall(ISRestoreIndices(gid, &idxs));
1571     PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum);
1572     PetscCall(ISDestroy(&gid));
1573     PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid));
1574 
1575     /* support for node-aware cell locality */
1576     PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis));
1577     PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown));
1578     PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown));
1579     PetscCall(VecGetArray(cown, &array));
1580     for (c = 0; c < numVertices; c++) array[c] = nid;
1581     PetscCall(VecRestoreArray(cown, &array));
1582     PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct));
1583     PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
1584     PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
1585     PetscCall(ISDestroy(&acis));
1586     PetscCall(VecScatterDestroy(&sct));
1587     PetscCall(VecDestroy(&cown));
1588 
1589     /* compute edgeCut */
1590     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]);
1591     PetscCall(PetscMalloc1(cum, &work));
1592     PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l));
1593     PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH));
1594     PetscCall(ISDestroy(&gid));
1595     PetscCall(VecGetArray(acown, &array));
1596     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
1597       PetscInt totl;
1598 
1599       totl = start[c + 1] - start[c];
1600       PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work));
1601       for (i = 0; i < totl; i++) {
1602         if (work[i] < 0) {
1603           ect += 1;
1604           ectn += (array[i + start[c]] != nid) ? 0 : 1;
1605         }
1606       }
1607     }
1608     PetscCall(PetscFree(work));
1609     PetscCall(VecRestoreArray(acown, &array));
1610     lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX;
1611     lm[1] = -numVertices;
1612     PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm));
1613     PetscCall(PetscViewerASCIIPrintf(viewer, "  Cell balance: %.2f (max %" PetscInt64_FMT ", min %" PetscInt64_FMT, -((double)gm[1]) / ((double)gm[0]), -gm[1], gm[0]));
1614     lm[0] = ect;                     /* edgeCut */
1615     lm[1] = ectn;                    /* node-aware edgeCut */
1616     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
1617     PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm));
1618     PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt64_FMT ")\n", gm[2]));
1619 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1620     PetscCall(PetscViewerASCIIPrintf(viewer, "  Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.));
1621 #else
1622     PetscCall(PetscViewerASCIIPrintf(viewer, "  Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, 0.0));
1623 #endif
1624     PetscCall(ISLocalToGlobalMappingDestroy(&g2l));
1625     PetscCall(PetscFree(start));
1626     PetscCall(PetscFree(adjacency));
1627     PetscCall(VecDestroy(&acown));
1628   } else {
1629     const char    *name;
1630     PetscInt      *sizes, *hybsizes, *ghostsizes;
1631     PetscInt       locDepth, depth, cellHeight, dim, d;
1632     PetscInt       pStart, pEnd, p, gcStart, gcEnd, gcNum;
1633     PetscInt       numLabels, l, maxSize = 17;
1634     DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN;
1635     MPI_Comm       comm;
1636     PetscMPIInt    size, rank;
1637 
1638     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1639     PetscCallMPI(MPI_Comm_size(comm, &size));
1640     PetscCallMPI(MPI_Comm_rank(comm, &rank));
1641     PetscCall(DMGetDimension(dm, &dim));
1642     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
1643     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
1644     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
1645     else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
1646     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
1647     PetscCall(DMPlexGetDepth(dm, &locDepth));
1648     PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm));
1649     PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd));
1650     gcNum = gcEnd - gcStart;
1651     if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes));
1652     else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes));
1653     for (d = 0; d <= depth; d++) {
1654       PetscInt Nc[2] = {0, 0}, ict;
1655 
1656       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
1657       if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0));
1658       ict = ct0;
1659       PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm));
1660       ct0 = (DMPolytopeType)ict;
1661       for (p = pStart; p < pEnd; ++p) {
1662         DMPolytopeType ct;
1663 
1664         PetscCall(DMPlexGetCellType(dm, p, &ct));
1665         if (ct == ct0) ++Nc[0];
1666         else ++Nc[1];
1667       }
1668       if (size < maxSize) {
1669         PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm));
1670         PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm));
1671         if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm));
1672         PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
1673         for (p = 0; p < size; ++p) {
1674           if (rank == 0) {
1675             PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p]));
1676             if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p]));
1677             if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p]));
1678           }
1679         }
1680       } else {
1681         PetscInt locMinMax[2];
1682 
1683         locMinMax[0] = Nc[0] + Nc[1];
1684         locMinMax[1] = Nc[0] + Nc[1];
1685         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
1686         locMinMax[0] = Nc[1];
1687         locMinMax[1] = Nc[1];
1688         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes));
1689         if (d == depth) {
1690           locMinMax[0] = gcNum;
1691           locMinMax[1] = gcNum;
1692           PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes));
1693         }
1694         PetscCall(PetscViewerASCIIPrintf(viewer, "  Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
1695         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
1696         if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1]));
1697         if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1]));
1698       }
1699       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
1700     }
1701     PetscCall(PetscFree3(sizes, hybsizes, ghostsizes));
1702     {
1703       const PetscReal *maxCell;
1704       const PetscReal *L;
1705       PetscBool        localized;
1706 
1707       PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L));
1708       PetscCall(DMGetCoordinatesLocalized(dm, &localized));
1709       if (L || localized) {
1710         PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh"));
1711         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1712         if (L) {
1713           PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
1714           for (d = 0; d < dim; ++d) {
1715             if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
1716             PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE"));
1717           }
1718           PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
1719         }
1720         PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized"));
1721         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1722       }
1723     }
1724     PetscCall(DMGetNumLabels(dm, &numLabels));
1725     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
1726     for (l = 0; l < numLabels; ++l) {
1727       DMLabel     label;
1728       const char *name;
1729       PetscInt   *values;
1730       PetscInt    numValues, v;
1731 
1732       PetscCall(DMGetLabelName(dm, l, &name));
1733       PetscCall(DMGetLabel(dm, name, &label));
1734       PetscCall(DMLabelGetNumValues(label, &numValues));
1735       PetscCall(PetscViewerASCIIPrintf(viewer, "  %s: %" PetscInt_FMT " strata with value/size (", name, numValues));
1736 
1737       { // Extract array of DMLabel values so it can be sorted
1738         IS              is_values;
1739         const PetscInt *is_values_local = NULL;
1740 
1741         PetscCall(DMLabelGetValueIS(label, &is_values));
1742         PetscCall(ISGetIndices(is_values, &is_values_local));
1743         PetscCall(PetscMalloc1(numValues, &values));
1744         PetscCall(PetscArraycpy(values, is_values_local, numValues));
1745         PetscCall(PetscSortInt(numValues, values));
1746         PetscCall(ISRestoreIndices(is_values, &is_values_local));
1747         PetscCall(ISDestroy(&is_values));
1748       }
1749       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1750       for (v = 0; v < numValues; ++v) {
1751         PetscInt size;
1752 
1753         PetscCall(DMLabelGetStratumSize(label, values[v], &size));
1754         if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
1755         PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size));
1756       }
1757       PetscCall(PetscViewerASCIIPrintf(viewer, ")\n"));
1758       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1759       PetscCall(PetscFree(values));
1760     }
1761     {
1762       char    **labelNames;
1763       PetscInt  Nl = numLabels;
1764       PetscBool flg;
1765 
1766       PetscCall(PetscMalloc1(Nl, &labelNames));
1767       PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg));
1768       for (l = 0; l < Nl; ++l) {
1769         DMLabel label;
1770 
1771         PetscCall(DMHasLabel(dm, labelNames[l], &flg));
1772         if (flg) {
1773           PetscCall(DMGetLabel(dm, labelNames[l], &label));
1774           PetscCall(DMLabelView(label, viewer));
1775         }
1776         PetscCall(PetscFree(labelNames[l]));
1777       }
1778       PetscCall(PetscFree(labelNames));
1779     }
1780     /* If no fields are specified, people do not want to see adjacency */
1781     if (dm->Nf) {
1782       PetscInt f;
1783 
1784       for (f = 0; f < dm->Nf; ++f) {
1785         const char *name;
1786 
1787         PetscCall(PetscObjectGetName(dm->fields[f].disc, &name));
1788         if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name));
1789         PetscCall(PetscViewerASCIIPushTab(viewer));
1790         if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer));
1791         if (dm->fields[f].adjacency[0]) {
1792           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n"));
1793           else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n"));
1794         } else {
1795           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n"));
1796           else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n"));
1797         }
1798         PetscCall(PetscViewerASCIIPopTab(viewer));
1799       }
1800     }
1801     DMPlexTransform tr;
1802 
1803     PetscCall(DMPlexGetTransform(dm, &tr));
1804     if (tr) {
1805       PetscCall(PetscViewerASCIIPushTab(viewer));
1806       PetscCall(PetscViewerASCIIPrintf(viewer, "Created using transform:\n"));
1807       PetscCall(DMPlexTransformView(tr, viewer));
1808       PetscCall(PetscViewerASCIIPopTab(viewer));
1809     }
1810     PetscCall(DMGetCoarseDM(dm, &cdm));
1811     if (cdm) {
1812       PetscCall(PetscViewerASCIIPushTab(viewer));
1813       PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n"));
1814       PetscCall(DMPlexView_Ascii(cdm, viewer));
1815       PetscCall(PetscViewerASCIIPopTab(viewer));
1816     }
1817   }
1818   PetscFunctionReturn(PETSC_SUCCESS);
1819 }
1820 
DMPlexDrawCell(DM dm,PetscDraw draw,PetscInt lC,PetscInt cC,PetscInt cell,const PetscScalar coords[])1821 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt lC, PetscInt cC, PetscInt cell, const PetscScalar coords[])
1822 {
1823   DMPolytopeType ct;
1824   PetscMPIInt    rank;
1825   PetscInt       cdim;
1826   int            lineColor, cellColor;
1827 
1828   PetscFunctionBegin;
1829   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1830   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1831   PetscCall(DMGetCoordinateDim(dm, &cdim));
1832   lineColor = (int)(lC < 0 ? PETSC_DRAW_BLACK : lC);
1833   cellColor = (int)(cC < 0 ? PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2 : cC);
1834   switch (ct) {
1835   case DM_POLYTOPE_SEGMENT:
1836   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1837     switch (cdim) {
1838     case 1: {
1839       const PetscReal y  = 0.5;  /* TODO Put it in the middle of the viewport */
1840       const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */
1841 
1842       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, lineColor));
1843       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, lineColor));
1844       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, lineColor));
1845     } break;
1846     case 2: {
1847       const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1]));
1848       const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0]));
1849       const PetscReal l  = 0.1 / PetscSqrtReal(dx * dx + dy * dy);
1850 
1851       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor));
1852       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, lineColor));
1853       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, lineColor));
1854     } break;
1855     default:
1856       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim);
1857     }
1858     break;
1859   case DM_POLYTOPE_TRIANGLE:
1860     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor));
1861     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor));
1862     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor));
1863     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor));
1864     break;
1865   case DM_POLYTOPE_QUADRILATERAL:
1866     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor));
1867     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), cellColor, cellColor, cellColor));
1868     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor));
1869     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor));
1870     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), lineColor));
1871     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor));
1872     break;
1873   case DM_POLYTOPE_SEG_PRISM_TENSOR:
1874     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor));
1875     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor));
1876     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor));
1877     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), lineColor));
1878     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor));
1879     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor));
1880     break;
1881   case DM_POLYTOPE_FV_GHOST:
1882     break;
1883   default:
1884     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1885   }
1886   PetscFunctionReturn(PETSC_SUCCESS);
1887 }
1888 
DrawPolygon_Private(DM dm,PetscDraw draw,PetscInt cell,PetscInt Nv,const PetscReal refVertices[],const PetscScalar coords[],PetscInt edgeDiv,PetscReal refCoords[],PetscReal edgeCoords[])1889 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1890 {
1891   PetscReal   centroid[2] = {0., 0.};
1892   PetscMPIInt rank;
1893   PetscMPIInt fillColor;
1894 
1895   PetscFunctionBegin;
1896   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1897   fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2;
1898   for (PetscInt v = 0; v < Nv; ++v) {
1899     centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv;
1900     centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv;
1901   }
1902   for (PetscInt e = 0; e < Nv; ++e) {
1903     refCoords[0] = refVertices[e * 2 + 0];
1904     refCoords[1] = refVertices[e * 2 + 1];
1905     for (PetscInt d = 1; d <= edgeDiv; ++d) {
1906       refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv;
1907       refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv;
1908     }
1909     PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords));
1910     for (PetscInt d = 0; d < edgeDiv; ++d) {
1911       PetscCall(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));
1912       PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK));
1913     }
1914   }
1915   PetscFunctionReturn(PETSC_SUCCESS);
1916 }
1917 
DMPlexDrawCellHighOrder(DM dm,PetscDraw draw,PetscInt cell,const PetscScalar coords[],PetscInt edgeDiv,PetscReal refCoords[],PetscReal edgeCoords[])1918 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1919 {
1920   DMPolytopeType ct;
1921 
1922   PetscFunctionBegin;
1923   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1924   switch (ct) {
1925   case DM_POLYTOPE_TRIANGLE: {
1926     PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.};
1927 
1928     PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords));
1929   } break;
1930   case DM_POLYTOPE_QUADRILATERAL: {
1931     PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.};
1932 
1933     PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords));
1934   } break;
1935   default:
1936     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1937   }
1938   PetscFunctionReturn(PETSC_SUCCESS);
1939 }
1940 
DMPlexView_Draw(DM dm,PetscViewer viewer)1941 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1942 {
1943   PetscDraw    draw;
1944   DM           cdm;
1945   PetscSection coordSection;
1946   Vec          coordinates;
1947   PetscReal    xyl[3], xyr[3];
1948   PetscReal   *refCoords, *edgeCoords;
1949   PetscBool    isnull, drawAffine;
1950   PetscInt     dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv, lineColor = PETSC_DETERMINE, cellColor = PETSC_DETERMINE;
1951 
1952   PetscFunctionBegin;
1953   PetscCall(DMGetCoordinateDim(dm, &dim));
1954   PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim);
1955   PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree));
1956   drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE;
1957   edgeDiv    = cDegree + 1;
1958   PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_line_color", &lineColor, NULL));
1959   PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_cell_color", &cellColor, NULL));
1960   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL));
1961   if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords));
1962   PetscCall(DMGetCoordinateDM(dm, &cdm));
1963   PetscCall(DMGetLocalSection(cdm, &coordSection));
1964   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
1965   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1966   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1967 
1968   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
1969   PetscCall(PetscDrawIsNull(draw, &isnull));
1970   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
1971   PetscCall(PetscDrawSetTitle(draw, "Mesh"));
1972 
1973   PetscCall(DMGetBoundingBox(dm, xyl, xyr));
1974   PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]));
1975   PetscCall(PetscDrawClear(draw));
1976 
1977   for (c = cStart; c < cEnd; ++c) {
1978     PetscScalar       *coords = NULL;
1979     const PetscScalar *coords_arr;
1980     PetscInt           numCoords;
1981     PetscBool          isDG;
1982 
1983     PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
1984     if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, lineColor, cellColor, c, coords));
1985     else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords));
1986     PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
1987   }
1988   if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords));
1989   PetscCall(PetscDrawFlush(draw));
1990   PetscCall(PetscDrawPause(draw));
1991   PetscCall(PetscDrawSave(draw));
1992   PetscFunctionReturn(PETSC_SUCCESS);
1993 }
1994 
DMPlexCreateHighOrderSurrogate_Internal(DM dm,DM * hdm)1995 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm)
1996 {
1997   DM           odm = dm, rdm = dm, cdm;
1998   PetscFE      fe;
1999   PetscSpace   sp;
2000   PetscClassId id;
2001   PetscInt     degree;
2002   PetscBool    hoView = PETSC_TRUE;
2003 
2004   PetscFunctionBegin;
2005   PetscObjectOptionsBegin((PetscObject)dm);
2006   PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL));
2007   PetscOptionsEnd();
2008   PetscCall(PetscObjectReference((PetscObject)dm));
2009   *hdm = dm;
2010   if (!hoView) PetscFunctionReturn(PETSC_SUCCESS);
2011   PetscCall(DMGetCoordinateDM(dm, &cdm));
2012   PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe));
2013   PetscCall(PetscObjectGetClassId((PetscObject)fe, &id));
2014   if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS);
2015   PetscCall(PetscFEGetBasisSpace(fe, &sp));
2016   PetscCall(PetscSpaceGetDegree(sp, &degree, NULL));
2017   for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) {
2018     DM  cdm, rcdm;
2019     Mat In;
2020     Vec cl, rcl;
2021 
2022     PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm));
2023     PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, PETSC_FALSE));
2024     PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates"));
2025     PetscCall(DMGetCoordinateDM(odm, &cdm));
2026     PetscCall(DMGetCoordinateDM(rdm, &rcdm));
2027     PetscCall(DMGetCoordinatesLocal(odm, &cl));
2028     PetscCall(DMGetCoordinatesLocal(rdm, &rcl));
2029     PetscCall(DMSetCoarseDM(rcdm, cdm));
2030     PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL));
2031     PetscCall(MatMult(In, cl, rcl));
2032     PetscCall(MatDestroy(&In));
2033     PetscCall(DMSetCoordinatesLocal(rdm, rcl));
2034     PetscCall(DMDestroy(&odm));
2035     odm = rdm;
2036   }
2037   *hdm = rdm;
2038   PetscFunctionReturn(PETSC_SUCCESS);
2039 }
2040 
2041 #if defined(PETSC_HAVE_EXODUSII)
2042   #include <exodusII.h>
2043 #endif
2044 
DMView_Plex(DM dm,PetscViewer viewer)2045 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
2046 {
2047   PetscBool isascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns, ispython;
2048   char      name[PETSC_MAX_PATH_LEN];
2049 
2050   PetscFunctionBegin;
2051   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2052   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2053   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
2054   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
2055   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2056   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
2057   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
2058   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus));
2059   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
2060   PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython));
2061   if (isascii) {
2062     PetscViewerFormat format;
2063     PetscCall(PetscViewerGetFormat(viewer, &format));
2064     if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer));
2065     else PetscCall(DMPlexView_Ascii(dm, viewer));
2066   } else if (ishdf5) {
2067 #if defined(PETSC_HAVE_HDF5)
2068     PetscCall(DMPlexView_HDF5_Internal(dm, viewer));
2069 #else
2070     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2071 #endif
2072   } else if (isvtk) {
2073     PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer));
2074   } else if (isdraw) {
2075     DM hdm;
2076 
2077     PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm));
2078     PetscCall(DMPlexView_Draw(hdm, viewer));
2079     PetscCall(DMDestroy(&hdm));
2080   } else if (isglvis) {
2081     PetscCall(DMPlexView_GLVis(dm, viewer));
2082 #if defined(PETSC_HAVE_EXODUSII)
2083   } else if (isexodus) {
2084     /*
2085       ExodusII requires that all sets be part of exactly one cell set.
2086       If the dm does not have a "Cell Sets" label defined, we create one
2087       with ID 1, containing all cells.
2088       Note that if the Cell Sets label is defined but does not cover all cells,
2089       we may still have a problem. This should probably be checked here or in the viewer;
2090     */
2091     PetscInt numCS;
2092     PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS));
2093     if (!numCS) {
2094       PetscInt cStart, cEnd, c;
2095       PetscCall(DMCreateLabel(dm, "Cell Sets"));
2096       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2097       for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1));
2098     }
2099     PetscCall(DMView_PlexExodusII(dm, viewer));
2100 #endif
2101 #if defined(PETSC_HAVE_CGNS)
2102   } else if (iscgns) {
2103     PetscCall(DMView_PlexCGNS(dm, viewer));
2104 #endif
2105   } else if (ispython) {
2106     PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm));
2107   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
2108   /* Optionally view the partition */
2109   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg));
2110   if (flg) {
2111     Vec ranks;
2112     PetscCall(DMPlexCreateRankField(dm, &ranks));
2113     PetscCall(VecView(ranks, viewer));
2114     PetscCall(VecDestroy(&ranks));
2115   }
2116   /* Optionally view a label */
2117   PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg));
2118   if (flg) {
2119     DMLabel label;
2120     Vec     val;
2121 
2122     PetscCall(DMGetLabel(dm, name, &label));
2123     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
2124     PetscCall(DMPlexCreateLabelField(dm, label, &val));
2125     PetscCall(VecView(val, viewer));
2126     PetscCall(VecDestroy(&val));
2127   }
2128   PetscFunctionReturn(PETSC_SUCCESS);
2129 }
2130 
2131 /*@
2132   DMPlexTopologyView - Saves a `DMPLEX` topology into a file
2133 
2134   Collective
2135 
2136   Input Parameters:
2137 + dm     - The `DM` whose topology is to be saved
2138 - viewer - The `PetscViewer` to save it in
2139 
2140   Level: advanced
2141 
2142 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer`
2143 @*/
DMPlexTopologyView(DM dm,PetscViewer viewer)2144 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
2145 {
2146   PetscBool ishdf5;
2147 
2148   PetscFunctionBegin;
2149   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2150   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2151   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2152   PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0));
2153   if (ishdf5) {
2154 #if defined(PETSC_HAVE_HDF5)
2155     IS                globalPointNumbering;
2156     PetscViewerFormat format;
2157 
2158     PetscCall(PetscViewerGetFormat(viewer, &format));
2159     PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
2160     PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
2161     PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer));
2162     PetscCall(ISDestroy(&globalPointNumbering));
2163 #else
2164     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2165 #endif
2166   }
2167   PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0));
2168   PetscFunctionReturn(PETSC_SUCCESS);
2169 }
2170 
2171 /*@
2172   DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file
2173 
2174   Collective
2175 
2176   Input Parameters:
2177 + dm     - The `DM` whose coordinates are to be saved
2178 - viewer - The `PetscViewer` for saving
2179 
2180   Level: advanced
2181 
2182 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer`
2183 @*/
DMPlexCoordinatesView(DM dm,PetscViewer viewer)2184 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
2185 {
2186   PetscBool ishdf5;
2187 
2188   PetscFunctionBegin;
2189   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2190   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2191   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2192   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
2193   if (ishdf5) {
2194 #if defined(PETSC_HAVE_HDF5)
2195     PetscViewerFormat format;
2196 
2197     PetscCall(PetscViewerGetFormat(viewer, &format));
2198     PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
2199     PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer));
2200 #else
2201     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2202 #endif
2203   }
2204   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
2205   PetscFunctionReturn(PETSC_SUCCESS);
2206 }
2207 
2208 /*@
2209   DMPlexLabelsView - Saves `DMPLEX` labels into a file
2210 
2211   Collective
2212 
2213   Input Parameters:
2214 + dm     - The `DM` whose labels are to be saved
2215 - viewer - The `PetscViewer` for saving
2216 
2217   Level: advanced
2218 
2219 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer`
2220 @*/
DMPlexLabelsView(DM dm,PetscViewer viewer)2221 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
2222 {
2223   PetscBool ishdf5;
2224 
2225   PetscFunctionBegin;
2226   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2227   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2228   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2229   PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0));
2230   if (ishdf5) {
2231 #if defined(PETSC_HAVE_HDF5)
2232     IS                globalPointNumbering;
2233     PetscViewerFormat format;
2234 
2235     PetscCall(PetscViewerGetFormat(viewer, &format));
2236     PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2237     PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
2238     PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer));
2239     PetscCall(ISDestroy(&globalPointNumbering));
2240 #else
2241     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2242 #endif
2243   }
2244   PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0));
2245   PetscFunctionReturn(PETSC_SUCCESS);
2246 }
2247 
2248 /*@
2249   DMPlexSectionView - Saves a section associated with a `DMPLEX`
2250 
2251   Collective
2252 
2253   Input Parameters:
2254 + dm        - The `DM` that contains the topology on which the section to be saved is defined
2255 . viewer    - The `PetscViewer` for saving
2256 - sectiondm - The `DM` that contains the section to be saved, can be `NULL`
2257 
2258   Level: advanced
2259 
2260   Notes:
2261   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.
2262 
2263   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 (or in case `sectiondm` is `NULL`) 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.
2264 
2265 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer`
2266 @*/
DMPlexSectionView(DM dm,PetscViewer viewer,DM sectiondm)2267 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
2268 {
2269   PetscBool ishdf5;
2270 
2271   PetscFunctionBegin;
2272   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2273   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2274   if (!sectiondm) sectiondm = dm;
2275   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2276   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2277   PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0));
2278   if (ishdf5) {
2279 #if defined(PETSC_HAVE_HDF5)
2280     PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm));
2281 #else
2282     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2283 #endif
2284   }
2285   PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0));
2286   PetscFunctionReturn(PETSC_SUCCESS);
2287 }
2288 
2289 /*@
2290   DMPlexGlobalVectorView - Saves a global vector
2291 
2292   Collective
2293 
2294   Input Parameters:
2295 + dm        - The `DM` that represents the topology
2296 . viewer    - The `PetscViewer` to save data with
2297 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL`
2298 - vec       - The global vector to be saved
2299 
2300   Level: advanced
2301 
2302   Notes:
2303   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 (or in case `sectiondm` is `NULL`) 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.
2304 
2305   Calling sequence:
2306 .vb
2307        DMCreate(PETSC_COMM_WORLD, &dm);
2308        DMSetType(dm, DMPLEX);
2309        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2310        DMClone(dm, &sectiondm);
2311        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2312        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2313        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2314        PetscSectionSetChart(section, pStart, pEnd);
2315        PetscSectionSetUp(section);
2316        DMSetLocalSection(sectiondm, section);
2317        PetscSectionDestroy(&section);
2318        DMGetGlobalVector(sectiondm, &vec);
2319        PetscObjectSetName((PetscObject)vec, "vec_name");
2320        DMPlexTopologyView(dm, viewer);
2321        DMPlexSectionView(dm, viewer, sectiondm);
2322        DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
2323        DMRestoreGlobalVector(sectiondm, &vec);
2324        DMDestroy(&sectiondm);
2325        DMDestroy(&dm);
2326 .ve
2327 
2328 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
2329 @*/
DMPlexGlobalVectorView(DM dm,PetscViewer viewer,DM sectiondm,Vec vec)2330 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2331 {
2332   PetscBool ishdf5;
2333 
2334   PetscFunctionBegin;
2335   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2336   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2337   if (!sectiondm) sectiondm = dm;
2338   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2339   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
2340   /* Check consistency */
2341   {
2342     PetscSection section;
2343     PetscBool    includesConstraints;
2344     PetscInt     m, m1;
2345 
2346     PetscCall(VecGetLocalSize(vec, &m1));
2347     PetscCall(DMGetGlobalSection(sectiondm, &section));
2348     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2349     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2350     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2351     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
2352   }
2353   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2354   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
2355   if (ishdf5) {
2356 #if defined(PETSC_HAVE_HDF5)
2357     PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
2358 #else
2359     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2360 #endif
2361   }
2362   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
2363   PetscFunctionReturn(PETSC_SUCCESS);
2364 }
2365 
2366 /*@
2367   DMPlexLocalVectorView - Saves a local vector
2368 
2369   Collective
2370 
2371   Input Parameters:
2372 + dm        - The `DM` that represents the topology
2373 . viewer    - The `PetscViewer` to save data with
2374 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL`
2375 - vec       - The local vector to be saved
2376 
2377   Level: advanced
2378 
2379   Note:
2380   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 (or in case `sectiondm` is `NULL`) 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.
2381 
2382   Calling sequence:
2383 .vb
2384        DMCreate(PETSC_COMM_WORLD, &dm);
2385        DMSetType(dm, DMPLEX);
2386        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2387        DMClone(dm, &sectiondm);
2388        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2389        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2390        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2391        PetscSectionSetChart(section, pStart, pEnd);
2392        PetscSectionSetUp(section);
2393        DMSetLocalSection(sectiondm, section);
2394        DMGetLocalVector(sectiondm, &vec);
2395        PetscObjectSetName((PetscObject)vec, "vec_name");
2396        DMPlexTopologyView(dm, viewer);
2397        DMPlexSectionView(dm, viewer, sectiondm);
2398        DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
2399        DMRestoreLocalVector(sectiondm, &vec);
2400        DMDestroy(&sectiondm);
2401        DMDestroy(&dm);
2402 .ve
2403 
2404 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
2405 @*/
DMPlexLocalVectorView(DM dm,PetscViewer viewer,DM sectiondm,Vec vec)2406 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2407 {
2408   PetscBool ishdf5;
2409 
2410   PetscFunctionBegin;
2411   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2412   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2413   if (!sectiondm) sectiondm = dm;
2414   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2415   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
2416   /* Check consistency */
2417   {
2418     PetscSection section;
2419     PetscBool    includesConstraints;
2420     PetscInt     m, m1;
2421 
2422     PetscCall(VecGetLocalSize(vec, &m1));
2423     PetscCall(DMGetLocalSection(sectiondm, &section));
2424     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2425     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2426     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2427     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
2428   }
2429   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2430   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
2431   if (ishdf5) {
2432 #if defined(PETSC_HAVE_HDF5)
2433     PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, 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   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
2439   PetscFunctionReturn(PETSC_SUCCESS);
2440 }
2441 
DMLoad_Plex(DM dm,PetscViewer viewer)2442 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
2443 {
2444   PetscBool ishdf5;
2445 
2446   PetscFunctionBegin;
2447   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2448   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2449   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2450   if (ishdf5) {
2451 #if defined(PETSC_HAVE_HDF5)
2452     PetscViewerFormat format;
2453     PetscCall(PetscViewerGetFormat(viewer, &format));
2454     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
2455       PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer));
2456     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2457       PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer));
2458     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2459     PetscFunctionReturn(PETSC_SUCCESS);
2460 #else
2461     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2462 #endif
2463   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
2464 }
2465 
2466 /*@
2467   DMPlexTopologyLoad - Loads a topology into a `DMPLEX`
2468 
2469   Collective
2470 
2471   Input Parameters:
2472 + dm     - The `DM` into which the topology is loaded
2473 - viewer - The `PetscViewer` for the saved topology
2474 
2475   Output Parameter:
2476 . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points;
2477   `NULL` if unneeded
2478 
2479   Level: advanced
2480 
2481 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2482           `PetscViewer`, `PetscSF`
2483 @*/
DMPlexTopologyLoad(DM dm,PetscViewer viewer,PetscSF * globalToLocalPointSF)2484 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
2485 {
2486   PetscBool ishdf5;
2487 
2488   PetscFunctionBegin;
2489   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2490   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2491   if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3);
2492   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2493   PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
2494   if (ishdf5) {
2495 #if defined(PETSC_HAVE_HDF5)
2496     PetscViewerFormat format;
2497 
2498     PetscCall(PetscViewerGetFormat(viewer, &format));
2499     PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2500     PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2501 #else
2502     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2503 #endif
2504   }
2505   PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
2506   PetscFunctionReturn(PETSC_SUCCESS);
2507 }
2508 
2509 /*@
2510   DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX`
2511 
2512   Collective
2513 
2514   Input Parameters:
2515 + dm                   - The `DM` into which the coordinates are loaded
2516 . viewer               - The `PetscViewer` for the saved coordinates
2517 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer
2518 
2519   Level: advanced
2520 
2521 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2522           `PetscSF`, `PetscViewer`
2523 @*/
DMPlexCoordinatesLoad(DM dm,PetscViewer viewer,PetscSF globalToLocalPointSF)2524 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2525 {
2526   PetscBool ishdf5;
2527 
2528   PetscFunctionBegin;
2529   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2530   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2531   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
2532   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2533   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
2534   if (ishdf5) {
2535 #if defined(PETSC_HAVE_HDF5)
2536     PetscViewerFormat format;
2537 
2538     PetscCall(PetscViewerGetFormat(viewer, &format));
2539     PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2540     PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2541 #else
2542     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2543 #endif
2544   }
2545   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
2546   PetscFunctionReturn(PETSC_SUCCESS);
2547 }
2548 
2549 /*@
2550   DMPlexLabelsLoad - Loads labels into a `DMPLEX`
2551 
2552   Collective
2553 
2554   Input Parameters:
2555 + dm                   - The `DM` into which the labels are loaded
2556 . viewer               - The `PetscViewer` for the saved labels
2557 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer
2558 
2559   Level: advanced
2560 
2561   Note:
2562   The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs.
2563 
2564 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2565           `PetscSF`, `PetscViewer`
2566 @*/
DMPlexLabelsLoad(DM dm,PetscViewer viewer,PetscSF globalToLocalPointSF)2567 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2568 {
2569   PetscBool ishdf5;
2570 
2571   PetscFunctionBegin;
2572   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2573   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2574   if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
2575   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2576   PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
2577   if (ishdf5) {
2578 #if defined(PETSC_HAVE_HDF5)
2579     PetscViewerFormat format;
2580 
2581     PetscCall(PetscViewerGetFormat(viewer, &format));
2582     PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2583     PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2584 #else
2585     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2586 #endif
2587   }
2588   PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
2589   PetscFunctionReturn(PETSC_SUCCESS);
2590 }
2591 
2592 /*@
2593   DMPlexSectionLoad - Loads section into a `DMPLEX`
2594 
2595   Collective
2596 
2597   Input Parameters:
2598 + dm                   - The `DM` that represents the topology
2599 . viewer               - The `PetscViewer` that represents the on-disk section (sectionA)
2600 . sectiondm            - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL`
2601 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer
2602 
2603   Output Parameters:
2604 + globalDofSF - The `PetscSF` 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)
2605 - localDofSF  - The `PetscSF` 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)
2606 
2607   Level: advanced
2608 
2609   Notes:
2610   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.
2611 
2612   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 (or in case `sectiondm` is `NULL`) 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.
2613 
2614   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.
2615 
2616   Example using 2 processes:
2617 .vb
2618   NX (number of points on dm): 4
2619   sectionA                   : the on-disk section
2620   vecA                       : a vector associated with sectionA
2621   sectionB                   : sectiondm's local section constructed in this function
2622   vecB (local)               : a vector associated with sectiondm's local section
2623   vecB (global)              : a vector associated with sectiondm's global section
2624 
2625                                      rank 0    rank 1
2626   vecA (global)                  : [.0 .4 .1 | .2 .3]        <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
2627   sectionA->atlasOff             :       0 2 | 1             <- loaded in PetscSectionLoad()
2628   sectionA->atlasDof             :       1 3 | 1             <- loaded in PetscSectionLoad()
2629   sectionA's global point numbers:       0 2 | 3             <- loaded in DMPlexSectionLoad()
2630   [0, NX)                        :       0 1 | 2 3           <- conceptual partition used in globalToLocalPointSF
2631   sectionB's global point numbers:     0 1 3 | 3 2           <- associated with [0, NX) by globalToLocalPointSF
2632   sectionB->atlasDof             :     1 0 1 | 1 3
2633   sectionB->atlasOff (no perm)   :     0 1 1 | 0 1
2634   vecB (local)                   :   [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
2635   vecB (global)                  :    [.0 .4 | .1 .2 .3]     <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
2636 .ve
2637   where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.
2638 
2639 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer`
2640 @*/
DMPlexSectionLoad(DM dm,PetscViewer viewer,PeOp DM sectiondm,PetscSF globalToLocalPointSF,PeOp PetscSF * globalDofSF,PeOp PetscSF * localDofSF)2641 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, PeOp DM sectiondm, PetscSF globalToLocalPointSF, PeOp PetscSF *globalDofSF, PeOp PetscSF *localDofSF)
2642 {
2643   PetscBool ishdf5;
2644 
2645   PetscFunctionBegin;
2646   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2647   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2648   if (!sectiondm) sectiondm = dm;
2649   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2650   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4);
2651   if (globalDofSF) PetscAssertPointer(globalDofSF, 5);
2652   if (localDofSF) PetscAssertPointer(localDofSF, 6);
2653   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2654   PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0));
2655   if (ishdf5) {
2656 #if defined(PETSC_HAVE_HDF5)
2657     PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF));
2658 #else
2659     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2660 #endif
2661   }
2662   PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0));
2663   PetscFunctionReturn(PETSC_SUCCESS);
2664 }
2665 
2666 /*@
2667   DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector
2668 
2669   Collective
2670 
2671   Input Parameters:
2672 + dm        - The `DM` that represents the topology
2673 . viewer    - The `PetscViewer` that represents the on-disk vector data
2674 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL`
2675 . sf        - The `PetscSF` that migrates the on-disk vector data into vec
2676 - vec       - The global vector to set values of
2677 
2678   Level: advanced
2679 
2680   Notes:
2681   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 (or in case `sectiondm` is `NULL`) 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.
2682 
2683   Calling sequence:
2684 .vb
2685        DMCreate(PETSC_COMM_WORLD, &dm);
2686        DMSetType(dm, DMPLEX);
2687        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2688        DMPlexTopologyLoad(dm, viewer, &sfX);
2689        DMClone(dm, &sectiondm);
2690        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2691        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL);
2692        DMGetGlobalVector(sectiondm, &vec);
2693        PetscObjectSetName((PetscObject)vec, "vec_name");
2694        DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec);
2695        DMRestoreGlobalVector(sectiondm, &vec);
2696        PetscSFDestroy(&gsf);
2697        PetscSFDestroy(&sfX);
2698        DMDestroy(&sectiondm);
2699        DMDestroy(&dm);
2700 .ve
2701 
2702 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2703           `PetscSF`, `PetscViewer`
2704 @*/
DMPlexGlobalVectorLoad(DM dm,PetscViewer viewer,DM sectiondm,PetscSF sf,Vec vec)2705 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2706 {
2707   PetscBool ishdf5;
2708 
2709   PetscFunctionBegin;
2710   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2711   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2712   if (!sectiondm) sectiondm = dm;
2713   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2714   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
2715   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
2716   /* Check consistency */
2717   {
2718     PetscSection section;
2719     PetscBool    includesConstraints;
2720     PetscInt     m, m1;
2721 
2722     PetscCall(VecGetLocalSize(vec, &m1));
2723     PetscCall(DMGetGlobalSection(sectiondm, &section));
2724     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2725     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2726     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2727     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
2728   }
2729   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2730   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
2731   if (ishdf5) {
2732 #if defined(PETSC_HAVE_HDF5)
2733     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
2734 #else
2735     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2736 #endif
2737   }
2738   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
2739   PetscFunctionReturn(PETSC_SUCCESS);
2740 }
2741 
2742 /*@
2743   DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector
2744 
2745   Collective
2746 
2747   Input Parameters:
2748 + dm        - The `DM` that represents the topology
2749 . viewer    - The `PetscViewer` that represents the on-disk vector data
2750 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL`
2751 . sf        - The `PetscSF` that migrates the on-disk vector data into vec
2752 - vec       - The local vector to set values of
2753 
2754   Level: advanced
2755 
2756   Notes:
2757   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 (or in case `sectiondm` is `NULL`) 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.
2758 
2759   Calling sequence:
2760 .vb
2761        DMCreate(PETSC_COMM_WORLD, &dm);
2762        DMSetType(dm, DMPLEX);
2763        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2764        DMPlexTopologyLoad(dm, viewer, &sfX);
2765        DMClone(dm, &sectiondm);
2766        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2767        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf);
2768        DMGetLocalVector(sectiondm, &vec);
2769        PetscObjectSetName((PetscObject)vec, "vec_name");
2770        DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec);
2771        DMRestoreLocalVector(sectiondm, &vec);
2772        PetscSFDestroy(&lsf);
2773        PetscSFDestroy(&sfX);
2774        DMDestroy(&sectiondm);
2775        DMDestroy(&dm);
2776 .ve
2777 
2778 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2779           `PetscSF`, `PetscViewer`
2780 @*/
DMPlexLocalVectorLoad(DM dm,PetscViewer viewer,DM sectiondm,PetscSF sf,Vec vec)2781 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2782 {
2783   PetscBool ishdf5;
2784 
2785   PetscFunctionBegin;
2786   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2787   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2788   if (!sectiondm) sectiondm = dm;
2789   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2790   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
2791   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
2792   /* Check consistency */
2793   {
2794     PetscSection section;
2795     PetscBool    includesConstraints;
2796     PetscInt     m, m1;
2797 
2798     PetscCall(VecGetLocalSize(vec, &m1));
2799     PetscCall(DMGetLocalSection(sectiondm, &section));
2800     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2801     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2802     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2803     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
2804   }
2805   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2806   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
2807   if (ishdf5) {
2808 #if defined(PETSC_HAVE_HDF5)
2809     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
2810 #else
2811     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2812 #endif
2813   }
2814   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
2815   PetscFunctionReturn(PETSC_SUCCESS);
2816 }
2817 
DMDestroy_Plex(DM dm)2818 PetscErrorCode DMDestroy_Plex(DM dm)
2819 {
2820   DM_Plex *mesh = (DM_Plex *)dm->data;
2821 
2822   PetscFunctionBegin;
2823   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL));
2824   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL));
2825   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL));
2826   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBounds_C", NULL));
2827   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL));
2828   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL));
2829   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
2830   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL));
2831   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL));
2832   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL));
2833   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL));
2834   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL));
2835   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL));
2836   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL));
2837   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL));
2838   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL));
2839   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
2840   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL));
2841   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL));
2842   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL));
2843   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL));
2844   if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
2845   PetscCall(PetscSectionDestroy(&mesh->coneSection));
2846   PetscCall(PetscFree(mesh->cones));
2847   PetscCall(PetscFree(mesh->coneOrientations));
2848   PetscCall(PetscSectionDestroy(&mesh->supportSection));
2849   PetscCall(PetscSectionDestroy(&mesh->subdomainSection));
2850   PetscCall(PetscFree(mesh->supports));
2851   PetscCall(PetscFree(mesh->cellTypes));
2852   PetscCall(DMPlexTransformDestroy(&mesh->tr));
2853   PetscCall(PetscFree(mesh->tetgenOpts));
2854   PetscCall(PetscFree(mesh->triangleOpts));
2855   PetscCall(PetscFree(mesh->transformType));
2856   PetscCall(PetscFree(mesh->distributionName));
2857   PetscCall(PetscPartitionerDestroy(&mesh->partitioner));
2858   PetscCall(DMLabelDestroy(&mesh->subpointMap));
2859   PetscCall(ISDestroy(&mesh->subpointIS));
2860   PetscCall(ISDestroy(&mesh->globalVertexNumbers));
2861   PetscCall(ISDestroy(&mesh->globalCellNumbers));
2862   if (mesh->periodic.face_sfs) {
2863     for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i]));
2864     PetscCall(PetscFree(mesh->periodic.face_sfs));
2865   }
2866   PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf));
2867   if (mesh->periodic.periodic_points) {
2868     for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i]));
2869     PetscCall(PetscFree(mesh->periodic.periodic_points));
2870   }
2871   if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform));
2872   PetscCall(PetscSectionDestroy(&mesh->anchorSection));
2873   PetscCall(ISDestroy(&mesh->anchorIS));
2874   PetscCall(PetscSectionDestroy(&mesh->parentSection));
2875   PetscCall(PetscFree(mesh->parents));
2876   PetscCall(PetscFree(mesh->childIDs));
2877   PetscCall(PetscSectionDestroy(&mesh->childSection));
2878   PetscCall(PetscFree(mesh->children));
2879   PetscCall(DMDestroy(&mesh->referenceTree));
2880   PetscCall(PetscGridHashDestroy(&mesh->lbox));
2881   PetscCall(PetscFree(mesh->neighbors));
2882   if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx));
2883   if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm));
2884   PetscCall(DMPlexTransformDestroy(&mesh->transform));
2885   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
2886   PetscCall(PetscFree(mesh));
2887   PetscFunctionReturn(PETSC_SUCCESS);
2888 }
2889 
DMCreateMatrix_Plex(DM dm,Mat * J)2890 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
2891 {
2892   PetscSection           sectionGlobal, sectionLocal;
2893   PetscInt               bs = -1, mbs;
2894   PetscInt               localSize, localStart = 0;
2895   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
2896   MatType                mtype;
2897   ISLocalToGlobalMapping ltog;
2898 
2899   PetscFunctionBegin;
2900   PetscCall(MatInitializePackage());
2901   mtype = dm->mattype;
2902   PetscCall(DMGetLocalSection(dm, &sectionLocal));
2903   PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
2904   /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */
2905   PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize));
2906   PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
2907   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
2908   PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE));
2909   PetscCall(MatSetType(*J, mtype));
2910   PetscCall(MatSetFromOptions(*J));
2911   PetscCall(MatGetBlockSize(*J, &mbs));
2912   if (mbs > 1) bs = mbs;
2913   PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell));
2914   PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock));
2915   PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock));
2916   PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock));
2917   PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock));
2918   PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock));
2919   PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock));
2920   PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS));
2921   if (!isShell) {
2922     // There are three states with pblocks, since block starts can have no dofs:
2923     // UNKNOWN) New Block:   An open block has been signalled by pblocks[p] == 1
2924     // TRUE)    Block Start: The first entry in a block has been added
2925     // FALSE)   Block Add:   An additional block entry has been added, since pblocks[p] == 0
2926     PetscBT         blst;
2927     PetscBool3      bstate     = PETSC_BOOL3_UNKNOWN;
2928     PetscBool       fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
2929     const PetscInt *perm       = NULL;
2930     PetscInt       *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks;
2931     PetscInt        pStart, pEnd, dof, cdof, num_fields;
2932 
2933     PetscCall(DMGetLocalToGlobalMapping(dm, &ltog));
2934     PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst));
2935     if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm));
2936 
2937     PetscCall(PetscCalloc1(localSize, &pblocks));
2938     PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
2939     PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields));
2940     // We need to process in the permuted order to get block sizes right
2941     for (PetscInt point = pStart; point < pEnd; ++point) {
2942       const PetscInt p = perm ? perm[point] : point;
2943 
2944       switch (dm->blocking_type) {
2945       case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point
2946         PetscInt bdof, offset;
2947 
2948         PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof));
2949         PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset));
2950         PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof));
2951         if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN;
2952         if (dof > 0) {
2953           // State change
2954           if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE;
2955           else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE;
2956 
2957           for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof;
2958           // Signal block concatenation
2959           if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof);
2960         }
2961         dof  = dof < 0 ? -(dof + 1) : dof;
2962         bdof = cdof && (dof - cdof) ? 1 : dof;
2963         if (dof) {
2964           if (bs < 0) {
2965             bs = bdof;
2966           } else if (bs != bdof) {
2967             bs = 1;
2968           }
2969         }
2970       } break;
2971       case DM_BLOCKING_FIELD_NODE: {
2972         for (PetscInt field = 0; field < num_fields; field++) {
2973           PetscInt num_comp, bdof, offset;
2974           PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp));
2975           PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof));
2976           if (dof < 0) continue;
2977           PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset));
2978           PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof));
2979           PetscAssert(dof % num_comp == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " field %" PetscInt_FMT " has %" PetscInt_FMT " dof, not divisible by %" PetscInt_FMT " component ", p, field, dof, num_comp);
2980           PetscInt num_nodes = dof / num_comp;
2981           for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes;
2982           // Handle possibly constant block size (unlikely)
2983           bdof = cdof && (dof - cdof) ? 1 : dof;
2984           if (dof) {
2985             if (bs < 0) {
2986               bs = bdof;
2987             } else if (bs != bdof) {
2988               bs = 1;
2989             }
2990           }
2991         }
2992       } break;
2993       }
2994     }
2995     if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm));
2996     /* Must have same blocksize on all procs (some might have no points) */
2997     bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs;
2998     bsLocal[1] = bs;
2999     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
3000     if (bsMinMax[0] != bsMinMax[1]) bs = 1;
3001     else bs = bsMinMax[0];
3002     bs = PetscMax(1, bs);
3003     PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog));
3004     if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters
3005       PetscCall(MatSetBlockSize(*J, bs));
3006       PetscCall(MatSetUp(*J));
3007     } else {
3008       PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu));
3009       PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix));
3010       PetscCall(PetscFree4(dnz, onz, dnzu, onzu));
3011     }
3012     if (pblocks) { // Consolidate blocks
3013       PetscInt nblocks = 0;
3014       pblocks[0]       = PetscAbs(pblocks[0]);
3015       for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) {
3016         if (pblocks[i] == 0) continue;
3017         // Negative block size indicates the blocks should be concatenated
3018         if (pblocks[i] < 0) {
3019           pblocks[i] = -pblocks[i];
3020           pblocks[nblocks - 1] += pblocks[i];
3021         } else {
3022           pblocks[nblocks++] = pblocks[i]; // nblocks always <= i
3023         }
3024         for (PetscInt j = 1; j < pblocks[i]; j++)
3025           PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " at %" PetscInt_FMT " mismatches entry %" PetscInt_FMT " at %" PetscInt_FMT, pblocks[i], i, pblocks[i + j], i + j);
3026       }
3027       PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks));
3028     }
3029     PetscCall(PetscFree(pblocks));
3030   }
3031   PetscCall(MatSetDM(*J, dm));
3032   PetscFunctionReturn(PETSC_SUCCESS);
3033 }
3034 
3035 /*@
3036   DMPlexGetSubdomainSection - Returns the section associated with the subdomain
3037 
3038   Not Collective
3039 
3040   Input Parameter:
3041 . dm - The `DMPLEX`
3042 
3043   Output Parameter:
3044 . subsection - The subdomain section
3045 
3046   Level: developer
3047 
3048 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection`
3049 @*/
DMPlexGetSubdomainSection(DM dm,PetscSection * subsection)3050 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
3051 {
3052   DM_Plex *mesh = (DM_Plex *)dm->data;
3053 
3054   PetscFunctionBegin;
3055   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3056   if (!mesh->subdomainSection) {
3057     PetscSection section;
3058     PetscSF      sf;
3059 
3060     PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf));
3061     PetscCall(DMGetLocalSection(dm, &section));
3062     PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection));
3063     PetscCall(PetscSFDestroy(&sf));
3064   }
3065   *subsection = mesh->subdomainSection;
3066   PetscFunctionReturn(PETSC_SUCCESS);
3067 }
3068 
3069 /*@
3070   DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`)
3071 
3072   Not Collective
3073 
3074   Input Parameter:
3075 . dm - The `DMPLEX`
3076 
3077   Output Parameters:
3078 + pStart - The first mesh point
3079 - pEnd   - The upper bound for mesh points
3080 
3081   Level: beginner
3082 
3083 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`
3084 @*/
DMPlexGetChart(DM dm,PetscInt * pStart,PetscInt * pEnd)3085 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
3086 {
3087   DM_Plex *mesh = (DM_Plex *)dm->data;
3088 
3089   PetscFunctionBegin;
3090   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3091   if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd));
3092   else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd));
3093   PetscFunctionReturn(PETSC_SUCCESS);
3094 }
3095 
3096 /*@
3097   DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`)
3098 
3099   Not Collective
3100 
3101   Input Parameters:
3102 + dm     - The `DMPLEX`
3103 . pStart - The first mesh point
3104 - pEnd   - The upper bound for mesh points
3105 
3106   Level: beginner
3107 
3108 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()`
3109 @*/
DMPlexSetChart(DM dm,PetscInt pStart,PetscInt pEnd)3110 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
3111 {
3112   DM_Plex *mesh = (DM_Plex *)dm->data;
3113 
3114   PetscFunctionBegin;
3115   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3116   PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd));
3117   PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd));
3118   PetscCall(PetscFree(mesh->cellTypes));
3119   PetscFunctionReturn(PETSC_SUCCESS);
3120 }
3121 
3122 /*@
3123   DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
3124 
3125   Not Collective
3126 
3127   Input Parameters:
3128 + dm - The `DMPLEX`
3129 - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3130 
3131   Output Parameter:
3132 . size - The cone size for point `p`
3133 
3134   Level: beginner
3135 
3136 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
3137 @*/
DMPlexGetConeSize(DM dm,PetscInt p,PetscInt * size)3138 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
3139 {
3140   DM_Plex *mesh = (DM_Plex *)dm->data;
3141 
3142   PetscFunctionBegin;
3143   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3144   PetscAssertPointer(size, 3);
3145   if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size));
3146   else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size));
3147   PetscFunctionReturn(PETSC_SUCCESS);
3148 }
3149 
3150 /*@
3151   DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
3152 
3153   Not Collective
3154 
3155   Input Parameters:
3156 + dm   - The `DMPLEX`
3157 . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
3158 - size - The cone size for point `p`
3159 
3160   Level: beginner
3161 
3162   Note:
3163   This should be called after `DMPlexSetChart()`.
3164 
3165 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()`
3166 @*/
DMPlexSetConeSize(DM dm,PetscInt p,PetscInt size)3167 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
3168 {
3169   DM_Plex *mesh = (DM_Plex *)dm->data;
3170 
3171   PetscFunctionBegin;
3172   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3173   PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined.");
3174   PetscCall(PetscSectionSetDof(mesh->coneSection, p, size));
3175   PetscFunctionReturn(PETSC_SUCCESS);
3176 }
3177 
3178 /*@C
3179   DMPlexGetCone - Return the points on the in-edges for this point in the DAG
3180 
3181   Not Collective
3182 
3183   Input Parameters:
3184 + dm - The `DMPLEX`
3185 - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3186 
3187   Output Parameter:
3188 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()`
3189 
3190   Level: beginner
3191 
3192   Fortran Notes:
3193   `cone` must be declared with
3194 .vb
3195   PetscInt, pointer :: cone(:)
3196 .ve
3197 
3198   You must call `DMPlexRestoreCone()` after you finish using the array.
3199   `DMPlexRestoreCone()` is not needed/available in C.
3200 
3201 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()`
3202 @*/
DMPlexGetCone(DM dm,PetscInt p,const PetscInt * cone[])3203 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
3204 {
3205   DM_Plex *mesh = (DM_Plex *)dm->data;
3206   PetscInt off;
3207 
3208   PetscFunctionBegin;
3209   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3210   PetscAssertPointer(cone, 3);
3211   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3212   *cone = PetscSafePointerPlusOffset(mesh->cones, off);
3213   PetscFunctionReturn(PETSC_SUCCESS);
3214 }
3215 
3216 /*@
3217   DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
3218 
3219   Not Collective
3220 
3221   Input Parameters:
3222 + dm - The `DMPLEX`
3223 - p  - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3224 
3225   Output Parameters:
3226 + pConesSection - `PetscSection` describing the layout of `pCones`
3227 - pCones        - An `IS` containing the points which are on the in-edges for the point set `p`
3228 
3229   Level: intermediate
3230 
3231 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS`
3232 @*/
DMPlexGetConeTuple(DM dm,IS p,PeOp PetscSection * pConesSection,PeOp IS * pCones)3233 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PeOp PetscSection *pConesSection, PeOp IS *pCones)
3234 {
3235   PetscSection cs, newcs;
3236   PetscInt    *cones;
3237   PetscInt    *newarr = NULL;
3238   PetscInt     n;
3239 
3240   PetscFunctionBegin;
3241   PetscCall(DMPlexGetCones(dm, &cones));
3242   PetscCall(DMPlexGetConeSection(dm, &cs));
3243   PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL));
3244   if (pConesSection) *pConesSection = newcs;
3245   if (pCones) {
3246     PetscCall(PetscSectionGetStorageSize(newcs, &n));
3247     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones));
3248   }
3249   PetscFunctionReturn(PETSC_SUCCESS);
3250 }
3251 
3252 /*@
3253   DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.
3254 
3255   Not Collective
3256 
3257   Input Parameters:
3258 + dm     - The `DMPLEX`
3259 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3260 
3261   Output Parameter:
3262 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points
3263 
3264   Level: advanced
3265 
3266   Notes:
3267   Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections.
3268 
3269   There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate.
3270 
3271 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`,
3272           `DMPlexGetDepth()`, `IS`
3273 @*/
DMPlexGetConeRecursiveVertices(DM dm,IS points,IS * expandedPoints)3274 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
3275 {
3276   IS      *expandedPointsAll;
3277   PetscInt depth;
3278 
3279   PetscFunctionBegin;
3280   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3281   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
3282   PetscAssertPointer(expandedPoints, 3);
3283   PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
3284   *expandedPoints = expandedPointsAll[0];
3285   PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0]));
3286   PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
3287   PetscFunctionReturn(PETSC_SUCCESS);
3288 }
3289 
3290 /*@
3291   DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices
3292   (DAG points of depth 0, i.e., without cones).
3293 
3294   Not Collective
3295 
3296   Input Parameters:
3297 + dm     - The `DMPLEX`
3298 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3299 
3300   Output Parameters:
3301 + depth          - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()`
3302 . expandedPoints - (optional) An array of index sets with recursively expanded cones
3303 - sections       - (optional) An array of sections which describe mappings from points to their cone points
3304 
3305   Level: advanced
3306 
3307   Notes:
3308   Like `DMPlexGetConeTuple()` but recursive.
3309 
3310   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.
3311   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.
3312 
3313   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\:
3314   (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d];
3315   (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d].
3316 
3317 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3318           `DMPlexGetDepth()`, `PetscSection`, `IS`
3319 @*/
DMPlexGetConeRecursive(DM dm,IS points,PeOp PetscInt * depth,PeOp IS * expandedPoints[],PeOp PetscSection * sections[])3320 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[])
3321 {
3322   const PetscInt *arr0 = NULL, *cone = NULL;
3323   PetscInt       *arr = NULL, *newarr = NULL;
3324   PetscInt        d, depth_, i, n, newn, cn, co, start, end;
3325   IS             *expandedPoints_;
3326   PetscSection   *sections_;
3327 
3328   PetscFunctionBegin;
3329   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3330   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
3331   if (depth) PetscAssertPointer(depth, 3);
3332   if (expandedPoints) PetscAssertPointer(expandedPoints, 4);
3333   if (sections) PetscAssertPointer(sections, 5);
3334   PetscCall(ISGetLocalSize(points, &n));
3335   PetscCall(ISGetIndices(points, &arr0));
3336   PetscCall(DMPlexGetDepth(dm, &depth_));
3337   PetscCall(PetscCalloc1(depth_, &expandedPoints_));
3338   PetscCall(PetscCalloc1(depth_, &sections_));
3339   arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */
3340   for (d = depth_ - 1; d >= 0; d--) {
3341     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]));
3342     PetscCall(PetscSectionSetChart(sections_[d], 0, n));
3343     for (i = 0; i < n; i++) {
3344       PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end));
3345       if (arr[i] >= start && arr[i] < end) {
3346         PetscCall(DMPlexGetConeSize(dm, arr[i], &cn));
3347         PetscCall(PetscSectionSetDof(sections_[d], i, cn));
3348       } else {
3349         PetscCall(PetscSectionSetDof(sections_[d], i, 1));
3350       }
3351     }
3352     PetscCall(PetscSectionSetUp(sections_[d]));
3353     PetscCall(PetscSectionGetStorageSize(sections_[d], &newn));
3354     PetscCall(PetscMalloc1(newn, &newarr));
3355     for (i = 0; i < n; i++) {
3356       PetscCall(PetscSectionGetDof(sections_[d], i, &cn));
3357       PetscCall(PetscSectionGetOffset(sections_[d], i, &co));
3358       if (cn > 1) {
3359         PetscCall(DMPlexGetCone(dm, arr[i], &cone));
3360         PetscCall(PetscArraycpy(&newarr[co], cone, cn));
3361       } else {
3362         newarr[co] = arr[i];
3363       }
3364     }
3365     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]));
3366     arr = newarr;
3367     n   = newn;
3368   }
3369   PetscCall(ISRestoreIndices(points, &arr0));
3370   *depth = depth_;
3371   if (expandedPoints) *expandedPoints = expandedPoints_;
3372   else {
3373     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d]));
3374     PetscCall(PetscFree(expandedPoints_));
3375   }
3376   if (sections) *sections = sections_;
3377   else {
3378     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&sections_[d]));
3379     PetscCall(PetscFree(sections_));
3380   }
3381   PetscFunctionReturn(PETSC_SUCCESS);
3382 }
3383 
3384 /*@
3385   DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()`
3386 
3387   Not Collective
3388 
3389   Input Parameters:
3390 + dm     - The `DMPLEX`
3391 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3392 
3393   Output Parameters:
3394 + depth          - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()`
3395 . expandedPoints - (optional) An array of recursively expanded cones
3396 - sections       - (optional) An array of sections which describe mappings from points to their cone points
3397 
3398   Level: advanced
3399 
3400   Note:
3401   See `DMPlexGetConeRecursive()`
3402 
3403 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3404           `DMPlexGetDepth()`, `IS`, `PetscSection`
3405 @*/
DMPlexRestoreConeRecursive(DM dm,IS points,PeOp PetscInt * depth,PeOp IS * expandedPoints[],PeOp PetscSection * sections[])3406 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[])
3407 {
3408   PetscInt d, depth_;
3409 
3410   PetscFunctionBegin;
3411   PetscCall(DMPlexGetDepth(dm, &depth_));
3412   PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
3413   if (depth) *depth = 0;
3414   if (expandedPoints) {
3415     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d]));
3416     PetscCall(PetscFree(*expandedPoints));
3417   }
3418   if (sections) {
3419     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d]));
3420     PetscCall(PetscFree(*sections));
3421   }
3422   PetscFunctionReturn(PETSC_SUCCESS);
3423 }
3424 
3425 /*@
3426   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
3427 
3428   Not Collective
3429 
3430   Input Parameters:
3431 + dm   - The `DMPLEX`
3432 . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
3433 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()`
3434 
3435   Level: beginner
3436 
3437   Note:
3438   This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`.
3439 
3440 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()`
3441 @*/
DMPlexSetCone(DM dm,PetscInt p,const PetscInt cone[])3442 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
3443 {
3444   DM_Plex *mesh = (DM_Plex *)dm->data;
3445   PetscInt dof, off, c;
3446 
3447   PetscFunctionBegin;
3448   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3449   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3450   if (dof) PetscAssertPointer(cone, 3);
3451   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3452   if (PetscDefined(USE_DEBUG)) {
3453     PetscInt pStart, pEnd;
3454     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3455     PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3456     for (c = 0; c < dof; ++c) {
3457       PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd);
3458       mesh->cones[off + c] = cone[c];
3459     }
3460   } else {
3461     for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c];
3462   }
3463   PetscFunctionReturn(PETSC_SUCCESS);
3464 }
3465 
3466 /*@C
3467   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
3468 
3469   Not Collective
3470 
3471   Input Parameters:
3472 + dm - The `DMPLEX`
3473 - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3474 
3475   Output Parameter:
3476 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an
3477                     integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()`
3478 
3479   Level: beginner
3480 
3481   Note:
3482   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3483   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3484   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
3485   with the identity.
3486 
3487   Fortran Notes:
3488   You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array.
3489   `DMPlexRestoreConeOrientation()` is not needed/available in C.
3490 
3491 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`,
3492           `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()`
3493 @*/
DMPlexGetConeOrientation(DM dm,PetscInt p,const PetscInt * coneOrientation[])3494 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
3495 {
3496   DM_Plex *mesh = (DM_Plex *)dm->data;
3497   PetscInt off;
3498 
3499   PetscFunctionBegin;
3500   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3501   if (PetscDefined(USE_DEBUG)) {
3502     PetscInt dof;
3503     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3504     if (dof) PetscAssertPointer(coneOrientation, 3);
3505   }
3506   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3507 
3508   *coneOrientation = &mesh->coneOrientations[off];
3509   PetscFunctionReturn(PETSC_SUCCESS);
3510 }
3511 
3512 /*@
3513   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
3514 
3515   Not Collective
3516 
3517   Input Parameters:
3518 + dm              - The `DMPLEX`
3519 . p               - The point, which must lie in the chart set with `DMPlexSetChart()`
3520 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()`
3521 
3522   Level: beginner
3523 
3524   Notes:
3525   This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`.
3526 
3527   The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`.
3528 
3529 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3530 @*/
DMPlexSetConeOrientation(DM dm,PetscInt p,const PetscInt coneOrientation[])3531 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
3532 {
3533   DM_Plex *mesh = (DM_Plex *)dm->data;
3534   PetscInt pStart, pEnd;
3535   PetscInt dof, off, c;
3536 
3537   PetscFunctionBegin;
3538   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3539   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3540   if (dof) PetscAssertPointer(coneOrientation, 3);
3541   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3542   if (PetscDefined(USE_DEBUG)) {
3543     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3544     PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3545     for (c = 0; c < dof; ++c) {
3546       PetscInt cdof, o = coneOrientation[c];
3547 
3548       PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof));
3549       PetscCheck(!o || (o >= -(cdof + 1) && o < cdof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof + 1), cdof);
3550       mesh->coneOrientations[off + c] = o;
3551     }
3552   } else {
3553     for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c];
3554   }
3555   PetscFunctionReturn(PETSC_SUCCESS);
3556 }
3557 
3558 /*@
3559   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
3560 
3561   Not Collective
3562 
3563   Input Parameters:
3564 + dm        - The `DMPLEX`
3565 . p         - The point, which must lie in the chart set with `DMPlexSetChart()`
3566 . conePos   - The local index in the cone where the point should be put
3567 - conePoint - The mesh point to insert
3568 
3569   Level: beginner
3570 
3571 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3572 @*/
DMPlexInsertCone(DM dm,PetscInt p,PetscInt conePos,PetscInt conePoint)3573 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
3574 {
3575   DM_Plex *mesh = (DM_Plex *)dm->data;
3576   PetscInt pStart, pEnd;
3577   PetscInt dof, off;
3578 
3579   PetscFunctionBegin;
3580   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3581   if (PetscDefined(USE_DEBUG)) {
3582     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3583     PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3584     PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd);
3585     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3586     PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof);
3587   }
3588   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3589   mesh->cones[off + conePos] = conePoint;
3590   PetscFunctionReturn(PETSC_SUCCESS);
3591 }
3592 
3593 /*@
3594   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
3595 
3596   Not Collective
3597 
3598   Input Parameters:
3599 + dm              - The `DMPLEX`
3600 . p               - The point, which must lie in the chart set with `DMPlexSetChart()`
3601 . conePos         - The local index in the cone where the point should be put
3602 - coneOrientation - The point orientation to insert
3603 
3604   Level: beginner
3605 
3606   Note:
3607   The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`.
3608 
3609 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3610 @*/
DMPlexInsertConeOrientation(DM dm,PetscInt p,PetscInt conePos,PetscInt coneOrientation)3611 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
3612 {
3613   DM_Plex *mesh = (DM_Plex *)dm->data;
3614   PetscInt pStart, pEnd;
3615   PetscInt dof, off;
3616 
3617   PetscFunctionBegin;
3618   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3619   if (PetscDefined(USE_DEBUG)) {
3620     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3621     PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3622     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3623     PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof);
3624   }
3625   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3626   mesh->coneOrientations[off + conePos] = coneOrientation;
3627   PetscFunctionReturn(PETSC_SUCCESS);
3628 }
3629 
3630 /*@C
3631   DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG
3632 
3633   Not collective
3634 
3635   Input Parameters:
3636 + dm - The DMPlex
3637 - p  - The point, which must lie in the chart set with DMPlexSetChart()
3638 
3639   Output Parameters:
3640 + cone - An array of points which are on the in-edges for point `p`
3641 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
3642          integer giving the prescription for cone traversal.
3643 
3644   Level: beginner
3645 
3646   Notes:
3647   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3648   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3649   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
3650   with the identity.
3651 
3652   You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array.
3653 
3654   Fortran Notes:
3655   `cone` and `ornt` must be declared with
3656 .vb
3657   PetscInt, pointer :: cone(:)
3658   PetscInt, pointer :: ornt(:)
3659 .ve
3660 
3661 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
3662 @*/
DMPlexGetOrientedCone(DM dm,PetscInt p,PeOp const PetscInt * cone[],PeOp const PetscInt * ornt[])3663 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, PeOp const PetscInt *cone[], PeOp const PetscInt *ornt[])
3664 {
3665   DM_Plex *mesh = (DM_Plex *)dm->data;
3666 
3667   PetscFunctionBegin;
3668   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3669   if (mesh->tr) {
3670     PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt));
3671   } else {
3672     PetscInt off;
3673     if (PetscDefined(USE_DEBUG)) {
3674       PetscInt dof;
3675       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3676       if (dof) {
3677         if (cone) PetscAssertPointer(cone, 3);
3678         if (ornt) PetscAssertPointer(ornt, 4);
3679       }
3680     }
3681     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3682     if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off);
3683     if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off);
3684   }
3685   PetscFunctionReturn(PETSC_SUCCESS);
3686 }
3687 
3688 /*@C
3689   DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()`
3690 
3691   Not Collective
3692 
3693   Input Parameters:
3694 + dm   - The DMPlex
3695 . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
3696 . cone - An array of points which are on the in-edges for point p
3697 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
3698          integer giving the prescription for cone traversal.
3699 
3700   Level: beginner
3701 
3702 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
3703 @*/
DMPlexRestoreOrientedCone(DM dm,PetscInt p,const PetscInt * cone[],const PetscInt * ornt[])3704 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
3705 {
3706   DM_Plex *mesh = (DM_Plex *)dm->data;
3707 
3708   PetscFunctionBegin;
3709   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3710   if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt));
3711   PetscFunctionReturn(PETSC_SUCCESS);
3712 }
3713 
3714 /*@
3715   DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
3716 
3717   Not Collective
3718 
3719   Input Parameters:
3720 + dm - The `DMPLEX`
3721 - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3722 
3723   Output Parameter:
3724 . size - The support size for point `p`
3725 
3726   Level: beginner
3727 
3728 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()`
3729 @*/
DMPlexGetSupportSize(DM dm,PetscInt p,PetscInt * size)3730 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
3731 {
3732   DM_Plex *mesh = (DM_Plex *)dm->data;
3733 
3734   PetscFunctionBegin;
3735   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3736   PetscAssertPointer(size, 3);
3737   PetscCall(PetscSectionGetDof(mesh->supportSection, p, size));
3738   PetscFunctionReturn(PETSC_SUCCESS);
3739 }
3740 
3741 /*@
3742   DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
3743 
3744   Not Collective
3745 
3746   Input Parameters:
3747 + dm   - The `DMPLEX`
3748 . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
3749 - size - The support size for point `p`
3750 
3751   Level: beginner
3752 
3753   Note:
3754   This should be called after `DMPlexSetChart()`.
3755 
3756 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()`
3757 @*/
DMPlexSetSupportSize(DM dm,PetscInt p,PetscInt size)3758 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
3759 {
3760   DM_Plex *mesh = (DM_Plex *)dm->data;
3761 
3762   PetscFunctionBegin;
3763   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3764   PetscCall(PetscSectionSetDof(mesh->supportSection, p, size));
3765   PetscFunctionReturn(PETSC_SUCCESS);
3766 }
3767 
3768 /*@C
3769   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
3770 
3771   Not Collective
3772 
3773   Input Parameters:
3774 + dm - The `DMPLEX`
3775 - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3776 
3777   Output Parameter:
3778 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()`
3779 
3780   Level: beginner
3781 
3782   Fortran Notes:
3783   `support` must be declared with
3784 .vb
3785   PetscInt, pointer :: support(:)
3786 .ve
3787 
3788   You must also call `DMPlexRestoreSupport()` after you finish using the returned array.
3789   `DMPlexRestoreSupport()` is not needed/available in C.
3790 
3791 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()`
3792 @*/
DMPlexGetSupport(DM dm,PetscInt p,const PetscInt * support[])3793 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
3794 {
3795   DM_Plex *mesh = (DM_Plex *)dm->data;
3796   PetscInt off;
3797 
3798   PetscFunctionBegin;
3799   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3800   PetscAssertPointer(support, 3);
3801   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3802   *support = PetscSafePointerPlusOffset(mesh->supports, off);
3803   PetscFunctionReturn(PETSC_SUCCESS);
3804 }
3805 
3806 /*@
3807   DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers
3808 
3809   Not Collective
3810 
3811   Input Parameters:
3812 + dm      - The `DMPLEX`
3813 . p       - The point, which must lie in the chart set with `DMPlexSetChart()`
3814 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()`
3815 
3816   Level: beginner
3817 
3818   Note:
3819   This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`.
3820 
3821 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()`
3822 @*/
DMPlexSetSupport(DM dm,PetscInt p,const PetscInt support[])3823 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
3824 {
3825   DM_Plex *mesh = (DM_Plex *)dm->data;
3826   PetscInt pStart, pEnd;
3827   PetscInt dof, off, c;
3828 
3829   PetscFunctionBegin;
3830   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3831   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
3832   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
3833   if (dof) PetscAssertPointer(support, 3);
3834   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3835   PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3836   for (c = 0; c < dof; ++c) {
3837     PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd);
3838     mesh->supports[off + c] = support[c];
3839   }
3840   PetscFunctionReturn(PETSC_SUCCESS);
3841 }
3842 
3843 /*@
3844   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
3845 
3846   Not Collective
3847 
3848   Input Parameters:
3849 + dm           - The `DMPLEX`
3850 . p            - The point, which must lie in the chart set with `DMPlexSetChart()`
3851 . supportPos   - The local index in the cone where the point should be put
3852 - supportPoint - The mesh point to insert
3853 
3854   Level: beginner
3855 
3856 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3857 @*/
DMPlexInsertSupport(DM dm,PetscInt p,PetscInt supportPos,PetscInt supportPoint)3858 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
3859 {
3860   DM_Plex *mesh = (DM_Plex *)dm->data;
3861   PetscInt pStart, pEnd;
3862   PetscInt dof, off;
3863 
3864   PetscFunctionBegin;
3865   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3866   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
3867   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
3868   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3869   PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3870   PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd);
3871   PetscCheck(supportPos < dof, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof);
3872   mesh->supports[off + supportPos] = supportPoint;
3873   PetscFunctionReturn(PETSC_SUCCESS);
3874 }
3875 
3876 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */
DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct,PetscInt o)3877 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o)
3878 {
3879   switch (ct) {
3880   case DM_POLYTOPE_SEGMENT:
3881     if (o == -1) return -2;
3882     break;
3883   case DM_POLYTOPE_TRIANGLE:
3884     if (o == -3) return -1;
3885     if (o == -2) return -3;
3886     if (o == -1) return -2;
3887     break;
3888   case DM_POLYTOPE_QUADRILATERAL:
3889     if (o == -4) return -2;
3890     if (o == -3) return -1;
3891     if (o == -2) return -4;
3892     if (o == -1) return -3;
3893     break;
3894   default:
3895     return o;
3896   }
3897   return o;
3898 }
3899 
3900 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */
DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct,PetscInt o)3901 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o)
3902 {
3903   switch (ct) {
3904   case DM_POLYTOPE_SEGMENT:
3905     if ((o == -2) || (o == 1)) return -1;
3906     if (o == -1) return 0;
3907     break;
3908   case DM_POLYTOPE_TRIANGLE:
3909     if (o == -3) return -2;
3910     if (o == -2) return -1;
3911     if (o == -1) return -3;
3912     break;
3913   case DM_POLYTOPE_QUADRILATERAL:
3914     if (o == -4) return -2;
3915     if (o == -3) return -1;
3916     if (o == -2) return -4;
3917     if (o == -1) return -3;
3918     break;
3919   default:
3920     return o;
3921   }
3922   return o;
3923 }
3924 
3925 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */
DMPlexConvertOldOrientations_Internal(DM dm)3926 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm)
3927 {
3928   PetscInt pStart, pEnd, p;
3929 
3930   PetscFunctionBegin;
3931   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3932   for (p = pStart; p < pEnd; ++p) {
3933     const PetscInt *cone, *ornt;
3934     PetscInt        coneSize, c;
3935 
3936     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
3937     PetscCall(DMPlexGetCone(dm, p, &cone));
3938     PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
3939     for (c = 0; c < coneSize; ++c) {
3940       DMPolytopeType ct;
3941       const PetscInt o = ornt[c];
3942 
3943       PetscCall(DMPlexGetCellType(dm, cone[c], &ct));
3944       switch (ct) {
3945       case DM_POLYTOPE_SEGMENT:
3946         if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
3947         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0));
3948         break;
3949       case DM_POLYTOPE_TRIANGLE:
3950         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
3951         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
3952         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3953         break;
3954       case DM_POLYTOPE_QUADRILATERAL:
3955         if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
3956         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
3957         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4));
3958         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3959         break;
3960       default:
3961         break;
3962       }
3963     }
3964   }
3965   PetscFunctionReturn(PETSC_SUCCESS);
3966 }
3967 
DMPlexGetTransitiveClosure_Hot_Private(DM dm,PetscInt p,PetscBool useCone,PetscInt * size,const PetscInt * arr[],const PetscInt * ornt[])3968 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[])
3969 {
3970   DM_Plex *mesh = (DM_Plex *)dm->data;
3971 
3972   PetscFunctionBeginHot;
3973   if (PetscDefined(USE_DEBUG) || mesh->tr) {
3974     if (useCone) {
3975       PetscCall(DMPlexGetConeSize(dm, p, size));
3976       PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt));
3977     } else {
3978       PetscCall(DMPlexGetSupportSize(dm, p, size));
3979       PetscCall(DMPlexGetSupport(dm, p, arr));
3980     }
3981   } else {
3982     if (useCone) {
3983       const PetscSection s   = mesh->coneSection;
3984       const PetscInt     ps  = p - s->pStart;
3985       const PetscInt     off = s->atlasOff[ps];
3986 
3987       *size = s->atlasDof[ps];
3988       *arr  = mesh->cones + off;
3989       *ornt = mesh->coneOrientations + off;
3990     } else {
3991       const PetscSection s   = mesh->supportSection;
3992       const PetscInt     ps  = p - s->pStart;
3993       const PetscInt     off = s->atlasOff[ps];
3994 
3995       *size = s->atlasDof[ps];
3996       *arr  = mesh->supports + off;
3997     }
3998   }
3999   PetscFunctionReturn(PETSC_SUCCESS);
4000 }
4001 
DMPlexRestoreTransitiveClosure_Hot_Private(DM dm,PetscInt p,PetscBool useCone,PetscInt * size,const PetscInt * arr[],const PetscInt * ornt[])4002 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[])
4003 {
4004   DM_Plex *mesh = (DM_Plex *)dm->data;
4005 
4006   PetscFunctionBeginHot;
4007   if (PetscDefined(USE_DEBUG) || mesh->tr) {
4008     if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt));
4009   }
4010   PetscFunctionReturn(PETSC_SUCCESS);
4011 }
4012 
DMPlexGetTransitiveClosure_Depth1_Private(DM dm,PetscInt p,PetscInt ornt,PetscBool useCone,PetscInt * numPoints,PetscInt * points[])4013 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4014 {
4015   DMPolytopeType  ct = DM_POLYTOPE_UNKNOWN;
4016   PetscInt       *closure;
4017   const PetscInt *tmp = NULL, *tmpO = NULL;
4018   PetscInt        off = 0, tmpSize, t;
4019 
4020   PetscFunctionBeginHot;
4021   if (ornt) {
4022     PetscCall(DMPlexGetCellType(dm, p, &ct));
4023     if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN;
4024   }
4025   if (*points) {
4026     closure = *points;
4027   } else {
4028     PetscInt maxConeSize, maxSupportSize;
4029     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
4030     PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure));
4031   }
4032   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
4033   if (ct == DM_POLYTOPE_UNKNOWN) {
4034     closure[off++] = p;
4035     closure[off++] = 0;
4036     for (t = 0; t < tmpSize; ++t) {
4037       closure[off++] = tmp[t];
4038       closure[off++] = tmpO ? tmpO[t] : 0;
4039     }
4040   } else {
4041     const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt);
4042 
4043     /* We assume that cells with a valid type have faces with a valid type */
4044     closure[off++] = p;
4045     closure[off++] = ornt;
4046     for (t = 0; t < tmpSize; ++t) {
4047       DMPolytopeType ft;
4048 
4049       PetscCall(DMPlexGetCellType(dm, tmp[t], &ft));
4050       closure[off++] = tmp[arr[t]];
4051       closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0;
4052     }
4053   }
4054   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
4055   if (numPoints) *numPoints = tmpSize + 1;
4056   if (points) *points = closure;
4057   PetscFunctionReturn(PETSC_SUCCESS);
4058 }
4059 
4060 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */
DMPlexTransitiveClosure_Tensor_Internal(DM dm,PetscInt point,DMPolytopeType ct,PetscInt o,PetscBool useCone,PetscInt * numPoints,PetscInt ** points)4061 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points)
4062 {
4063   const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o);
4064   const PetscInt *cone, *ornt;
4065   PetscInt       *pts, *closure = NULL;
4066   DMPolytopeType  ft;
4067   PetscInt        maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize;
4068   PetscInt        dim, coneSize, c, d, clSize, cl;
4069 
4070   PetscFunctionBeginHot;
4071   PetscCall(DMGetDimension(dm, &dim));
4072   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
4073   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
4074   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1;
4075   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1;
4076   maxSize       = PetscMax(coneSeries, supportSeries);
4077   if (*points) {
4078     pts = *points;
4079   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts));
4080   c        = 0;
4081   pts[c++] = point;
4082   pts[c++] = o;
4083   PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft));
4084   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure));
4085   for (cl = 0; cl < clSize * 2; cl += 2) {
4086     pts[c++] = closure[cl];
4087     pts[c++] = closure[cl + 1];
4088   }
4089   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure));
4090   for (cl = 0; cl < clSize * 2; cl += 2) {
4091     pts[c++] = closure[cl];
4092     pts[c++] = closure[cl + 1];
4093   }
4094   PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure));
4095   for (d = 2; d < coneSize; ++d) {
4096     PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft));
4097     pts[c++] = cone[arr[d * 2 + 0]];
4098     pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]);
4099   }
4100   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
4101   if (dim >= 3) {
4102     for (d = 2; d < coneSize; ++d) {
4103       const PetscInt  fpoint = cone[arr[d * 2 + 0]];
4104       const PetscInt *fcone, *fornt;
4105       PetscInt        fconeSize, fc, i;
4106 
4107       PetscCall(DMPlexGetCellType(dm, fpoint, &ft));
4108       const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]));
4109       PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
4110       for (fc = 0; fc < fconeSize; ++fc) {
4111         const PetscInt cp = fcone[farr[fc * 2 + 0]];
4112         const PetscInt co = farr[fc * 2 + 1];
4113 
4114         for (i = 0; i < c; i += 2)
4115           if (pts[i] == cp) break;
4116         if (i == c) {
4117           PetscCall(DMPlexGetCellType(dm, cp, &ft));
4118           pts[c++] = cp;
4119           pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]);
4120         }
4121       }
4122       PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
4123     }
4124   }
4125   *numPoints = c / 2;
4126   *points    = pts;
4127   PetscFunctionReturn(PETSC_SUCCESS);
4128 }
4129 
DMPlexGetTransitiveClosure_Internal(DM dm,PetscInt p,PetscInt ornt,PetscBool useCone,PetscInt * numPoints,PetscInt * points[])4130 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4131 {
4132   DMPolytopeType ct;
4133   PetscInt      *closure, *fifo;
4134   PetscInt       closureSize = 0, fifoStart = 0, fifoSize = 0;
4135   PetscInt       maxConeSize, maxSupportSize, coneSeries, supportSeries;
4136   PetscInt       depth, maxSize;
4137 
4138   PetscFunctionBeginHot;
4139   PetscCall(DMPlexGetDepth(dm, &depth));
4140   if (depth == 1) {
4141     PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points));
4142     PetscFunctionReturn(PETSC_SUCCESS);
4143   }
4144   PetscCall(DMPlexGetCellType(dm, p, &ct));
4145   if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN;
4146   if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) {
4147     PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points));
4148     PetscFunctionReturn(PETSC_SUCCESS);
4149   }
4150   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
4151   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1;
4152   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1;
4153   maxSize       = PetscMax(coneSeries, supportSeries);
4154   PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
4155   if (*points) {
4156     closure = *points;
4157   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure));
4158   closure[closureSize++] = p;
4159   closure[closureSize++] = ornt;
4160   fifo[fifoSize++]       = p;
4161   fifo[fifoSize++]       = ornt;
4162   fifo[fifoSize++]       = ct;
4163   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
4164   while (fifoSize - fifoStart) {
4165     const PetscInt       q    = fifo[fifoStart++];
4166     const PetscInt       o    = fifo[fifoStart++];
4167     const DMPolytopeType qt   = (DMPolytopeType)fifo[fifoStart++];
4168     const PetscInt      *qarr = DMPolytopeTypeGetArrangement(qt, o);
4169     const PetscInt      *tmp, *tmpO = NULL;
4170     PetscInt             tmpSize, t;
4171 
4172     if (PetscDefined(USE_DEBUG)) {
4173       PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2;
4174       PetscCheck(!o || !(o >= nO || o < -nO), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q);
4175     }
4176     PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
4177     for (t = 0; t < tmpSize; ++t) {
4178       const PetscInt ip = useCone && qarr ? qarr[t * 2] : t;
4179       const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0;
4180       const PetscInt cp = tmp[ip];
4181       PetscCall(DMPlexGetCellType(dm, cp, &ct));
4182       const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0;
4183       PetscInt       c;
4184 
4185       /* Check for duplicate */
4186       for (c = 0; c < closureSize; c += 2) {
4187         if (closure[c] == cp) break;
4188       }
4189       if (c == closureSize) {
4190         closure[closureSize++] = cp;
4191         closure[closureSize++] = co;
4192         fifo[fifoSize++]       = cp;
4193         fifo[fifoSize++]       = co;
4194         fifo[fifoSize++]       = ct;
4195       }
4196     }
4197     PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
4198   }
4199   PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
4200   if (numPoints) *numPoints = closureSize / 2;
4201   if (points) *points = closure;
4202   PetscFunctionReturn(PETSC_SUCCESS);
4203 }
4204 
4205 /*@C
4206   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
4207 
4208   Not Collective
4209 
4210   Input Parameters:
4211 + dm      - The `DMPLEX`
4212 . p       - The mesh point
4213 - useCone - `PETSC_TRUE` for the closure, otherwise return the support
4214 
4215   Input/Output Parameter:
4216 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...];
4217            if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`,
4218            otherwise the provided array is used to hold the values
4219 
4220   Output Parameter:
4221 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints`
4222 
4223   Level: beginner
4224 
4225   Note:
4226   If using internal storage (points is `NULL` on input), each call overwrites the last output.
4227 
4228   Fortran Notes:
4229   `points` must be declared with
4230 .vb
4231   PetscInt, pointer :: points(:)
4232 .ve
4233   and is always allocated by the function.
4234 
4235   Pass `PETSC_NULL_INTEGER` for `numPoints` if it is not needed
4236 
4237 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
4238 @*/
DMPlexGetTransitiveClosure(DM dm,PetscInt p,PetscBool useCone,PetscInt * numPoints,PetscInt * points[])4239 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4240 {
4241   PetscFunctionBeginHot;
4242   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4243   if (numPoints) PetscAssertPointer(numPoints, 4);
4244   if (points) PetscAssertPointer(points, 5);
4245   if (PetscDefined(USE_DEBUG)) {
4246     PetscInt pStart, pEnd;
4247     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4248     PetscCheck(p >= pStart && p < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
4249   }
4250   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points));
4251   PetscFunctionReturn(PETSC_SUCCESS);
4252 }
4253 
4254 /*@C
4255   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
4256 
4257   Not Collective
4258 
4259   Input Parameters:
4260 + dm        - The `DMPLEX`
4261 . p         - The mesh point
4262 . useCone   - `PETSC_TRUE` for the closure, otherwise return the star
4263 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints`
4264 - points    - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
4265 
4266   Level: beginner
4267 
4268   Note:
4269   If not using internal storage (points is not `NULL` on input), this call is unnecessary
4270 
4271 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
4272 @*/
DMPlexRestoreTransitiveClosure(DM dm,PetscInt p,PetscBool useCone,PetscInt * numPoints,PetscInt * points[])4273 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4274 {
4275   PetscFunctionBeginHot;
4276   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4277   if (numPoints) *numPoints = 0;
4278   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points));
4279   PetscFunctionReturn(PETSC_SUCCESS);
4280 }
4281 
4282 /*@
4283   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
4284 
4285   Not Collective
4286 
4287   Input Parameter:
4288 . dm - The `DMPLEX`
4289 
4290   Output Parameters:
4291 + maxConeSize    - The maximum number of in-edges
4292 - maxSupportSize - The maximum number of out-edges
4293 
4294   Level: beginner
4295 
4296 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
4297 @*/
DMPlexGetMaxSizes(DM dm,PeOp PetscInt * maxConeSize,PeOp PetscInt * maxSupportSize)4298 PetscErrorCode DMPlexGetMaxSizes(DM dm, PeOp PetscInt *maxConeSize, PeOp PetscInt *maxSupportSize)
4299 {
4300   DM_Plex *mesh = (DM_Plex *)dm->data;
4301 
4302   PetscFunctionBegin;
4303   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4304   if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize));
4305   if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize));
4306   PetscFunctionReturn(PETSC_SUCCESS);
4307 }
4308 
DMSetUp_Plex(DM dm)4309 PetscErrorCode DMSetUp_Plex(DM dm)
4310 {
4311   DM_Plex *mesh = (DM_Plex *)dm->data;
4312   PetscInt size, maxSupportSize;
4313 
4314   PetscFunctionBegin;
4315   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4316   PetscCall(PetscSectionSetUp(mesh->coneSection));
4317   PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size));
4318   PetscCall(PetscMalloc1(size, &mesh->cones));
4319   PetscCall(PetscCalloc1(size, &mesh->coneOrientations));
4320   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
4321   if (maxSupportSize) {
4322     PetscCall(PetscSectionSetUp(mesh->supportSection));
4323     PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size));
4324     PetscCall(PetscMalloc1(size, &mesh->supports));
4325   }
4326   PetscFunctionReturn(PETSC_SUCCESS);
4327 }
4328 
DMCreateSubDM_Plex(DM dm,PetscInt numFields,const PetscInt fields[],IS * is,DM * subdm)4329 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
4330 {
4331   PetscFunctionBegin;
4332   if (subdm) PetscCall(DMClone(dm, subdm));
4333   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm));
4334   if (subdm) (*subdm)->useNatural = dm->useNatural;
4335   if (dm->useNatural && dm->sfMigration) {
4336     PetscSF sfNatural;
4337 
4338     (*subdm)->sfMigration = dm->sfMigration;
4339     PetscCall(PetscObjectReference((PetscObject)dm->sfMigration));
4340     PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural));
4341     (*subdm)->sfNatural = sfNatural;
4342   }
4343   PetscFunctionReturn(PETSC_SUCCESS);
4344 }
4345 
DMCreateSuperDM_Plex(DM dms[],PetscInt len,IS ** is,DM * superdm)4346 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
4347 {
4348   PetscInt i = 0;
4349 
4350   PetscFunctionBegin;
4351   PetscCall(DMClone(dms[0], superdm));
4352   PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm));
4353   (*superdm)->useNatural = PETSC_FALSE;
4354   for (i = 0; i < len; i++) {
4355     if (dms[i]->useNatural && dms[i]->sfMigration) {
4356       PetscSF sfNatural;
4357 
4358       (*superdm)->sfMigration = dms[i]->sfMigration;
4359       PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration));
4360       (*superdm)->useNatural = PETSC_TRUE;
4361       PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural));
4362       (*superdm)->sfNatural = sfNatural;
4363       break;
4364     }
4365   }
4366   PetscFunctionReturn(PETSC_SUCCESS);
4367 }
4368 
4369 /*@
4370   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
4371 
4372   Not Collective
4373 
4374   Input Parameter:
4375 . dm - The `DMPLEX`
4376 
4377   Level: beginner
4378 
4379   Note:
4380   This should be called after all calls to `DMPlexSetCone()`
4381 
4382 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()`
4383 @*/
DMPlexSymmetrize(DM dm)4384 PetscErrorCode DMPlexSymmetrize(DM dm)
4385 {
4386   DM_Plex  *mesh = (DM_Plex *)dm->data;
4387   PetscInt *offsets;
4388   PetscInt  supportSize;
4389   PetscInt  pStart, pEnd, p;
4390 
4391   PetscFunctionBegin;
4392   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4393   PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
4394   PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0));
4395   /* Calculate support sizes */
4396   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4397   for (p = pStart; p < pEnd; ++p) {
4398     PetscInt dof, off, c;
4399 
4400     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
4401     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
4402     for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1));
4403   }
4404   PetscCall(PetscSectionSetUp(mesh->supportSection));
4405   /* Calculate supports */
4406   PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize));
4407   PetscCall(PetscMalloc1(supportSize, &mesh->supports));
4408   PetscCall(PetscCalloc1(pEnd - pStart, &offsets));
4409   for (p = pStart; p < pEnd; ++p) {
4410     PetscInt dof, off, c;
4411 
4412     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
4413     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
4414     for (c = off; c < off + dof; ++c) {
4415       const PetscInt q = mesh->cones[c];
4416       PetscInt       offS;
4417 
4418       PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS));
4419 
4420       mesh->supports[offS + offsets[q]] = p;
4421       ++offsets[q];
4422     }
4423   }
4424   PetscCall(PetscFree(offsets));
4425   PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0));
4426   PetscFunctionReturn(PETSC_SUCCESS);
4427 }
4428 
DMPlexCreateDepthStratum(DM dm,DMLabel label,PetscInt depth,PetscInt pStart,PetscInt pEnd)4429 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
4430 {
4431   IS stratumIS;
4432 
4433   PetscFunctionBegin;
4434   if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS);
4435   if (PetscDefined(USE_DEBUG)) {
4436     PetscInt  qStart, qEnd, numLevels, level;
4437     PetscBool overlap = PETSC_FALSE;
4438     PetscCall(DMLabelGetNumValues(label, &numLevels));
4439     for (level = 0; level < numLevels; level++) {
4440       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4441       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {
4442         overlap = PETSC_TRUE;
4443         break;
4444       }
4445     }
4446     PetscCheck(!overlap, PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ") overlaps with depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ")", depth, pStart, pEnd, level, qStart, qEnd);
4447   }
4448   PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS));
4449   PetscCall(DMLabelSetStratumIS(label, depth, stratumIS));
4450   PetscCall(ISDestroy(&stratumIS));
4451   PetscFunctionReturn(PETSC_SUCCESS);
4452 }
4453 
DMPlexStratify_CellType_Private(DM dm,DMLabel label)4454 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label)
4455 {
4456   PetscInt *pMin, *pMax;
4457   PetscInt  pStart, pEnd;
4458   PetscInt  dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN;
4459 
4460   PetscFunctionBegin;
4461   {
4462     DMLabel label2;
4463 
4464     PetscCall(DMPlexGetCellTypeLabel(dm, &label2));
4465     PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view"));
4466   }
4467   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4468   for (PetscInt p = pStart; p < pEnd; ++p) {
4469     DMPolytopeType ct;
4470 
4471     PetscCall(DMPlexGetCellType(dm, p, &ct));
4472     dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin);
4473     dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax);
4474   }
4475   PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax));
4476   for (PetscInt d = dmin; d <= dmax; ++d) {
4477     pMin[d] = PETSC_INT_MAX;
4478     pMax[d] = PETSC_INT_MIN;
4479   }
4480   for (PetscInt p = pStart; p < pEnd; ++p) {
4481     DMPolytopeType ct;
4482     PetscInt       d;
4483 
4484     PetscCall(DMPlexGetCellType(dm, p, &ct));
4485     d       = DMPolytopeTypeGetDim(ct);
4486     pMin[d] = PetscMin(p, pMin[d]);
4487     pMax[d] = PetscMax(p, pMax[d]);
4488   }
4489   for (PetscInt d = dmin; d <= dmax; ++d) {
4490     if (pMin[d] > pMax[d]) continue;
4491     PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1));
4492   }
4493   PetscCall(PetscFree2(pMin, pMax));
4494   PetscFunctionReturn(PETSC_SUCCESS);
4495 }
4496 
DMPlexStratify_Topological_Private(DM dm,DMLabel label)4497 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label)
4498 {
4499   PetscInt pStart, pEnd;
4500   PetscInt numRoots = 0, numLeaves = 0;
4501 
4502   PetscFunctionBegin;
4503   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4504   {
4505     /* Initialize roots and count leaves */
4506     PetscInt sMin = PETSC_INT_MAX;
4507     PetscInt sMax = PETSC_INT_MIN;
4508     PetscInt coneSize, supportSize;
4509 
4510     for (PetscInt p = pStart; p < pEnd; ++p) {
4511       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4512       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4513       if (!coneSize && supportSize) {
4514         sMin = PetscMin(p, sMin);
4515         sMax = PetscMax(p, sMax);
4516         ++numRoots;
4517       } else if (!supportSize && coneSize) {
4518         ++numLeaves;
4519       } else if (!supportSize && !coneSize) {
4520         /* Isolated points */
4521         sMin = PetscMin(p, sMin);
4522         sMax = PetscMax(p, sMax);
4523       }
4524     }
4525     PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1));
4526   }
4527 
4528   if (numRoots + numLeaves == (pEnd - pStart)) {
4529     PetscInt sMin = PETSC_INT_MAX;
4530     PetscInt sMax = PETSC_INT_MIN;
4531     PetscInt coneSize, supportSize;
4532 
4533     for (PetscInt p = pStart; p < pEnd; ++p) {
4534       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4535       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4536       if (!supportSize && coneSize) {
4537         sMin = PetscMin(p, sMin);
4538         sMax = PetscMax(p, sMax);
4539       }
4540     }
4541     PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1));
4542   } else {
4543     PetscInt level = 0;
4544     PetscInt qStart, qEnd;
4545 
4546     PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4547     while (qEnd > qStart) {
4548       PetscInt sMin = PETSC_INT_MAX;
4549       PetscInt sMax = PETSC_INT_MIN;
4550 
4551       for (PetscInt q = qStart; q < qEnd; ++q) {
4552         const PetscInt *support;
4553         PetscInt        supportSize;
4554 
4555         PetscCall(DMPlexGetSupportSize(dm, q, &supportSize));
4556         PetscCall(DMPlexGetSupport(dm, q, &support));
4557         for (PetscInt s = 0; s < supportSize; ++s) {
4558           sMin = PetscMin(support[s], sMin);
4559           sMax = PetscMax(support[s], sMax);
4560         }
4561       }
4562       PetscCall(DMLabelGetNumValues(label, &level));
4563       PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1));
4564       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4565     }
4566   }
4567   PetscFunctionReturn(PETSC_SUCCESS);
4568 }
4569 
4570 /*@
4571   DMPlexStratify - Computes the strata for all points in the `DMPLEX`
4572 
4573   Collective
4574 
4575   Input Parameter:
4576 . dm - The `DMPLEX`
4577 
4578   Level: beginner
4579 
4580   Notes:
4581   The strata group all points of the same grade, and this function calculates the strata. This
4582   grade can be seen as the height (or depth) of the point in the DAG.
4583 
4584   The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
4585   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram).
4586   Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
4587   meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on
4588   until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or
4589   manually via `DMGetLabel()`.  The height is defined implicitly by height = maxDimension - depth, and can be accessed
4590   via `DMPlexGetHeightStratum()`.  For example, cells have height 0 and faces have height 1.
4591 
4592   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
4593   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
4594   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
4595   to interpolate only that one (e0), so that
4596 .vb
4597   cone(c0) = {e0, v2}
4598   cone(e0) = {v0, v1}
4599 .ve
4600   If `DMPlexStratify()` is run on this mesh, it will give depths
4601 .vb
4602    depth 0 = {v0, v1, v2}
4603    depth 1 = {e0, c0}
4604 .ve
4605   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.
4606 
4607   `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()`
4608 
4609 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()`
4610 @*/
DMPlexStratify(DM dm)4611 PetscErrorCode DMPlexStratify(DM dm)
4612 {
4613   DM_Plex  *mesh = (DM_Plex *)dm->data;
4614   DMLabel   label;
4615   PetscBool flg = PETSC_FALSE;
4616 
4617   PetscFunctionBegin;
4618   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4619   PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0));
4620 
4621   // Create depth label
4622   PetscCall(DMRemoveLabel(dm, "depth", NULL));
4623   PetscCall(DMCreateLabel(dm, "depth"));
4624   PetscCall(DMPlexGetDepthLabel(dm, &label));
4625 
4626   PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL));
4627   if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label));
4628   else PetscCall(DMPlexStratify_Topological_Private(dm, label));
4629 
4630   { /* just in case there is an empty process */
4631     PetscInt numValues, maxValues = 0, v;
4632 
4633     PetscCall(DMLabelGetNumValues(label, &numValues));
4634     PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
4635     for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v));
4636   }
4637   PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState));
4638   PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0));
4639   PetscFunctionReturn(PETSC_SUCCESS);
4640 }
4641 
DMPlexComputeCellType_Internal(DM dm,PetscInt p,PetscInt pdepth,DMPolytopeType * pt)4642 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
4643 {
4644   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4645   PetscInt       dim, depth, pheight, coneSize;
4646   PetscBool      preferTensor;
4647 
4648   PetscFunctionBeginHot;
4649   PetscCall(DMGetDimension(dm, &dim));
4650   PetscCall(DMPlexGetDepth(dm, &depth));
4651   PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4652   PetscCall(DMPlexGetInterpolatePreferTensor(dm, &preferTensor));
4653   pheight = depth - pdepth;
4654   if (depth <= 1) {
4655     switch (pdepth) {
4656     case 0:
4657       ct = DM_POLYTOPE_POINT;
4658       break;
4659     case 1:
4660       switch (coneSize) {
4661       case 2:
4662         ct = DM_POLYTOPE_SEGMENT;
4663         break;
4664       case 3:
4665         ct = DM_POLYTOPE_TRIANGLE;
4666         break;
4667       case 4:
4668         switch (dim) {
4669         case 2:
4670           ct = DM_POLYTOPE_QUADRILATERAL;
4671           break;
4672         case 3:
4673           ct = DM_POLYTOPE_TETRAHEDRON;
4674           break;
4675         default:
4676           break;
4677         }
4678         break;
4679       case 5:
4680         ct = DM_POLYTOPE_PYRAMID;
4681         break;
4682       case 6:
4683         ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM;
4684         break;
4685       case 8:
4686         ct = DM_POLYTOPE_HEXAHEDRON;
4687         break;
4688       default:
4689         break;
4690       }
4691     }
4692   } else {
4693     if (pdepth == 0) {
4694       ct = DM_POLYTOPE_POINT;
4695     } else if (pheight == 0) {
4696       switch (dim) {
4697       case 1:
4698         switch (coneSize) {
4699         case 2:
4700           ct = DM_POLYTOPE_SEGMENT;
4701           break;
4702         default:
4703           break;
4704         }
4705         break;
4706       case 2:
4707         switch (coneSize) {
4708         case 3:
4709           ct = DM_POLYTOPE_TRIANGLE;
4710           break;
4711         case 4:
4712           ct = DM_POLYTOPE_QUADRILATERAL;
4713           break;
4714         default:
4715           break;
4716         }
4717         break;
4718       case 3:
4719         switch (coneSize) {
4720         case 4:
4721           ct = DM_POLYTOPE_TETRAHEDRON;
4722           break;
4723         case 5: {
4724           const PetscInt *cone;
4725           PetscInt        faceConeSize;
4726 
4727           PetscCall(DMPlexGetCone(dm, p, &cone));
4728           PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize));
4729           switch (faceConeSize) {
4730           case 3:
4731             ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM;
4732             break;
4733           case 4:
4734             ct = DM_POLYTOPE_PYRAMID;
4735             break;
4736           }
4737         } break;
4738         case 6:
4739           ct = DM_POLYTOPE_HEXAHEDRON;
4740           break;
4741         default:
4742           break;
4743         }
4744         break;
4745       default:
4746         break;
4747       }
4748     } else if (pheight > 0) {
4749       switch (coneSize) {
4750       case 2:
4751         ct = DM_POLYTOPE_SEGMENT;
4752         break;
4753       case 3:
4754         ct = DM_POLYTOPE_TRIANGLE;
4755         break;
4756       case 4:
4757         ct = DM_POLYTOPE_QUADRILATERAL;
4758         break;
4759       default:
4760         break;
4761       }
4762     }
4763   }
4764   *pt = ct;
4765   PetscFunctionReturn(PETSC_SUCCESS);
4766 }
4767 
4768 /*@
4769   DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size.
4770 
4771   Collective
4772 
4773   Input Parameter:
4774 . dm - The `DMPLEX`
4775 
4776   Level: developer
4777 
4778   Note:
4779   This function is normally called automatically when a cell type is requested. It creates an
4780   internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable
4781   automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype").
4782 
4783   `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()`
4784 
4785 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()`
4786 @*/
DMPlexComputeCellTypes(DM dm)4787 PetscErrorCode DMPlexComputeCellTypes(DM dm)
4788 {
4789   DM_Plex *mesh;
4790   DMLabel  ctLabel;
4791   PetscInt pStart, pEnd, p;
4792 
4793   PetscFunctionBegin;
4794   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4795   mesh = (DM_Plex *)dm->data;
4796   PetscCall(DMCreateLabel(dm, "celltype"));
4797   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
4798   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4799   PetscCall(PetscFree(mesh->cellTypes));
4800   PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
4801   for (p = pStart; p < pEnd; ++p) {
4802     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4803     PetscInt       pdepth;
4804 
4805     PetscCall(DMPlexGetPointDepth(dm, p, &pdepth));
4806     PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct));
4807     PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " has invalid celltype (%s)", p, DMPolytopeTypes[ct]);
4808     PetscCall(DMLabelSetValue(ctLabel, p, ct));
4809     mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct;
4810   }
4811   PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState));
4812   PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view"));
4813   PetscFunctionReturn(PETSC_SUCCESS);
4814 }
4815 
4816 /*@C
4817   DMPlexGetJoin - Get an array for the join of the set of points
4818 
4819   Not Collective
4820 
4821   Input Parameters:
4822 + dm        - The `DMPLEX` object
4823 . numPoints - The number of input points for the join
4824 - points    - The input points
4825 
4826   Output Parameters:
4827 + numCoveredPoints - The number of points in the join
4828 - coveredPoints    - The points in the join
4829 
4830   Level: intermediate
4831 
4832   Note:
4833   Currently, this is restricted to a single level join
4834 
4835   Fortran Notes:
4836   `converedPoints` must be declared with
4837 .vb
4838   PetscInt, pointer :: coveredPints(:)
4839 .ve
4840 
4841 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4842 @*/
DMPlexGetJoin(DM dm,PetscInt numPoints,const PetscInt points[],PetscInt * numCoveredPoints,const PetscInt * coveredPoints[])4843 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
4844 {
4845   DM_Plex  *mesh = (DM_Plex *)dm->data;
4846   PetscInt *join[2];
4847   PetscInt  joinSize, i = 0;
4848   PetscInt  dof, off, p, c, m;
4849   PetscInt  maxSupportSize;
4850 
4851   PetscFunctionBegin;
4852   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4853   PetscAssertPointer(points, 3);
4854   PetscAssertPointer(numCoveredPoints, 4);
4855   PetscAssertPointer(coveredPoints, 5);
4856   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
4857   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0]));
4858   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1]));
4859   /* Copy in support of first point */
4860   PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof));
4861   PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off));
4862   for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize];
4863   /* Check each successive support */
4864   for (p = 1; p < numPoints; ++p) {
4865     PetscInt newJoinSize = 0;
4866 
4867     PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof));
4868     PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off));
4869     for (c = 0; c < dof; ++c) {
4870       const PetscInt point = mesh->supports[off + c];
4871 
4872       for (m = 0; m < joinSize; ++m) {
4873         if (point == join[i][m]) {
4874           join[1 - i][newJoinSize++] = point;
4875           break;
4876         }
4877       }
4878     }
4879     joinSize = newJoinSize;
4880     i        = 1 - i;
4881   }
4882   *numCoveredPoints = joinSize;
4883   *coveredPoints    = join[i];
4884   PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i]));
4885   PetscFunctionReturn(PETSC_SUCCESS);
4886 }
4887 
4888 /*@C
4889   DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()`
4890 
4891   Not Collective
4892 
4893   Input Parameters:
4894 + dm        - The `DMPLEX` object
4895 . numPoints - The number of input points for the join
4896 - points    - The input points
4897 
4898   Output Parameters:
4899 + numCoveredPoints - The number of points in the join
4900 - coveredPoints    - The points in the join
4901 
4902   Level: intermediate
4903 
4904   Fortran Notes:
4905   `converedPoints` must be declared with
4906 .vb
4907   PetscInt, pointer :: coveredPoints(:)
4908 .ve
4909 
4910   Pass `PETSC_NULL_INTEGER` for `numCoveredPoints` if it is not needed
4911 
4912 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()`
4913 @*/
DMPlexRestoreJoin(DM dm,PetscInt numPoints,const PetscInt points[],PetscInt * numCoveredPoints,const PetscInt * coveredPoints[])4914 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
4915 {
4916   PetscFunctionBegin;
4917   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4918   if (points) PetscAssertPointer(points, 3);
4919   if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
4920   PetscAssertPointer(coveredPoints, 5);
4921   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4922   if (numCoveredPoints) *numCoveredPoints = 0;
4923   PetscFunctionReturn(PETSC_SUCCESS);
4924 }
4925 
4926 /*@C
4927   DMPlexGetFullJoin - Get an array for the join of the set of points
4928 
4929   Not Collective
4930 
4931   Input Parameters:
4932 + dm        - The `DMPLEX` object
4933 . numPoints - The number of input points for the join
4934 - points    - The input points, its length is `numPoints`
4935 
4936   Output Parameters:
4937 + numCoveredPoints - The number of points in the join
4938 - coveredPoints    - The points in the join, its length is `numCoveredPoints`
4939 
4940   Level: intermediate
4941 
4942   Fortran Notes:
4943 .vb
4944   PetscInt, pointer :: coveredPints(:)
4945 .ve
4946 
4947 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4948 @*/
DMPlexGetFullJoin(DM dm,PetscInt numPoints,const PetscInt points[],PetscInt * numCoveredPoints,const PetscInt * coveredPoints[])4949 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
4950 {
4951   PetscInt *offsets, **closures;
4952   PetscInt *join[2];
4953   PetscInt  depth = 0, maxSize, joinSize = 0, i = 0;
4954   PetscInt  p, d, c, m, ms;
4955 
4956   PetscFunctionBegin;
4957   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4958   PetscAssertPointer(points, 3);
4959   PetscAssertPointer(numCoveredPoints, 4);
4960   PetscAssertPointer(coveredPoints, 5);
4961 
4962   PetscCall(DMPlexGetDepth(dm, &depth));
4963   PetscCall(PetscCalloc1(numPoints, &closures));
4964   PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
4965   PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms));
4966   maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1;
4967   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]));
4968   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]));
4969 
4970   for (p = 0; p < numPoints; ++p) {
4971     PetscInt closureSize;
4972 
4973     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]));
4974 
4975     offsets[p * (depth + 2) + 0] = 0;
4976     for (d = 0; d < depth + 1; ++d) {
4977       PetscInt pStart, pEnd, i;
4978 
4979       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
4980       for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) {
4981         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
4982           offsets[p * (depth + 2) + d + 1] = i;
4983           break;
4984         }
4985       }
4986       if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i;
4987     }
4988     PetscCheck(offsets[p * (depth + 2) + depth + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (depth + 2) + depth + 1], closureSize);
4989   }
4990   for (d = 0; d < depth + 1; ++d) {
4991     PetscInt dof;
4992 
4993     /* Copy in support of first point */
4994     dof = offsets[d + 1] - offsets[d];
4995     for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2];
4996     /* Check each successive cone */
4997     for (p = 1; p < numPoints && joinSize; ++p) {
4998       PetscInt newJoinSize = 0;
4999 
5000       dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d];
5001       for (c = 0; c < dof; ++c) {
5002         const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2];
5003 
5004         for (m = 0; m < joinSize; ++m) {
5005           if (point == join[i][m]) {
5006             join[1 - i][newJoinSize++] = point;
5007             break;
5008           }
5009         }
5010       }
5011       joinSize = newJoinSize;
5012       i        = 1 - i;
5013     }
5014     if (joinSize) break;
5015   }
5016   *numCoveredPoints = joinSize;
5017   *coveredPoints    = join[i];
5018   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]));
5019   PetscCall(PetscFree(closures));
5020   PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
5021   PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i]));
5022   PetscFunctionReturn(PETSC_SUCCESS);
5023 }
5024 
5025 /*@C
5026   DMPlexGetMeet - Get an array for the meet of the set of points
5027 
5028   Not Collective
5029 
5030   Input Parameters:
5031 + dm        - The `DMPLEX` object
5032 . numPoints - The number of input points for the meet
5033 - points    - The input points, of length `numPoints`
5034 
5035   Output Parameters:
5036 + numCoveringPoints - The number of points in the meet
5037 - coveringPoints    - The points in the meet, of length `numCoveringPoints`
5038 
5039   Level: intermediate
5040 
5041   Note:
5042   Currently, this is restricted to a single level meet
5043 
5044   Fortran Note:
5045   `coveringPoints` must be declared with
5046 .vb
5047   PetscInt, pointer :: coveringPoints(:)
5048 .ve
5049 
5050 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
5051 @*/
DMPlexGetMeet(DM dm,PetscInt numPoints,const PetscInt points[],PetscInt * numCoveringPoints,const PetscInt * coveringPoints[])5052 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[])
5053 {
5054   DM_Plex  *mesh = (DM_Plex *)dm->data;
5055   PetscInt *meet[2];
5056   PetscInt  meetSize, i = 0;
5057   PetscInt  dof, off, p, c, m;
5058   PetscInt  maxConeSize;
5059 
5060   PetscFunctionBegin;
5061   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5062   PetscAssertPointer(points, 3);
5063   PetscAssertPointer(numCoveringPoints, 4);
5064   PetscAssertPointer(coveringPoints, 5);
5065   PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize));
5066   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0]));
5067   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1]));
5068   /* Copy in cone of first point */
5069   PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof));
5070   PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off));
5071   for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize];
5072   /* Check each successive cone */
5073   for (p = 1; p < numPoints; ++p) {
5074     PetscInt newMeetSize = 0;
5075 
5076     PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof));
5077     PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off));
5078     for (c = 0; c < dof; ++c) {
5079       const PetscInt point = mesh->cones[off + c];
5080 
5081       for (m = 0; m < meetSize; ++m) {
5082         if (point == meet[i][m]) {
5083           meet[1 - i][newMeetSize++] = point;
5084           break;
5085         }
5086       }
5087     }
5088     meetSize = newMeetSize;
5089     i        = 1 - i;
5090   }
5091   *numCoveringPoints = meetSize;
5092   *coveringPoints    = meet[i];
5093   PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i]));
5094   PetscFunctionReturn(PETSC_SUCCESS);
5095 }
5096 
5097 /*@C
5098   DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()`
5099 
5100   Not Collective
5101 
5102   Input Parameters:
5103 + dm        - The `DMPLEX` object
5104 . numPoints - The number of input points for the meet
5105 - points    - The input points
5106 
5107   Output Parameters:
5108 + numCoveredPoints - The number of points in the meet
5109 - coveredPoints    - The points in the meet
5110 
5111   Level: intermediate
5112 
5113 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()`
5114 @*/
DMPlexRestoreMeet(DM dm,PetscInt numPoints,const PetscInt points[],PetscInt * numCoveredPoints,const PetscInt * coveredPoints[])5115 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
5116 {
5117   PetscFunctionBegin;
5118   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5119   if (points) PetscAssertPointer(points, 3);
5120   if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
5121   PetscAssertPointer(coveredPoints, 5);
5122   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
5123   if (numCoveredPoints) *numCoveredPoints = 0;
5124   PetscFunctionReturn(PETSC_SUCCESS);
5125 }
5126 
5127 /*@C
5128   DMPlexGetFullMeet - Get an array for the meet of the set of points
5129 
5130   Not Collective
5131 
5132   Input Parameters:
5133 + dm        - The `DMPLEX` object
5134 . numPoints - The number of input points for the meet
5135 - points    - The input points, of length  `numPoints`
5136 
5137   Output Parameters:
5138 + numCoveredPoints - The number of points in the meet
5139 - coveredPoints    - The points in the meet, of length  `numCoveredPoints`
5140 
5141   Level: intermediate
5142 
5143   Fortran Notes:
5144   `coveredPoints` must be declared with
5145 .vb
5146   PetscInt, pointer :: coveredPoints(:)
5147 .ve
5148 
5149 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
5150 @*/
DMPlexGetFullMeet(DM dm,PetscInt numPoints,const PetscInt points[],PetscInt * numCoveredPoints,const PetscInt * coveredPoints[])5151 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
5152 {
5153   PetscInt *offsets, **closures;
5154   PetscInt *meet[2];
5155   PetscInt  height = 0, maxSize, meetSize = 0, i = 0;
5156   PetscInt  p, h, c, m, mc;
5157 
5158   PetscFunctionBegin;
5159   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5160   PetscAssertPointer(points, 3);
5161   PetscAssertPointer(numCoveredPoints, 4);
5162   PetscAssertPointer(coveredPoints, 5);
5163 
5164   PetscCall(DMPlexGetDepth(dm, &height));
5165   PetscCall(PetscMalloc1(numPoints, &closures));
5166   PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
5167   PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL));
5168   maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1;
5169   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]));
5170   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]));
5171 
5172   for (p = 0; p < numPoints; ++p) {
5173     PetscInt closureSize;
5174 
5175     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]));
5176 
5177     offsets[p * (height + 2) + 0] = 0;
5178     for (h = 0; h < height + 1; ++h) {
5179       PetscInt pStart, pEnd, i;
5180 
5181       PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd));
5182       for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) {
5183         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
5184           offsets[p * (height + 2) + h + 1] = i;
5185           break;
5186         }
5187       }
5188       if (i == closureSize) offsets[p * (height + 2) + h + 1] = i;
5189     }
5190     PetscCheck(offsets[p * (height + 2) + height + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (height + 2) + height + 1], closureSize);
5191   }
5192   for (h = 0; h < height + 1; ++h) {
5193     PetscInt dof;
5194 
5195     /* Copy in cone of first point */
5196     dof = offsets[h + 1] - offsets[h];
5197     for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2];
5198     /* Check each successive cone */
5199     for (p = 1; p < numPoints && meetSize; ++p) {
5200       PetscInt newMeetSize = 0;
5201 
5202       dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h];
5203       for (c = 0; c < dof; ++c) {
5204         const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2];
5205 
5206         for (m = 0; m < meetSize; ++m) {
5207           if (point == meet[i][m]) {
5208             meet[1 - i][newMeetSize++] = point;
5209             break;
5210           }
5211         }
5212       }
5213       meetSize = newMeetSize;
5214       i        = 1 - i;
5215     }
5216     if (meetSize) break;
5217   }
5218   *numCoveredPoints = meetSize;
5219   *coveredPoints    = meet[i];
5220   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]));
5221   PetscCall(PetscFree(closures));
5222   PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
5223   PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i]));
5224   PetscFunctionReturn(PETSC_SUCCESS);
5225 }
5226 
5227 /*@
5228   DMPlexEqual - Determine if two `DM` have the same topology
5229 
5230   Not Collective
5231 
5232   Input Parameters:
5233 + dmA - A `DMPLEX` object
5234 - dmB - A `DMPLEX` object
5235 
5236   Output Parameter:
5237 . equal - `PETSC_TRUE` if the topologies are identical
5238 
5239   Level: intermediate
5240 
5241   Note:
5242   We are not solving graph isomorphism, so we do not permute.
5243 
5244 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
5245 @*/
DMPlexEqual(DM dmA,DM dmB,PetscBool * equal)5246 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
5247 {
5248   PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;
5249 
5250   PetscFunctionBegin;
5251   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
5252   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
5253   PetscAssertPointer(equal, 3);
5254 
5255   *equal = PETSC_FALSE;
5256   PetscCall(DMPlexGetDepth(dmA, &depth));
5257   PetscCall(DMPlexGetDepth(dmB, &depthB));
5258   if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS);
5259   PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd));
5260   PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB));
5261   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS);
5262   for (p = pStart; p < pEnd; ++p) {
5263     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
5264     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
5265 
5266     PetscCall(DMPlexGetConeSize(dmA, p, &coneSize));
5267     PetscCall(DMPlexGetCone(dmA, p, &cone));
5268     PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt));
5269     PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB));
5270     PetscCall(DMPlexGetCone(dmB, p, &coneB));
5271     PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB));
5272     if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS);
5273     for (c = 0; c < coneSize; ++c) {
5274       if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS);
5275       if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS);
5276     }
5277     PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize));
5278     PetscCall(DMPlexGetSupport(dmA, p, &support));
5279     PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB));
5280     PetscCall(DMPlexGetSupport(dmB, p, &supportB));
5281     if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS);
5282     for (s = 0; s < supportSize; ++s) {
5283       if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS);
5284     }
5285   }
5286   *equal = PETSC_TRUE;
5287   PetscFunctionReturn(PETSC_SUCCESS);
5288 }
5289 
5290 /*@
5291   DMPlexGetNumFaceVertices - Returns the number of vertices on a face
5292 
5293   Not Collective
5294 
5295   Input Parameters:
5296 + dm         - The `DMPLEX`
5297 . cellDim    - The cell dimension
5298 - numCorners - The number of vertices on a cell
5299 
5300   Output Parameter:
5301 . numFaceVertices - The number of vertices on a face
5302 
5303   Level: developer
5304 
5305   Note:
5306   Of course this can only work for a restricted set of symmetric shapes
5307 
5308 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
5309 @*/
DMPlexGetNumFaceVertices(DM dm,PetscInt cellDim,PetscInt numCorners,PetscInt * numFaceVertices)5310 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
5311 {
5312   MPI_Comm comm;
5313 
5314   PetscFunctionBegin;
5315   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5316   PetscAssertPointer(numFaceVertices, 4);
5317   switch (cellDim) {
5318   case 0:
5319     *numFaceVertices = 0;
5320     break;
5321   case 1:
5322     *numFaceVertices = 1;
5323     break;
5324   case 2:
5325     switch (numCorners) {
5326     case 3:                 /* triangle */
5327       *numFaceVertices = 2; /* Edge has 2 vertices */
5328       break;
5329     case 4:                 /* quadrilateral */
5330       *numFaceVertices = 2; /* Edge has 2 vertices */
5331       break;
5332     case 6:                 /* quadratic triangle, tri and quad cohesive Lagrange cells */
5333       *numFaceVertices = 3; /* Edge has 3 vertices */
5334       break;
5335     case 9:                 /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
5336       *numFaceVertices = 3; /* Edge has 3 vertices */
5337       break;
5338     default:
5339       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
5340     }
5341     break;
5342   case 3:
5343     switch (numCorners) {
5344     case 4:                 /* tetradehdron */
5345       *numFaceVertices = 3; /* Face has 3 vertices */
5346       break;
5347     case 6:                 /* tet cohesive cells */
5348       *numFaceVertices = 4; /* Face has 4 vertices */
5349       break;
5350     case 8:                 /* hexahedron */
5351       *numFaceVertices = 4; /* Face has 4 vertices */
5352       break;
5353     case 9:                 /* tet cohesive Lagrange cells */
5354       *numFaceVertices = 6; /* Face has 6 vertices */
5355       break;
5356     case 10:                /* quadratic tetrahedron */
5357       *numFaceVertices = 6; /* Face has 6 vertices */
5358       break;
5359     case 12:                /* hex cohesive Lagrange cells */
5360       *numFaceVertices = 6; /* Face has 6 vertices */
5361       break;
5362     case 18:                /* quadratic tet cohesive Lagrange cells */
5363       *numFaceVertices = 6; /* Face has 6 vertices */
5364       break;
5365     case 27:                /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
5366       *numFaceVertices = 9; /* Face has 9 vertices */
5367       break;
5368     default:
5369       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
5370     }
5371     break;
5372   default:
5373     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim);
5374   }
5375   PetscFunctionReturn(PETSC_SUCCESS);
5376 }
5377 
5378 /*@
5379   DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point
5380 
5381   Not Collective
5382 
5383   Input Parameter:
5384 . dm - The `DMPLEX` object
5385 
5386   Output Parameter:
5387 . depthLabel - The `DMLabel` recording point depth
5388 
5389   Level: developer
5390 
5391 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`,
5392 @*/
DMPlexGetDepthLabel(DM dm,DMLabel * depthLabel)5393 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
5394 {
5395   PetscFunctionBegin;
5396   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5397   PetscAssertPointer(depthLabel, 2);
5398   *depthLabel = dm->depthLabel;
5399   PetscFunctionReturn(PETSC_SUCCESS);
5400 }
5401 
5402 /*@
5403   DMPlexGetDepth - Get the depth of the DAG representing this mesh
5404 
5405   Not Collective
5406 
5407   Input Parameter:
5408 . dm - The `DMPLEX` object
5409 
5410   Output Parameter:
5411 . depth - The number of strata (breadth first levels) in the DAG
5412 
5413   Level: developer
5414 
5415   Notes:
5416   This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`.
5417 
5418   The point depth is described more in detail in `DMPlexGetDepthStratum()`.
5419 
5420   An empty mesh gives -1.
5421 
5422 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`
5423 @*/
DMPlexGetDepth(DM dm,PetscInt * depth)5424 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
5425 {
5426   DM_Plex *mesh = (DM_Plex *)dm->data;
5427   DMLabel  label;
5428   PetscInt d = -1;
5429 
5430   PetscFunctionBegin;
5431   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5432   PetscAssertPointer(depth, 2);
5433   if (mesh->tr) {
5434     PetscCall(DMPlexTransformGetDepth(mesh->tr, depth));
5435   } else {
5436     PetscCall(DMPlexGetDepthLabel(dm, &label));
5437     // Allow missing depths
5438     if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d));
5439     *depth = d;
5440   }
5441   PetscFunctionReturn(PETSC_SUCCESS);
5442 }
5443 
5444 /*@
5445   DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth.
5446 
5447   Not Collective
5448 
5449   Input Parameters:
5450 + dm    - The `DMPLEX` object
5451 - depth - The requested depth
5452 
5453   Output Parameters:
5454 + start - The first point at this `depth`
5455 - end   - One beyond the last point at this `depth`
5456 
5457   Level: developer
5458 
5459   Notes:
5460   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
5461   often "vertices".  If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next
5462   higher dimension, e.g., "edges".
5463 
5464 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()`
5465 @*/
DMPlexGetDepthStratum(DM dm,PetscInt depth,PeOp PetscInt * start,PeOp PetscInt * end)5466 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PeOp PetscInt *start, PeOp PetscInt *end)
5467 {
5468   DM_Plex *mesh = (DM_Plex *)dm->data;
5469   DMLabel  label;
5470   PetscInt pStart, pEnd;
5471 
5472   PetscFunctionBegin;
5473   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5474   if (start) {
5475     PetscAssertPointer(start, 3);
5476     *start = 0;
5477   }
5478   if (end) {
5479     PetscAssertPointer(end, 4);
5480     *end = 0;
5481   }
5482   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
5483   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5484   if (depth < 0) {
5485     if (start) *start = pStart;
5486     if (end) *end = pEnd;
5487     PetscFunctionReturn(PETSC_SUCCESS);
5488   }
5489   if (mesh->tr) {
5490     PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end));
5491   } else {
5492     PetscCall(DMPlexGetDepthLabel(dm, &label));
5493     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
5494     PetscCall(DMLabelGetStratumBounds(label, depth, start, end));
5495   }
5496   PetscFunctionReturn(PETSC_SUCCESS);
5497 }
5498 
5499 /*@
5500   DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height.
5501 
5502   Not Collective
5503 
5504   Input Parameters:
5505 + dm     - The `DMPLEX` object
5506 - height - The requested height
5507 
5508   Output Parameters:
5509 + start - The first point at this `height`
5510 - end   - One beyond the last point at this `height`
5511 
5512   Level: developer
5513 
5514   Notes:
5515   Height indexing is related to topological codimension.  Height stratum 0 contains the highest topological dimension
5516   points, often called "cells" or "elements".  If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height
5517   stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
5518 
5519 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5520 @*/
DMPlexGetHeightStratum(DM dm,PetscInt height,PeOp PetscInt * start,PeOp PetscInt * end)5521 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PeOp PetscInt *start, PeOp PetscInt *end)
5522 {
5523   DMLabel  label;
5524   PetscInt depth, pStart, pEnd;
5525 
5526   PetscFunctionBegin;
5527   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5528   if (start) {
5529     PetscAssertPointer(start, 3);
5530     *start = 0;
5531   }
5532   if (end) {
5533     PetscAssertPointer(end, 4);
5534     *end = 0;
5535   }
5536   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
5537   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5538   if (height < 0) {
5539     if (start) *start = pStart;
5540     if (end) *end = pEnd;
5541     PetscFunctionReturn(PETSC_SUCCESS);
5542   }
5543   PetscCall(DMPlexGetDepthLabel(dm, &label));
5544   if (label) PetscCall(DMLabelGetNumValues(label, &depth));
5545   else PetscCall(DMGetDimension(dm, &depth));
5546   PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed");
5547   PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end));
5548   PetscFunctionReturn(PETSC_SUCCESS);
5549 }
5550 
5551 /*@
5552   DMPlexGetPointDepth - Get the `depth` of a given point
5553 
5554   Not Collective
5555 
5556   Input Parameters:
5557 + dm    - The `DMPLEX` object
5558 - point - The point
5559 
5560   Output Parameter:
5561 . depth - The depth of the `point`
5562 
5563   Level: intermediate
5564 
5565 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5566 @*/
DMPlexGetPointDepth(DM dm,PetscInt point,PetscInt * depth)5567 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
5568 {
5569   PetscFunctionBegin;
5570   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5571   PetscAssertPointer(depth, 3);
5572   PetscCall(DMLabelGetValue(dm->depthLabel, point, depth));
5573   PetscFunctionReturn(PETSC_SUCCESS);
5574 }
5575 
5576 /*@
5577   DMPlexGetPointHeight - Get the `height` of a given point
5578 
5579   Not Collective
5580 
5581   Input Parameters:
5582 + dm    - The `DMPLEX` object
5583 - point - The point
5584 
5585   Output Parameter:
5586 . height - The height of the `point`
5587 
5588   Level: intermediate
5589 
5590 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()`
5591 @*/
DMPlexGetPointHeight(DM dm,PetscInt point,PetscInt * height)5592 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
5593 {
5594   PetscInt n, pDepth;
5595 
5596   PetscFunctionBegin;
5597   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5598   PetscAssertPointer(height, 3);
5599   PetscCall(DMLabelGetNumValues(dm->depthLabel, &n));
5600   PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth));
5601   *height = n - 1 - pDepth; /* DAG depth is n-1 */
5602   PetscFunctionReturn(PETSC_SUCCESS);
5603 }
5604 
5605 /*@
5606   DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell
5607 
5608   Not Collective
5609 
5610   Input Parameter:
5611 . dm - The `DMPLEX` object
5612 
5613   Output Parameter:
5614 . celltypeLabel - The `DMLabel` recording cell polytope type
5615 
5616   Level: developer
5617 
5618   Note:
5619   This function will trigger automatica computation of cell types. This can be disabled by calling
5620   `DMCreateLabel`(dm, "celltype") beforehand.
5621 
5622 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()`
5623 @*/
DMPlexGetCellTypeLabel(DM dm,DMLabel * celltypeLabel)5624 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
5625 {
5626   PetscFunctionBegin;
5627   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5628   PetscAssertPointer(celltypeLabel, 2);
5629   if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm));
5630   *celltypeLabel = dm->celltypeLabel;
5631   PetscFunctionReturn(PETSC_SUCCESS);
5632 }
5633 
5634 /*@
5635   DMPlexGetCellType - Get the polytope type of a given cell
5636 
5637   Not Collective
5638 
5639   Input Parameters:
5640 + dm   - The `DMPLEX` object
5641 - cell - The cell
5642 
5643   Output Parameter:
5644 . celltype - The polytope type of the cell
5645 
5646   Level: intermediate
5647 
5648 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`
5649 @*/
DMPlexGetCellType(DM dm,PetscInt cell,DMPolytopeType * celltype)5650 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
5651 {
5652   DM_Plex *mesh = (DM_Plex *)dm->data;
5653   DMLabel  label;
5654   PetscInt ct;
5655 
5656   PetscFunctionBegin;
5657   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5658   PetscAssertPointer(celltype, 3);
5659   if (mesh->tr) {
5660     PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype));
5661   } else {
5662     PetscInt pStart, pEnd;
5663 
5664     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL));
5665     if (!mesh->cellTypes) { /* XXX remove? optimize? */
5666       PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd));
5667       if (pEnd <= pStart) {
5668         *celltype = DM_POLYTOPE_UNKNOWN;
5669         PetscFunctionReturn(PETSC_SUCCESS);
5670       }
5671       PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
5672       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
5673       for (PetscInt p = pStart; p < pEnd; p++) {
5674         PetscCall(DMLabelGetValue(label, p, &ct));
5675         mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct;
5676       }
5677     }
5678     *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8;
5679     if (PetscDefined(USE_DEBUG)) {
5680       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
5681       PetscCall(DMLabelGetValue(label, cell, &ct));
5682       PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell);
5683       PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct);
5684     }
5685   }
5686   PetscFunctionReturn(PETSC_SUCCESS);
5687 }
5688 
5689 /*@
5690   DMPlexSetCellType - Set the polytope type of a given cell
5691 
5692   Not Collective
5693 
5694   Input Parameters:
5695 + dm       - The `DMPLEX` object
5696 . cell     - The cell
5697 - celltype - The polytope type of the cell
5698 
5699   Level: advanced
5700 
5701   Note:
5702   By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function
5703   is executed. This function will override the computed type. However, if automatic classification will not succeed
5704   and a user wants to manually specify all types, the classification must be disabled by calling
5705   DMCreateLabel(dm, "celltype") before getting or setting any cell types.
5706 
5707 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()`
5708 @*/
DMPlexSetCellType(DM dm,PetscInt cell,DMPolytopeType celltype)5709 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
5710 {
5711   DM_Plex *mesh = (DM_Plex *)dm->data;
5712   DMLabel  label;
5713   PetscInt pStart, pEnd;
5714 
5715   PetscFunctionBegin;
5716   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5717   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
5718   PetscCall(DMPlexGetCellTypeLabel(dm, &label));
5719   PetscCall(DMLabelSetValue(label, cell, celltype));
5720   if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
5721   mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype;
5722   PetscFunctionReturn(PETSC_SUCCESS);
5723 }
5724 
DMCreateCoordinateDM_Plex(DM dm,DM * cdm)5725 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
5726 {
5727   PetscSection section;
5728   PetscInt     maxHeight;
5729   const char  *prefix;
5730 
5731   PetscFunctionBegin;
5732   PetscCall(DMClone(dm, cdm));
5733   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
5734   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix));
5735   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_"));
5736   PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight));
5737   PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight));
5738   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
5739   PetscCall(DMSetLocalSection(*cdm, section));
5740   PetscCall(PetscSectionDestroy(&section));
5741 
5742   PetscCall(DMSetNumFields(*cdm, 1));
5743   PetscCall(DMCreateDS(*cdm));
5744   (*cdm)->cloneOpts = PETSC_TRUE;
5745   if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm));
5746   PetscFunctionReturn(PETSC_SUCCESS);
5747 }
5748 
DMCreateCellCoordinateDM_Plex(DM dm,DM * cdm)5749 PetscErrorCode DMCreateCellCoordinateDM_Plex(DM dm, DM *cdm)
5750 {
5751   DM           cgcdm;
5752   PetscSection section;
5753   const char  *prefix;
5754 
5755   PetscFunctionBegin;
5756   PetscCall(DMGetCoordinateDM(dm, &cgcdm));
5757   PetscCall(DMClone(cgcdm, cdm));
5758   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
5759   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix));
5760   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cellcdm_"));
5761   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
5762   PetscCall(DMSetLocalSection(*cdm, section));
5763   PetscCall(PetscSectionDestroy(&section));
5764   PetscCall(DMSetNumFields(*cdm, 1));
5765   PetscCall(DMCreateDS(*cdm));
5766   (*cdm)->cloneOpts = PETSC_TRUE;
5767   if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm));
5768   PetscFunctionReturn(PETSC_SUCCESS);
5769 }
5770 
DMCreateCoordinateField_Plex(DM dm,DMField * field)5771 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
5772 {
5773   Vec coordsLocal, cellCoordsLocal;
5774   DM  coordsDM, cellCoordsDM;
5775 
5776   PetscFunctionBegin;
5777   *field = NULL;
5778   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
5779   PetscCall(DMGetCoordinateDM(dm, &coordsDM));
5780   PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal));
5781   PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM));
5782   if (coordsLocal && coordsDM) {
5783     if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field));
5784     else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field));
5785   }
5786   PetscFunctionReturn(PETSC_SUCCESS);
5787 }
5788 
5789 /*@
5790   DMPlexGetConeSection - Return a section which describes the layout of cone data
5791 
5792   Not Collective
5793 
5794   Input Parameter:
5795 . dm - The `DMPLEX` object
5796 
5797   Output Parameter:
5798 . section - The `PetscSection` object
5799 
5800   Level: developer
5801 
5802 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection`
5803 @*/
DMPlexGetConeSection(DM dm,PetscSection * section)5804 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
5805 {
5806   DM_Plex *mesh = (DM_Plex *)dm->data;
5807 
5808   PetscFunctionBegin;
5809   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5810   if (section) *section = mesh->coneSection;
5811   PetscFunctionReturn(PETSC_SUCCESS);
5812 }
5813 
5814 /*@
5815   DMPlexGetSupportSection - Return a section which describes the layout of support data
5816 
5817   Not Collective
5818 
5819   Input Parameter:
5820 . dm - The `DMPLEX` object
5821 
5822   Output Parameter:
5823 . section - The `PetscSection` object
5824 
5825   Level: developer
5826 
5827 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection`
5828 @*/
DMPlexGetSupportSection(DM dm,PetscSection * section)5829 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
5830 {
5831   DM_Plex *mesh = (DM_Plex *)dm->data;
5832 
5833   PetscFunctionBegin;
5834   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5835   if (section) *section = mesh->supportSection;
5836   PetscFunctionReturn(PETSC_SUCCESS);
5837 }
5838 
5839 /*@C
5840   DMPlexGetCones - Return cone data
5841 
5842   Not Collective
5843 
5844   Input Parameter:
5845 . dm - The `DMPLEX` object
5846 
5847   Output Parameter:
5848 . cones - The cone for each point
5849 
5850   Level: developer
5851 
5852 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`
5853 @*/
DMPlexGetCones(DM dm,PetscInt * cones[])5854 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
5855 {
5856   DM_Plex *mesh = (DM_Plex *)dm->data;
5857 
5858   PetscFunctionBegin;
5859   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5860   if (cones) *cones = mesh->cones;
5861   PetscFunctionReturn(PETSC_SUCCESS);
5862 }
5863 
5864 /*@C
5865   DMPlexGetConeOrientations - Return cone orientation data
5866 
5867   Not Collective
5868 
5869   Input Parameter:
5870 . dm - The `DMPLEX` object
5871 
5872   Output Parameter:
5873 . coneOrientations - The array of cone orientations for all points
5874 
5875   Level: developer
5876 
5877   Notes:
5878   The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points
5879   as returned by `DMPlexGetConeOrientation()`.
5880 
5881   The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`.
5882 
5883 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection`
5884 @*/
DMPlexGetConeOrientations(DM dm,PetscInt * coneOrientations[])5885 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
5886 {
5887   DM_Plex *mesh = (DM_Plex *)dm->data;
5888 
5889   PetscFunctionBegin;
5890   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5891   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
5892   PetscFunctionReturn(PETSC_SUCCESS);
5893 }
5894 
5895 /* FEM Support */
5896 
DMPlexGetAllCells_Internal(DM plex,IS * cellIS)5897 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS)
5898 {
5899   PetscInt depth;
5900 
5901   PetscFunctionBegin;
5902   PetscCall(DMPlexGetDepth(plex, &depth));
5903   PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS));
5904   if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS));
5905   PetscFunctionReturn(PETSC_SUCCESS);
5906 }
5907 
DMPlexGetAllFaces_Internal(DM plex,IS * faceIS)5908 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS)
5909 {
5910   PetscInt depth;
5911 
5912   PetscFunctionBegin;
5913   PetscCall(DMPlexGetDepth(plex, &depth));
5914   PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS));
5915   if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS));
5916   PetscFunctionReturn(PETSC_SUCCESS);
5917 }
5918 
5919 /*
5920  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
5921  representing a line in the section.
5922 */
PetscSectionFieldGetTensorDegree_Private(DM dm,PetscSection section,PetscInt field,PetscInt line,PetscInt * Nc,PetscInt * k,PetscBool * continuous,PetscBool * tensor)5923 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor)
5924 {
5925   PetscObject  obj;
5926   PetscClassId id;
5927   PetscFE      fe = NULL;
5928 
5929   PetscFunctionBeginHot;
5930   PetscCall(PetscSectionGetFieldComponents(section, field, Nc));
5931   PetscCall(DMGetField(dm, field, NULL, &obj));
5932   PetscCall(PetscObjectGetClassId(obj, &id));
5933   if (id == PETSCFE_CLASSID) fe = (PetscFE)obj;
5934 
5935   if (!fe) {
5936     /* Assume the full interpolated mesh is in the chart; lines in particular */
5937     /* An order k SEM disc has k-1 dofs on an edge */
5938     PetscCall(PetscSectionGetFieldDof(section, line, field, k));
5939     *k = *k / *Nc + 1;
5940   } else {
5941     PetscInt       dual_space_size, dim;
5942     PetscDualSpace dsp;
5943 
5944     PetscCall(DMGetDimension(dm, &dim));
5945     PetscCall(PetscFEGetDualSpace(fe, &dsp));
5946     PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size));
5947     *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1;
5948     PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous));
5949     PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor));
5950   }
5951   PetscFunctionReturn(PETSC_SUCCESS);
5952 }
5953 
GetFieldSize_Private(PetscInt dim,PetscInt k,PetscBool tensor,PetscInt * dof)5954 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof)
5955 {
5956   PetscFunctionBeginHot;
5957   if (tensor) {
5958     *dof = PetscPowInt(k + 1, dim);
5959   } else {
5960     switch (dim) {
5961     case 1:
5962       *dof = k + 1;
5963       break;
5964     case 2:
5965       *dof = ((k + 1) * (k + 2)) / 2;
5966       break;
5967     case 3:
5968       *dof = ((k + 1) * (k + 2) * (k + 3)) / 6;
5969       break;
5970     default:
5971       *dof = 0;
5972     }
5973   }
5974   PetscFunctionReturn(PETSC_SUCCESS);
5975 }
5976 
5977 /*@
5978   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
5979   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
5980   section provided (or the section of the `DM`).
5981 
5982   Input Parameters:
5983 + dm      - The `DM`
5984 . point   - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE`
5985 - section - The `PetscSection` to reorder, or `NULL` for the default section
5986 
5987   Example:
5988   A typical interpolated single-quad mesh might order points as
5989 .vb
5990   [c0, v1, v2, v3, v4, e5, e6, e7, e8]
5991 
5992   v4 -- e6 -- v3
5993   |           |
5994   e7    c0    e8
5995   |           |
5996   v1 -- e5 -- v2
5997 .ve
5998 
5999   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
6000   dofs in the order of points, e.g.,
6001 .vb
6002     c0 -> [0,1,2,3]
6003     v1 -> [4]
6004     ...
6005     e5 -> [8, 9]
6006 .ve
6007 
6008   which corresponds to the dofs
6009 .vb
6010     6   10  11  7
6011     13  2   3   15
6012     12  0   1   14
6013     4   8   9   5
6014 .ve
6015 
6016   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
6017 .vb
6018   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
6019 .ve
6020 
6021   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
6022 .vb
6023    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
6024 .ve
6025 
6026   Level: developer
6027 
6028   Notes:
6029   The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
6030   degree of the basis.
6031 
6032   This is required to run with libCEED.
6033 
6034 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()`
6035 @*/
DMPlexSetClosurePermutationTensor(DM dm,PetscInt point,PetscSection section)6036 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
6037 {
6038   DMLabel   label;
6039   PetscInt  dim, depth = -1, eStart = -1, Nf;
6040   PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE;
6041 
6042   PetscFunctionBegin;
6043   PetscCall(DMGetDimension(dm, &dim));
6044   if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS);
6045   if (point < 0) {
6046     PetscInt sStart, sEnd;
6047 
6048     PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd));
6049     point = sEnd - sStart ? sStart : point;
6050   }
6051   PetscCall(DMPlexGetDepthLabel(dm, &label));
6052   if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth));
6053   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6054   if (depth == 1) {
6055     eStart = point;
6056   } else if (depth == dim) {
6057     const PetscInt *cone;
6058 
6059     PetscCall(DMPlexGetCone(dm, point, &cone));
6060     if (dim == 2) eStart = cone[0];
6061     else if (dim == 3) {
6062       const PetscInt *cone2;
6063       PetscCall(DMPlexGetCone(dm, cone[0], &cone2));
6064       eStart = cone2[0];
6065     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim);
6066   } else PetscCheck(depth < 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim);
6067 
6068   PetscCall(PetscSectionGetNumFields(section, &Nf));
6069   for (PetscInt d = 1; d <= dim; d++) {
6070     PetscInt  k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
6071     PetscInt *perm;
6072 
6073     for (f = 0; f < Nf; ++f) {
6074       PetscInt dof;
6075 
6076       PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
6077       PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f);
6078       if (!continuous && d < dim) continue;
6079       PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
6080       size += dof * Nc;
6081     }
6082     PetscCall(PetscMalloc1(size, &perm));
6083     for (f = 0; f < Nf; ++f) {
6084       switch (d) {
6085       case 1:
6086         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
6087         if (!continuous && d < dim) continue;
6088         /*
6089          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
6090          We want              [ vtx0; edge of length k-1; vtx1 ]
6091          */
6092         if (continuous) {
6093           for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset;
6094           for (i = 0; i < k - 1; i++)
6095             for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset;
6096           for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset;
6097           foffset = offset;
6098         } else {
6099           PetscInt dof;
6100 
6101           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
6102           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
6103           foffset = offset;
6104         }
6105         break;
6106       case 2:
6107         /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
6108         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
6109         if (!continuous && d < dim) continue;
6110         /* The SEM order is
6111 
6112          v_lb, {e_b}, v_rb,
6113          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
6114          v_lt, reverse {e_t}, v_rt
6115          */
6116         if (continuous) {
6117           const PetscInt of   = 0;
6118           const PetscInt oeb  = of + PetscSqr(k - 1);
6119           const PetscInt oer  = oeb + (k - 1);
6120           const PetscInt oet  = oer + (k - 1);
6121           const PetscInt oel  = oet + (k - 1);
6122           const PetscInt ovlb = oel + (k - 1);
6123           const PetscInt ovrb = ovlb + 1;
6124           const PetscInt ovrt = ovrb + 1;
6125           const PetscInt ovlt = ovrt + 1;
6126           PetscInt       o;
6127 
6128           /* bottom */
6129           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset;
6130           for (o = oeb; o < oer; ++o)
6131             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6132           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset;
6133           /* middle */
6134           for (i = 0; i < k - 1; ++i) {
6135             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset;
6136             for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o)
6137               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6138             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset;
6139           }
6140           /* top */
6141           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset;
6142           for (o = oel - 1; o >= oet; --o)
6143             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6144           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset;
6145           foffset = offset;
6146         } else {
6147           PetscInt dof;
6148 
6149           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
6150           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
6151           foffset = offset;
6152         }
6153         break;
6154       case 3:
6155         /* The original hex closure is
6156 
6157          {c,
6158          f_b, f_t, f_f, f_b, f_r, f_l,
6159          e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
6160          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
6161          */
6162         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
6163         if (!continuous && d < dim) continue;
6164         /* The SEM order is
6165          Bottom Slice
6166          v_blf, {e^{(k-1)-n}_bf}, v_brf,
6167          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
6168          v_blb, {e_bb}, v_brb,
6169 
6170          Middle Slice (j)
6171          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
6172          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
6173          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
6174 
6175          Top Slice
6176          v_tlf, {e_tf}, v_trf,
6177          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
6178          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
6179          */
6180         if (continuous) {
6181           const PetscInt oc    = 0;
6182           const PetscInt ofb   = oc + PetscSqr(k - 1) * (k - 1);
6183           const PetscInt oft   = ofb + PetscSqr(k - 1);
6184           const PetscInt off   = oft + PetscSqr(k - 1);
6185           const PetscInt ofk   = off + PetscSqr(k - 1);
6186           const PetscInt ofr   = ofk + PetscSqr(k - 1);
6187           const PetscInt ofl   = ofr + PetscSqr(k - 1);
6188           const PetscInt oebl  = ofl + PetscSqr(k - 1);
6189           const PetscInt oebb  = oebl + (k - 1);
6190           const PetscInt oebr  = oebb + (k - 1);
6191           const PetscInt oebf  = oebr + (k - 1);
6192           const PetscInt oetf  = oebf + (k - 1);
6193           const PetscInt oetr  = oetf + (k - 1);
6194           const PetscInt oetb  = oetr + (k - 1);
6195           const PetscInt oetl  = oetb + (k - 1);
6196           const PetscInt oerf  = oetl + (k - 1);
6197           const PetscInt oelf  = oerf + (k - 1);
6198           const PetscInt oelb  = oelf + (k - 1);
6199           const PetscInt oerb  = oelb + (k - 1);
6200           const PetscInt ovblf = oerb + (k - 1);
6201           const PetscInt ovblb = ovblf + 1;
6202           const PetscInt ovbrb = ovblb + 1;
6203           const PetscInt ovbrf = ovbrb + 1;
6204           const PetscInt ovtlf = ovbrf + 1;
6205           const PetscInt ovtrf = ovtlf + 1;
6206           const PetscInt ovtrb = ovtrf + 1;
6207           const PetscInt ovtlb = ovtrb + 1;
6208           PetscInt       o, n;
6209 
6210           /* Bottom Slice */
6211           /*   bottom */
6212           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset;
6213           for (o = oetf - 1; o >= oebf; --o)
6214             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6215           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset;
6216           /*   middle */
6217           for (i = 0; i < k - 1; ++i) {
6218             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset;
6219             for (n = 0; n < k - 1; ++n) {
6220               o = ofb + n * (k - 1) + i;
6221               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6222             }
6223             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset;
6224           }
6225           /*   top */
6226           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset;
6227           for (o = oebb; o < oebr; ++o)
6228             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6229           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset;
6230 
6231           /* Middle Slice */
6232           for (j = 0; j < k - 1; ++j) {
6233             /*   bottom */
6234             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset;
6235             for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o)
6236               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6237             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset;
6238             /*   middle */
6239             for (i = 0; i < k - 1; ++i) {
6240               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset;
6241               for (n = 0; n < k - 1; ++n)
6242                 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset;
6243               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset;
6244             }
6245             /*   top */
6246             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset;
6247             for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o)
6248               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6249             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset;
6250           }
6251 
6252           /* Top Slice */
6253           /*   bottom */
6254           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset;
6255           for (o = oetf; o < oetr; ++o)
6256             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6257           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset;
6258           /*   middle */
6259           for (i = 0; i < k - 1; ++i) {
6260             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset;
6261             for (n = 0; n < k - 1; ++n)
6262               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset;
6263             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset;
6264           }
6265           /*   top */
6266           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset;
6267           for (o = oetl - 1; o >= oetb; --o)
6268             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6269           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset;
6270 
6271           foffset = offset;
6272         } else {
6273           PetscInt dof;
6274 
6275           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
6276           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
6277           foffset = offset;
6278         }
6279         break;
6280       default:
6281         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d);
6282       }
6283     }
6284     PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size);
6285     /* Check permutation */
6286     {
6287       PetscInt *check;
6288 
6289       PetscCall(PetscMalloc1(size, &check));
6290       for (i = 0; i < size; ++i) {
6291         check[i] = -1;
6292         PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]);
6293       }
6294       for (i = 0; i < size; ++i) check[perm[i]] = i;
6295       for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i);
6296       PetscCall(PetscFree(check));
6297     }
6298     PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm));
6299     if (d == dim) { // Add permutation for localized (in case this is a coordinate DM)
6300       PetscInt *loc_perm;
6301       PetscCall(PetscMalloc1(size * 2, &loc_perm));
6302       for (PetscInt i = 0; i < size; i++) {
6303         loc_perm[i]        = perm[i];
6304         loc_perm[size + i] = size + perm[i];
6305       }
6306       PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm));
6307     }
6308   }
6309   PetscFunctionReturn(PETSC_SUCCESS);
6310 }
6311 
DMPlexGetPointDualSpaceFEM(DM dm,PetscInt point,PetscInt field,PetscDualSpace * dspace)6312 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
6313 {
6314   PetscDS  prob;
6315   PetscInt depth, Nf, h;
6316   DMLabel  label;
6317 
6318   PetscFunctionBeginHot;
6319   PetscCall(DMGetDS(dm, &prob));
6320   Nf      = prob->Nf;
6321   label   = dm->depthLabel;
6322   *dspace = NULL;
6323   if (field < Nf) {
6324     PetscObject disc = prob->disc[field];
6325 
6326     if (disc->classid == PETSCFE_CLASSID) {
6327       PetscDualSpace dsp;
6328 
6329       PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
6330       PetscCall(DMLabelGetNumValues(label, &depth));
6331       PetscCall(DMLabelGetValue(label, point, &h));
6332       h = depth - 1 - h;
6333       if (h) {
6334         PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace));
6335       } else {
6336         *dspace = dsp;
6337       }
6338     }
6339   }
6340   PetscFunctionReturn(PETSC_SUCCESS);
6341 }
6342 
DMPlexVecGetClosure_Depth1_Static(DM dm,PetscSection section,Vec v,PetscInt point,PetscInt * csize,PetscScalar * values[])6343 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6344 {
6345   PetscScalar       *array;
6346   const PetscScalar *vArray;
6347   const PetscInt    *cone, *coneO;
6348   PetscInt           pStart, pEnd, p, numPoints, size = 0, offset = 0;
6349 
6350   PetscFunctionBeginHot;
6351   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
6352   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
6353   PetscCall(DMPlexGetCone(dm, point, &cone));
6354   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
6355   if (!values || !*values) {
6356     if ((point >= pStart) && (point < pEnd)) {
6357       PetscInt dof;
6358 
6359       PetscCall(PetscSectionGetDof(section, point, &dof));
6360       size += dof;
6361     }
6362     for (p = 0; p < numPoints; ++p) {
6363       const PetscInt cp = cone[p];
6364       PetscInt       dof;
6365 
6366       if ((cp < pStart) || (cp >= pEnd)) continue;
6367       PetscCall(PetscSectionGetDof(section, cp, &dof));
6368       size += dof;
6369     }
6370     if (!values) {
6371       if (csize) *csize = size;
6372       PetscFunctionReturn(PETSC_SUCCESS);
6373     }
6374     PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array));
6375   } else {
6376     array = *values;
6377   }
6378   size = 0;
6379   PetscCall(VecGetArrayRead(v, &vArray));
6380   if ((point >= pStart) && (point < pEnd)) {
6381     PetscInt           dof, off, d;
6382     const PetscScalar *varr;
6383 
6384     PetscCall(PetscSectionGetDof(section, point, &dof));
6385     PetscCall(PetscSectionGetOffset(section, point, &off));
6386     varr = PetscSafePointerPlusOffset(vArray, off);
6387     for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
6388     size += dof;
6389   }
6390   for (p = 0; p < numPoints; ++p) {
6391     const PetscInt     cp = cone[p];
6392     PetscInt           o  = coneO[p];
6393     PetscInt           dof, off, d;
6394     const PetscScalar *varr;
6395 
6396     if ((cp < pStart) || (cp >= pEnd)) continue;
6397     PetscCall(PetscSectionGetDof(section, cp, &dof));
6398     PetscCall(PetscSectionGetOffset(section, cp, &off));
6399     varr = PetscSafePointerPlusOffset(vArray, off);
6400     if (o >= 0) {
6401       for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
6402     } else {
6403       for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d];
6404     }
6405     size += dof;
6406   }
6407   PetscCall(VecRestoreArrayRead(v, &vArray));
6408   if (!*values) {
6409     if (csize) *csize = size;
6410     *values = array;
6411   } else {
6412     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
6413     *csize = size;
6414   }
6415   PetscFunctionReturn(PETSC_SUCCESS);
6416 }
6417 
6418 /* Compress out points not in the section */
CompressPoints_Private(PetscSection section,PetscInt * numPoints,PetscInt points[])6419 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
6420 {
6421   const PetscInt np = *numPoints;
6422   PetscInt       pStart, pEnd, p, q;
6423 
6424   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
6425   for (p = 0, q = 0; p < np; ++p) {
6426     const PetscInt r = points[p * 2];
6427     if ((r >= pStart) && (r < pEnd)) {
6428       points[q * 2]     = r;
6429       points[q * 2 + 1] = points[p * 2 + 1];
6430       ++q;
6431     }
6432   }
6433   *numPoints = q;
6434   return PETSC_SUCCESS;
6435 }
6436 
6437 /* Compressed closure does not apply closure permutation */
DMPlexGetCompressedClosure(DM dm,PetscSection section,PetscInt point,PetscInt ornt,PetscInt * numPoints,PetscInt ** points,PetscSection * clSec,IS * clPoints,const PetscInt ** clp)6438 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
6439 {
6440   const PetscInt *cla = NULL;
6441   PetscInt        np, *pts = NULL;
6442 
6443   PetscFunctionBeginHot;
6444   PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints));
6445   if (!ornt && *clPoints) {
6446     PetscInt dof, off;
6447 
6448     PetscCall(PetscSectionGetDof(*clSec, point, &dof));
6449     PetscCall(PetscSectionGetOffset(*clSec, point, &off));
6450     PetscCall(ISGetIndices(*clPoints, &cla));
6451     np  = dof / 2;
6452     pts = PetscSafePointerPlusOffset((PetscInt *)cla, off);
6453   } else {
6454     PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts));
6455     PetscCall(CompressPoints_Private(section, &np, pts));
6456   }
6457   *numPoints = np;
6458   *points    = pts;
6459   *clp       = cla;
6460   PetscFunctionReturn(PETSC_SUCCESS);
6461 }
6462 
DMPlexRestoreCompressedClosure(DM dm,PetscSection section,PetscInt point,PetscInt * numPoints,PetscInt ** points,PetscSection * clSec,IS * clPoints,const PetscInt ** clp)6463 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
6464 {
6465   PetscFunctionBeginHot;
6466   if (!*clPoints) {
6467     PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points));
6468   } else {
6469     PetscCall(ISRestoreIndices(*clPoints, clp));
6470   }
6471   *numPoints = 0;
6472   *points    = NULL;
6473   *clSec     = NULL;
6474   *clPoints  = NULL;
6475   *clp       = NULL;
6476   PetscFunctionReturn(PETSC_SUCCESS);
6477 }
6478 
DMPlexVecGetClosure_Static(DM dm,PetscSection section,PetscInt numPoints,const PetscInt points[],const PetscInt clperm[],const PetscScalar vArray[],PetscInt * size,PetscScalar array[])6479 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
6480 {
6481   PetscInt            offset = 0, p;
6482   const PetscInt    **perms  = NULL;
6483   const PetscScalar **flips  = NULL;
6484 
6485   PetscFunctionBeginHot;
6486   *size = 0;
6487   PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
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     PetscInt           dof, off, d;
6493     const PetscScalar *varr;
6494 
6495     PetscCall(PetscSectionGetDof(section, point, &dof));
6496     PetscCall(PetscSectionGetOffset(section, point, &off));
6497     varr = PetscSafePointerPlusOffset(vArray, off);
6498     if (clperm) {
6499       if (perm) {
6500         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
6501       } else {
6502         for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d];
6503       }
6504       if (flip) {
6505         for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d];
6506       }
6507     } else {
6508       if (perm) {
6509         for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
6510       } else {
6511         for (d = 0; d < dof; d++) array[offset + d] = varr[d];
6512       }
6513       if (flip) {
6514         for (d = 0; d < dof; d++) array[offset + d] *= flip[d];
6515       }
6516     }
6517     offset += dof;
6518   }
6519   PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
6520   *size = offset;
6521   PetscFunctionReturn(PETSC_SUCCESS);
6522 }
6523 
DMPlexVecGetClosure_Fields_Static(DM dm,PetscSection section,PetscInt numPoints,const PetscInt points[],PetscInt numFields,const PetscInt clperm[],const PetscScalar vArray[],PetscInt * size,PetscScalar array[])6524 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[])
6525 {
6526   PetscInt offset = 0, f;
6527 
6528   PetscFunctionBeginHot;
6529   *size = 0;
6530   for (f = 0; f < numFields; ++f) {
6531     PetscInt            p;
6532     const PetscInt    **perms = NULL;
6533     const PetscScalar **flips = NULL;
6534 
6535     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6536     for (p = 0; p < numPoints; p++) {
6537       const PetscInt     point = points[2 * p];
6538       PetscInt           fdof, foff, b;
6539       const PetscScalar *varr;
6540       const PetscInt    *perm = perms ? perms[p] : NULL;
6541       const PetscScalar *flip = flips ? flips[p] : NULL;
6542 
6543       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
6544       PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
6545       varr = &vArray[foff];
6546       if (clperm) {
6547         if (perm) {
6548           for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b];
6549         } else {
6550           for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b];
6551         }
6552         if (flip) {
6553           for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b];
6554         }
6555       } else {
6556         if (perm) {
6557           for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b];
6558         } else {
6559           for (b = 0; b < fdof; b++) array[offset + b] = varr[b];
6560         }
6561         if (flip) {
6562           for (b = 0; b < fdof; b++) array[offset + b] *= flip[b];
6563         }
6564       }
6565       offset += fdof;
6566     }
6567     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6568   }
6569   *size = offset;
6570   PetscFunctionReturn(PETSC_SUCCESS);
6571 }
6572 
6573 /*@C
6574   DMPlexVecGetOrientedClosure - Get an array of the values on the closure of 'point' with a given orientation, optionally applying the closure permutation.
6575 
6576   Not collective
6577 
6578   Input Parameters:
6579 + dm        - The `DM`
6580 . section   - The section describing the layout in `v`, or `NULL` to use the default section
6581 . useClPerm - Flag for whether the provided closure permutation should be applied to the values
6582 . v         - The local vector
6583 . point     - The point in the `DM`
6584 - ornt      - The orientation of the cell, an integer giving the prescription for cone traversal. Typically, this will be 0.
6585 
6586   Input/Output Parameters:
6587 + csize  - The size of the input values array, or `NULL`; on output the number of values in the closure
6588 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically;
6589            if the user provided `NULL`, it is a borrowed array and should not be freed, use  `DMPlexVecRestoreClosure()` to return it
6590 
6591   Level: advanced
6592 
6593   Notes:
6594   `DMPlexVecGetOrientedClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the
6595   calling function. This is because `DMPlexVecGetOrientedClosure()` is typically called in the inner loop of a `Vec` or `Mat`
6596   assembly function, and a user may already have allocated storage for this operation.
6597 
6598   Fortran Notes:
6599   The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed.
6600   In that case one may pass `PETSC_NULL_INTEGER` for `csize`.
6601 
6602   `values` must be declared with
6603 .vb
6604   PetscScalar,dimension(:),pointer   :: values
6605 .ve
6606   and it will be allocated internally by PETSc to hold the values returned
6607 
6608 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexGetCellCoordinates()`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`
6609 @*/
DMPlexVecGetOrientedClosure(DM dm,PetscSection section,PetscBool useClPerm,Vec v,PetscInt point,PetscInt ornt,PetscInt * csize,PetscScalar * values[])6610 PetscErrorCode DMPlexVecGetOrientedClosure(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[])
6611 {
6612   PetscSection    clSection;
6613   IS              clPoints;
6614   PetscInt       *points = NULL;
6615   const PetscInt *clp, *perm = NULL;
6616   PetscInt        depth, numFields, numPoints, asize;
6617 
6618   PetscFunctionBeginHot;
6619   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6620   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6621   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6622   PetscValidHeaderSpecific(v, VEC_CLASSID, 4);
6623   PetscCall(DMPlexGetDepth(dm, &depth));
6624   PetscCall(PetscSectionGetNumFields(section, &numFields));
6625   if (depth == 1 && numFields < 2) {
6626     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
6627     PetscFunctionReturn(PETSC_SUCCESS);
6628   }
6629   /* Get points */
6630   PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp));
6631   /* Get sizes */
6632   asize = 0;
6633   for (PetscInt p = 0; p < numPoints * 2; p += 2) {
6634     PetscInt dof;
6635     PetscCall(PetscSectionGetDof(section, points[p], &dof));
6636     asize += dof;
6637   }
6638   if (values) {
6639     const PetscScalar *vArray;
6640     PetscInt           size;
6641 
6642     if (*values) {
6643       PetscCheck(*csize >= asize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided array size %" PetscInt_FMT " not sufficient to hold closure size %" PetscInt_FMT, *csize, asize);
6644     } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values));
6645     if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm));
6646     PetscCall(VecGetArrayRead(v, &vArray));
6647     /* Get values */
6648     if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values));
6649     else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values));
6650     PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size);
6651     /* Cleanup array */
6652     PetscCall(VecRestoreArrayRead(v, &vArray));
6653   }
6654   if (csize) *csize = asize;
6655   /* Cleanup points */
6656   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6657   PetscFunctionReturn(PETSC_SUCCESS);
6658 }
6659 
6660 /*@C
6661   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
6662 
6663   Not collective
6664 
6665   Input Parameters:
6666 + dm      - The `DM`
6667 . section - The section describing the layout in `v`, or `NULL` to use the default section
6668 . v       - The local vector
6669 - point   - The point in the `DM`
6670 
6671   Input/Output Parameters:
6672 + csize  - The size of the input values array, or `NULL`; on output the number of values in the closure
6673 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically;
6674            if the user provided `NULL`, it is a borrowed array and should not be freed, use  `DMPlexVecRestoreClosure()` to return it
6675 
6676   Level: intermediate
6677 
6678   Notes:
6679   This is used for getting the all values in a `Vec` in the closure of a mesh point.
6680   To get only the values in the closure of a mesh point at a specific depth (for example, at mesh vertices), use `DMPlexVecGetClosureAtDepth()`.
6681 
6682   `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the
6683   calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat`
6684   assembly function, and a user may already have allocated storage for this operation.
6685 
6686   A typical use could be
6687 .vb
6688    values = NULL;
6689    PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6690    for (cl = 0; cl < clSize; ++cl) {
6691      <Compute on closure>
6692    }
6693    PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values));
6694 .ve
6695   or
6696 .vb
6697    PetscMalloc1(clMaxSize, &values);
6698    for (p = pStart; p < pEnd; ++p) {
6699      clSize = clMaxSize;
6700      PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6701      for (cl = 0; cl < clSize; ++cl) {
6702        <Compute on closure>
6703      }
6704    }
6705    PetscFree(values);
6706 .ve
6707 
6708   Fortran Notes:
6709   The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed.
6710   In that case one may pass `PETSC_NULL_INTEGER` for `csize`.
6711 
6712   `values` must be declared with
6713 .vb
6714   PetscScalar,dimension(:),pointer   :: values
6715 .ve
6716   and it will be allocated internally by PETSc to hold the values returned
6717 
6718 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosureAtDepth()`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6719 @*/
DMPlexVecGetClosure(DM dm,PetscSection section,Vec v,PetscInt point,PetscInt * csize,PetscScalar * values[])6720 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6721 {
6722   PetscFunctionBeginHot;
6723   PetscCall(DMPlexVecGetOrientedClosure(dm, section, PETSC_TRUE, v, point, 0, csize, values));
6724   PetscFunctionReturn(PETSC_SUCCESS);
6725 }
6726 
6727 /*@C
6728   DMPlexVecGetClosureAtDepth - Get an array of the values on the closure of 'point' that are at a specific depth
6729 
6730   Not collective
6731 
6732   Input Parameters:
6733 + dm      - The `DM`
6734 . section - The section describing the layout in `v`, or `NULL` to use the default section
6735 . v       - The local vector
6736 . depth   - The depth of mesh points that should be returned
6737 - point   - The point in the `DM`
6738 
6739   Input/Output Parameters:
6740 + csize  - The size of the input values array, or `NULL`; on output the number of values in the closure
6741 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically;
6742            if the user provided `NULL`, it is a borrowed array and should not be freed, use  `DMPlexVecRestoreClosure()` to return it
6743 
6744   Level: intermediate
6745 
6746   Notes:
6747   This is used for getting the values in a `Vec` associated with specific mesh points.
6748   For example, to get only the values at mesh vertices, pass `depth=0`. To get all the values in the closure of a mesh point, use `DMPlexVecGetClosure()`.
6749 
6750   `DMPlexVecGetClosureAtDepth()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the
6751   calling function. This is because `DMPlexVecGetClosureAtDepth()` is typically called in the inner loop of a `Vec` or `Mat`
6752   assembly function, and a user may already have allocated storage for this operation.
6753 
6754   A typical use could be
6755 .vb
6756    values = NULL;
6757    PetscCall(DMPlexVecGetClosureAtDepth(dm, NULL, v, p, depth, &clSize, &values));
6758    for (cl = 0; cl < clSize; ++cl) {
6759      <Compute on closure>
6760    }
6761    PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values));
6762 .ve
6763   or
6764 .vb
6765    PetscMalloc1(clMaxSize, &values);
6766    for (p = pStart; p < pEnd; ++p) {
6767      clSize = clMaxSize;
6768      PetscCall(DMPlexVecGetClosureAtDepth(dm, NULL, v, p, depth, &clSize, &values));
6769      for (cl = 0; cl < clSize; ++cl) {
6770        <Compute on closure>
6771      }
6772    }
6773    PetscFree(values);
6774 .ve
6775 
6776   Fortran Notes:
6777   The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed.
6778   In that case one may pass `PETSC_NULL_INTEGER` for `csize`.
6779 
6780   `values` must be declared with
6781 .vb
6782   PetscScalar,dimension(:),pointer   :: values
6783 .ve
6784   and it will be allocated internally by PETSc to hold the values returned
6785 
6786 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6787 @*/
DMPlexVecGetClosureAtDepth(DM dm,PetscSection section,Vec v,PetscInt point,PetscInt depth,PetscInt * csize,PetscScalar * values[])6788 PetscErrorCode DMPlexVecGetClosureAtDepth(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
6789 {
6790   DMLabel            depthLabel;
6791   PetscSection       clSection;
6792   IS                 clPoints;
6793   PetscScalar       *array;
6794   const PetscScalar *vArray;
6795   PetscInt          *points = NULL;
6796   const PetscInt    *clp, *perm = NULL;
6797   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;
6798 
6799   PetscFunctionBeginHot;
6800   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6801   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6802   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6803   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6804   PetscCall(DMPlexGetDepth(dm, &mdepth));
6805   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
6806   PetscCall(PetscSectionGetNumFields(section, &numFields));
6807   if (mdepth == 1 && numFields < 2) {
6808     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
6809     PetscFunctionReturn(PETSC_SUCCESS);
6810   }
6811   /* Get points */
6812   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6813   for (clsize = 0, p = 0; p < Np; p++) {
6814     PetscInt dof;
6815     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6816     clsize += dof;
6817   }
6818   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm));
6819   /* Filter points */
6820   for (p = 0; p < numPoints * 2; p += 2) {
6821     PetscInt dep;
6822 
6823     PetscCall(DMLabelGetValue(depthLabel, points[p], &dep));
6824     if (dep != depth) continue;
6825     points[Np * 2 + 0] = points[p];
6826     points[Np * 2 + 1] = points[p + 1];
6827     ++Np;
6828   }
6829   /* Get array */
6830   if (!values || !*values) {
6831     PetscInt asize = 0, dof;
6832 
6833     for (p = 0; p < Np * 2; p += 2) {
6834       PetscCall(PetscSectionGetDof(section, points[p], &dof));
6835       asize += dof;
6836     }
6837     if (!values) {
6838       PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6839       if (csize) *csize = asize;
6840       PetscFunctionReturn(PETSC_SUCCESS);
6841     }
6842     PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array));
6843   } else {
6844     array = *values;
6845   }
6846   PetscCall(VecGetArrayRead(v, &vArray));
6847   /* Get values */
6848   if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array));
6849   else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array));
6850   /* Cleanup points */
6851   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6852   /* Cleanup array */
6853   PetscCall(VecRestoreArrayRead(v, &vArray));
6854   if (!*values) {
6855     if (csize) *csize = size;
6856     *values = array;
6857   } else {
6858     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
6859     *csize = size;
6860   }
6861   PetscFunctionReturn(PETSC_SUCCESS);
6862 }
6863 
6864 /*@C
6865   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()`
6866 
6867   Not collective
6868 
6869   Input Parameters:
6870 + dm      - The `DM`
6871 . section - The section describing the layout in `v`, or `NULL` to use the default section
6872 . v       - The local vector
6873 . point   - The point in the `DM`
6874 . csize   - The number of values in the closure, or `NULL`
6875 - values  - The array of values
6876 
6877   Level: intermediate
6878 
6879   Note:
6880   The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()`
6881 
6882   Fortran Note:
6883   The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed.
6884   In that case one may pass `PETSC_NULL_INTEGER` for `csize`.
6885 
6886 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6887 @*/
DMPlexVecRestoreClosure(DM dm,PetscSection section,Vec v,PetscInt point,PetscInt * csize,PetscScalar * values[])6888 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6889 {
6890   PetscInt size = 0;
6891 
6892   PetscFunctionBegin;
6893   /* Should work without recalculating size */
6894   PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values));
6895   *values = NULL;
6896   PetscFunctionReturn(PETSC_SUCCESS);
6897 }
6898 
add(PetscScalar * x,PetscScalar y)6899 static inline void add(PetscScalar *x, PetscScalar y)
6900 {
6901   *x += y;
6902 }
insert(PetscScalar * x,PetscScalar y)6903 static inline void insert(PetscScalar *x, PetscScalar y)
6904 {
6905   *x = y;
6906 }
6907 
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[])6908 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[])
6909 {
6910   PetscInt        cdof;  /* The number of constraints on this point */
6911   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6912   PetscScalar    *a;
6913   PetscInt        off, cind = 0, k;
6914 
6915   PetscFunctionBegin;
6916   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
6917   PetscCall(PetscSectionGetOffset(section, point, &off));
6918   a = &array[off];
6919   if (!cdof || setBC) {
6920     if (clperm) {
6921       if (perm) {
6922         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6923       } else {
6924         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
6925       }
6926     } else {
6927       if (perm) {
6928         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
6929       } else {
6930         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
6931       }
6932     }
6933   } else {
6934     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
6935     if (clperm) {
6936       if (perm) {
6937         for (k = 0; k < dof; ++k) {
6938           if ((cind < cdof) && (k == cdofs[cind])) {
6939             ++cind;
6940             continue;
6941           }
6942           fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6943         }
6944       } else {
6945         for (k = 0; k < dof; ++k) {
6946           if ((cind < cdof) && (k == cdofs[cind])) {
6947             ++cind;
6948             continue;
6949           }
6950           fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
6951         }
6952       }
6953     } else {
6954       if (perm) {
6955         for (k = 0; k < dof; ++k) {
6956           if ((cind < cdof) && (k == cdofs[cind])) {
6957             ++cind;
6958             continue;
6959           }
6960           fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
6961         }
6962       } else {
6963         for (k = 0; k < dof; ++k) {
6964           if ((cind < cdof) && (k == cdofs[cind])) {
6965             ++cind;
6966             continue;
6967           }
6968           fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
6969         }
6970       }
6971     }
6972   }
6973   PetscFunctionReturn(PETSC_SUCCESS);
6974 }
6975 
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[])6976 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[])
6977 {
6978   PetscInt        cdof;  /* The number of constraints on this point */
6979   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6980   PetscScalar    *a;
6981   PetscInt        off, cind = 0, k;
6982 
6983   PetscFunctionBegin;
6984   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
6985   PetscCall(PetscSectionGetOffset(section, point, &off));
6986   a = &array[off];
6987   if (cdof) {
6988     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
6989     if (clperm) {
6990       if (perm) {
6991         for (k = 0; k < dof; ++k) {
6992           if ((cind < cdof) && (k == cdofs[cind])) {
6993             fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6994             cind++;
6995           }
6996         }
6997       } else {
6998         for (k = 0; k < dof; ++k) {
6999           if ((cind < cdof) && (k == cdofs[cind])) {
7000             fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
7001             cind++;
7002           }
7003         }
7004       }
7005     } else {
7006       if (perm) {
7007         for (k = 0; k < dof; ++k) {
7008           if ((cind < cdof) && (k == cdofs[cind])) {
7009             fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
7010             cind++;
7011           }
7012         }
7013       } else {
7014         for (k = 0; k < dof; ++k) {
7015           if ((cind < cdof) && (k == cdofs[cind])) {
7016             fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
7017             cind++;
7018           }
7019         }
7020       }
7021     }
7022   }
7023   PetscFunctionReturn(PETSC_SUCCESS);
7024 }
7025 
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[])7026 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[])
7027 {
7028   PetscScalar    *a;
7029   PetscInt        fdof, foff, fcdof, foffset = *offset;
7030   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7031   PetscInt        cind = 0, b;
7032 
7033   PetscFunctionBegin;
7034   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
7035   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
7036   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
7037   a = &array[foff];
7038   if (!fcdof || setBC) {
7039     if (clperm) {
7040       if (perm) {
7041         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
7042       } else {
7043         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
7044       }
7045     } else {
7046       if (perm) {
7047         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
7048       } else {
7049         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
7050       }
7051     }
7052   } else {
7053     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
7054     if (clperm) {
7055       if (perm) {
7056         for (b = 0; b < fdof; b++) {
7057           if ((cind < fcdof) && (b == fcdofs[cind])) {
7058             ++cind;
7059             continue;
7060           }
7061           fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
7062         }
7063       } else {
7064         for (b = 0; b < fdof; b++) {
7065           if ((cind < fcdof) && (b == fcdofs[cind])) {
7066             ++cind;
7067             continue;
7068           }
7069           fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
7070         }
7071       }
7072     } else {
7073       if (perm) {
7074         for (b = 0; b < fdof; b++) {
7075           if ((cind < fcdof) && (b == fcdofs[cind])) {
7076             ++cind;
7077             continue;
7078           }
7079           fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
7080         }
7081       } else {
7082         for (b = 0; b < fdof; b++) {
7083           if ((cind < fcdof) && (b == fcdofs[cind])) {
7084             ++cind;
7085             continue;
7086           }
7087           fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
7088         }
7089       }
7090     }
7091   }
7092   *offset += fdof;
7093   PetscFunctionReturn(PETSC_SUCCESS);
7094 }
7095 
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[])7096 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[])
7097 {
7098   PetscScalar    *a;
7099   PetscInt        fdof, foff, fcdof, foffset = *offset;
7100   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7101   PetscInt        Nc, cind = 0, ncind = 0, b;
7102   PetscBool       ncSet, fcSet;
7103 
7104   PetscFunctionBegin;
7105   PetscCall(PetscSectionGetFieldComponents(section, f, &Nc));
7106   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
7107   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
7108   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
7109   a = &array[foff];
7110   if (fcdof) {
7111     /* We just override fcdof and fcdofs with Ncc and comps */
7112     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
7113     if (clperm) {
7114       if (perm) {
7115         if (comps) {
7116           for (b = 0; b < fdof; b++) {
7117             ncSet = fcSet = PETSC_FALSE;
7118             if (b % Nc == comps[ncind]) {
7119               ncind = (ncind + 1) % Ncc;
7120               ncSet = PETSC_TRUE;
7121             }
7122             if ((cind < fcdof) && (b == fcdofs[cind])) {
7123               ++cind;
7124               fcSet = PETSC_TRUE;
7125             }
7126             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
7127           }
7128         } else {
7129           for (b = 0; b < fdof; b++) {
7130             if ((cind < fcdof) && (b == fcdofs[cind])) {
7131               fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
7132               ++cind;
7133             }
7134           }
7135         }
7136       } else {
7137         if (comps) {
7138           for (b = 0; b < fdof; b++) {
7139             ncSet = fcSet = PETSC_FALSE;
7140             if (b % Nc == comps[ncind]) {
7141               ncind = (ncind + 1) % Ncc;
7142               ncSet = PETSC_TRUE;
7143             }
7144             if ((cind < fcdof) && (b == fcdofs[cind])) {
7145               ++cind;
7146               fcSet = PETSC_TRUE;
7147             }
7148             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
7149           }
7150         } else {
7151           for (b = 0; b < fdof; b++) {
7152             if ((cind < fcdof) && (b == fcdofs[cind])) {
7153               fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
7154               ++cind;
7155             }
7156           }
7157         }
7158       }
7159     } else {
7160       if (perm) {
7161         if (comps) {
7162           for (b = 0; b < fdof; b++) {
7163             ncSet = fcSet = PETSC_FALSE;
7164             if (b % Nc == comps[ncind]) {
7165               ncind = (ncind + 1) % Ncc;
7166               ncSet = PETSC_TRUE;
7167             }
7168             if ((cind < fcdof) && (b == fcdofs[cind])) {
7169               ++cind;
7170               fcSet = PETSC_TRUE;
7171             }
7172             if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
7173           }
7174         } else {
7175           for (b = 0; b < fdof; b++) {
7176             if ((cind < fcdof) && (b == fcdofs[cind])) {
7177               fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
7178               ++cind;
7179             }
7180           }
7181         }
7182       } else {
7183         if (comps) {
7184           for (b = 0; b < fdof; b++) {
7185             ncSet = fcSet = PETSC_FALSE;
7186             if (b % Nc == comps[ncind]) {
7187               ncind = (ncind + 1) % Ncc;
7188               ncSet = PETSC_TRUE;
7189             }
7190             if ((cind < fcdof) && (b == fcdofs[cind])) {
7191               ++cind;
7192               fcSet = PETSC_TRUE;
7193             }
7194             if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
7195           }
7196         } else {
7197           for (b = 0; b < fdof; b++) {
7198             if ((cind < fcdof) && (b == fcdofs[cind])) {
7199               fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
7200               ++cind;
7201             }
7202           }
7203         }
7204       }
7205     }
7206   }
7207   *offset += fdof;
7208   PetscFunctionReturn(PETSC_SUCCESS);
7209 }
7210 
DMPlexVecSetClosure_Depth1_Static(DM dm,PetscSection section,Vec v,PetscInt point,const PetscScalar values[],InsertMode mode)7211 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
7212 {
7213   PetscScalar    *array;
7214   const PetscInt *cone, *coneO;
7215   PetscInt        pStart, pEnd, p, numPoints, off, dof;
7216 
7217   PetscFunctionBeginHot;
7218   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
7219   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
7220   PetscCall(DMPlexGetCone(dm, point, &cone));
7221   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
7222   PetscCall(VecGetArray(v, &array));
7223   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
7224     const PetscInt cp = !p ? point : cone[p - 1];
7225     const PetscInt o  = !p ? 0 : coneO[p - 1];
7226 
7227     if ((cp < pStart) || (cp >= pEnd)) {
7228       dof = 0;
7229       continue;
7230     }
7231     PetscCall(PetscSectionGetDof(section, cp, &dof));
7232     /* ADD_VALUES */
7233     {
7234       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7235       PetscScalar    *a;
7236       PetscInt        cdof, coff, cind = 0, k;
7237 
7238       PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof));
7239       PetscCall(PetscSectionGetOffset(section, cp, &coff));
7240       a = &array[coff];
7241       if (!cdof) {
7242         if (o >= 0) {
7243           for (k = 0; k < dof; ++k) a[k] += values[off + k];
7244         } else {
7245           for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1];
7246         }
7247       } else {
7248         PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs));
7249         if (o >= 0) {
7250           for (k = 0; k < dof; ++k) {
7251             if ((cind < cdof) && (k == cdofs[cind])) {
7252               ++cind;
7253               continue;
7254             }
7255             a[k] += values[off + k];
7256           }
7257         } else {
7258           for (k = 0; k < dof; ++k) {
7259             if ((cind < cdof) && (k == cdofs[cind])) {
7260               ++cind;
7261               continue;
7262             }
7263             a[k] += values[off + dof - k - 1];
7264           }
7265         }
7266       }
7267     }
7268   }
7269   PetscCall(VecRestoreArray(v, &array));
7270   PetscFunctionReturn(PETSC_SUCCESS);
7271 }
7272 
7273 /*@C
7274   DMPlexVecSetClosure - Set an array of the values on the closure of `point`
7275 
7276   Not collective
7277 
7278   Input Parameters:
7279 + dm      - The `DM`
7280 . section - The section describing the layout in `v`, or `NULL` to use the default section
7281 . v       - The local vector
7282 . point   - The point in the `DM`
7283 . values  - The array of values
7284 - mode    - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`,
7285             where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions.
7286 
7287   Level: intermediate
7288 
7289   Note:
7290   Usually the input arrays were obtained with `DMPlexVecGetClosure()`
7291 
7292 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`
7293 @*/
DMPlexVecSetClosure(DM dm,PetscSection section,Vec v,PetscInt point,const PetscScalar values[],InsertMode mode)7294 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
7295 {
7296   PetscSection    clSection;
7297   IS              clPoints;
7298   PetscScalar    *array;
7299   PetscInt       *points = NULL;
7300   const PetscInt *clp, *clperm = NULL;
7301   PetscInt        depth, numFields, numPoints, p, clsize;
7302 
7303   PetscFunctionBeginHot;
7304   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7305   if (!section) PetscCall(DMGetLocalSection(dm, &section));
7306   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7307   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
7308   PetscCall(DMPlexGetDepth(dm, &depth));
7309   PetscCall(PetscSectionGetNumFields(section, &numFields));
7310   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
7311     PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode));
7312     PetscFunctionReturn(PETSC_SUCCESS);
7313   }
7314   /* Get points */
7315   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
7316   for (clsize = 0, p = 0; p < numPoints; p++) {
7317     PetscInt dof;
7318     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
7319     clsize += dof;
7320   }
7321   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
7322   /* Get array */
7323   PetscCall(VecGetArray(v, &array));
7324   /* Get values */
7325   if (numFields > 0) {
7326     PetscInt offset = 0, f;
7327     for (f = 0; f < numFields; ++f) {
7328       const PetscInt    **perms = NULL;
7329       const PetscScalar **flips = NULL;
7330 
7331       PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7332       switch (mode) {
7333       case INSERT_VALUES:
7334         for (p = 0; p < numPoints; p++) {
7335           const PetscInt     point = points[2 * p];
7336           const PetscInt    *perm  = perms ? perms[p] : NULL;
7337           const PetscScalar *flip  = flips ? flips[p] : NULL;
7338           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array));
7339         }
7340         break;
7341       case INSERT_ALL_VALUES:
7342         for (p = 0; p < numPoints; p++) {
7343           const PetscInt     point = points[2 * p];
7344           const PetscInt    *perm  = perms ? perms[p] : NULL;
7345           const PetscScalar *flip  = flips ? flips[p] : NULL;
7346           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array));
7347         }
7348         break;
7349       case INSERT_BC_VALUES:
7350         for (p = 0; p < numPoints; p++) {
7351           const PetscInt     point = points[2 * p];
7352           const PetscInt    *perm  = perms ? perms[p] : NULL;
7353           const PetscScalar *flip  = flips ? flips[p] : NULL;
7354           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array));
7355         }
7356         break;
7357       case ADD_VALUES:
7358         for (p = 0; p < numPoints; p++) {
7359           const PetscInt     point = points[2 * p];
7360           const PetscInt    *perm  = perms ? perms[p] : NULL;
7361           const PetscScalar *flip  = flips ? flips[p] : NULL;
7362           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array));
7363         }
7364         break;
7365       case ADD_ALL_VALUES:
7366         for (p = 0; p < numPoints; p++) {
7367           const PetscInt     point = points[2 * p];
7368           const PetscInt    *perm  = perms ? perms[p] : NULL;
7369           const PetscScalar *flip  = flips ? flips[p] : NULL;
7370           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array));
7371         }
7372         break;
7373       case ADD_BC_VALUES:
7374         for (p = 0; p < numPoints; p++) {
7375           const PetscInt     point = points[2 * p];
7376           const PetscInt    *perm  = perms ? perms[p] : NULL;
7377           const PetscScalar *flip  = flips ? flips[p] : NULL;
7378           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array));
7379         }
7380         break;
7381       default:
7382         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7383       }
7384       PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7385     }
7386   } else {
7387     PetscInt            dof, off;
7388     const PetscInt    **perms = NULL;
7389     const PetscScalar **flips = NULL;
7390 
7391     PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
7392     switch (mode) {
7393     case INSERT_VALUES:
7394       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
7395         const PetscInt     point = points[2 * p];
7396         const PetscInt    *perm  = perms ? perms[p] : NULL;
7397         const PetscScalar *flip  = flips ? flips[p] : NULL;
7398         PetscCall(PetscSectionGetDof(section, point, &dof));
7399         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array));
7400       }
7401       break;
7402     case INSERT_ALL_VALUES:
7403       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
7404         const PetscInt     point = points[2 * p];
7405         const PetscInt    *perm  = perms ? perms[p] : NULL;
7406         const PetscScalar *flip  = flips ? flips[p] : NULL;
7407         PetscCall(PetscSectionGetDof(section, point, &dof));
7408         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array));
7409       }
7410       break;
7411     case INSERT_BC_VALUES:
7412       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
7413         const PetscInt     point = points[2 * p];
7414         const PetscInt    *perm  = perms ? perms[p] : NULL;
7415         const PetscScalar *flip  = flips ? flips[p] : NULL;
7416         PetscCall(PetscSectionGetDof(section, point, &dof));
7417         PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array));
7418       }
7419       break;
7420     case ADD_VALUES:
7421       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
7422         const PetscInt     point = points[2 * p];
7423         const PetscInt    *perm  = perms ? perms[p] : NULL;
7424         const PetscScalar *flip  = flips ? flips[p] : NULL;
7425         PetscCall(PetscSectionGetDof(section, point, &dof));
7426         PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array));
7427       }
7428       break;
7429     case ADD_ALL_VALUES:
7430       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
7431         const PetscInt     point = points[2 * p];
7432         const PetscInt    *perm  = perms ? perms[p] : NULL;
7433         const PetscScalar *flip  = flips ? flips[p] : NULL;
7434         PetscCall(PetscSectionGetDof(section, point, &dof));
7435         PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array));
7436       }
7437       break;
7438     case ADD_BC_VALUES:
7439       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
7440         const PetscInt     point = points[2 * p];
7441         const PetscInt    *perm  = perms ? perms[p] : NULL;
7442         const PetscScalar *flip  = flips ? flips[p] : NULL;
7443         PetscCall(PetscSectionGetDof(section, point, &dof));
7444         PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array));
7445       }
7446       break;
7447     default:
7448       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7449     }
7450     PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
7451   }
7452   /* Cleanup points */
7453   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
7454   /* Cleanup array */
7455   PetscCall(VecRestoreArray(v, &array));
7456   PetscFunctionReturn(PETSC_SUCCESS);
7457 }
7458 
7459 /* Check whether the given point is in the label. If not, update the offset to skip this point */
CheckPoint_Private(DMLabel label,PetscInt labelId,PetscSection section,PetscInt point,PetscInt f,PetscInt * offset,PetscBool * contains)7460 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains)
7461 {
7462   PetscFunctionBegin;
7463   *contains = PETSC_TRUE;
7464   if (label) {
7465     PetscInt fdof;
7466 
7467     PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains));
7468     if (!*contains) {
7469       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
7470       *offset += fdof;
7471       PetscFunctionReturn(PETSC_SUCCESS);
7472     }
7473   }
7474   PetscFunctionReturn(PETSC_SUCCESS);
7475 }
7476 
7477 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
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)7478 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)
7479 {
7480   PetscSection    clSection;
7481   IS              clPoints;
7482   PetscScalar    *array;
7483   PetscInt       *points = NULL;
7484   const PetscInt *clp;
7485   PetscInt        numFields, numPoints, p;
7486   PetscInt        offset = 0, f;
7487 
7488   PetscFunctionBeginHot;
7489   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7490   if (!section) PetscCall(DMGetLocalSection(dm, &section));
7491   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7492   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
7493   PetscCall(PetscSectionGetNumFields(section, &numFields));
7494   /* Get points */
7495   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
7496   /* Get array */
7497   PetscCall(VecGetArray(v, &array));
7498   /* Get values */
7499   for (f = 0; f < numFields; ++f) {
7500     const PetscInt    **perms = NULL;
7501     const PetscScalar **flips = NULL;
7502     PetscBool           contains;
7503 
7504     if (!fieldActive[f]) {
7505       for (p = 0; p < numPoints * 2; p += 2) {
7506         PetscInt fdof;
7507         PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
7508         offset += fdof;
7509       }
7510       continue;
7511     }
7512     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7513     switch (mode) {
7514     case INSERT_VALUES:
7515       for (p = 0; p < numPoints; p++) {
7516         const PetscInt     point = points[2 * p];
7517         const PetscInt    *perm  = perms ? perms[p] : NULL;
7518         const PetscScalar *flip  = flips ? flips[p] : NULL;
7519         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
7520         if (!contains) continue;
7521         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array));
7522       }
7523       break;
7524     case INSERT_ALL_VALUES:
7525       for (p = 0; p < numPoints; p++) {
7526         const PetscInt     point = points[2 * p];
7527         const PetscInt    *perm  = perms ? perms[p] : NULL;
7528         const PetscScalar *flip  = flips ? flips[p] : NULL;
7529         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
7530         if (!contains) continue;
7531         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array));
7532       }
7533       break;
7534     case INSERT_BC_VALUES:
7535       for (p = 0; p < numPoints; p++) {
7536         const PetscInt     point = points[2 * p];
7537         const PetscInt    *perm  = perms ? perms[p] : NULL;
7538         const PetscScalar *flip  = flips ? flips[p] : NULL;
7539         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
7540         if (!contains) continue;
7541         PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array));
7542       }
7543       break;
7544     case ADD_VALUES:
7545       for (p = 0; p < numPoints; p++) {
7546         const PetscInt     point = points[2 * p];
7547         const PetscInt    *perm  = perms ? perms[p] : NULL;
7548         const PetscScalar *flip  = flips ? flips[p] : NULL;
7549         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
7550         if (!contains) continue;
7551         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array));
7552       }
7553       break;
7554     case ADD_ALL_VALUES:
7555       for (p = 0; p < numPoints; p++) {
7556         const PetscInt     point = points[2 * p];
7557         const PetscInt    *perm  = perms ? perms[p] : NULL;
7558         const PetscScalar *flip  = flips ? flips[p] : NULL;
7559         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
7560         if (!contains) continue;
7561         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array));
7562       }
7563       break;
7564     default:
7565       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7566     }
7567     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7568   }
7569   /* Cleanup points */
7570   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
7571   /* Cleanup array */
7572   PetscCall(VecRestoreArray(v, &array));
7573   PetscFunctionReturn(PETSC_SUCCESS);
7574 }
7575 
DMPlexPrintMatSetValues(PetscViewer viewer,Mat A,PetscInt point,PetscInt numRIndices,const PetscInt rindices[],PetscInt numCIndices,const PetscInt cindices[],const PetscScalar values[])7576 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
7577 {
7578   PetscMPIInt rank;
7579   PetscInt    i, j;
7580 
7581   PetscFunctionBegin;
7582   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
7583   PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point));
7584   for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i]));
7585   for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i]));
7586   numCIndices = numCIndices ? numCIndices : numRIndices;
7587   if (!values) PetscFunctionReturn(PETSC_SUCCESS);
7588   for (i = 0; i < numRIndices; i++) {
7589     PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank));
7590     for (j = 0; j < numCIndices; j++) {
7591 #if defined(PETSC_USE_COMPLEX)
7592       PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j])));
7593 #else
7594       PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j]));
7595 #endif
7596     }
7597     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
7598   }
7599   PetscFunctionReturn(PETSC_SUCCESS);
7600 }
7601 
7602 /*
7603   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
7604 
7605   Input Parameters:
7606 + section - The section for this data layout
7607 . islocal - Is the section (and thus indices being requested) local or global?
7608 . point   - The point contributing dofs with these indices
7609 . off     - The global offset of this point
7610 . loff    - The local offset of each field
7611 . setBC   - The flag determining whether to include indices of boundary values
7612 . perm    - A permutation of the dofs on this point, or NULL
7613 - indperm - A permutation of the entire indices array, or NULL
7614 
7615   Output Parameter:
7616 . indices - Indices for dofs on this point
7617 
7618   Level: developer
7619 
7620   Note: The indices could be local or global, depending on the value of 'off'.
7621 */
DMPlexGetIndicesPoint_Internal(PetscSection section,PetscBool islocal,PetscInt point,PetscInt off,PetscInt * loff,PetscBool setBC,const PetscInt perm[],const PetscInt indperm[],PetscInt indices[])7622 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
7623 {
7624   PetscInt        dof;   /* The number of unknowns on this point */
7625   PetscInt        cdof;  /* The number of constraints on this point */
7626   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7627   PetscInt        cind = 0, k;
7628 
7629   PetscFunctionBegin;
7630   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
7631   PetscCall(PetscSectionGetDof(section, point, &dof));
7632   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
7633   if (!cdof || setBC) {
7634     for (k = 0; k < dof; ++k) {
7635       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
7636       const PetscInt ind    = indperm ? indperm[preind] : preind;
7637 
7638       indices[ind] = off + k;
7639     }
7640   } else {
7641     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
7642     for (k = 0; k < dof; ++k) {
7643       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
7644       const PetscInt ind    = indperm ? indperm[preind] : preind;
7645 
7646       if ((cind < cdof) && (k == cdofs[cind])) {
7647         /* Insert check for returning constrained indices */
7648         indices[ind] = -(off + k + 1);
7649         ++cind;
7650       } else {
7651         indices[ind] = off + k - (islocal ? 0 : cind);
7652       }
7653     }
7654   }
7655   *loff += dof;
7656   PetscFunctionReturn(PETSC_SUCCESS);
7657 }
7658 
7659 /*
7660  DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.
7661 
7662  Input Parameters:
7663 + section - a section (global or local)
7664 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global
7665 . point - point within section
7666 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
7667 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
7668 . setBC - identify constrained (boundary condition) points via involution.
7669 . perms - perms[f][permsoff][:] is a permutation of dofs within each field
7670 . permsoff - offset
7671 - indperm - index permutation
7672 
7673  Output Parameter:
7674 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
7675 . indices - array to hold indices (as defined by section) of each dof associated with point
7676 
7677  Notes:
7678  If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
7679  If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
7680  in the local vector.
7681 
7682  If section is global and setBC=false, the indices for constrained points are negative (and their value is not
7683  significant).  It is invalid to call with a global section and setBC=true.
7684 
7685  Developer Note:
7686  The section is only used for field layout, so islocal is technically a statement about the offset (off).  At some point
7687  in the future, global sections may have fields set, in which case we could pass the global section and obtain the
7688  offset could be obtained from the section instead of passing it explicitly as we do now.
7689 
7690  Example:
7691  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
7692  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
7693  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
7694  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.
7695 
7696  Level: developer
7697 */
DMPlexGetIndicesPointFields_Internal(PetscSection section,PetscBool islocal,PetscInt point,PetscInt off,PetscInt foffs[],PetscBool setBC,const PetscInt *** perms,PetscInt permsoff,const PetscInt indperm[],PetscInt indices[])7698 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[])
7699 {
7700   PetscInt numFields, foff, f;
7701 
7702   PetscFunctionBegin;
7703   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
7704   PetscCall(PetscSectionGetNumFields(section, &numFields));
7705   for (f = 0, foff = 0; f < numFields; ++f) {
7706     PetscInt        fdof, cfdof;
7707     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7708     PetscInt        cind = 0, b;
7709     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
7710 
7711     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
7712     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
7713     if (!cfdof || setBC) {
7714       for (b = 0; b < fdof; ++b) {
7715         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7716         const PetscInt ind    = indperm ? indperm[preind] : preind;
7717 
7718         indices[ind] = off + foff + b;
7719       }
7720     } else {
7721       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
7722       for (b = 0; b < fdof; ++b) {
7723         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7724         const PetscInt ind    = indperm ? indperm[preind] : preind;
7725 
7726         if ((cind < cfdof) && (b == fcdofs[cind])) {
7727           indices[ind] = -(off + foff + b + 1);
7728           ++cind;
7729         } else {
7730           indices[ind] = off + foff + b - (islocal ? 0 : cind);
7731         }
7732       }
7733     }
7734     foff += (setBC || islocal ? fdof : (fdof - cfdof));
7735     foffs[f] += fdof;
7736   }
7737   PetscFunctionReturn(PETSC_SUCCESS);
7738 }
7739 
7740 /*
7741   This version believes the globalSection offsets for each field, rather than just the point offset
7742 
7743  . foffs - The offset into 'indices' for each field, since it is segregated by field
7744 
7745  Notes:
7746  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
7747  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
7748 */
DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section,PetscSection globalSection,PetscInt point,PetscInt foffs[],const PetscInt *** perms,PetscInt permsoff,const PetscInt indperm[],PetscInt indices[])7749 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
7750 {
7751   PetscInt numFields, foff, f;
7752 
7753   PetscFunctionBegin;
7754   PetscCall(PetscSectionGetNumFields(section, &numFields));
7755   for (f = 0; f < numFields; ++f) {
7756     PetscInt        fdof, cfdof;
7757     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7758     PetscInt        cind = 0, b;
7759     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
7760 
7761     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
7762     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
7763     PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff));
7764     if (!cfdof) {
7765       for (b = 0; b < fdof; ++b) {
7766         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7767         const PetscInt ind    = indperm ? indperm[preind] : preind;
7768 
7769         indices[ind] = foff + b;
7770       }
7771     } else {
7772       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
7773       for (b = 0; b < fdof; ++b) {
7774         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7775         const PetscInt ind    = indperm ? indperm[preind] : preind;
7776 
7777         if ((cind < cfdof) && (b == fcdofs[cind])) {
7778           indices[ind] = -(foff + b + 1);
7779           ++cind;
7780         } else {
7781           indices[ind] = foff + b - cind;
7782         }
7783       }
7784     }
7785     foffs[f] += fdof;
7786   }
7787   PetscFunctionReturn(PETSC_SUCCESS);
7788 }
7789 
DMPlexAnchorsGetSubMatIndices(PetscInt nPoints,const PetscInt pnts[],PetscSection section,PetscSection cSec,PetscInt tmpIndices[],PetscInt fieldOffsets[],PetscInt indices[],const PetscInt *** perms)7790 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms)
7791 {
7792   PetscInt numFields, sStart, sEnd, cStart, cEnd;
7793 
7794   PetscFunctionBegin;
7795   PetscCall(PetscSectionGetNumFields(section, &numFields));
7796   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
7797   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
7798   for (PetscInt p = 0; p < nPoints; p++) {
7799     PetscInt     b       = pnts[2 * p];
7800     PetscInt     bSecDof = 0, bOff;
7801     PetscInt     cSecDof = 0;
7802     PetscSection indices_section;
7803 
7804     if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7805     if (!bSecDof) continue;
7806     if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof));
7807     indices_section = cSecDof > 0 ? cSec : section;
7808     if (numFields) {
7809       PetscInt fStart[32], fEnd[32];
7810 
7811       fStart[0] = 0;
7812       fEnd[0]   = 0;
7813       for (PetscInt f = 0; f < numFields; f++) {
7814         PetscInt fDof = 0;
7815 
7816         PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof));
7817         fStart[f + 1] = fStart[f] + fDof;
7818         fEnd[f + 1]   = fStart[f + 1];
7819       }
7820       PetscCall(PetscSectionGetOffset(indices_section, b, &bOff));
7821       // only apply permutations on one side
7822       PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices));
7823       for (PetscInt f = 0; f < numFields; f++) {
7824         for (PetscInt i = fStart[f]; i < fEnd[f]; i++) indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1);
7825       }
7826     } else {
7827       PetscInt bEnd = 0;
7828 
7829       PetscCall(PetscSectionGetOffset(indices_section, b, &bOff));
7830       PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices));
7831 
7832       for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1);
7833     }
7834   }
7835   PetscFunctionReturn(PETSC_SUCCESS);
7836 }
7837 
DMPlexAnchorsGetSubMatModification(DM dm,PetscSection section,PetscInt numPoints,PetscInt numIndices,const PetscInt points[],const PetscInt *** perms,PetscInt * outNumPoints,PetscInt * outNumIndices,PetscInt * outPoints[],PetscInt offsets[],PetscScalar * outMat[])7838 PETSC_INTERN PetscErrorCode DMPlexAnchorsGetSubMatModification(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscInt offsets[], PetscScalar *outMat[])
7839 {
7840   Mat             cMat;
7841   PetscSection    aSec, cSec;
7842   IS              aIS;
7843   PetscInt        aStart = -1, aEnd = -1;
7844   PetscInt        sStart = -1, sEnd = -1;
7845   PetscInt        cStart = -1, cEnd = -1;
7846   const PetscInt *anchors;
7847   PetscInt        numFields, p;
7848   PetscInt        newNumPoints = 0, newNumIndices = 0;
7849   PetscInt       *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices;
7850   PetscInt        oldOffsets[32];
7851   PetscInt        newOffsets[32];
7852   PetscInt        oldOffsetsCopy[32];
7853   PetscInt        newOffsetsCopy[32];
7854   PetscScalar    *modMat         = NULL;
7855   PetscBool       anyConstrained = PETSC_FALSE;
7856 
7857   PetscFunctionBegin;
7858   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7859   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7860   PetscCall(PetscSectionGetNumFields(section, &numFields));
7861 
7862   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
7863   /* if there are point-to-point constraints */
7864   if (aSec) {
7865     PetscCall(PetscArrayzero(newOffsets, 32));
7866     PetscCall(PetscArrayzero(oldOffsets, 32));
7867     PetscCall(ISGetIndices(aIS, &anchors));
7868     PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
7869     PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
7870     /* figure out how many points are going to be in the new element matrix
7871      * (we allow double counting, because it's all just going to be summed
7872      * into the global matrix anyway) */
7873     for (p = 0; p < 2 * numPoints; p += 2) {
7874       PetscInt b    = points[p];
7875       PetscInt bDof = 0, bSecDof = 0;
7876 
7877       if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7878       if (!bSecDof) continue;
7879 
7880       for (PetscInt f = 0; f < numFields; f++) {
7881         PetscInt fDof = 0;
7882 
7883         PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7884         oldOffsets[f + 1] += fDof;
7885       }
7886       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7887       if (bDof) {
7888         /* this point is constrained */
7889         /* it is going to be replaced by its anchors */
7890         PetscInt bOff, q;
7891 
7892         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7893         for (q = 0; q < bDof; q++) {
7894           PetscInt a    = anchors[bOff + q];
7895           PetscInt aDof = 0;
7896 
7897           if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof));
7898           if (aDof) {
7899             anyConstrained = PETSC_TRUE;
7900             newNumPoints += 1;
7901           }
7902           newNumIndices += aDof;
7903           for (PetscInt f = 0; f < numFields; ++f) {
7904             PetscInt fDof = 0;
7905 
7906             if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof));
7907             newOffsets[f + 1] += fDof;
7908           }
7909         }
7910       } else {
7911         /* this point is not constrained */
7912         newNumPoints++;
7913         newNumIndices += bSecDof;
7914         for (PetscInt f = 0; f < numFields; ++f) {
7915           PetscInt fDof;
7916 
7917           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7918           newOffsets[f + 1] += fDof;
7919         }
7920       }
7921     }
7922   }
7923   if (!anyConstrained) {
7924     if (outNumPoints) *outNumPoints = 0;
7925     if (outNumIndices) *outNumIndices = 0;
7926     if (outPoints) *outPoints = NULL;
7927     if (outMat) *outMat = NULL;
7928     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
7929     PetscFunctionReturn(PETSC_SUCCESS);
7930   }
7931 
7932   if (outNumPoints) *outNumPoints = newNumPoints;
7933   if (outNumIndices) *outNumIndices = newNumIndices;
7934 
7935   for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f];
7936   for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f];
7937 
7938   if (!outPoints && !outMat) {
7939     if (offsets) {
7940       for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
7941     }
7942     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
7943     PetscFunctionReturn(PETSC_SUCCESS);
7944   }
7945 
7946   PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices);
7947   PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices);
7948 
7949   PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
7950   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
7951 
7952   /* output arrays */
7953   PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
7954   PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints));
7955 
7956   // get the new Points
7957   for (PetscInt p = 0, newP = 0; p < numPoints; p++) {
7958     PetscInt b    = points[2 * p];
7959     PetscInt bDof = 0, bSecDof = 0, bOff;
7960 
7961     if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7962     if (!bSecDof) continue;
7963     if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7964     if (bDof) {
7965       PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7966       for (PetscInt q = 0; q < bDof; q++) {
7967         PetscInt a = anchors[bOff + q], aDof = 0;
7968 
7969         if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof));
7970         if (aDof) {
7971           newPoints[2 * newP]     = a;
7972           newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation
7973           newP++;
7974         }
7975       }
7976     } else {
7977       newPoints[2 * newP]     = b;
7978       newPoints[2 * newP + 1] = points[2 * p + 1];
7979       newP++;
7980     }
7981   }
7982 
7983   if (outMat) {
7984     PetscScalar *tmpMat;
7985     PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32));
7986     PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32));
7987 
7988     PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices));
7989     PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices));
7990     PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices));
7991     PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices));
7992 
7993     for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1;
7994     for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1;
7995 
7996     PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms));
7997     PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL));
7998 
7999     PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat));
8000     PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat));
8001     PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices));
8002     // for each field, insert the anchor modification into modMat
8003     for (PetscInt f = 0; f < PetscMax(1, numFields); f++) {
8004       PetscInt fStart    = oldOffsets[f];
8005       PetscInt fNewStart = newOffsets[f];
8006       for (PetscInt p = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) {
8007         PetscInt b    = points[2 * p];
8008         PetscInt bDof = 0, bSecDof = 0, bOff;
8009 
8010         if (b >= sStart && b < sEnd) {
8011           if (numFields) {
8012             PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof));
8013           } else {
8014             PetscCall(PetscSectionGetDof(section, b, &bSecDof));
8015           }
8016         }
8017         if (!bSecDof) continue;
8018         if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
8019         if (bDof) {
8020           PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
8021           for (PetscInt q = 0; q < bDof; q++) {
8022             PetscInt a = anchors[bOff + q], aDof = 0;
8023 
8024             if (a >= sStart && a < sEnd) {
8025               if (numFields) {
8026                 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
8027               } else {
8028                 PetscCall(PetscSectionGetDof(section, a, &aDof));
8029               }
8030             }
8031             if (aDof) {
8032               PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat));
8033               for (PetscInt d = 0; d < bSecDof; d++) {
8034                 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e];
8035               }
8036             }
8037             oNew += aDof;
8038           }
8039         } else {
8040           // Insert the identity matrix in this block
8041           for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1;
8042           oNew += bSecDof;
8043         }
8044         o += bSecDof;
8045       }
8046     }
8047 
8048     *outMat = modMat;
8049 
8050     PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat));
8051     PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices));
8052     PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices));
8053     PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices));
8054     PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices));
8055   }
8056   PetscCall(ISRestoreIndices(aIS, &anchors));
8057 
8058   /* output */
8059   if (outPoints) {
8060     *outPoints = newPoints;
8061   } else {
8062     PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
8063   }
8064   for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
8065   PetscFunctionReturn(PETSC_SUCCESS);
8066 }
8067 
DMPlexAnchorsModifyMat_Internal(DM dm,PetscSection section,PetscInt numPoints,PetscInt numIndices,const PetscInt points[],const PetscInt *** perms,PetscInt numRows,PetscInt numCols,const PetscScalar values[],PetscInt * outNumPoints,PetscInt * outNumIndices,PetscInt * outPoints[],PetscScalar * outValues[],PetscInt offsets[],PetscBool multiplyRight,PetscBool multiplyLeft)8068 PETSC_INTERN PetscErrorCode DMPlexAnchorsModifyMat_Internal(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt numRows, PetscInt numCols, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyRight, PetscBool multiplyLeft)
8069 {
8070   PetscScalar *modMat        = NULL;
8071   PetscInt     newNumIndices = -1;
8072 
8073   PetscFunctionBegin;
8074   /* If M is the matrix represented by values, get the matrix C such that we will add M * C (or, if multiplyLeft, C^T * M * C) into the global matrix.
8075      modMat is that matrix C */
8076   PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL));
8077   if (outNumIndices) *outNumIndices = newNumIndices;
8078   if (modMat) {
8079     const PetscScalar *newValues = values;
8080 
8081     if (multiplyRight) {
8082       PetscScalar *newNewValues = NULL;
8083       PetscBLASInt M, N, K;
8084       PetscScalar  a = 1.0, b = 0.0;
8085 
8086       PetscCheck(numCols == numIndices, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "values matrix has the wrong number of columns: %" PetscInt_FMT ", expected %" PetscInt_FMT, numCols, numIndices);
8087 
8088       PetscCall(PetscBLASIntCast(newNumIndices, &M));
8089       PetscCall(PetscBLASIntCast(numRows, &N));
8090       PetscCall(PetscBLASIntCast(numIndices, &K));
8091       PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues));
8092       // row-major to column-major conversion, right multiplication becomes left multiplication
8093       PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M));
8094       numCols   = newNumIndices;
8095       newValues = newNewValues;
8096     }
8097 
8098     if (multiplyLeft) {
8099       PetscScalar *newNewValues = NULL;
8100       PetscBLASInt M, N, K;
8101       PetscScalar  a = 1.0, b = 0.0;
8102 
8103       PetscCheck(numRows == numIndices, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "values matrix has the wrong number of rows: %" PetscInt_FMT ", expected %" PetscInt_FMT, numRows, numIndices);
8104 
8105       PetscCall(PetscBLASIntCast(numCols, &M));
8106       PetscCall(PetscBLASIntCast(newNumIndices, &N));
8107       PetscCall(PetscBLASIntCast(numIndices, &K));
8108       PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues));
8109       // row-major to column-major conversion, left multiplication becomes right multiplication
8110       PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M));
8111       if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues));
8112       newValues = newNewValues;
8113     }
8114     *outValues = (PetscScalar *)newValues;
8115     PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat));
8116   }
8117   PetscFunctionReturn(PETSC_SUCCESS);
8118 }
8119 
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)8120 PETSC_INTERN 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)
8121 {
8122   PetscFunctionBegin;
8123   PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft));
8124   PetscFunctionReturn(PETSC_SUCCESS);
8125 }
8126 
DMPlexGetClosureIndicesSize_Internal(DM dm,PetscSection section,PetscInt point,PetscInt * closureSize)8127 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize)
8128 {
8129   /* Closure ordering */
8130   PetscSection    clSection;
8131   IS              clPoints;
8132   const PetscInt *clp;
8133   PetscInt       *points;
8134   PetscInt        Ncl, Ni = 0;
8135 
8136   PetscFunctionBeginHot;
8137   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp));
8138   for (PetscInt p = 0; p < Ncl * 2; p += 2) {
8139     PetscInt dof;
8140 
8141     PetscCall(PetscSectionGetDof(section, points[p], &dof));
8142     Ni += dof;
8143   }
8144   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
8145   *closureSize = Ni;
8146   PetscFunctionReturn(PETSC_SUCCESS);
8147 }
8148 
DMPlexGetClosureIndices_Internal(DM dm,PetscSection section,PetscSection idxSection,PetscInt point,PetscBool useClPerm,PetscInt * numRows,PetscInt * numCols,PetscInt * indices[],PetscInt outOffsets[],PetscScalar * values[],PetscBool multiplyRight,PetscBool multiplyLeft)8149 static PetscErrorCode DMPlexGetClosureIndices_Internal(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numRows, PetscInt *numCols, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[], PetscBool multiplyRight, PetscBool multiplyLeft)
8150 {
8151   /* Closure ordering */
8152   PetscSection    clSection;
8153   IS              clPoints;
8154   const PetscInt *clp;
8155   PetscInt       *points;
8156   const PetscInt *clperm = NULL;
8157   /* Dof permutation and sign flips */
8158   const PetscInt    **perms[32] = {NULL};
8159   const PetscScalar **flips[32] = {NULL};
8160   PetscScalar        *valCopy   = NULL;
8161   /* Hanging node constraints */
8162   PetscInt    *pointsC = NULL;
8163   PetscScalar *valuesC = NULL;
8164   PetscInt     NclC, NiC;
8165 
8166   PetscInt *idx;
8167   PetscInt  Nf, Ncl, Ni = 0, offsets[32], p, f;
8168   PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
8169   PetscInt  idxStart, idxEnd;
8170   PetscInt  nRows, nCols;
8171 
8172   PetscFunctionBeginHot;
8173   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8174   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
8175   PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3);
8176   PetscAssertPointer(numRows, 6);
8177   PetscAssertPointer(numCols, 7);
8178   if (indices) PetscAssertPointer(indices, 8);
8179   if (outOffsets) PetscAssertPointer(outOffsets, 9);
8180   if (values) PetscAssertPointer(values, 10);
8181   PetscCall(PetscSectionGetNumFields(section, &Nf));
8182   PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf);
8183   PetscCall(PetscArrayzero(offsets, 32));
8184   /* 1) Get points in closure */
8185   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp));
8186   if (useClPerm) {
8187     PetscInt depth, clsize;
8188     PetscCall(DMPlexGetPointDepth(dm, point, &depth));
8189     for (clsize = 0, p = 0; p < Ncl; p++) {
8190       PetscInt dof;
8191       PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
8192       clsize += dof;
8193     }
8194     PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
8195   }
8196   /* 2) Get number of indices on these points and field offsets from section */
8197   for (p = 0; p < Ncl * 2; p += 2) {
8198     PetscInt dof, fdof;
8199 
8200     PetscCall(PetscSectionGetDof(section, points[p], &dof));
8201     for (f = 0; f < Nf; ++f) {
8202       PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
8203       offsets[f + 1] += fdof;
8204     }
8205     Ni += dof;
8206   }
8207   if (*numRows == -1) *numRows = Ni;
8208   if (*numCols == -1) *numCols = Ni;
8209   nRows = *numRows;
8210   nCols = *numCols;
8211   for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f];
8212   PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni);
8213   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
8214   if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols);
8215   if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows);
8216   for (f = 0; f < PetscMax(1, Nf); ++f) {
8217     if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
8218     else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]));
8219     /* may need to apply sign changes to the element matrix */
8220     if (values && flips[f]) {
8221       PetscInt foffset = offsets[f];
8222 
8223       for (p = 0; p < Ncl; ++p) {
8224         PetscInt           pnt  = points[2 * p], fdof;
8225         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
8226 
8227         if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof));
8228         else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof));
8229         if (flip) {
8230           PetscInt i, j, k;
8231 
8232           if (!valCopy) {
8233             PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
8234             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
8235             *values = valCopy;
8236           }
8237           for (i = 0; i < fdof; ++i) {
8238             PetscScalar fval = flip[i];
8239 
8240             if (multiplyRight) {
8241               for (k = 0; k < nRows; ++k) valCopy[Ni * k + (foffset + i)] *= fval;
8242             }
8243             if (multiplyLeft) {
8244               for (k = 0; k < nCols; ++k) valCopy[nCols * (foffset + i) + k] *= fval;
8245             }
8246           }
8247         }
8248         foffset += fdof;
8249       }
8250     }
8251   }
8252   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
8253   PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft));
8254   if (NclC) {
8255     if (multiplyRight) *numCols = NiC;
8256     if (multiplyLeft) *numRows = NiC;
8257     if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
8258     for (f = 0; f < PetscMax(1, Nf); ++f) {
8259       if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
8260       else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
8261     }
8262     for (f = 0; f < PetscMax(1, Nf); ++f) {
8263       if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]));
8264       else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]));
8265     }
8266     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
8267     Ncl    = NclC;
8268     Ni     = NiC;
8269     points = pointsC;
8270     if (values) *values = valuesC;
8271   }
8272   /* 5) Calculate indices */
8273   PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx));
8274   PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd));
8275   if (Nf) {
8276     PetscInt  idxOff;
8277     PetscBool useFieldOffsets;
8278 
8279     if (outOffsets) {
8280       for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];
8281     }
8282     PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets));
8283     if (useFieldOffsets) {
8284       for (p = 0; p < Ncl; ++p) {
8285         const PetscInt pnt = points[p * 2];
8286 
8287         PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx));
8288       }
8289     } else {
8290       for (p = 0; p < Ncl; ++p) {
8291         const PetscInt pnt = points[p * 2];
8292 
8293         if (pnt < idxStart || pnt >= idxEnd) continue;
8294         PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
8295         /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
8296          * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
8297          * global section. */
8298         PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx));
8299       }
8300     }
8301   } else {
8302     PetscInt off = 0, idxOff;
8303 
8304     for (p = 0; p < Ncl; ++p) {
8305       const PetscInt  pnt  = points[p * 2];
8306       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
8307 
8308       if (pnt < idxStart || pnt >= idxEnd) continue;
8309       PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
8310       /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
8311        * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
8312       PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx));
8313     }
8314   }
8315   /* 6) Cleanup */
8316   for (f = 0; f < PetscMax(1, Nf); ++f) {
8317     if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
8318     else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
8319   }
8320   if (NclC) {
8321     PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC));
8322   } else {
8323     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
8324   }
8325 
8326   if (indices) *indices = idx;
8327   PetscFunctionReturn(PETSC_SUCCESS);
8328 }
8329 
8330 /*@C
8331   DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.
8332 
8333   Not collective
8334 
8335   Input Parameters:
8336 + dm         - The `DM`
8337 . section    - The `PetscSection` describing the points (a local section)
8338 . idxSection - The `PetscSection` from which to obtain indices (may be local or global)
8339 . point      - The point defining the closure
8340 - useClPerm  - Use the closure point permutation if available
8341 
8342   Output Parameters:
8343 + numIndices - The number of dof indices in the closure of point with the input sections
8344 . indices    - The dof indices
8345 . outOffsets - Array, of length the number of fields plus 1, to write the field offsets into, or `NULL`
8346 - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL`
8347 
8348   Level: advanced
8349 
8350   Notes:
8351   Call `DMPlexRestoreClosureIndices()` to free allocated memory
8352 
8353   If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices.  The value
8354   of those indices is not significant.  If `idxSection` is local, the constrained dofs will yield the involution -(idx+1)
8355   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
8356   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when `idxSection` == section, otherwise global
8357   indices (with the above semantics) are implied.
8358 
8359 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`,
8360           `PetscSection`, `DMGetGlobalSection()`
8361 @*/
DMPlexGetClosureIndices(DM dm,PetscSection section,PetscSection idxSection,PetscInt point,PetscBool useClPerm,PetscInt * numIndices,PetscInt * indices[],PeOp PetscInt outOffsets[],PeOp PetscScalar * values[])8362 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[])
8363 {
8364   PetscInt numRows = -1, numCols = -1;
8365 
8366   PetscFunctionBeginHot;
8367   PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE));
8368   PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols);
8369   *numIndices = numRows;
8370   PetscFunctionReturn(PETSC_SUCCESS);
8371 }
8372 
8373 /*@C
8374   DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.
8375 
8376   Not collective
8377 
8378   Input Parameters:
8379 + dm         - The `DM`
8380 . section    - The `PetscSection` describing the points (a local section)
8381 . idxSection - The `PetscSection` from which to obtain indices (may be local or global)
8382 . point      - The point defining the closure
8383 - useClPerm  - Use the closure point permutation if available
8384 
8385   Output Parameters:
8386 + numIndices - The number of dof indices in the closure of point with the input sections
8387 . indices    - The dof indices
8388 . outOffsets - Array to write the field offsets into, or `NULL`
8389 - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL`
8390 
8391   Level: advanced
8392 
8393   Notes:
8394   If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values).
8395 
8396   If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices.  The value
8397   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
8398   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
8399   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
8400   indices (with the above semantics) are implied.
8401 
8402 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
8403 @*/
DMPlexRestoreClosureIndices(DM dm,PetscSection section,PetscSection idxSection,PetscInt point,PetscBool useClPerm,PetscInt * numIndices,PetscInt * indices[],PeOp PetscInt outOffsets[],PeOp PetscScalar * values[])8404 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[])
8405 {
8406   PetscFunctionBegin;
8407   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8408   PetscAssertPointer(indices, 7);
8409   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices));
8410   PetscFunctionReturn(PETSC_SUCCESS);
8411 }
8412 
DMPlexMatSetClosure_Internal(DM dm,PetscSection section,PetscSection globalSection,PetscBool useClPerm,Mat A,PetscInt point,const PetscScalar values[],InsertMode mode)8413 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8414 {
8415   DM_Plex           *mesh = (DM_Plex *)dm->data;
8416   PetscInt          *indices;
8417   PetscInt           numIndices;
8418   const PetscScalar *valuesOrig = values;
8419   PetscErrorCode     ierr;
8420 
8421   PetscFunctionBegin;
8422   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8423   if (!section) PetscCall(DMGetLocalSection(dm, &section));
8424   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
8425   if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection));
8426   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
8427   PetscValidHeaderSpecific(A, MAT_CLASSID, 5);
8428 
8429   PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values));
8430 
8431   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values));
8432   /* TODO: fix this code to not use error codes as handle-able exceptions! */
8433   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8434   if (ierr) {
8435     PetscMPIInt rank;
8436 
8437     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
8438     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
8439     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values));
8440     PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
8441     if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
8442     SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values");
8443   }
8444   if (mesh->printFEM > 1) {
8445     PetscInt i;
8446     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Indices:"));
8447     for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i]));
8448     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
8449   }
8450 
8451   PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
8452   if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
8453   PetscFunctionReturn(PETSC_SUCCESS);
8454 }
8455 
8456 /*@C
8457   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
8458 
8459   Not collective
8460 
8461   Input Parameters:
8462 + dm            - The `DM`
8463 . section       - The section describing the layout in `v`, or `NULL` to use the default section
8464 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section
8465 . A             - The matrix
8466 . point         - The point in the `DM`
8467 . values        - The array of values
8468 - mode          - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions
8469 
8470   Level: intermediate
8471 
8472 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
8473 @*/
DMPlexMatSetClosure(DM dm,PetscSection section,PetscSection globalSection,Mat A,PetscInt point,const PetscScalar values[],InsertMode mode)8474 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8475 {
8476   PetscFunctionBegin;
8477   PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode));
8478   PetscFunctionReturn(PETSC_SUCCESS);
8479 }
8480 
8481 /*@C
8482   DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section
8483 
8484   Not collective
8485 
8486   Input Parameters:
8487 + dmRow            - The `DM` for the row fields
8488 . sectionRow       - The section describing the layout, or `NULL` to use the default section in `dmRow`
8489 . useRowPerm       - The flag to use the closure permutation of the `dmRow` if available
8490 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow`
8491 . dmCol            - The `DM` for the column fields
8492 . sectionCol       - The section describing the layout, or `NULL` to use the default section in `dmCol`
8493 . useColPerm       - The flag to use the closure permutation of the `dmCol` if available
8494 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol`
8495 . A                - The matrix
8496 . point            - The point in the `DM`
8497 . values           - The array of values
8498 - mode             - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions
8499 
8500   Level: intermediate
8501 
8502 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
8503 @*/
DMPlexMatSetClosureGeneral(DM dmRow,PetscSection sectionRow,PetscSection globalSectionRow,PetscBool useRowPerm,DM dmCol,PetscSection sectionCol,PetscSection globalSectionCol,PetscBool useColPerm,Mat A,PetscInt point,const PetscScalar values[],InsertMode mode)8504 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, PetscBool useRowPerm, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, PetscBool useColPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8505 {
8506   DM_Plex           *mesh = (DM_Plex *)dmRow->data;
8507   PetscInt          *indicesRow, *indicesCol;
8508   PetscInt           numIndicesRow = -1, numIndicesCol = -1;
8509   const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2;
8510 
8511   PetscErrorCode ierr;
8512 
8513   PetscFunctionBegin;
8514   PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1);
8515   if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, &sectionRow));
8516   PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2);
8517   if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow));
8518   PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3);
8519   PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5);
8520   if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, &sectionCol));
8521   PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6);
8522   if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol));
8523   PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7);
8524   PetscValidHeaderSpecific(A, MAT_CLASSID, 9);
8525 
8526   PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow));
8527   PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol));
8528   valuesV1 = valuesV0;
8529   PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE));
8530   valuesV2 = valuesV1;
8531   PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE));
8532 
8533   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2));
8534   /* TODO: fix this code to not use error codes as handle-able exceptions! */
8535   ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode);
8536   if (ierr) {
8537     PetscMPIInt rank;
8538 
8539     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
8540     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
8541     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
8542     PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2));
8543     PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1));
8544     if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2));
8545     if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1));
8546   }
8547 
8548   PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2));
8549   PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1));
8550   if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2));
8551   if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1));
8552   PetscFunctionReturn(PETSC_SUCCESS);
8553 }
8554 
DMPlexMatSetClosureRefined(DM dmf,PetscSection fsection,PetscSection globalFSection,DM dmc,PetscSection csection,PetscSection globalCSection,Mat A,PetscInt point,const PetscScalar values[],InsertMode mode)8555 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8556 {
8557   DM_Plex        *mesh    = (DM_Plex *)dmf->data;
8558   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
8559   PetscInt       *cpoints = NULL;
8560   PetscInt       *findices, *cindices;
8561   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
8562   PetscInt        foffsets[32], coffsets[32];
8563   DMPolytopeType  ct;
8564   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
8565   PetscErrorCode  ierr;
8566 
8567   PetscFunctionBegin;
8568   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
8569   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
8570   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
8571   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
8572   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
8573   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
8574   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
8575   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
8576   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
8577   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
8578   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
8579   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
8580   PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
8581   PetscCall(PetscArrayzero(foffsets, 32));
8582   PetscCall(PetscArrayzero(coffsets, 32));
8583   /* Column indices */
8584   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
8585   maxFPoints = numCPoints;
8586   /* Compress out points not in the section */
8587   /*   TODO: Squeeze out points with 0 dof as well */
8588   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
8589   for (p = 0, q = 0; p < numCPoints * 2; p += 2) {
8590     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
8591       cpoints[q * 2]     = cpoints[p];
8592       cpoints[q * 2 + 1] = cpoints[p + 1];
8593       ++q;
8594     }
8595   }
8596   numCPoints = q;
8597   for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) {
8598     PetscInt fdof;
8599 
8600     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
8601     if (!dof) continue;
8602     for (f = 0; f < numFields; ++f) {
8603       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
8604       coffsets[f + 1] += fdof;
8605     }
8606     numCIndices += dof;
8607   }
8608   for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f];
8609   /* Row indices */
8610   PetscCall(DMPlexGetCellType(dmc, point, &ct));
8611   {
8612     DMPlexTransform tr;
8613     DMPolytopeType *rct;
8614     PetscInt       *rsize, *rcone, *rornt, Nt;
8615 
8616     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
8617     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
8618     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
8619     numSubcells = rsize[Nt - 1];
8620     PetscCall(DMPlexTransformDestroy(&tr));
8621   }
8622   PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints));
8623   for (r = 0, q = 0; r < numSubcells; ++r) {
8624     /* TODO Map from coarse to fine cells */
8625     PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
8626     /* Compress out points not in the section */
8627     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
8628     for (p = 0; p < numFPoints * 2; p += 2) {
8629       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
8630         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
8631         if (!dof) continue;
8632         for (s = 0; s < q; ++s)
8633           if (fpoints[p] == ftotpoints[s * 2]) break;
8634         if (s < q) continue;
8635         ftotpoints[q * 2]     = fpoints[p];
8636         ftotpoints[q * 2 + 1] = fpoints[p + 1];
8637         ++q;
8638       }
8639     }
8640     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
8641   }
8642   numFPoints = q;
8643   for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) {
8644     PetscInt fdof;
8645 
8646     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
8647     if (!dof) continue;
8648     for (f = 0; f < numFields; ++f) {
8649       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
8650       foffsets[f + 1] += fdof;
8651     }
8652     numFIndices += dof;
8653   }
8654   for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f];
8655 
8656   PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices);
8657   PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices);
8658   PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices));
8659   PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
8660   if (numFields) {
8661     const PetscInt **permsF[32] = {NULL};
8662     const PetscInt **permsC[32] = {NULL};
8663 
8664     for (f = 0; f < numFields; f++) {
8665       PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
8666       PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
8667     }
8668     for (p = 0; p < numFPoints; p++) {
8669       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
8670       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
8671     }
8672     for (p = 0; p < numCPoints; p++) {
8673       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
8674       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
8675     }
8676     for (f = 0; f < numFields; f++) {
8677       PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
8678       PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
8679     }
8680   } else {
8681     const PetscInt **permsF = NULL;
8682     const PetscInt **permsC = NULL;
8683 
8684     PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
8685     PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL));
8686     for (p = 0, off = 0; p < numFPoints; p++) {
8687       const PetscInt *perm = permsF ? permsF[p] : NULL;
8688 
8689       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
8690       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
8691     }
8692     for (p = 0, off = 0; p < numCPoints; p++) {
8693       const PetscInt *perm = permsC ? permsC[p] : NULL;
8694 
8695       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
8696       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
8697     }
8698     PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
8699     PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL));
8700   }
8701   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
8702   /* TODO: flips */
8703   /* TODO: fix this code to not use error codes as handle-able exceptions! */
8704   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
8705   if (ierr) {
8706     PetscMPIInt rank;
8707 
8708     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
8709     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
8710     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
8711     PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
8712     PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
8713   }
8714   PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints));
8715   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
8716   PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
8717   PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
8718   PetscFunctionReturn(PETSC_SUCCESS);
8719 }
8720 
DMPlexMatGetClosureIndicesRefined(DM dmf,PetscSection fsection,PetscSection globalFSection,DM dmc,PetscSection csection,PetscSection globalCSection,PetscInt point,PetscInt cindices[],PetscInt findices[])8721 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
8722 {
8723   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
8724   PetscInt       *cpoints      = NULL;
8725   PetscInt        foffsets[32] = {0}, coffsets[32] = {0};
8726   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
8727   DMPolytopeType  ct;
8728   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
8729 
8730   PetscFunctionBegin;
8731   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
8732   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
8733   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
8734   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
8735   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
8736   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
8737   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
8738   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
8739   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
8740   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
8741   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
8742   PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
8743   /* Column indices */
8744   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
8745   maxFPoints = numCPoints;
8746   /* Compress out points not in the section */
8747   /*   TODO: Squeeze out points with 0 dof as well */
8748   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
8749   for (p = 0, q = 0; p < numCPoints * 2; p += 2) {
8750     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
8751       cpoints[q * 2]     = cpoints[p];
8752       cpoints[q * 2 + 1] = cpoints[p + 1];
8753       ++q;
8754     }
8755   }
8756   numCPoints = q;
8757   for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) {
8758     PetscInt fdof;
8759 
8760     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
8761     if (!dof) continue;
8762     for (f = 0; f < numFields; ++f) {
8763       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
8764       coffsets[f + 1] += fdof;
8765     }
8766     numCIndices += dof;
8767   }
8768   for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f];
8769   /* Row indices */
8770   PetscCall(DMPlexGetCellType(dmc, point, &ct));
8771   {
8772     DMPlexTransform tr;
8773     DMPolytopeType *rct;
8774     PetscInt       *rsize, *rcone, *rornt, Nt;
8775 
8776     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
8777     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
8778     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
8779     numSubcells = rsize[Nt - 1];
8780     PetscCall(DMPlexTransformDestroy(&tr));
8781   }
8782   PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints));
8783   for (r = 0, q = 0; r < numSubcells; ++r) {
8784     /* TODO Map from coarse to fine cells */
8785     PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
8786     /* Compress out points not in the section */
8787     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
8788     for (p = 0; p < numFPoints * 2; p += 2) {
8789       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
8790         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
8791         if (!dof) continue;
8792         for (s = 0; s < q; ++s)
8793           if (fpoints[p] == ftotpoints[s * 2]) break;
8794         if (s < q) continue;
8795         ftotpoints[q * 2]     = fpoints[p];
8796         ftotpoints[q * 2 + 1] = fpoints[p + 1];
8797         ++q;
8798       }
8799     }
8800     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
8801   }
8802   numFPoints = q;
8803   for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) {
8804     PetscInt fdof;
8805 
8806     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
8807     if (!dof) continue;
8808     for (f = 0; f < numFields; ++f) {
8809       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
8810       foffsets[f + 1] += fdof;
8811     }
8812     numFIndices += dof;
8813   }
8814   for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f];
8815 
8816   PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices);
8817   PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices);
8818   if (numFields) {
8819     const PetscInt **permsF[32] = {NULL};
8820     const PetscInt **permsC[32] = {NULL};
8821 
8822     for (f = 0; f < numFields; f++) {
8823       PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
8824       PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
8825     }
8826     for (p = 0; p < numFPoints; p++) {
8827       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
8828       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
8829     }
8830     for (p = 0; p < numCPoints; p++) {
8831       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
8832       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
8833     }
8834     for (f = 0; f < numFields; f++) {
8835       PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
8836       PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
8837     }
8838   } else {
8839     const PetscInt **permsF = NULL;
8840     const PetscInt **permsC = NULL;
8841 
8842     PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
8843     PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL));
8844     for (p = 0, off = 0; p < numFPoints; p++) {
8845       const PetscInt *perm = permsF ? permsF[p] : NULL;
8846 
8847       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
8848       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
8849     }
8850     for (p = 0, off = 0; p < numCPoints; p++) {
8851       const PetscInt *perm = permsC ? permsC[p] : NULL;
8852 
8853       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
8854       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
8855     }
8856     PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
8857     PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL));
8858   }
8859   PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints));
8860   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
8861   PetscFunctionReturn(PETSC_SUCCESS);
8862 }
8863 
8864 /*@
8865   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
8866 
8867   Input Parameter:
8868 . dm - The `DMPLEX` object
8869 
8870   Output Parameter:
8871 . cellHeight - The height of a cell
8872 
8873   Level: developer
8874 
8875 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()`
8876 @*/
DMPlexGetVTKCellHeight(DM dm,PetscInt * cellHeight)8877 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
8878 {
8879   DM_Plex *mesh = (DM_Plex *)dm->data;
8880 
8881   PetscFunctionBegin;
8882   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8883   PetscAssertPointer(cellHeight, 2);
8884   *cellHeight = mesh->vtkCellHeight;
8885   PetscFunctionReturn(PETSC_SUCCESS);
8886 }
8887 
8888 /*@
8889   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
8890 
8891   Input Parameters:
8892 + dm         - The `DMPLEX` object
8893 - cellHeight - The height of a cell
8894 
8895   Level: developer
8896 
8897 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()`
8898 @*/
DMPlexSetVTKCellHeight(DM dm,PetscInt cellHeight)8899 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
8900 {
8901   DM_Plex *mesh = (DM_Plex *)dm->data;
8902 
8903   PetscFunctionBegin;
8904   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8905   mesh->vtkCellHeight = cellHeight;
8906   PetscFunctionReturn(PETSC_SUCCESS);
8907 }
8908 
8909 /*@
8910   DMPlexGetCellTypeStratum - Get the range of cells of a given celltype
8911 
8912   Input Parameters:
8913 + dm - The `DMPLEX` object
8914 - ct - The `DMPolytopeType` of the cell
8915 
8916   Output Parameters:
8917 + start - The first cell of this type, or `NULL`
8918 - end   - The upper bound on this celltype, or `NULL`
8919 
8920   Level: advanced
8921 
8922 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
8923 @*/
DMPlexGetCellTypeStratum(DM dm,DMPolytopeType ct,PeOp PetscInt * start,PeOp PetscInt * end)8924 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PeOp PetscInt *start, PeOp PetscInt *end)
8925 {
8926   DM_Plex *mesh = (DM_Plex *)dm->data;
8927   DMLabel  label;
8928   PetscInt pStart, pEnd;
8929 
8930   PetscFunctionBegin;
8931   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8932   if (start) {
8933     PetscAssertPointer(start, 3);
8934     *start = 0;
8935   }
8936   if (end) {
8937     PetscAssertPointer(end, 4);
8938     *end = 0;
8939   }
8940   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8941   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
8942   if (mesh->tr) {
8943     PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end));
8944   } else {
8945     PetscCall(DMPlexGetCellTypeLabel(dm, &label));
8946     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found");
8947     PetscCall(DMLabelGetStratumBounds(label, ct, start, end));
8948   }
8949   PetscFunctionReturn(PETSC_SUCCESS);
8950 }
8951 
8952 /*@
8953   DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum
8954 
8955   Input Parameters:
8956 + dm    - The `DMPLEX` object
8957 - depth - The depth for the given point stratum
8958 
8959   Output Parameter:
8960 . gsize - The global number of points in the stratum
8961 
8962   Level: advanced
8963 
8964 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
8965 @*/
DMPlexGetDepthStratumGlobalSize(DM dm,PetscInt depth,PetscInt * gsize)8966 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize)
8967 {
8968   PetscSF         sf;
8969   const PetscInt *leaves;
8970   PetscInt        Nl, loc, start, end, lsize = 0;
8971 
8972   PetscFunctionBegin;
8973   PetscCall(DMGetPointSF(dm, &sf));
8974   PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL));
8975   PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end));
8976   for (PetscInt p = start; p < end; ++p) {
8977     PetscCall(PetscFindInt(p, Nl, leaves, &loc));
8978     if (loc < 0) ++lsize;
8979   }
8980   PetscCallMPI(MPIU_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
8981   PetscFunctionReturn(PETSC_SUCCESS);
8982 }
8983 
DMPlexCreateNumbering_Plex(DM dm,PetscInt pStart,PetscInt pEnd,PetscInt shift,PetscInt * globalSize,PetscSF sf,IS * numbering)8984 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
8985 {
8986   PetscSection section, globalSection;
8987   PetscInt    *numbers, p;
8988 
8989   PetscFunctionBegin;
8990   if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE));
8991   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
8992   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
8993   for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1));
8994   PetscCall(PetscSectionSetUp(section));
8995   PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection));
8996   PetscCall(PetscMalloc1(pEnd - pStart, &numbers));
8997   for (p = pStart; p < pEnd; ++p) {
8998     PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart]));
8999     if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift;
9000     else numbers[p - pStart] += shift;
9001   }
9002   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering));
9003   if (globalSize) {
9004     PetscLayout layout;
9005     PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout));
9006     PetscCall(PetscLayoutGetSize(layout, globalSize));
9007     PetscCall(PetscLayoutDestroy(&layout));
9008   }
9009   PetscCall(PetscSectionDestroy(&section));
9010   PetscCall(PetscSectionDestroy(&globalSection));
9011   PetscFunctionReturn(PETSC_SUCCESS);
9012 }
9013 
9014 /*@
9015   DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process
9016 
9017   Input Parameters:
9018 + dm         - The `DMPLEX` object
9019 - includeAll - Whether to include all cells, or just the simplex and box cells
9020 
9021   Output Parameter:
9022 . globalCellNumbers - Global cell numbers for all cells on this process
9023 
9024   Level: developer
9025 
9026 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`
9027 @*/
DMPlexCreateCellNumbering(DM dm,PetscBool includeAll,IS * globalCellNumbers)9028 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers)
9029 {
9030   PetscInt cellHeight, cStart, cEnd;
9031 
9032   PetscFunctionBegin;
9033   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
9034   if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
9035   else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
9036   PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers));
9037   PetscFunctionReturn(PETSC_SUCCESS);
9038 }
9039 
9040 /*@
9041   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
9042 
9043   Input Parameter:
9044 . dm - The `DMPLEX` object
9045 
9046   Output Parameter:
9047 . globalCellNumbers - Global cell numbers for all cells on this process
9048 
9049   Level: developer
9050 
9051 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()`
9052 @*/
DMPlexGetCellNumbering(DM dm,IS * globalCellNumbers)9053 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
9054 {
9055   DM_Plex *mesh = (DM_Plex *)dm->data;
9056 
9057   PetscFunctionBegin;
9058   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9059   if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers));
9060   *globalCellNumbers = mesh->globalCellNumbers;
9061   PetscFunctionReturn(PETSC_SUCCESS);
9062 }
9063 
DMPlexCreateVertexNumbering_Internal(DM dm,PetscBool includeHybrid,IS * globalVertexNumbers)9064 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
9065 {
9066   PetscInt vStart, vEnd;
9067 
9068   PetscFunctionBegin;
9069   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9070   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9071   PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers));
9072   PetscFunctionReturn(PETSC_SUCCESS);
9073 }
9074 
9075 /*@
9076   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
9077 
9078   Input Parameter:
9079 . dm - The `DMPLEX` object
9080 
9081   Output Parameter:
9082 . globalVertexNumbers - Global vertex numbers for all vertices on this process
9083 
9084   Level: developer
9085 
9086 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`
9087 @*/
DMPlexGetVertexNumbering(DM dm,IS * globalVertexNumbers)9088 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9089 {
9090   DM_Plex *mesh = (DM_Plex *)dm->data;
9091 
9092   PetscFunctionBegin;
9093   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9094   if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers));
9095   *globalVertexNumbers = mesh->globalVertexNumbers;
9096   PetscFunctionReturn(PETSC_SUCCESS);
9097 }
9098 
9099 /*@
9100   DMPlexCreatePointNumbering - Create a global numbering for all points.
9101 
9102   Collective
9103 
9104   Input Parameter:
9105 . dm - The `DMPLEX` object
9106 
9107   Output Parameter:
9108 . globalPointNumbers - Global numbers for all points on this process
9109 
9110   Level: developer
9111 
9112   Notes:
9113   The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global
9114   points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points
9115   will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example,
9116   consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0.
9117 
9118   The partitioned mesh is
9119   ```
9120   (2)--0--(3)--1--(4)    (1)--0--(2)
9121   ```
9122   and its global numbering is
9123   ```
9124   (3)--0--(4)--1--(5)--2--(6)
9125   ```
9126   Then the global numbering is provided as
9127   ```
9128   [0] Number of indices in set 5
9129   [0] 0 0
9130   [0] 1 1
9131   [0] 2 3
9132   [0] 3 4
9133   [0] 4 -6
9134   [1] Number of indices in set 3
9135   [1] 0 2
9136   [1] 1 5
9137   [1] 2 6
9138   ```
9139 
9140 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`
9141 @*/
DMPlexCreatePointNumbering(DM dm,IS * globalPointNumbers)9142 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
9143 {
9144   IS        nums[4];
9145   PetscInt  depths[4], gdepths[4], starts[4];
9146   PetscInt  depth, d, shift = 0;
9147   PetscBool empty = PETSC_FALSE;
9148 
9149   PetscFunctionBegin;
9150   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9151   PetscCall(DMPlexGetDepth(dm, &depth));
9152   // For unstratified meshes use dim instead of depth
9153   if (depth < 0) PetscCall(DMGetDimension(dm, &depth));
9154   // If any stratum is empty, we must mark all empty
9155   for (d = 0; d <= depth; ++d) {
9156     PetscInt end;
9157 
9158     depths[d] = depth - d;
9159     PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end));
9160     if (!(starts[d] - end)) empty = PETSC_TRUE;
9161   }
9162   if (empty)
9163     for (d = 0; d <= depth; ++d) {
9164       depths[d] = -1;
9165       starts[d] = -1;
9166     }
9167   else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths));
9168   PetscCallMPI(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
9169   for (d = 0; d <= depth; ++d) PetscCheck(starts[d] < 0 || depths[d] == gdepths[d], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected depth %" PetscInt_FMT ", found %" PetscInt_FMT, depths[d], gdepths[d]);
9170   // Note here that 'shift' is collective, so that the numbering is stratified by depth
9171   for (d = 0; d <= depth; ++d) {
9172     PetscInt pStart, pEnd, gsize;
9173 
9174     PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd));
9175     PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]));
9176     shift += gsize;
9177   }
9178   PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers));
9179   for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d]));
9180   PetscFunctionReturn(PETSC_SUCCESS);
9181 }
9182 
9183 /*@
9184   DMPlexCreateEdgeNumbering - Create a global numbering for edges.
9185 
9186   Collective
9187 
9188   Input Parameter:
9189 . dm - The `DMPLEX` object
9190 
9191   Output Parameter:
9192 . globalEdgeNumbers - Global numbers for all edges on this process
9193 
9194   Level: developer
9195 
9196   Notes:
9197   The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). In the IS, owned edges will have their non-negative value while edges owned by different ranks will be involuted -(idx+1).
9198 
9199 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()`
9200 @*/
DMPlexCreateEdgeNumbering(DM dm,IS * globalEdgeNumbers)9201 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers)
9202 {
9203   PetscSF  sf;
9204   PetscInt eStart, eEnd;
9205 
9206   PetscFunctionBegin;
9207   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9208   PetscCall(DMGetPointSF(dm, &sf));
9209   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
9210   PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers));
9211   PetscFunctionReturn(PETSC_SUCCESS);
9212 }
9213 
9214 /*@
9215   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
9216 
9217   Input Parameter:
9218 . dm - The `DMPLEX` object
9219 
9220   Output Parameter:
9221 . ranks - The rank field
9222 
9223   Options Database Key:
9224 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer
9225 
9226   Level: intermediate
9227 
9228 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`
9229 @*/
DMPlexCreateRankField(DM dm,Vec * ranks)9230 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
9231 {
9232   DM             rdm;
9233   PetscFE        fe;
9234   PetscScalar   *r;
9235   PetscMPIInt    rank;
9236   DMPolytopeType ct;
9237   PetscInt       dim, cStart, cEnd, c;
9238   PetscBool      simplex;
9239 
9240   PetscFunctionBeginUser;
9241   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9242   PetscAssertPointer(ranks, 2);
9243   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
9244   PetscCall(DMClone(dm, &rdm));
9245   PetscCall(DMGetDimension(rdm, &dim));
9246   PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd));
9247   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
9248   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
9249   PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe));
9250   PetscCall(PetscObjectSetName((PetscObject)fe, "rank"));
9251   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe));
9252   PetscCall(PetscFEDestroy(&fe));
9253   PetscCall(DMCreateDS(rdm));
9254   PetscCall(DMCreateGlobalVector(rdm, ranks));
9255   PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition"));
9256   PetscCall(VecGetArray(*ranks, &r));
9257   for (c = cStart; c < cEnd; ++c) {
9258     PetscScalar *lr;
9259 
9260     PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr));
9261     if (lr) *lr = rank;
9262   }
9263   PetscCall(VecRestoreArray(*ranks, &r));
9264   PetscCall(DMDestroy(&rdm));
9265   PetscFunctionReturn(PETSC_SUCCESS);
9266 }
9267 
9268 /*@
9269   DMPlexCreateLabelField - Create a field whose value is the label value for that point
9270 
9271   Input Parameters:
9272 + dm    - The `DMPLEX`
9273 - label - The `DMLabel`
9274 
9275   Output Parameter:
9276 . val - The label value field
9277 
9278   Options Database Key:
9279 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer
9280 
9281   Level: intermediate
9282 
9283 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`
9284 @*/
DMPlexCreateLabelField(DM dm,DMLabel label,Vec * val)9285 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
9286 {
9287   DM             rdm, plex;
9288   Vec            lval;
9289   PetscSection   section;
9290   PetscFE        fe;
9291   PetscScalar   *v;
9292   PetscInt       dim, pStart, pEnd, p, cStart;
9293   DMPolytopeType ct;
9294   char           name[PETSC_MAX_PATH_LEN];
9295   const char    *lname, *prefix;
9296 
9297   PetscFunctionBeginUser;
9298   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9299   PetscAssertPointer(label, 2);
9300   PetscAssertPointer(val, 3);
9301   PetscCall(DMClone(dm, &rdm));
9302   PetscCall(DMConvert(rdm, DMPLEX, &plex));
9303   PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL));
9304   PetscCall(DMPlexGetCellType(plex, cStart, &ct));
9305   PetscCall(DMDestroy(&plex));
9306   PetscCall(DMGetDimension(rdm, &dim));
9307   PetscCall(DMGetOptionsPrefix(dm, &prefix));
9308   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
9309   PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname));
9310   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe));
9311   PetscCall(PetscObjectSetName((PetscObject)fe, ""));
9312   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe));
9313   PetscCall(PetscFEDestroy(&fe));
9314   PetscCall(DMCreateDS(rdm));
9315   PetscCall(DMCreateGlobalVector(rdm, val));
9316   PetscCall(DMCreateLocalVector(rdm, &lval));
9317   PetscCall(PetscObjectSetName((PetscObject)*val, lname));
9318   PetscCall(DMGetLocalSection(rdm, &section));
9319   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
9320   PetscCall(VecGetArray(lval, &v));
9321   for (p = pStart; p < pEnd; ++p) {
9322     PetscInt cval, dof, off;
9323 
9324     PetscCall(PetscSectionGetDof(section, p, &dof));
9325     if (!dof) continue;
9326     PetscCall(DMLabelGetValue(label, p, &cval));
9327     PetscCall(PetscSectionGetOffset(section, p, &off));
9328     for (PetscInt d = 0; d < dof; d++) v[off + d] = cval;
9329   }
9330   PetscCall(VecRestoreArray(lval, &v));
9331   PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val));
9332   PetscCall(VecDestroy(&lval));
9333   PetscCall(DMDestroy(&rdm));
9334   PetscFunctionReturn(PETSC_SUCCESS);
9335 }
9336 
9337 /*@
9338   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
9339 
9340   Input Parameter:
9341 . dm - The `DMPLEX` object
9342 
9343   Level: developer
9344 
9345   Notes:
9346   This is a useful diagnostic when creating meshes programmatically.
9347 
9348   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9349 
9350 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
9351 @*/
DMPlexCheckSymmetry(DM dm)9352 PetscErrorCode DMPlexCheckSymmetry(DM dm)
9353 {
9354   PetscSection    coneSection, supportSection;
9355   const PetscInt *cone, *support;
9356   PetscInt        coneSize, c, supportSize, s;
9357   PetscInt        pStart, pEnd, p, pp, csize, ssize;
9358   PetscBool       storagecheck = PETSC_TRUE;
9359 
9360   PetscFunctionBegin;
9361   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9362   PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view"));
9363   PetscCall(DMPlexGetConeSection(dm, &coneSection));
9364   PetscCall(DMPlexGetSupportSection(dm, &supportSection));
9365   /* Check that point p is found in the support of its cone points, and vice versa */
9366   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
9367   for (p = pStart; p < pEnd; ++p) {
9368     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
9369     PetscCall(DMPlexGetCone(dm, p, &cone));
9370     for (c = 0; c < coneSize; ++c) {
9371       PetscBool dup = PETSC_FALSE;
9372       PetscInt  d;
9373       for (d = c - 1; d >= 0; --d) {
9374         if (cone[c] == cone[d]) {
9375           dup = PETSC_TRUE;
9376           break;
9377         }
9378       }
9379       PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize));
9380       PetscCall(DMPlexGetSupport(dm, cone[c], &support));
9381       for (s = 0; s < supportSize; ++s) {
9382         if (support[s] == p) break;
9383       }
9384       if ((s >= supportSize) || (dup && (support[s + 1] != p))) {
9385         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p));
9386         for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s]));
9387         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
9388         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c]));
9389         for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s]));
9390         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
9391         PetscCheck(!dup, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not repeatedly found in support of repeated cone point %" PetscInt_FMT, p, cone[c]);
9392         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]);
9393       }
9394     }
9395     PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL));
9396     if (p != pp) {
9397       storagecheck = PETSC_FALSE;
9398       continue;
9399     }
9400     PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
9401     PetscCall(DMPlexGetSupport(dm, p, &support));
9402     for (s = 0; s < supportSize; ++s) {
9403       PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize));
9404       PetscCall(DMPlexGetCone(dm, support[s], &cone));
9405       for (c = 0; c < coneSize; ++c) {
9406         PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL));
9407         if (cone[c] != pp) {
9408           c = 0;
9409           break;
9410         }
9411         if (cone[c] == p) break;
9412       }
9413       if (c >= coneSize) {
9414         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p));
9415         for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c]));
9416         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
9417         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s]));
9418         for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c]));
9419         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
9420         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]);
9421       }
9422     }
9423   }
9424   if (storagecheck) {
9425     PetscCall(PetscSectionGetStorageSize(coneSection, &csize));
9426     PetscCall(PetscSectionGetStorageSize(supportSection, &ssize));
9427     PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize);
9428   }
9429   PetscFunctionReturn(PETSC_SUCCESS);
9430 }
9431 
9432 /*
9433   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.
9434 */
DMPlexCellUnsplitVertices_Private(DM dm,PetscInt c,DMPolytopeType ct,PetscInt * unsplit)9435 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit)
9436 {
9437   DMPolytopeType  cct;
9438   PetscInt        ptpoints[4];
9439   const PetscInt *cone, *ccone, *ptcone;
9440   PetscInt        coneSize, cp, cconeSize, ccp, npt = 0, pt;
9441 
9442   PetscFunctionBegin;
9443   *unsplit = 0;
9444   switch (ct) {
9445   case DM_POLYTOPE_POINT_PRISM_TENSOR:
9446     ptpoints[npt++] = c;
9447     break;
9448   case DM_POLYTOPE_SEG_PRISM_TENSOR:
9449     PetscCall(DMPlexGetCone(dm, c, &cone));
9450     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
9451     for (cp = 0; cp < coneSize; ++cp) {
9452       PetscCall(DMPlexGetCellType(dm, cone[cp], &cct));
9453       if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp];
9454     }
9455     break;
9456   case DM_POLYTOPE_TRI_PRISM_TENSOR:
9457   case DM_POLYTOPE_QUAD_PRISM_TENSOR:
9458     PetscCall(DMPlexGetCone(dm, c, &cone));
9459     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
9460     for (cp = 0; cp < coneSize; ++cp) {
9461       PetscCall(DMPlexGetCone(dm, cone[cp], &ccone));
9462       PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize));
9463       for (ccp = 0; ccp < cconeSize; ++ccp) {
9464         PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct));
9465         if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) {
9466           PetscInt p;
9467           for (p = 0; p < npt; ++p)
9468             if (ptpoints[p] == ccone[ccp]) break;
9469           if (p == npt) ptpoints[npt++] = ccone[ccp];
9470         }
9471       }
9472     }
9473     break;
9474   default:
9475     break;
9476   }
9477   for (pt = 0; pt < npt; ++pt) {
9478     PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone));
9479     if (ptcone[0] == ptcone[1]) ++(*unsplit);
9480   }
9481   PetscFunctionReturn(PETSC_SUCCESS);
9482 }
9483 
9484 /*@
9485   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
9486 
9487   Input Parameters:
9488 + dm         - The `DMPLEX` object
9489 - cellHeight - Normally 0
9490 
9491   Level: developer
9492 
9493   Notes:
9494   This is a useful diagnostic when creating meshes programmatically.
9495   Currently applicable only to homogeneous simplex or tensor meshes.
9496 
9497   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9498 
9499 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
9500 @*/
DMPlexCheckSkeleton(DM dm,PetscInt cellHeight)9501 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
9502 {
9503   DMPlexInterpolatedFlag interp;
9504   DMPolytopeType         ct;
9505   PetscInt               vStart, vEnd, cStart, cEnd, c;
9506 
9507   PetscFunctionBegin;
9508   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9509   PetscCall(DMPlexIsInterpolated(dm, &interp));
9510   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
9511   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9512   for (c = cStart; c < cEnd; ++c) {
9513     PetscInt *closure = NULL;
9514     PetscInt  coneSize, closureSize, cl, Nv = 0;
9515 
9516     PetscCall(DMPlexGetCellType(dm, c, &ct));
9517     if (ct == DM_POLYTOPE_UNKNOWN) continue;
9518     if (interp == DMPLEX_INTERPOLATED_FULL) {
9519       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
9520       PetscCheck(coneSize == DMPolytopeTypeGetConeSize(ct), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " of type %s has cone size %" PetscInt_FMT " != %" PetscInt_FMT, c, DMPolytopeTypes[ct], coneSize, DMPolytopeTypeGetConeSize(ct));
9521     }
9522     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
9523     for (cl = 0; cl < closureSize * 2; cl += 2) {
9524       const PetscInt p = closure[cl];
9525       if ((p >= vStart) && (p < vEnd)) ++Nv;
9526     }
9527     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
9528     /* Special Case: Tensor faces with identified vertices */
9529     if (Nv < DMPolytopeTypeGetNumVertices(ct)) {
9530       PetscInt unsplit;
9531 
9532       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9533       if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue;
9534     }
9535     PetscCheck(Nv == DMPolytopeTypeGetNumVertices(ct), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " of type %s has %" PetscInt_FMT " vertices != %" PetscInt_FMT, c, DMPolytopeTypes[ct], Nv, DMPolytopeTypeGetNumVertices(ct));
9536   }
9537   PetscFunctionReturn(PETSC_SUCCESS);
9538 }
9539 
9540 /*@
9541   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
9542 
9543   Collective
9544 
9545   Input Parameters:
9546 + dm         - The `DMPLEX` object
9547 - cellHeight - Normally 0
9548 
9549   Level: developer
9550 
9551   Notes:
9552   This is a useful diagnostic when creating meshes programmatically.
9553   This routine is only relevant for meshes that are fully interpolated across all ranks.
9554   It will error out if a partially interpolated mesh is given on some rank.
9555   It will do nothing for locally uninterpolated mesh (as there is nothing to check).
9556 
9557   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9558 
9559 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()`
9560 @*/
DMPlexCheckFaces(DM dm,PetscInt cellHeight)9561 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
9562 {
9563   PetscInt               dim, depth, vStart, vEnd, cStart, cEnd, c, h;
9564   DMPlexInterpolatedFlag interpEnum;
9565 
9566   PetscFunctionBegin;
9567   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9568   PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum));
9569   if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS);
9570   if (interpEnum != DMPLEX_INTERPOLATED_FULL) {
9571     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"));
9572     PetscFunctionReturn(PETSC_SUCCESS);
9573   }
9574 
9575   PetscCall(DMGetDimension(dm, &dim));
9576   PetscCall(DMPlexGetDepth(dm, &depth));
9577   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9578   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
9579     PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd));
9580     for (c = cStart; c < cEnd; ++c) {
9581       const PetscInt       *cone, *ornt, *faceSizes, *faces;
9582       const DMPolytopeType *faceTypes;
9583       DMPolytopeType        ct;
9584       PetscInt              numFaces, coneSize, f;
9585       PetscInt             *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit;
9586 
9587       PetscCall(DMPlexGetCellType(dm, c, &ct));
9588       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9589       if (unsplit) continue;
9590       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
9591       PetscCall(DMPlexGetCone(dm, c, &cone));
9592       PetscCall(DMPlexGetConeOrientation(dm, c, &ornt));
9593       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
9594       for (cl = 0; cl < closureSize * 2; cl += 2) {
9595         const PetscInt p = closure[cl];
9596         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
9597       }
9598       PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
9599       PetscCheck(coneSize == numFaces, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " of type %s has %" PetscInt_FMT " faces but should have %" PetscInt_FMT, c, DMPolytopeTypes[ct], coneSize, numFaces);
9600       for (f = 0; f < numFaces; ++f) {
9601         DMPolytopeType fct;
9602         PetscInt      *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
9603 
9604         PetscCall(DMPlexGetCellType(dm, cone[f], &fct));
9605         PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure));
9606         for (cl = 0; cl < fclosureSize * 2; cl += 2) {
9607           const PetscInt p = fclosure[cl];
9608           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
9609         }
9610         PetscCheck(fnumCorners == faceSizes[f], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " of type %s (cone idx %" PetscInt_FMT ") of cell %" PetscInt_FMT " of type %s has %" PetscInt_FMT " vertices but should have %" PetscInt_FMT, cone[f], DMPolytopeTypes[fct], f, c, DMPolytopeTypes[ct], fnumCorners, faceSizes[f]);
9611         for (v = 0; v < fnumCorners; ++v) {
9612           if (fclosure[v] != faces[fOff + v]) {
9613             PetscInt v1;
9614 
9615             PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:"));
9616             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1]));
9617             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:"));
9618             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1]));
9619             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
9620             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " of type %s (cone idx %" PetscInt_FMT ", ornt %" PetscInt_FMT ") of cell %" PetscInt_FMT " of type %s vertex %" PetscInt_FMT ", %" PetscInt_FMT " != %" PetscInt_FMT, cone[f], DMPolytopeTypes[fct], f, ornt[f], c, DMPolytopeTypes[ct], v, fclosure[v], faces[fOff + v]);
9621           }
9622         }
9623         PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure));
9624         fOff += faceSizes[f];
9625       }
9626       PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
9627       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
9628     }
9629   }
9630   PetscFunctionReturn(PETSC_SUCCESS);
9631 }
9632 
9633 /*@
9634   DMPlexCheckGeometry - Check the geometry of mesh cells
9635 
9636   Input Parameter:
9637 . dm - The `DMPLEX` object
9638 
9639   Level: developer
9640 
9641   Notes:
9642   This is a useful diagnostic when creating meshes programmatically.
9643 
9644   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9645 
9646 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
9647 @*/
DMPlexCheckGeometry(DM dm)9648 PetscErrorCode DMPlexCheckGeometry(DM dm)
9649 {
9650   Vec       coordinates;
9651   PetscReal detJ, J[9], refVol = 1.0;
9652   PetscReal vol;
9653   PetscInt  dim, depth, dE, d, cStart, cEnd, c;
9654 
9655   PetscFunctionBegin;
9656   PetscCall(DMGetDimension(dm, &dim));
9657   PetscCall(DMGetCoordinateDim(dm, &dE));
9658   if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS);
9659   PetscCall(DMPlexGetDepth(dm, &depth));
9660   for (d = 0; d < dim; ++d) refVol *= 2.0;
9661   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
9662   /* Make sure local coordinates are created, because that step is collective */
9663   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
9664   if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS);
9665   for (c = cStart; c < cEnd; ++c) {
9666     DMPolytopeType ct;
9667     PetscInt       unsplit;
9668     PetscBool      ignoreZeroVol = PETSC_FALSE;
9669 
9670     PetscCall(DMPlexGetCellType(dm, c, &ct));
9671     switch (ct) {
9672     case DM_POLYTOPE_SEG_PRISM_TENSOR:
9673     case DM_POLYTOPE_TRI_PRISM_TENSOR:
9674     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
9675       ignoreZeroVol = PETSC_TRUE;
9676       break;
9677     default:
9678       break;
9679     }
9680     switch (ct) {
9681     case DM_POLYTOPE_TRI_PRISM:
9682     case DM_POLYTOPE_TRI_PRISM_TENSOR:
9683     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
9684     case DM_POLYTOPE_PYRAMID:
9685       continue;
9686     default:
9687       break;
9688     }
9689     PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9690     if (unsplit) continue;
9691     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ));
9692     PetscCheck(detJ >= -PETSC_SMALL && (detJ > 0.0 || ignoreZeroVol), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " of type %s is inverted, |J| = %g", c, DMPolytopeTypes[ct], (double)detJ);
9693     PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol)));
9694     /* This should work with periodicity since DG coordinates should be used */
9695     if (depth > 1) {
9696       PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL));
9697       PetscCheck(vol >= -PETSC_SMALL && (vol > 0.0 || ignoreZeroVol), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " of type %s is inverted, vol = %g", c, DMPolytopeTypes[ct], (double)vol);
9698       PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol));
9699     }
9700   }
9701   PetscFunctionReturn(PETSC_SUCCESS);
9702 }
9703 
9704 /*@
9705   DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex.
9706 
9707   Collective
9708 
9709   Input Parameters:
9710 + dm              - The `DMPLEX` object
9711 . pointSF         - The `PetscSF`, or `NULL` for `PointSF` attached to `DM`
9712 - allowExtraRoots - Flag to allow extra points not present in the `DM`
9713 
9714   Level: developer
9715 
9716   Notes:
9717   This is mainly intended for debugging/testing purposes.
9718 
9719   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9720 
9721   Extra roots can come from periodic cuts, where additional points appear on the boundary
9722 
9723 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()`
9724 @*/
DMPlexCheckPointSF(DM dm,PetscSF pointSF,PetscBool allowExtraRoots)9725 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots)
9726 {
9727   PetscInt           l, nleaves, nroots, overlap;
9728   const PetscInt    *locals;
9729   const PetscSFNode *remotes;
9730   PetscBool          distributed;
9731   MPI_Comm           comm;
9732   PetscMPIInt        rank;
9733 
9734   PetscFunctionBegin;
9735   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9736   if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2);
9737   else pointSF = dm->sf;
9738   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
9739   PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached");
9740   PetscCallMPI(MPI_Comm_rank(comm, &rank));
9741   {
9742     PetscMPIInt mpiFlag;
9743 
9744     PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag));
9745     PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag);
9746   }
9747   PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes));
9748   PetscCall(DMPlexIsDistributed(dm, &distributed));
9749   if (!distributed) {
9750     PetscCheck(nroots < 0 || nleaves == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Undistributed DMPlex cannot have non-empty PointSF (has %" PetscInt_FMT " roots, %" PetscInt_FMT " leaves)", nroots, nleaves);
9751     PetscFunctionReturn(PETSC_SUCCESS);
9752   }
9753   PetscCheck(nroots >= 0, comm, PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set (has %" PetscInt_FMT " roots, %" PetscInt_FMT " leaves)", nroots, nleaves);
9754   PetscCall(DMPlexGetOverlap(dm, &overlap));
9755 
9756   /* Check SF graph is compatible with DMPlex chart */
9757   {
9758     PetscInt pStart, pEnd, maxLeaf;
9759 
9760     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
9761     PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf));
9762     PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots);
9763     PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd);
9764   }
9765 
9766   /* Check there are no cells in interface */
9767   if (!overlap) {
9768     PetscInt cellHeight, cStart, cEnd;
9769 
9770     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
9771     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
9772     for (l = 0; l < nleaves; ++l) {
9773       const PetscInt point = locals ? locals[l] : l;
9774 
9775       PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point);
9776     }
9777   }
9778 
9779   /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
9780   {
9781     const PetscInt *rootdegree;
9782 
9783     PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree));
9784     PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree));
9785     for (l = 0; l < nleaves; ++l) {
9786       const PetscInt  point = locals ? locals[l] : l;
9787       const PetscInt *cone;
9788       PetscInt        coneSize, c, idx;
9789 
9790       PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
9791       PetscCall(DMPlexGetCone(dm, point, &cone));
9792       for (c = 0; c < coneSize; ++c) {
9793         if (!rootdegree[cone[c]]) {
9794           if (locals) {
9795             PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx));
9796           } else {
9797             idx = (cone[c] < nleaves) ? cone[c] : -1;
9798           }
9799           PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]);
9800         }
9801       }
9802     }
9803   }
9804   PetscFunctionReturn(PETSC_SUCCESS);
9805 }
9806 
9807 /*@
9808   DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices.
9809 
9810   Collective
9811 
9812   Input Parameter:
9813 . dm - The `DMPLEX` object
9814 
9815   Level: developer
9816 
9817   Notes:
9818   This is mainly intended for debugging/testing purposes.
9819 
9820   Other cell types which are disconnected would be caught by the symmetry and face checks.
9821 
9822   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9823 
9824 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()`
9825 @*/
DMPlexCheckOrphanVertices(DM dm)9826 PetscErrorCode DMPlexCheckOrphanVertices(DM dm)
9827 {
9828   PetscInt pStart, pEnd, vStart, vEnd;
9829 
9830   PetscFunctionBegin;
9831   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
9832   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9833   if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS);
9834   for (PetscInt v = vStart; v < vEnd; ++v) {
9835     PetscInt suppSize;
9836 
9837     PetscCall(DMPlexGetSupportSize(dm, v, &suppSize));
9838     PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v);
9839   }
9840   PetscFunctionReturn(PETSC_SUCCESS);
9841 }
9842 
9843 /*@
9844   DMPlexCheck - Perform various checks of `DMPLEX` sanity
9845 
9846   Input Parameter:
9847 . dm - The `DMPLEX` object
9848 
9849   Level: developer
9850 
9851   Notes:
9852   This is a useful diagnostic when creating meshes programmatically.
9853 
9854   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9855 
9856   Currently does not include `DMPlexCheckCellShape()`.
9857 
9858 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
9859 @*/
DMPlexCheck(DM dm)9860 PetscErrorCode DMPlexCheck(DM dm)
9861 {
9862   PetscInt cellHeight;
9863 
9864   PetscFunctionBegin;
9865   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
9866   PetscCall(DMPlexCheckSymmetry(dm));
9867   PetscCall(DMPlexCheckSkeleton(dm, cellHeight));
9868   PetscCall(DMPlexCheckFaces(dm, cellHeight));
9869   PetscCall(DMPlexCheckGeometry(dm));
9870   PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE));
9871   PetscCall(DMPlexCheckInterfaceCones(dm));
9872   PetscCall(DMPlexCheckOrphanVertices(dm));
9873   PetscFunctionReturn(PETSC_SUCCESS);
9874 }
9875 
9876 typedef struct cell_stats {
9877   PetscReal min, max, sum, squaresum;
9878   PetscInt  count;
9879 } cell_stats_t;
9880 
cell_stats_reduce(void * a,void * b,int * len,MPI_Datatype * datatype)9881 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype)
9882 {
9883   PetscInt i, N = *len;
9884 
9885   for (i = 0; i < N; i++) {
9886     cell_stats_t *A = (cell_stats_t *)a;
9887     cell_stats_t *B = (cell_stats_t *)b;
9888 
9889     B->min = PetscMin(A->min, B->min);
9890     B->max = PetscMax(A->max, B->max);
9891     B->sum += A->sum;
9892     B->squaresum += A->squaresum;
9893     B->count += A->count;
9894   }
9895 }
9896 
9897 /*@
9898   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
9899 
9900   Collective
9901 
9902   Input Parameters:
9903 + dm        - The `DMPLEX` object
9904 . output    - If true, statistics will be displayed on `stdout`
9905 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output
9906 
9907   Level: developer
9908 
9909   Notes:
9910   This is mainly intended for debugging/testing purposes.
9911 
9912   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9913 
9914 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()`
9915 @*/
DMPlexCheckCellShape(DM dm,PetscBool output,PetscReal condLimit)9916 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
9917 {
9918   DM           dmCoarse;
9919   cell_stats_t stats, globalStats;
9920   MPI_Comm     comm = PetscObjectComm((PetscObject)dm);
9921   PetscReal   *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
9922   PetscReal    limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
9923   PetscInt     cdim, cStart, cEnd, c, eStart, eEnd, count = 0;
9924   PetscMPIInt  rank, size;
9925 
9926   PetscFunctionBegin;
9927   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9928   stats.min = PETSC_MAX_REAL;
9929   stats.max = PETSC_MIN_REAL;
9930   stats.sum = stats.squaresum = 0.;
9931   stats.count                 = 0;
9932 
9933   PetscCallMPI(MPI_Comm_size(comm, &size));
9934   PetscCallMPI(MPI_Comm_rank(comm, &rank));
9935   PetscCall(DMGetCoordinateDim(dm, &cdim));
9936   PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ));
9937   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
9938   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
9939   for (c = cStart; c < cEnd; c++) {
9940     PetscInt  i;
9941     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
9942 
9943     PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ));
9944     PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c);
9945     for (i = 0; i < PetscSqr(cdim); ++i) {
9946       frobJ += J[i] * J[i];
9947       frobInvJ += invJ[i] * invJ[i];
9948     }
9949     cond2 = frobJ * frobInvJ;
9950     cond  = PetscSqrtReal(cond2);
9951 
9952     stats.min = PetscMin(stats.min, cond);
9953     stats.max = PetscMax(stats.max, cond);
9954     stats.sum += cond;
9955     stats.squaresum += cond2;
9956     stats.count++;
9957     if (output && cond > limit) {
9958       PetscSection coordSection;
9959       Vec          coordsLocal;
9960       PetscScalar *coords = NULL;
9961       PetscInt     Nv, d, clSize, cl, *closure = NULL;
9962 
9963       PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
9964       PetscCall(DMGetCoordinateSection(dm, &coordSection));
9965       PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
9966       PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond));
9967       for (i = 0; i < Nv / cdim; ++i) {
9968         PetscCall(PetscSynchronizedPrintf(comm, "  Vertex %" PetscInt_FMT ": (", i));
9969         for (d = 0; d < cdim; ++d) {
9970           if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", "));
9971           PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d])));
9972         }
9973         PetscCall(PetscSynchronizedPrintf(comm, ")\n"));
9974       }
9975       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
9976       for (cl = 0; cl < clSize * 2; cl += 2) {
9977         const PetscInt edge = closure[cl];
9978 
9979         if ((edge >= eStart) && (edge < eEnd)) {
9980           PetscReal len;
9981 
9982           PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL));
9983           PetscCall(PetscSynchronizedPrintf(comm, "  Edge %" PetscInt_FMT ": length %g\n", edge, (double)len));
9984         }
9985       }
9986       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
9987       PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
9988     }
9989   }
9990   if (output) PetscCall(PetscSynchronizedFlush(comm, NULL));
9991 
9992   if (size > 1) {
9993     PetscMPIInt  blockLengths[2] = {4, 1};
9994     MPI_Aint     blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)};
9995     MPI_Datatype blockTypes[2]   = {MPIU_REAL, MPIU_INT}, statType;
9996     MPI_Op       statReduce;
9997 
9998     PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType));
9999     PetscCallMPI(MPI_Type_commit(&statType));
10000     PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce));
10001     PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm));
10002     PetscCallMPI(MPI_Op_free(&statReduce));
10003     PetscCallMPI(MPI_Type_free(&statType));
10004   } else {
10005     PetscCall(PetscArraycpy(&globalStats, &stats, 1));
10006   }
10007   if (rank == 0) {
10008     count = globalStats.count;
10009     min   = globalStats.min;
10010     max   = globalStats.max;
10011     mean  = globalStats.sum / globalStats.count;
10012     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0;
10013   }
10014 
10015   if (output) PetscCall(PetscPrintf(comm, "Mesh with %" PetscInt_FMT " cells, shape condition numbers: min = %g, max = %g, mean = %g, stddev = %g\n", count, (double)min, (double)max, (double)mean, (double)stdev));
10016   PetscCall(PetscFree2(J, invJ));
10017 
10018   PetscCall(DMGetCoarseDM(dm, &dmCoarse));
10019   if (dmCoarse) {
10020     PetscBool isplex;
10021 
10022     PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex));
10023     if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit));
10024   }
10025   PetscFunctionReturn(PETSC_SUCCESS);
10026 }
10027 
10028 /*@
10029   DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with
10030   orthogonal quality below given tolerance.
10031 
10032   Collective
10033 
10034   Input Parameters:
10035 + dm   - The `DMPLEX` object
10036 . fv   - Optional `PetscFV` object for pre-computed cell/face centroid information
10037 - atol - [0, 1] Absolute tolerance for tagging cells.
10038 
10039   Output Parameters:
10040 + OrthQual      - `Vec` containing orthogonal quality per cell
10041 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE`
10042 
10043   Options Database Keys:
10044 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported.
10045 - -dm_plex_orthogonal_quality_vec_view   - view OrthQual vector.
10046 
10047   Level: intermediate
10048 
10049   Notes:
10050   Orthogonal quality is given by the following formula\:
10051 
10052   $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$
10053 
10054   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
10055   is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the
10056   current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by
10057   calculating the cosine of the angle between these vectors.
10058 
10059   Orthogonal quality ranges from 1 (best) to 0 (worst).
10060 
10061   This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for
10062   pre-computed FVM cell data, but if it is not passed in then this data will be computed.
10063 
10064   Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance.
10065 
10066 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec`
10067 @*/
DMPlexComputeOrthogonalQuality(DM dm,PeOp PetscFV fv,PetscReal atol,Vec * OrthQual,DMLabel * OrthQualLabel)10068 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PeOp PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel)
10069 {
10070   PetscInt               nc, cellHeight, cStart, cEnd, cell, cellIter = 0;
10071   PetscInt              *idx;
10072   PetscScalar           *oqVals;
10073   const PetscScalar     *cellGeomArr, *faceGeomArr;
10074   PetscReal             *ci, *fi, *Ai;
10075   MPI_Comm               comm;
10076   Vec                    cellgeom, facegeom;
10077   DM                     dmFace, dmCell;
10078   IS                     glob;
10079   ISLocalToGlobalMapping ltog;
10080   PetscViewer            vwr;
10081 
10082   PetscFunctionBegin;
10083   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10084   if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);
10085   PetscAssertPointer(OrthQual, 4);
10086   PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol);
10087   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
10088   PetscCall(DMGetDimension(dm, &nc));
10089   PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc);
10090   {
10091     DMPlexInterpolatedFlag interpFlag;
10092 
10093     PetscCall(DMPlexIsInterpolated(dm, &interpFlag));
10094     if (interpFlag != DMPLEX_INTERPOLATED_FULL) {
10095       PetscMPIInt rank;
10096 
10097       PetscCallMPI(MPI_Comm_rank(comm, &rank));
10098       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank);
10099     }
10100   }
10101   if (OrthQualLabel) {
10102     PetscAssertPointer(OrthQualLabel, 5);
10103     PetscCall(DMCreateLabel(dm, "Orthogonal_Quality"));
10104     PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel));
10105   } else {
10106     *OrthQualLabel = NULL;
10107   }
10108   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
10109   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
10110   PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob));
10111   PetscCall(ISLocalToGlobalMappingCreateIS(glob, &ltog));
10112   PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH));
10113   PetscCall(VecCreate(comm, OrthQual));
10114   PetscCall(VecSetType(*OrthQual, VECSTANDARD));
10115   PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE));
10116   PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog));
10117   PetscCall(VecSetUp(*OrthQual));
10118   PetscCall(ISDestroy(&glob));
10119   PetscCall(ISLocalToGlobalMappingDestroy(&ltog));
10120   PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL));
10121   PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr));
10122   PetscCall(VecGetArrayRead(facegeom, &faceGeomArr));
10123   PetscCall(VecGetDM(cellgeom, &dmCell));
10124   PetscCall(VecGetDM(facegeom, &dmFace));
10125   PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai));
10126   for (cell = cStart; cell < cEnd; cellIter++, cell++) {
10127     PetscInt         cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE;
10128     PetscInt         cellarr[2], *adj = NULL;
10129     PetscScalar     *cArr, *fArr;
10130     PetscReal        minvalc = 1.0, minvalf = 1.0;
10131     PetscFVCellGeom *cg;
10132 
10133     idx[cellIter] = cell - cStart;
10134     cellarr[0]    = cell;
10135     /* Make indexing into cellGeom easier */
10136     PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg));
10137     PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj));
10138     /* Technically 1 too big, but easier than fiddling with empty adjacency array */
10139     PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr));
10140     for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) {
10141       PetscInt         i;
10142       const PetscInt   neigh  = adj[cellneigh];
10143       PetscReal        normci = 0, normfi = 0, normai = 0;
10144       PetscFVCellGeom *cgneigh;
10145       PetscFVFaceGeom *fg;
10146 
10147       /* Don't count ourselves in the neighbor list */
10148       if (neigh == cell) continue;
10149       PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh));
10150       cellarr[1] = neigh;
10151       {
10152         PetscInt        numcovpts;
10153         const PetscInt *covpts;
10154 
10155         PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts));
10156         PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg));
10157         PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts));
10158       }
10159 
10160       /* Compute c_i, f_i and their norms */
10161       for (i = 0; i < nc; i++) {
10162         ci[i] = cgneigh->centroid[i] - cg->centroid[i];
10163         fi[i] = fg->centroid[i] - cg->centroid[i];
10164         Ai[i] = fg->normal[i];
10165         normci += PetscPowReal(ci[i], 2);
10166         normfi += PetscPowReal(fi[i], 2);
10167         normai += PetscPowReal(Ai[i], 2);
10168       }
10169       normci = PetscSqrtReal(normci);
10170       normfi = PetscSqrtReal(normfi);
10171       normai = PetscSqrtReal(normai);
10172 
10173       /* Normalize and compute for each face-cell-normal pair */
10174       for (i = 0; i < nc; i++) {
10175         ci[i] = ci[i] / normci;
10176         fi[i] = fi[i] / normfi;
10177         Ai[i] = Ai[i] / normai;
10178         /* PetscAbs because I don't know if normals are guaranteed to point out */
10179         cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]);
10180         fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]);
10181       }
10182       if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]);
10183       if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]);
10184     }
10185     PetscCall(PetscFree(adj));
10186     PetscCall(PetscFree2(cArr, fArr));
10187     /* Defer to cell if they're equal */
10188     oqVals[cellIter] = PetscMin(minvalf, minvalc);
10189     if (OrthQualLabel) {
10190       if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE));
10191     }
10192   }
10193   PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES));
10194   PetscCall(VecAssemblyBegin(*OrthQual));
10195   PetscCall(VecAssemblyEnd(*OrthQual));
10196   PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr));
10197   PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr));
10198   PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL));
10199   if (OrthQualLabel) {
10200     if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr));
10201   }
10202   PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai));
10203   PetscCall(PetscViewerDestroy(&vwr));
10204   PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view"));
10205   PetscFunctionReturn(PETSC_SUCCESS);
10206 }
10207 
10208 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect
10209  * interpolator construction */
DMGetFullDM(DM dm,DM * odm)10210 static PetscErrorCode DMGetFullDM(DM dm, DM *odm)
10211 {
10212   PetscSection section, newSection, gsection;
10213   PetscSF      sf;
10214   PetscBool    hasConstraints, ghasConstraints;
10215 
10216   PetscFunctionBegin;
10217   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10218   PetscAssertPointer(odm, 2);
10219   PetscCall(DMGetLocalSection(dm, &section));
10220   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
10221   PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
10222   if (!ghasConstraints) {
10223     PetscCall(PetscObjectReference((PetscObject)dm));
10224     *odm = dm;
10225     PetscFunctionReturn(PETSC_SUCCESS);
10226   }
10227   PetscCall(DMClone(dm, odm));
10228   PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm));
10229   PetscCall(DMGetLocalSection(*odm, &newSection));
10230   PetscCall(DMGetPointSF(*odm, &sf));
10231   PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection));
10232   PetscCall(DMSetGlobalSection(*odm, gsection));
10233   PetscCall(PetscSectionDestroy(&gsection));
10234   PetscFunctionReturn(PETSC_SUCCESS);
10235 }
10236 
DMCreateAffineInterpolationCorrection_Plex(DM dmc,DM dmf,Vec * shift)10237 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift)
10238 {
10239   DM        dmco, dmfo;
10240   Mat       interpo;
10241   Vec       rscale;
10242   Vec       cglobalo, clocal;
10243   Vec       fglobal, fglobalo, flocal;
10244   PetscBool regular;
10245 
10246   PetscFunctionBegin;
10247   PetscCall(DMGetFullDM(dmc, &dmco));
10248   PetscCall(DMGetFullDM(dmf, &dmfo));
10249   PetscCall(DMSetCoarseDM(dmfo, dmco));
10250   PetscCall(DMPlexGetRegularRefinement(dmf, &regular));
10251   PetscCall(DMPlexSetRegularRefinement(dmfo, regular));
10252   PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale));
10253   PetscCall(DMCreateGlobalVector(dmco, &cglobalo));
10254   PetscCall(DMCreateLocalVector(dmc, &clocal));
10255   PetscCall(VecSet(cglobalo, 0.));
10256   PetscCall(VecSet(clocal, 0.));
10257   PetscCall(DMCreateGlobalVector(dmf, &fglobal));
10258   PetscCall(DMCreateGlobalVector(dmfo, &fglobalo));
10259   PetscCall(DMCreateLocalVector(dmf, &flocal));
10260   PetscCall(VecSet(fglobal, 0.));
10261   PetscCall(VecSet(fglobalo, 0.));
10262   PetscCall(VecSet(flocal, 0.));
10263   PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL));
10264   PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo));
10265   PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo));
10266   PetscCall(MatMult(interpo, cglobalo, fglobalo));
10267   PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal));
10268   PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal));
10269   PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal));
10270   PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal));
10271   *shift = fglobal;
10272   PetscCall(VecDestroy(&flocal));
10273   PetscCall(VecDestroy(&fglobalo));
10274   PetscCall(VecDestroy(&clocal));
10275   PetscCall(VecDestroy(&cglobalo));
10276   PetscCall(VecDestroy(&rscale));
10277   PetscCall(MatDestroy(&interpo));
10278   PetscCall(DMDestroy(&dmfo));
10279   PetscCall(DMDestroy(&dmco));
10280   PetscFunctionReturn(PETSC_SUCCESS);
10281 }
10282 
DMInterpolateSolution_Plex(DM coarse,DM fine,Mat interp,Vec coarseSol,Vec fineSol)10283 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
10284 {
10285   PetscObject shifto;
10286   Vec         shift;
10287 
10288   PetscFunctionBegin;
10289   if (!interp) {
10290     Vec rscale;
10291 
10292     PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale));
10293     PetscCall(VecDestroy(&rscale));
10294   } else {
10295     PetscCall(PetscObjectReference((PetscObject)interp));
10296   }
10297   PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto));
10298   if (!shifto) {
10299     PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift));
10300     PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift));
10301     shifto = (PetscObject)shift;
10302     PetscCall(VecDestroy(&shift));
10303   }
10304   shift = (Vec)shifto;
10305   PetscCall(MatInterpolate(interp, coarseSol, fineSol));
10306   PetscCall(VecAXPY(fineSol, 1.0, shift));
10307   PetscCall(MatDestroy(&interp));
10308   PetscFunctionReturn(PETSC_SUCCESS);
10309 }
10310 
10311 /* Pointwise interpolation
10312      Just code FEM for now
10313      u^f = I u^c
10314      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
10315      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
10316      I_{ij} = psi^f_i phi^c_j
10317 */
DMCreateInterpolation_Plex(DM dmCoarse,DM dmFine,Mat * interpolation,Vec * scaling)10318 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
10319 {
10320   PetscSection gsc, gsf;
10321   PetscInt     m, n;
10322   void        *ctx;
10323   DM           cdm;
10324   PetscBool    regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE;
10325 
10326   PetscFunctionBegin;
10327   PetscCall(DMGetGlobalSection(dmFine, &gsf));
10328   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
10329   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
10330   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
10331 
10332   PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis));
10333   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation));
10334   PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
10335   PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype));
10336   PetscCall(DMGetApplicationContext(dmFine, &ctx));
10337 
10338   PetscCall(DMGetCoarseDM(dmFine, &cdm));
10339   PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
10340   if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx));
10341   else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx));
10342   PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
10343   if (scaling) {
10344     /* Use naive scaling */
10345     PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
10346   }
10347   PetscFunctionReturn(PETSC_SUCCESS);
10348 }
10349 
DMCreateInjection_Plex(DM dmCoarse,DM dmFine,Mat * mat)10350 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
10351 {
10352   VecScatter ctx;
10353 
10354   PetscFunctionBegin;
10355   PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL));
10356   PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat));
10357   PetscCall(VecScatterDestroy(&ctx));
10358   PetscFunctionReturn(PETSC_SUCCESS);
10359 }
10360 
g0_identity_private(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g0[])10361 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
10362 {
10363   const PetscInt f  = (PetscInt)PetscRealPart(constants[numConstants]);
10364   const PetscInt Nc = uOff[f + 1] - uOff[f];
10365   for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0;
10366 }
10367 
10368 // The assumption here is that the test field is a vector and the basis field is a scalar (so we need the gradient)
g1_identity_private(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g1[])10369 static void g1_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[])
10370 {
10371   for (PetscInt c = 0; c < dim; ++c) g1[c * dim + c] = 1.0;
10372 }
10373 
DMCreateMassMatrixLumped_Plex(DM dm,Vec * lmass,Vec * mass)10374 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass)
10375 {
10376   DM           dmc;
10377   PetscDS      ds;
10378   Vec          ones, locmass;
10379   IS           cellIS;
10380   PetscFormKey key;
10381   PetscInt     depth;
10382 
10383   PetscFunctionBegin;
10384   PetscCall(DMClone(dm, &dmc));
10385   PetscCall(DMCopyDisc(dm, dmc));
10386   PetscCall(DMGetDS(dmc, &ds));
10387   for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL));
10388   if (mass) PetscCall(DMCreateGlobalVector(dm, mass));
10389   if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass));
10390   else PetscCall(DMGetLocalVector(dm, &locmass));
10391   PetscCall(DMGetLocalVector(dm, &ones));
10392   PetscCall(DMPlexGetDepth(dm, &depth));
10393   PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS));
10394   PetscCall(VecSet(locmass, 0.0));
10395   PetscCall(VecSet(ones, 1.0));
10396   key.label = NULL;
10397   key.value = 0;
10398   key.field = 0;
10399   key.part  = 0;
10400   PetscCall(DMPlexComputeJacobianActionByKey(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL));
10401   PetscCall(ISDestroy(&cellIS));
10402   if (mass) {
10403     PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass));
10404     PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass));
10405   }
10406   PetscCall(DMRestoreLocalVector(dm, &ones));
10407   if (lmass) *lmass = locmass;
10408   else PetscCall(DMRestoreLocalVector(dm, &locmass));
10409   PetscCall(DMDestroy(&dmc));
10410   PetscFunctionReturn(PETSC_SUCCESS);
10411 }
10412 
DMCreateMassMatrix_Plex(DM dmCoarse,DM dmFine,Mat * mass)10413 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
10414 {
10415   PetscSection gsc, gsf;
10416   PetscInt     m, n;
10417   void        *ctx;
10418   DM           cdm;
10419   PetscBool    regular;
10420 
10421   PetscFunctionBegin;
10422   if (dmFine == dmCoarse) {
10423     DM            dmc;
10424     PetscDS       ds;
10425     PetscWeakForm wf;
10426     Vec           u;
10427     IS            cellIS;
10428     PetscFormKey  key;
10429     PetscInt      depth;
10430 
10431     PetscCall(DMClone(dmFine, &dmc));
10432     PetscCall(DMCopyDisc(dmFine, dmc));
10433     PetscCall(DMGetDS(dmc, &ds));
10434     PetscCall(PetscDSGetWeakForm(ds, &wf));
10435     PetscCall(PetscWeakFormClear(wf));
10436     for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL));
10437     PetscCall(DMCreateMatrix(dmc, mass));
10438     PetscCall(DMGetLocalVector(dmc, &u));
10439     PetscCall(DMPlexGetDepth(dmc, &depth));
10440     PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS));
10441     PetscCall(MatZeroEntries(*mass));
10442     key.label = NULL;
10443     key.value = 0;
10444     key.field = 0;
10445     key.part  = 0;
10446     PetscCall(DMPlexComputeJacobianByKey(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL));
10447     PetscCall(ISDestroy(&cellIS));
10448     PetscCall(DMRestoreLocalVector(dmc, &u));
10449     PetscCall(DMDestroy(&dmc));
10450   } else {
10451     PetscCall(DMGetGlobalSection(dmFine, &gsf));
10452     PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
10453     PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
10454     PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
10455 
10456     PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
10457     PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
10458     PetscCall(MatSetType(*mass, dmCoarse->mattype));
10459     PetscCall(DMGetApplicationContext(dmFine, &ctx));
10460 
10461     PetscCall(DMGetCoarseDM(dmFine, &cdm));
10462     PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
10463     if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx));
10464     else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx));
10465   }
10466   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view"));
10467   PetscFunctionReturn(PETSC_SUCCESS);
10468 }
10469 
DMCreateGradientMatrix_Plex(DM dmc,DM dmr,Mat * derv)10470 PetscErrorCode DMCreateGradientMatrix_Plex(DM dmc, DM dmr, Mat *derv)
10471 {
10472   PetscSection gsc, gsf;
10473   PetscInt     m, n;
10474   void        *ctx;
10475 
10476   PetscFunctionBegin;
10477   PetscCall(DMGetGlobalSection(dmr, &gsf));
10478   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
10479   PetscCall(DMGetGlobalSection(dmc, &gsc));
10480   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
10481 
10482   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmc), derv));
10483   PetscCall(PetscObjectSetName((PetscObject)*derv, "Plex Derivative Matrix"));
10484   PetscCall(MatSetSizes(*derv, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
10485   PetscCall(MatSetType(*derv, dmc->mattype));
10486 
10487   PetscCall(DMGetApplicationContext(dmr, &ctx));
10488   {
10489     DM            ndmr;
10490     PetscDS       ds;
10491     PetscWeakForm wf;
10492     Vec           u;
10493     IS            cellIS;
10494     PetscFormKey  key;
10495     PetscInt      depth, Nf;
10496 
10497     PetscCall(DMClone(dmr, &ndmr));
10498     PetscCall(DMCopyDisc(dmr, ndmr));
10499     PetscCall(DMGetDS(ndmr, &ds));
10500     PetscCall(PetscDSGetWeakForm(ds, &wf));
10501     PetscCall(PetscWeakFormClear(wf));
10502     PetscCall(PetscDSGetNumFields(ds, &Nf));
10503     for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, NULL, g1_identity_private, NULL, NULL));
10504     PetscCall(DMGetLocalVector(ndmr, &u));
10505     PetscCall(DMPlexGetDepth(ndmr, &depth));
10506     PetscCall(DMGetStratumIS(ndmr, "depth", depth, &cellIS));
10507     PetscCall(MatZeroEntries(*derv));
10508     key.label = NULL;
10509     key.value = 0;
10510     key.field = 0;
10511     key.part  = 0;
10512     PetscCall(DMPlexComputeJacobianByKeyGeneral(ndmr, dmc, key, cellIS, 0.0, 0.0, u, NULL, *derv, *derv, NULL));
10513     PetscCall(ISDestroy(&cellIS));
10514     PetscCall(DMRestoreLocalVector(ndmr, &u));
10515     PetscCall(DMDestroy(&ndmr));
10516   }
10517   PetscCall(MatViewFromOptions(*derv, NULL, "-gradient_mat_view"));
10518   PetscFunctionReturn(PETSC_SUCCESS);
10519 }
10520 
10521 /*@
10522   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
10523 
10524   Input Parameter:
10525 . dm - The `DMPLEX` object
10526 
10527   Output Parameter:
10528 . regular - The flag
10529 
10530   Level: intermediate
10531 
10532 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()`
10533 @*/
DMPlexGetRegularRefinement(DM dm,PetscBool * regular)10534 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
10535 {
10536   PetscFunctionBegin;
10537   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10538   PetscAssertPointer(regular, 2);
10539   *regular = ((DM_Plex *)dm->data)->regularRefinement;
10540   PetscFunctionReturn(PETSC_SUCCESS);
10541 }
10542 
10543 /*@
10544   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
10545 
10546   Input Parameters:
10547 + dm      - The `DMPLEX` object
10548 - regular - The flag
10549 
10550   Level: intermediate
10551 
10552 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()`
10553 @*/
DMPlexSetRegularRefinement(DM dm,PetscBool regular)10554 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
10555 {
10556   PetscFunctionBegin;
10557   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10558   ((DM_Plex *)dm->data)->regularRefinement = regular;
10559   PetscFunctionReturn(PETSC_SUCCESS);
10560 }
10561 
10562 /*@
10563   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
10564   call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`.
10565 
10566   Not Collective
10567 
10568   Input Parameter:
10569 . dm - The `DMPLEX` object
10570 
10571   Output Parameters:
10572 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points.
10573 - anchorIS      - If not `NULL`, set to the list of anchors indexed by `anchorSection`
10574 
10575   Level: intermediate
10576 
10577 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection`
10578 @*/
DMPlexGetAnchors(DM dm,PeOp PetscSection * anchorSection,PeOp IS * anchorIS)10579 PetscErrorCode DMPlexGetAnchors(DM dm, PeOp PetscSection *anchorSection, PeOp IS *anchorIS)
10580 {
10581   DM_Plex *plex = (DM_Plex *)dm->data;
10582 
10583   PetscFunctionBegin;
10584   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10585   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm));
10586   if (anchorSection) *anchorSection = plex->anchorSection;
10587   if (anchorIS) *anchorIS = plex->anchorIS;
10588   PetscFunctionReturn(PETSC_SUCCESS);
10589 }
10590 
10591 /*@
10592   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.
10593 
10594   Collective
10595 
10596   Input Parameters:
10597 + dm            - The `DMPLEX` object
10598 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS.
10599                   Must have a local communicator (`PETSC_COMM_SELF` or derivative).
10600 - anchorIS      - The list of all anchor points.  Must have a local communicator (`PETSC_COMM_SELF` or derivative).
10601 
10602   Level: intermediate
10603 
10604   Notes:
10605   Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to
10606   an outside value, the anchor constraints set a point's degrees of freedom to be a linear
10607   combination of other points' degrees of freedom.
10608 
10609   After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling
10610   `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix.
10611 
10612   The reference counts of `anchorSection` and `anchorIS` are incremented.
10613 
10614 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`
10615 @*/
DMPlexSetAnchors(DM dm,PetscSection anchorSection,IS anchorIS)10616 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
10617 {
10618   DM_Plex    *plex = (DM_Plex *)dm->data;
10619   PetscMPIInt result;
10620 
10621   PetscFunctionBegin;
10622   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10623   if (anchorSection) {
10624     PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2);
10625     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result));
10626     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator");
10627   }
10628   if (anchorIS) {
10629     PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3);
10630     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result));
10631     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator");
10632   }
10633 
10634   PetscCall(PetscObjectReference((PetscObject)anchorSection));
10635   PetscCall(PetscSectionDestroy(&plex->anchorSection));
10636   plex->anchorSection = anchorSection;
10637 
10638   PetscCall(PetscObjectReference((PetscObject)anchorIS));
10639   PetscCall(ISDestroy(&plex->anchorIS));
10640   plex->anchorIS = anchorIS;
10641 
10642   if (PetscUnlikelyDebug(anchorIS && anchorSection)) {
10643     PetscInt        size, a, pStart, pEnd;
10644     const PetscInt *anchors;
10645 
10646     PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd));
10647     PetscCall(ISGetLocalSize(anchorIS, &size));
10648     PetscCall(ISGetIndices(anchorIS, &anchors));
10649     for (a = 0; a < size; a++) {
10650       PetscInt p;
10651 
10652       p = anchors[a];
10653       if (p >= pStart && p < pEnd) {
10654         PetscInt dof;
10655 
10656         PetscCall(PetscSectionGetDof(anchorSection, p, &dof));
10657         if (dof) {
10658           PetscCall(ISRestoreIndices(anchorIS, &anchors));
10659           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p);
10660         }
10661       }
10662     }
10663     PetscCall(ISRestoreIndices(anchorIS, &anchors));
10664   }
10665   /* reset the generic constraints */
10666   PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL));
10667   PetscFunctionReturn(PETSC_SUCCESS);
10668 }
10669 
DMPlexCreateConstraintSection_Anchors(DM dm,PetscSection section,PetscSection * cSec)10670 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
10671 {
10672   PetscSection anchorSection;
10673   PetscInt     pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
10674 
10675   PetscFunctionBegin;
10676   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10677   PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL));
10678   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec));
10679   PetscCall(PetscSectionGetNumFields(section, &numFields));
10680   if (numFields) {
10681     PetscInt f;
10682     PetscCall(PetscSectionSetNumFields(*cSec, numFields));
10683 
10684     for (f = 0; f < numFields; f++) {
10685       PetscInt numComp;
10686 
10687       PetscCall(PetscSectionGetFieldComponents(section, f, &numComp));
10688       PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp));
10689     }
10690   }
10691   PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd));
10692   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
10693   pStart = PetscMax(pStart, sStart);
10694   pEnd   = PetscMin(pEnd, sEnd);
10695   pEnd   = PetscMax(pStart, pEnd);
10696   PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd));
10697   for (p = pStart; p < pEnd; p++) {
10698     PetscCall(PetscSectionGetDof(anchorSection, p, &dof));
10699     if (dof) {
10700       PetscCall(PetscSectionGetDof(section, p, &dof));
10701       PetscCall(PetscSectionSetDof(*cSec, p, dof));
10702       for (f = 0; f < numFields; f++) {
10703         PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
10704         PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof));
10705       }
10706     }
10707   }
10708   PetscCall(PetscSectionSetUp(*cSec));
10709   PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section"));
10710   PetscFunctionReturn(PETSC_SUCCESS);
10711 }
10712 
DMPlexCreateConstraintMatrix_Anchors(DM dm,PetscSection section,PetscSection cSec,Mat * cMat)10713 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
10714 {
10715   PetscSection    aSec;
10716   PetscInt        pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
10717   const PetscInt *anchors;
10718   PetscInt        numFields, f;
10719   IS              aIS;
10720   MatType         mtype;
10721   PetscBool       iscuda, iskokkos;
10722 
10723   PetscFunctionBegin;
10724   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10725   PetscCall(PetscSectionGetStorageSize(cSec, &m));
10726   PetscCall(PetscSectionGetStorageSize(section, &n));
10727   PetscCall(MatCreate(PETSC_COMM_SELF, cMat));
10728   PetscCall(MatSetSizes(*cMat, m, n, m, n));
10729   PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda));
10730   if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda));
10731   PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos));
10732   if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos));
10733   if (iscuda) mtype = MATSEQAIJCUSPARSE;
10734   else if (iskokkos) mtype = MATSEQAIJKOKKOS;
10735   else mtype = MATSEQAIJ;
10736   PetscCall(MatSetType(*cMat, mtype));
10737   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
10738   PetscCall(ISGetIndices(aIS, &anchors));
10739   /* cSec will be a subset of aSec and section */
10740   PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd));
10741   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
10742   PetscCall(PetscMalloc1(m + 1, &i));
10743   i[0] = 0;
10744   PetscCall(PetscSectionGetNumFields(section, &numFields));
10745   for (p = pStart; p < pEnd; p++) {
10746     PetscInt rDof, rOff, r;
10747 
10748     PetscCall(PetscSectionGetDof(aSec, p, &rDof));
10749     if (!rDof) continue;
10750     PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
10751     if (numFields) {
10752       for (f = 0; f < numFields; f++) {
10753         annz = 0;
10754         for (r = 0; r < rDof; r++) {
10755           a = anchors[rOff + r];
10756           if (a < sStart || a >= sEnd) continue;
10757           PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
10758           annz += aDof;
10759         }
10760         PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof));
10761         PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off));
10762         for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz;
10763       }
10764     } else {
10765       annz = 0;
10766       PetscCall(PetscSectionGetDof(cSec, p, &dof));
10767       for (q = 0; q < dof; q++) {
10768         a = anchors[rOff + q];
10769         if (a < sStart || a >= sEnd) continue;
10770         PetscCall(PetscSectionGetDof(section, a, &aDof));
10771         annz += aDof;
10772       }
10773       PetscCall(PetscSectionGetDof(cSec, p, &dof));
10774       PetscCall(PetscSectionGetOffset(cSec, p, &off));
10775       for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz;
10776     }
10777   }
10778   nnz = i[m];
10779   PetscCall(PetscMalloc1(nnz, &j));
10780   offset = 0;
10781   for (p = pStart; p < pEnd; p++) {
10782     if (numFields) {
10783       for (f = 0; f < numFields; f++) {
10784         PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof));
10785         for (q = 0; q < dof; q++) {
10786           PetscInt rDof, rOff, r;
10787           PetscCall(PetscSectionGetDof(aSec, p, &rDof));
10788           PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
10789           for (r = 0; r < rDof; r++) {
10790             PetscInt s;
10791 
10792             a = anchors[rOff + r];
10793             if (a < sStart || a >= sEnd) continue;
10794             PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
10795             PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff));
10796             for (s = 0; s < aDof; s++) j[offset++] = aOff + s;
10797           }
10798         }
10799       }
10800     } else {
10801       PetscCall(PetscSectionGetDof(cSec, p, &dof));
10802       for (q = 0; q < dof; q++) {
10803         PetscInt rDof, rOff, r;
10804         PetscCall(PetscSectionGetDof(aSec, p, &rDof));
10805         PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
10806         for (r = 0; r < rDof; r++) {
10807           PetscInt s;
10808 
10809           a = anchors[rOff + r];
10810           if (a < sStart || a >= sEnd) continue;
10811           PetscCall(PetscSectionGetDof(section, a, &aDof));
10812           PetscCall(PetscSectionGetOffset(section, a, &aOff));
10813           for (s = 0; s < aDof; s++) j[offset++] = aOff + s;
10814         }
10815       }
10816     }
10817   }
10818   PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL));
10819   PetscCall(PetscFree(i));
10820   PetscCall(PetscFree(j));
10821   PetscCall(ISRestoreIndices(aIS, &anchors));
10822   PetscFunctionReturn(PETSC_SUCCESS);
10823 }
10824 
DMCreateDefaultConstraints_Plex(DM dm)10825 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
10826 {
10827   DM_Plex     *plex = (DM_Plex *)dm->data;
10828   PetscSection anchorSection, section, cSec;
10829   Mat          cMat;
10830 
10831   PetscFunctionBegin;
10832   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10833   PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL));
10834   if (anchorSection) {
10835     PetscInt Nf;
10836 
10837     PetscCall(DMGetLocalSection(dm, &section));
10838     PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec));
10839     PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat));
10840     PetscCall(DMGetNumFields(dm, &Nf));
10841     if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat));
10842     PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL));
10843     PetscCall(PetscSectionDestroy(&cSec));
10844     PetscCall(MatDestroy(&cMat));
10845   }
10846   PetscFunctionReturn(PETSC_SUCCESS);
10847 }
10848 
DMCreateSubDomainDM_Plex(DM dm,DMLabel label,PetscInt value,IS * is,DM * subdm)10849 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
10850 {
10851   IS           subis;
10852   PetscSection section, subsection;
10853 
10854   PetscFunctionBegin;
10855   PetscCall(DMGetLocalSection(dm, &section));
10856   PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
10857   PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
10858   /* Create subdomain */
10859   PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, PetscObjectComm((PetscObject)dm), NULL, subdm));
10860   /* Create submodel */
10861   PetscCall(DMPlexGetSubpointIS(*subdm, &subis));
10862   PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection));
10863   PetscCall(DMSetLocalSection(*subdm, subsection));
10864   PetscCall(PetscSectionDestroy(&subsection));
10865   PetscCall(DMCopyDisc(dm, *subdm));
10866   /* Create map from submodel to global model */
10867   if (is) {
10868     PetscSection    sectionGlobal, subsectionGlobal;
10869     IS              spIS;
10870     const PetscInt *spmap;
10871     PetscInt       *subIndices;
10872     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
10873     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
10874 
10875     PetscCall(DMPlexGetSubpointIS(*subdm, &spIS));
10876     PetscCall(ISGetIndices(spIS, &spmap));
10877     PetscCall(PetscSectionGetNumFields(section, &Nf));
10878     PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
10879     PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal));
10880     PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd));
10881     for (p = pStart; p < pEnd; ++p) {
10882       PetscInt gdof, pSubSize = 0;
10883 
10884       PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
10885       if (gdof > 0) {
10886         for (f = 0; f < Nf; ++f) {
10887           PetscInt fdof, fcdof;
10888 
10889           PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof));
10890           PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof));
10891           pSubSize += fdof - fcdof;
10892         }
10893         subSize += pSubSize;
10894         if (pSubSize) {
10895           if (bs < 0) {
10896             bs = pSubSize;
10897           } else if (bs != pSubSize) {
10898             /* Layout does not admit a pointwise block size */
10899             bs = 1;
10900           }
10901         }
10902       }
10903     }
10904     /* Must have same blocksize on all procs (some might have no points) */
10905     bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs;
10906     bsLocal[1] = bs;
10907     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
10908     if (bsMinMax[0] != bsMinMax[1]) {
10909       bs = 1;
10910     } else {
10911       bs = bsMinMax[0];
10912     }
10913     PetscCall(PetscMalloc1(subSize, &subIndices));
10914     for (p = pStart; p < pEnd; ++p) {
10915       PetscInt gdof, goff;
10916 
10917       PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof));
10918       if (gdof > 0) {
10919         const PetscInt point = spmap[p];
10920 
10921         PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff));
10922         for (f = 0; f < Nf; ++f) {
10923           PetscInt fdof, fcdof, fc, f2, poff = 0;
10924 
10925           /* Can get rid of this loop by storing field information in the global section */
10926           for (f2 = 0; f2 < f; ++f2) {
10927             PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof));
10928             PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof));
10929             poff += fdof - fcdof;
10930           }
10931           PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
10932           PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
10933           for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc;
10934         }
10935       }
10936     }
10937     PetscCall(ISRestoreIndices(spIS, &spmap));
10938     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is));
10939     if (bs > 1) {
10940       /* We need to check that the block size does not come from non-contiguous fields */
10941       PetscInt i, j, set = 1;
10942       for (i = 0; i < subSize; i += bs) {
10943         for (j = 0; j < bs; ++j) {
10944           if (subIndices[i + j] != subIndices[i] + j) {
10945             set = 0;
10946             break;
10947           }
10948         }
10949       }
10950       if (set) PetscCall(ISSetBlockSize(*is, bs));
10951     }
10952     // Attach nullspace
10953     if (dm->nullspaceConstructors) {
10954       for (f = 0; f < Nf; ++f) {
10955         (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
10956         if ((*subdm)->nullspaceConstructors[f]) break;
10957       }
10958       if (f < Nf) {
10959         MatNullSpace nullSpace;
10960         PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace));
10961 
10962         PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace));
10963         PetscCall(MatNullSpaceDestroy(&nullSpace));
10964       }
10965     }
10966   }
10967   PetscFunctionReturn(PETSC_SUCCESS);
10968 }
10969 
10970 /*@
10971   DMPlexMonitorThroughput - Report the cell throughput of FE integration
10972 
10973   Input Parameters:
10974 + dm     - The `DM`
10975 - unused - unused argument
10976 
10977   Options Database Key:
10978 . -dm_plex_monitor_throughput - Activate the monitor
10979 
10980   Level: developer
10981 
10982 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()`
10983 @*/
DMPlexMonitorThroughput(DM dm,void * unused)10984 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *unused)
10985 {
10986   PetscLogHandler default_handler;
10987 
10988   PetscFunctionBegin;
10989   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10990   PetscCall(PetscLogGetDefaultHandler(&default_handler));
10991   if (default_handler) {
10992     PetscLogEvent      event;
10993     PetscEventPerfInfo eventInfo;
10994     PetscLogDouble     cellRate, flopRate;
10995     PetscInt           cStart, cEnd, Nf, N;
10996     const char        *name;
10997 
10998     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
10999     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
11000     PetscCall(DMGetNumFields(dm, &Nf));
11001     PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event));
11002     PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo));
11003     N        = (cEnd - cStart) * Nf * eventInfo.count;
11004     flopRate = eventInfo.flops / eventInfo.time;
11005     cellRate = N / eventInfo.time;
11006     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DM (%s) FE Residual Integration: %" PetscInt_FMT " integrals %d reps\n  Cell rate: %.2g/s flop rate: %.2g MF/s\n", name ? name : "unknown", N, eventInfo.count, cellRate, flopRate / 1.e6));
11007   } else {
11008     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off or the default log handler is not running. Reconfigure using --with-log and run with -log_view.");
11009   }
11010   PetscFunctionReturn(PETSC_SUCCESS);
11011 }
11012