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, §ion));
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, °ree, 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, §iondm);
2311 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2312 PetscSectionCreate(PETSC_COMM_WORLD, §ion);
2313 DMPlexGetChart(sectiondm, &pStart, &pEnd);
2314 PetscSectionSetChart(section, pStart, pEnd);
2315 PetscSectionSetUp(section);
2316 DMSetLocalSection(sectiondm, section);
2317 PetscSectionDestroy(§ion);
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(§iondm);
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, §ion));
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, §iondm);
2388 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2389 PetscSectionCreate(PETSC_COMM_WORLD, §ion);
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(§iondm);
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, §ion));
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, §iondm);
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(§iondm);
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, §ion));
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, §iondm);
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(§iondm);
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, §ion));
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, §ionLocal));
2903 PetscCall(DMGetGlobalSection(dm, §ionGlobal));
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, <og));
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, §ion));
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_, §ions_));
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, §ions_[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(§ions_[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), §ion));
5739 PetscCall(DMSetLocalSection(*cdm, section));
5740 PetscCall(PetscSectionDestroy(§ion));
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), §ion));
5762 PetscCall(DMSetLocalSection(*cdm, section));
5763 PetscCall(PetscSectionDestroy(§ion));
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, §ion));
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, §ion));
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, §ion));
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, §ion));
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, §ion));
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, §ion));
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, §ionRow));
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, §ionCol));
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), §ion));
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(§ion));
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, §ion));
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, <og));
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(<og));
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, §ion));
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, ®ular));
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, ®ular));
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, ®ular));
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, §ion));
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, §ion));
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, §ionGlobal));
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