numerics 0.1.0
Loading...
Searching...
No Matches
diffusion.hpp
Go to the documentation of this file.
1/// @file pde/diffusion.hpp
2/// @brief Diffusion operators and implicit system builders for 2D grids.
3///
4/// Explicit Euler stencil steps (periodic or Dirichlet BCs):
5/// diffusion_step_2d -- periodic
6/// diffusion_step_2d_dirichlet -- Dirichlet, 2nd-order
7/// diffusion_step_2d_4th_dirichlet -- Dirichlet, 4th-order
8///
9/// Implicit system builders (backward Euler):
10/// laplacian_sparse_2d -- bare N^2 x N^2 Laplacian matrix
11/// backward_euler_matrix -- A = I - coeff*L (sparse, SPD)
12///
13/// Solver factory:
14/// make_cg_solver(A) -- returns a LinearSolver using matrix-free CG
15///
16/// Time integration lives in ode/implicit.hpp: num::ode::advance(u, solver, p).
17#pragma once
18
19#include "pde/stencil.hpp"
20#include "core/vector.hpp"
21#include "core/policy.hpp"
22#include "fields/grid2d.hpp"
24#include "linalg/solvers/cg.hpp"
26
27namespace num::pde {
28
29/// Explicit Euler diffusion step on a periodic 2D grid:
30/// u += coeff * Lap_periodic(u)
31inline void diffusion_step_2d(Vector& u, int N, double coeff,
33 Vector lap(u.size());
35 axpy(coeff, lap, u, b);
36}
37
38/// Explicit Euler diffusion step with Dirichlet (zero) BCs:
39/// u += coeff * Lap_dirichlet(u)
40inline void diffusion_step_2d_dirichlet(Vector& u, int N, double coeff,
42 Vector lap(u.size());
43 laplacian_stencil_2d(u, lap, N);
44 axpy(coeff, lap, u, b);
45}
46
47/// Explicit Euler diffusion step with Dirichlet BCs and 4th-order Laplacian.
48/// Stability requires coeff <= ~0.08 (vs 0.25 for 2nd order).
49inline void diffusion_step_2d_4th_dirichlet(Vector& u, int N, double coeff,
51 Vector lap(u.size());
52 laplacian_stencil_2d_4th(u, lap, N);
53 axpy(coeff, lap, u, b);
54}
55
56// ScalarField2D overloads
57
58inline void diffusion_step_2d_dirichlet(ScalarField2D& g, double coeff,
60 diffusion_step_2d_dirichlet(g.vec(), g.N(), coeff, b);
61}
62
65 diffusion_step_2d_4th_dirichlet(g.vec(), g.N(), coeff, b);
66}
67
68/// Build the N^2 x N^2 sparse 5-point Laplacian matrix (Dirichlet BCs).
69/// Entry (k,k) = -4, off-diagonals = +1 for each interior neighbor.
71 const int n = N * N;
72 std::vector<idx> rows, cols;
73 std::vector<real> vals;
74 rows.reserve(5 * n); cols.reserve(5 * n); vals.reserve(5 * n);
75 for (int i = 0; i < N; ++i) {
76 for (int j = 0; j < N; ++j) {
77 int k = i * N + j;
78 rows.push_back(k); cols.push_back(k); vals.push_back(-4.0);
79 if (i > 0) { rows.push_back(k); cols.push_back((i-1)*N+j); vals.push_back(1.0); }
80 if (i < N-1) { rows.push_back(k); cols.push_back((i+1)*N+j); vals.push_back(1.0); }
81 if (j > 0) { rows.push_back(k); cols.push_back(i*N+(j-1)); vals.push_back(1.0); }
82 if (j < N-1) { rows.push_back(k); cols.push_back(i*N+(j+1)); vals.push_back(1.0); }
83 }
84 }
85 return SparseMatrix::from_triplets(n, n, rows, cols, vals);
86}
87
88/// Build the backward Euler system matrix A = I - coeff*L.
89/// Solve A * u^{n+1} = u^n at each time step.
90inline SparseMatrix backward_euler_matrix(int N, double coeff) {
91 const int n = N * N;
92 std::vector<idx> rows, cols;
93 std::vector<real> vals;
94 rows.reserve(5 * n); cols.reserve(5 * n); vals.reserve(5 * n);
95 for (int i = 0; i < N; ++i) {
96 for (int j = 0; j < N; ++j) {
97 int k = i * N + j;
98 rows.push_back(k); cols.push_back(k); vals.push_back(1.0 + 4.0 * coeff);
99 if (i > 0) { rows.push_back(k); cols.push_back((i-1)*N+j); vals.push_back(-coeff); }
100 if (i < N-1) { rows.push_back(k); cols.push_back((i+1)*N+j); vals.push_back(-coeff); }
101 if (j > 0) { rows.push_back(k); cols.push_back(i*N+(j-1)); vals.push_back(-coeff); }
102 if (j < N-1) { rows.push_back(k); cols.push_back(i*N+(j+1)); vals.push_back(-coeff); }
103 }
104 }
105 return SparseMatrix::from_triplets(n, n, rows, cols, vals);
106}
107
108/// Grid2D overload -- N is read from the grid.
109inline SparseMatrix backward_euler_matrix(const Grid2D& grid, double coeff) {
110 return backward_euler_matrix(grid.N, coeff);
111}
112
113/// Returns a LinearSolver that solves A*x = rhs using matrix-free CG.
114/// Captures A by reference -- A must outlive the returned callable.
115inline LinearSolver make_cg_solver(const SparseMatrix& A, real tol = 1e-6) {
116 return [&A, tol](const Vector& rhs, Vector& x) {
117 auto matvec = [&A](const Vector& v, Vector& w) { sparse_matvec(A, v, w); };
118 return cg_matfree(matvec, rhs, x, tol);
119 };
120}
121
122} // namespace num::pde
123
124// Lift make_cg_solver into num:: so callers can write num::make_cg_solver(A).
125namespace num {
127}
Conjugate gradient solvers (dense and matrix-free)
constexpr idx size() const noexcept
Definition vector.hpp:80
Vector & vec()
Satisfy VecField concept: exposes the underlying flat vector.
Sparse matrix in Compressed Sparse Row (CSR) format.
Definition sparse.hpp:15
static SparseMatrix from_triplets(idx n_rows, idx n_cols, const std::vector< idx > &rows, const std::vector< idx > &cols, const std::vector< real > &vals)
Build from coordinate (COO / triplet) lists.
Definition sparse.cpp:26
Backend enum for linear algebra operations.
2D uniform interior grid: geometry only, no field data.
Universal linear solver callable type.
SparseMatrix laplacian_sparse_2d(int N)
Definition diffusion.hpp:70
void diffusion_step_2d_4th_dirichlet(Vector &u, int N, double coeff, Backend b=best_backend)
Definition diffusion.hpp:49
void diffusion_step_2d_dirichlet(Vector &u, int N, double coeff, Backend b=best_backend)
Definition diffusion.hpp:40
void diffusion_step_2d(Vector &u, int N, double coeff, Backend b=best_backend)
Definition diffusion.hpp:31
SparseMatrix backward_euler_matrix(int N, double coeff)
Definition diffusion.hpp:90
LinearSolver make_cg_solver(const SparseMatrix &A, real tol=1e-6)
void laplacian_stencil_2d(const BasicVector< T > &x, BasicVector< T > &y, int N)
Definition stencil.hpp:35
double real
Definition types.hpp:10
Backend
Selects which backend handles a linalg operation.
Definition policy.hpp:19
std::function< SolverResult(const Vector &rhs, Vector &x)> LinearSolver
constexpr Backend best_backend
Definition policy.hpp:105
void laplacian_stencil_2d_4th(const BasicVector< T > &x, BasicVector< T > &y, int N)
Definition stencil.hpp:95
void matvec(const Matrix &A, const Vector &x, Vector &y, Backend b=default_backend)
y = A * x
Definition matrix.cpp:120
void sparse_matvec(const SparseMatrix &A, const Vector &x, Vector &y)
y = A * x
Definition sparse.cpp:124
void laplacian_stencil_2d_periodic(const BasicVector< T > &x, BasicVector< T > &y, int N)
Definition stencil.hpp:59
constexpr real e
Definition math.hpp:43
void axpy(real alpha, const Vector &x, Vector &y, Backend b=default_backend)
y += alpha * x
Definition vector.cpp:58
SolverResult cg_matfree(MatVecFn matvec, const Vector &b, Vector &x, real tol=1e-6, idx max_iter=1000)
Matrix-free conjugate gradient for Ax = b where A is SPD.
Definition cg.cpp:78
Compressed Sparse Row (CSR) matrix and operations.
Higher-order stencil and grid-sweep utilities.
int N
interior nodes per side
Definition grid2d.hpp:14
Vector operations.