Mimetic Operators Library Enhanced 4.0
Loading...
Searching...
No Matches
addscalarbc.cpp
Go to the documentation of this file.
1/*
2 * SPDX-License-Identifier: GPL-3.0-or-later
3 * 2008-2024 San Diego State University Research Foundation (SDSURF).
4 * See LICENSE file or https://www.gnu.org/licenses/gpl-3.0.html for details.
5 */
6
15
16#include "addscalarbc.h"
17
18namespace AddScalarBC {
19
20// ============================================================================
21// Internal Helpers
22// ============================================================================
23
24namespace {
25
31Real boundaryNorm(const vec &dc, const vec &nc, uword i, uword j) {
32 return dc(i)*dc(i) + dc(j)*dc(j) + nc(i)*nc(i) + nc(j)*nc(j);
33}
34
38uvec collectUniqueRows(const sp_mat &M) {
39 uvec temp(M.n_nonzero);
40 uword count = 0;
41 for (sp_mat::const_iterator it = M.begin(); it != M.end(); ++it) {
42 temp(count++) = it.row();
43 }
44 temp.resize(count);
45 return unique(temp);
46}
47
53void zeroRows(sp_mat &A, const uvec &rows) {
54 for (uword i = 0; i < rows.n_elem; i++) {
55 uword row_idx = rows(i);
56 for (sp_mat::const_row_iterator it = A.begin_row(row_idx);
57 it != A.end_row(row_idx); ++it) {
58 A(it.row(), it.col()) = 0;
59 }
60 }
61}
62
66void applyBCMatrix(sp_mat &A, vec &b, const sp_mat &Abc, uvec &rows) {
67 rows = collectUniqueRows(Abc);
68 zeroRows(A, rows);
69 A = A + Abc;
70 b(rows).zeros();
71}
72
76void applyRhsSide(vec &b, const uvec &indices, const vec &values) {
77 for (uword i = 0; i < indices.n_elem && i < values.n_elem; i++) {
78 b(indices(i)) = values(i);
79 }
80}
81
86sp_mat buildIdentity(uword sz, bool zeroCorners = false) {
87 sp_mat I = speye<sp_mat>(sz, sz);
88 if (zeroCorners && sz >= 2) {
89 I(0, 0) = 0;
90 I(sz-1, sz-1) = 0;
91 }
92 return I;
93}
94
98struct BCPairLhs {
99 Real q; // boundaryNorm result; skip if == 0
100 sp_mat &Mleft; // BC matrix for the left/bottom/front face
101 sp_mat &Mright; // BC matrix for the right/top/back face
102 uvec &rowsL; // output: row indices for left/bottom/front face
103 uvec &rowsR; // output: row indices for right/top/back face
104};
105
109void applyBCPair(sp_mat &A, vec &b, BCPairLhs &p) {
110 if (p.q == 0) return;
111 uvec rows;
112 applyBCMatrix(A, b, p.Mleft + p.Mright, rows);
113 p.rowsL = collectUniqueRows(p.Mleft);
114 p.rowsR = collectUniqueRows(p.Mright);
115}
116
120struct BCPairRhs {
121 uword i, j; // dc/nc indices for boundaryNorm check
122 const uvec &rowsL; // row indices for the left/bottom/front face
123 const uvec &rowsR; // row indices for the right/top/back face
124 uword vL, vR; // indices into the boundary value vector v[]
125};
126
131void applyBCPairRhs(vec &b, const vec &dc, const vec &nc,
132 const std::vector<vec> &v, const BCPairRhs &p) {
133 if (boundaryNorm(dc, nc, p.i, p.j) == 0) return;
134 if (v.size() <= p.vR) return;
135 if (v[p.vL].n_elem > 0) applyRhsSide(b, p.rowsL, v[p.vL]);
136 if (v[p.vR].n_elem > 0) applyRhsSide(b, p.rowsR, v[p.vR]);
137}
138
139} // anonymous namespace
140
141// ============================================================================
142// LHS: Boundary matrix construction (1D, 2D, 3D overloads)
143// ============================================================================
144
145void addScalarBClhs(u16 k, u32 m, Real dx,
146 const vec &dc, const vec &nc,
147 sp_mat &Al, sp_mat &Ar) {
148 Al = sp_mat(m+2, m+2);
149 Ar = sp_mat(m+2, m+2);
150
151 if (dc(0) != 0.0) Al(0, 0) = dc(0);
152 if (dc(1) != 0.0) Ar(m+1, m+1) = dc(1);
153
154 if (nc(0) != 0.0 || nc(1) != 0.0) {
155 Gradient G(k, m, dx);
156 sp_mat G_mat = sp_mat(G);
157
158 if (nc(0) != 0.0) {
159 sp_mat Bl(m+2, m+1);
160 Bl(0, 0) = -nc(0);
161 Al = Al + Bl * G_mat;
162 }
163 if (nc(1) != 0.0) {
164 sp_mat Br(m+2, m+1);
165 Br(m+1, m) = nc(1);
166 Ar = Ar + Br * G_mat;
167 }
168 }
169}
170
171void addScalarBClhs(u16 k, u32 m, Real dx, u32 n, Real dy,
172 const vec &dc, const vec &nc,
173 sp_mat &Al, sp_mat &Ar, sp_mat &Ab, sp_mat &At) {
174 Al.set_size(0, 0); Ar.set_size(0, 0);
175 Ab.set_size(0, 0); At.set_size(0, 0);
176
177 Real qrl = boundaryNorm(dc, nc, 0, 1);
178 Real qbt = boundaryNorm(dc, nc, 2, 3);
179
180 if (qrl > 0) {
181 sp_mat Al0, Ar0;
182 addScalarBClhs(k, m, dx, {dc(0), dc(1)}, {nc(0), nc(1)}, Al0, Ar0);
183
184 sp_mat In = (qbt == 0) ? buildIdentity(n)
185 : buildIdentity(n+2, /*zeroCorners=*/true);
186 Al = kron(In, Al0);
187 Ar = kron(In, Ar0);
188 }
189
190 if (qbt > 0) {
191 sp_mat Ab0, At0;
192 addScalarBClhs(k, n, dy, {dc(2), dc(3)}, {nc(2), nc(3)}, Ab0, At0);
193
194 sp_mat Im = (qrl == 0) ? buildIdentity(m)
195 : buildIdentity(m+2);
196 Ab = kron(Ab0, Im);
197 At = kron(At0, Im);
198 }
199}
200
201void addScalarBClhs(u16 k, u32 m, Real dx, u32 n, Real dy, u32 o, Real dz,
202 const vec &dc, const vec &nc,
203 sp_mat &Al, sp_mat &Ar, sp_mat &Ab,
204 sp_mat &At, sp_mat &Af, sp_mat &Ak) {
205 Al.set_size(0,0); Ar.set_size(0,0);
206 Ab.set_size(0,0); At.set_size(0,0);
207 Af.set_size(0,0); Ak.set_size(0,0);
208
209 Real qrl = boundaryNorm(dc, nc, 0, 1);
210 Real qbt = boundaryNorm(dc, nc, 2, 3);
211 Real qfk = boundaryNorm(dc, nc, 4, 5);
212
213 auto makeId = [](u32 sz, Real q, bool excludeCorners) -> sp_mat {
214 return (q == 0) ? buildIdentity(sz)
215 : buildIdentity(sz + 2, excludeCorners);
216 };
217
218 if (qrl > 0) {
219 sp_mat Al0, Ar0;
220 addScalarBClhs(k, m, dx, {dc(0), dc(1)}, {nc(0), nc(1)}, Al0, Ar0);
221
222 sp_mat In = makeId(n, qbt, /*excludeCorners=*/true);
223 sp_mat Io = makeId(o, qfk, /*excludeCorners=*/true);
224 Al = kron(kron(Io, In), Al0);
225 Ar = kron(kron(Io, In), Ar0);
226 }
227
228 if (qbt > 0) {
229 sp_mat Ab0, At0;
230 addScalarBClhs(k, n, dy, {dc(2), dc(3)}, {nc(2), nc(3)}, Ab0, At0);
231
232 sp_mat Im = makeId(m, qrl, /*excludeCorners=*/false);
233 sp_mat Io = makeId(o, qfk, /*excludeCorners=*/true);
234 Ab = kron(kron(Io, Ab0), Im);
235 At = kron(kron(Io, At0), Im);
236 }
237
238 if (qfk > 0) {
239 sp_mat Af0, Ak0;
240 addScalarBClhs(k, o, dz, {dc(4), dc(5)}, {nc(4), nc(5)}, Af0, Ak0);
241
242 sp_mat Im = makeId(m, qrl, /*excludeCorners=*/false);
243 sp_mat In = makeId(n, qbt, /*excludeCorners=*/false);
244 Af = kron(kron(Af0, In), Im);
245 Ak = kron(kron(Ak0, In), Im);
246 }
247}
248
249// ============================================================================
250// RHS: Boundary value application (1D, 2D, 3D overloads)
251// ============================================================================
252
253void addScalarBCrhs(vec &b, const vec &v, const uvec &indices) {
254 for (uword i = 0; i < indices.n_elem; i++) {
255 b(indices(i)) = v(i);
256 }
257}
258
259void addScalarBCrhs(vec &b, const vec &dc, const vec &nc,
260 const std::vector<vec> &v,
261 const uvec &rl, const uvec &rr,
262 const uvec &rb, const uvec &rt) {
263 const BCPairRhs pairs[] = {
264 {0, 1, rl, rr, 0, 1}, // Left / Right
265 {2, 3, rb, rt, 2, 3}, // Bottom / Top
266 };
267 for (const auto &p : pairs) applyBCPairRhs(b, dc, nc, v, p);
268}
269
270void addScalarBCrhs(vec &b, const vec &dc, const vec &nc,
271 const std::vector<vec> &v,
272 const uvec &rl, const uvec &rr, const uvec &rb,
273 const uvec &rt, const uvec &rf, const uvec &rk) {
274 const BCPairRhs pairs[] = {
275 {0, 1, rl, rr, 0, 1}, // Left / Right
276 {2, 3, rb, rt, 2, 3}, // Bottom / Top
277 {4, 5, rf, rk, 4, 5}, // Front / Back
278 };
279 for (const auto &p : pairs) applyBCPairRhs(b, dc, nc, v, p);
280}
281
282// ============================================================================
283// Top-level BC application (1D, 2D, 3D overloads)
284// ============================================================================
285
286void addScalarBC(sp_mat &A, vec &b, u16 k, u32 m, Real dx, const BC1D &bc) {
287 assert(bc.dc.n_elem == 2 && "dc must be a 2x1 vector");
288 assert(bc.nc.n_elem == 2 && "nc must be a 2x1 vector");
289 assert(A.n_rows == A.n_cols && "A must be square");
290 assert(A.n_cols == b.n_elem && "b size must equal A columns");
291
292 if (boundaryNorm(bc.dc, bc.nc, 0, 1) == 0.0) return;
293
294 assert(bc.v.n_elem == 2 && "v must be a 2x1 vector");
295
296 uvec indices = {0, (uword)(A.n_rows - 1)};
297 zeroRows(A, indices);
298 b(indices).zeros();
299
300 sp_mat Al, Ar;
301 addScalarBClhs(k, m, dx, bc.dc, bc.nc, Al, Ar);
302 A = A + Al + Ar;
303
304 addScalarBCrhs(b, bc.v, indices);
305}
306
307void addScalarBC(sp_mat &A, vec &b, u16 k, u32 m, Real dx,
308 u32 n, Real dy, const BC2D &bc) {
309 assert(bc.dc.n_elem == 4 && "dc must be a 4x1 vector");
310 assert(bc.nc.n_elem == 4 && "nc must be a 4x1 vector");
311 assert(bc.v.size() == 4 && "v must have 4 vectors");
312 assert(A.n_rows == A.n_cols && "A must be square");
313 assert(A.n_cols == b.n_elem && "b size must equal A columns");
314
315 sp_mat Al, Ar, Ab, At;
316 addScalarBClhs(k, m, dx, n, dy, bc.dc, bc.nc, Al, Ar, Ab, At);
317
318 uvec rl, rr, rb, rt;
319
320 BCPairLhs pairs[] = {
321 {boundaryNorm(bc.dc, bc.nc, 0, 1), Al, Ar, rl, rr}, // Left / Right
322 {boundaryNorm(bc.dc, bc.nc, 2, 3), Ab, At, rb, rt}, // Bottom / Top
323 };
324 for (auto &p : pairs) applyBCPair(A, b, p);
325
326 addScalarBCrhs(b, bc.dc, bc.nc, bc.v, rl, rr, rb, rt);
327}
328
329void addScalarBC(sp_mat &A, vec &b, u16 k, u32 m, Real dx,
330 u32 n, Real dy, u32 o, Real dz, const BC3D &bc) {
331 assert(bc.dc.n_elem == 6 && "dc must be a 6x1 vector");
332 assert(bc.nc.n_elem == 6 && "nc must be a 6x1 vector");
333 assert(bc.v.size() == 6 && "v must have 6 vectors");
334 assert(A.n_rows == A.n_cols && "A must be square");
335 assert(A.n_cols == b.n_elem && "b size must equal A columns");
336
337 sp_mat Al, Ar, Ab, At, Af, Ak;
338 addScalarBClhs(k, m, dx, n, dy, o, dz, bc.dc, bc.nc,
339 Al, Ar, Ab, At, Af, Ak);
340
341 uvec rl, rr, rb, rt, rf, rk;
342
343 BCPairLhs pairs[] = {
344 {boundaryNorm(bc.dc, bc.nc, 0, 1), Al, Ar, rl, rr}, // Left / Right
345 {boundaryNorm(bc.dc, bc.nc, 2, 3), Ab, At, rb, rt}, // Bottom / Top
346 {boundaryNorm(bc.dc, bc.nc, 4, 5), Af, Ak, rf, rk}, // Front / Back
347 };
348 for (auto &p : pairs) applyBCPair(A, b, p);
349
350 addScalarBCrhs(b, bc.dc, bc.nc, bc.v, rl, rr, rb, rt, rf, rk);
351}
352
353} // namespace AddScalarBC
Boundary Condition Application for Scalar PDEs.
Mimetic Gradient operator.
Definition gradient.h:27
void addScalarBC(sp_mat &A, vec &b, u16 k, u32 m, Real dx, const BC1D &bc)
Apply boundary conditions to a 1D discrete operator and RHS.
void addScalarBCrhs(vec &b, const vec &v, const uvec &indices)
Apply boundary values to the RHS vector for a 1D problem.
void addScalarBClhs(u16 k, u32 m, Real dx, const vec &dc, const vec &nc, sp_mat &Al, sp_mat &Ar)
Compute LHS boundary condition matrices for a 1D problem.
Structure to hold boundary condition data for 1D problems.
Definition addscalarbc.h:42
Structure to hold boundary condition data for 2D problems.
Definition addscalarbc.h:55
std::vector< vec > v
Definition addscalarbc.h:58
Structure to hold boundary condition data for 3D problems.
Definition addscalarbc.h:68
std::vector< vec > v
Definition addscalarbc.h:71
double Real
Definition utils.h:21