PetIBM 0.5.4
Toolbox and applications of the immersed-boundary method for distributed-memory architectures
createlaplacian.cpp
Go to the documentation of this file.
1
8// STL
9#include <map>
10#include <numeric>
11
12// here goes PETSc headers
13#include <petscmat.h>
14
15// here goes headers from our PetIBM
16#include <petibm/boundary.h>
17#include <petibm/mesh.h>
18#include <petibm/misc.h>
19#include <petibm/type.h>
20
21// private functions
22#include "../private/private.h"
23
24namespace // anonymous namespace for internal linkage
25{
26// a helper type definition for vector of MatStencil
27typedef std::vector<MatStencil> StencilVec;
28
29// a function type for functions returning neighbor stencils
30typedef std::function<StencilVec(const PetscInt &, const PetscInt &,
31 const PetscInt &)>
32 GetStencilsFunc;
33
34// a private struct for matrix-free constraint mat
35struct LagrangianCtx
36{
39
40 LagrangianCtx(const petibm::type::Boundary &_bc)
41 : bc(_bc), modifier(bc->dim){};
42};
43
44// a user-defined MatMult for constraint mat
45PetscErrorCode LCorrectionMult(Mat mat, Vec x, Vec y)
46{
47 PetscFunctionBeginUser;
48
49 PetscErrorCode ierr;
50
51 LagrangianCtx *ctx;
52
53 // get the context
54 ierr = MatShellGetContext(mat, (void *)&ctx); CHKERRQ(ierr);
55
56 // zero the output vector
57 ierr = VecSet(y, 0.0); CHKERRQ(ierr);
58
59 // set the correction values to corresponding rows
60 for (PetscInt f = 0; f < ctx->bc->dim; ++f)
61 for (auto &bd : ctx->bc->bds[f])
62 if (bd->onThisProc)
63 for (auto &pt : bd->points)
64 {
65 ierr = VecSetValue(
66 y, ctx->modifier[f][pt.first].row,
67 ctx->modifier[f][pt.first].coeff * pt.second.a1,
68 ADD_VALUES); CHKERRQ(ierr);
69 }
70
71 // assembly (not sure if this is necessary and if this causes overhead)
72 // but there is an implicit MPI barrier in assembly, which we definitely
73 // need
74 ierr = VecAssemblyBegin(y); CHKERRQ(ierr);
75 ierr = VecAssemblyEnd(y); CHKERRQ(ierr);
76
77 PetscFunctionReturn(0);
78} // LCorrectionMult
79
80// a user-defined MatDestroy for constraint mat
81PetscErrorCode LCorrectionDestroy(Mat mat)
82{
83 PetscFunctionBeginUser;
84
85 PetscErrorCode ierr;
86 LagrangianCtx *ctx;
87
88 // get the context
89 ierr = MatShellGetContext(mat, (void *)&ctx); CHKERRQ(ierr);
90
91 // deallocate the context
92 delete ctx;
93
94 PetscFunctionReturn(0);
95} // LCorrectionDestroy
96
97// a private function that sets values of a row in Laplacian.
98// mesh: an instance of CartesianMesh class.
99// bc: an instance of Boundary class.
100// getStencils: a function that returns stencils according to dim.
101// f: the index of field (u=0, v=1, z=2).
102// i: the x-index of current row in the Cartesian mesh.
103// j: the y-index of current row in the Cartesian mesh.
104// k: the z-index of current row in the Cartesian mesh.
105// L: the Laplacian matrix.
106// rowModifiers: an object holding information about where in a matrix should be
107// modified.
108inline PetscErrorCode setRowValues(
109 const petibm::type::Mesh &mesh, const petibm::type::Boundary &bc,
110 const GetStencilsFunc &getStencils, const PetscInt &f, const PetscInt &i,
111 const PetscInt &j, const PetscInt &k, Mat &L,
112 std::map<MatStencil, petibm::type::RowModifier> &rowModifiers)
113{
114 PetscFunctionBeginUser;
115
116 PetscErrorCode ierr;
117
118 StencilVec stencils = getStencils(i, j, k);
119
120 petibm::type::IntVec1D cols(1 + 2 * mesh->dim, -1);
121
122 petibm::type::RealVec1D values(1 + 2 * mesh->dim, 0.0);
123
124 // get the local index for points in stencils
125 for (unsigned int id = 0; id < stencils.size(); ++id)
126 {
127 ierr = mesh->getPackedGlobalIndex(f, stencils[id], cols[id]);
128 CHKERRQ(ierr);
129 }
130
131 // get the values. One direction each time.
132 // Luckily we have dL for ghost points, and the index of -1 is usable in dL,
133 // so we don't have to use "if" to find out the boundary points
134 for (PetscInt dir = 0; dir < mesh->dim; ++dir)
135 {
136 // determine the index based on the direction
137 const PetscInt &self = (dir == 0) ? i : (dir == 1) ? j : k;
138
139 // alias for cleaner code
140 const PetscReal &dLSelf = mesh->dL[f][dir][self];
141 const PetscReal &dLNeg =
142 mesh->coord[f][dir][self] - mesh->coord[f][dir][self - 1];
143 const PetscReal &dLPos =
144 mesh->coord[f][dir][self + 1] - mesh->coord[f][dir][self];
145
146 values[dir * 2 + 1] = 1.0 / (dLNeg * dLSelf);
147 values[dir * 2 + 2] = 1.0 / (dLPos * dLSelf);
148 }
149
150 // update diagonal value
151 values[0] = -std::accumulate(values.begin() + 1, values.end(), 0.0);
152
153 // set the coefficient for the left point
154 ierr = MatSetValues(L, 1, &cols[0], stencils.size(), cols.data(),
155 values.data(), INSERT_VALUES); CHKERRQ(ierr);
156
157 // save the values for boundary ghost points
158 for (unsigned int id = 0; id < stencils.size(); ++id)
159 if (cols[id] == -1) rowModifiers[stencils[id]] = {cols[0], values[id]};
160
161 PetscFunctionReturn(0);
162} // setRowValues
163} // end of anonymous namespace
164
165namespace petibm
166{
167namespace operators
168{
169// implementation of petibm::operators::createLaplacian
170PetscErrorCode createLaplacian(const type::Mesh &mesh, const type::Boundary &bc,
171 Mat &L, Mat &LCorrection)
172{
173 using namespace std::placeholders;
174
175 PetscFunctionBeginUser;
176
177 PetscErrorCode ierr;
178
179 GetStencilsFunc getStencils;
180
181 LagrangianCtx *ctx;
182
183 // initialize modifier, regardless what's inside it now
184 ctx = new LagrangianCtx(bc);
185
186 // set up getStencils
187 if (mesh->dim == 2)
188 getStencils = [](const PetscInt &i, const PetscInt &j,
189 const PetscInt &k) -> StencilVec {
190 return {{k, j, i, 0},
191 {k, j, i - 1, 0},
192 {k, j, i + 1, 0},
193 {k, j - 1, i, 0},
194 {k, j + 1, i, 0}};
195 };
196 else // implies dim == 3
197 getStencils = [](const PetscInt &i, const PetscInt &j,
198 const PetscInt &k) -> StencilVec {
199 return {{k, j, i, 0}, {k, j, i - 1, 0}, {k, j, i + 1, 0},
200 {k, j - 1, i, 0}, {k, j + 1, i, 0}, {k - 1, j, i, 0},
201 {k + 1, j, i, 0}};
202 };
203
204 // create matrix
205 ierr = DMCreateMatrix(mesh->UPack, &L); CHKERRQ(ierr);
206 ierr = MatSetFromOptions(L); CHKERRQ(ierr);
207 ierr = MatSetOption(L, MAT_KEEP_NONZERO_PATTERN, PETSC_FALSE);
208 CHKERRQ(ierr);
209 ierr = MatSetOption(L, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE); CHKERRQ(ierr);
210
211 // set values, one field each time
212 for (PetscInt field = 0; field < mesh->dim; ++field)
213 {
214 // set row values
215 // the std::bind originally only binds values, in order to use
216 // reference instead of value-copying, we have to use std::ref
217 ierr = misc::tripleLoops(
218 {mesh->bg[field][2], mesh->ed[field][2]},
219 {mesh->bg[field][1], mesh->ed[field][1]},
220 {mesh->bg[field][0], mesh->ed[field][0]},
221 std::bind(setRowValues, std::ref(mesh), std::ref(bc),
222 std::ref(getStencils), std::ref(field), _3, _2, _1,
223 std::ref(L), std::ref(ctx->modifier[field])));
224 CHKERRQ(ierr);
225 }
226
227 // temporarily assemble matrix
228 ierr = MatAssemblyBegin(L, MAT_FLUSH_ASSEMBLY); CHKERRQ(ierr);
229 ierr = MatAssemblyEnd(L, MAT_FLUSH_ASSEMBLY); CHKERRQ(ierr);
230
231 // TODO: check if a0 coefficients are already up-to-date.
232 for (PetscInt f = 0; f < mesh->dim; ++f)
233 for (auto &bd : bc->bds[f])
234 if (bd->onThisProc)
235 for (auto &pt : bd->points)
236 {
237 PetscInt col = pt.second.targetPackedId;
238 PetscReal value =
239 ctx->modifier[f][pt.first].coeff * pt.second.a0;
240
241 ierr = MatSetValue(L, ctx->modifier[f][pt.first].row, col,
242 value, ADD_VALUES); CHKERRQ(ierr);
243 }
244
245 // assemble matrix, an implicit MPI barrier is applied
246 ierr = MatAssemblyBegin(L, MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
247 ierr = MatAssemblyEnd(L, MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
248
249 // create a matrix-free constraint matrix for boundary correction
250 ierr = MatCreateShell(mesh->comm, mesh->UNLocal, mesh->UNLocal,
251 PETSC_DETERMINE, PETSC_DETERMINE, (void *)ctx,
252 &LCorrection); CHKERRQ(ierr);
253
254 ierr = MatShellSetOperation(LCorrection, MATOP_MULT,
255 (void (*)(void))LCorrectionMult);
256 CHKERRQ(ierr);
257
258 ierr = MatShellSetOperation(LCorrection, MATOP_DESTROY,
259 (void (*)(void))LCorrectionDestroy);
260 CHKERRQ(ierr);
261
262 PetscFunctionReturn(0);
263} // createLaplacian
264
265} // end of namespace operators
266} // end of namespace petibm
boundary::BoundaryBase, type::Boundary, and factory function.
std::shared_ptr< boundary::BoundaryBase > Boundary
Type definition of petibm::type::Boundary.
Definition: boundary.h:175
std::shared_ptr< mesh::MeshBase > Mesh
Type definition of Mesh.
Definition: mesh.h:348
PetscErrorCode tripleLoops(const LoopBound &bound1, const LoopBound &bound2, const LoopBound &bound3, const std::function< PetscErrorCode(const PetscInt &, const PetscInt &, const PetscInt &)> &f)
A helper function to carry out a triple loop on a given function.
Definition: misc.h:211
PetscErrorCode createLaplacian(const type::Mesh &mesh, const type::Boundary &bc, Mat &L, Mat &LCorrection)
Create a Laplacian operator, , and boundary correction, for velocity fields.
std::vector< std::map< MatStencil, RowModifier > > MatrixModifier
A type that holds necessary info for a matrix modifier that modifies matrix coefficient based on BCs.
Definition: type.h:195
std::vector< PetscInt > IntVec1D
1D std::vector holding PetscInt.
Definition: type.h:133
std::vector< PetscReal > RealVec1D
1D std::vector holding PetscReal.
Definition: type.h:140
Prototype of mesh::MeshBase, type::Mesh, and factory function.
Prototypes of some miscellaneous functions.
std::vector< MatStencil > StencilVec
STL vector holding MatStencil.
A toolbox for building flow solvers.
Definition: bodypack.h:52
Definition of user-defined types for convenience.