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