numerics
Loading...
Searching...
No Matches
adi.hpp
Go to the documentation of this file.
1/// @file pde/adi.hpp
2/// @brief Crank-Nicolson ADI solver for 2D parabolic equations via fiber sweeps.
3///
4/// CrankNicolsonADI encapsulates the prefactored complex tridiagonals for
5/// Strang-split time stepping of equations of the form:
6///
7/// i ∂ψ/∂t = -(1/2) ∆ψ + V(x,y) ψ (Schrödinger)
8/// ∂u/∂t = κ ∆u (complex-coefficient diffusion)
9///
10/// Each CN sub-step τ along one axis solves a 1D system per fiber:
11///
12/// (I - ia·Lap₁D) ψⁿ⁺¹ = (I + ia·Lap₁D) ψⁿ, ia = i·τ/(4h²)
13///
14/// Two tridiagonals are prefactored once — for τ = dt/2 and τ = dt —
15/// covering the full Strang splitting: sweep_x(dt/2) → sweep_y(dt) → sweep_x(dt/2).
16///
17/// Typical usage (TDSE Strang splitting):
18/// @code
19/// num::CrankNicolsonADI adi(N, dt, h);
20///
21/// // one full time step:
22/// adi.sweep(psi, true, dt * 0.5); // x, half-step
23/// adi.sweep(psi, false, dt); // y, full-step
24/// adi.sweep(psi, true, dt * 0.5); // x, half-step
25/// @endcode
26#pragma once
27
28#include "pde/stencil.hpp"
30#include "core/vector.hpp"
31#include <vector>
32#include <complex>
33
34namespace num {
35
37 int N = 0;
38 double dt = 0.0;
39 double h = 0.0;
40
41 CrankNicolsonADI() = default;
42
43 /// Pre-factor both tridiagonals.
44 /// @param N_ Interior grid points per axis
45 /// @param dt_ Full timestep
46 /// @param h_ Grid spacing
47 CrankNicolsonADI(int N_, double dt_, double h_)
48 : N(N_), dt(dt_), h(h_)
49 {
50 using cplx = std::complex<double>;
51 // alpha = tau/(4h²). LHS tridiagonal: a=c=-i*alpha, b=1+2i*alpha.
52 auto factor = [&](double tau) {
53 double alpha = tau / (4.0 * h * h);
54 cplx a(0.0, -alpha);
55 cplx b(1.0, 2.0 * alpha);
57 td.factor(N, a, b, a);
58 return td;
59 };
60 td_half_ = factor(dt * 0.5);
61 td_full_ = factor(dt);
62 }
63
64 /// Apply one CN sweep along x (col fibers, x_axis=true) or y (row fibers).
65 /// Selects the half-step tridiagonal for tau < 0.75*dt, full-step otherwise.
66 void sweep(CVector& psi, bool x_axis, double tau) const {
67 using cplx = std::complex<double>;
68 const ComplexTriDiag& td = (tau < dt * 0.75) ? td_half_ : td_full_;
69 const cplx ia(0.0, tau / (4.0 * h * h));
70 const cplx diag(1.0, -2.0 * tau / (4.0 * h * h));
71
72 auto apply = [&](std::vector<cplx>& fiber) {
73 std::vector<cplx> rhs(N);
74 for (int i = 0; i < N; ++i) {
75 cplx prev = (i > 0) ? fiber[i-1] : cplx{};
76 cplx next = (i < N-1) ? fiber[i+1] : cplx{};
77 rhs[i] = ia * prev + diag * fiber[i] + ia * next;
78 }
79 td.solve(rhs);
80 fiber = std::move(rhs);
81 };
82
83 if (x_axis) col_fiber_sweep(psi, N, apply);
84 else row_fiber_sweep(psi, N, apply);
85 }
86
87private:
88 ComplexTriDiag td_half_;
89 ComplexTriDiag td_full_;
90};
91
92} // namespace num
Dense vector with optional GPU storage, templated over scalar type T.
Definition vector.hpp:23
void row_fiber_sweep(BasicVector< T > &data, int N, F &&f)
Definition stencil.hpp:91
constexpr T ipow(T x) noexcept
Compute x^N at compile time via repeated squaring.
std::complex< real > cplx
Definition types.hpp:12
void col_fiber_sweep(BasicVector< T > &data, int N, F &&f)
Definition stencil.hpp:77
Higher-order stencil and grid-sweep utilities.
Constant-coefficient complex tridiagonal solver (precomputed LU).
void factor(int n_, cplx a_, cplx b_, cplx c_)
Factor the tridiagonal matrix.
CrankNicolsonADI(int N_, double dt_, double h_)
Definition adi.hpp:47
CrankNicolsonADI()=default
void sweep(CVector &psi, bool x_axis, double tau) const
Definition adi.hpp:66
Precomputed LU Thomas solver for constant-coefficient complex tridiagonal systems.
Vector operations.