Skip to main content

caustic/tooling/core/time/
lie.rs

1//! Lie (first-order) splitting: drift(Δt) → kick(Δt). Only 1st-order accurate.
2//! Use only for testing and comparison.
3
4use super::super::{
5    advecator::Advector, integrator::TimeIntegrator, phasespace::PhaseSpaceRepr,
6    solver::PoissonSolver, types::*,
7};
8
9/// Lie (1st-order) operator splitting: drift(Δt) → kick(Δt).
10pub struct LieSplitting {
11    pub g: f64,
12}
13
14impl LieSplitting {
15    pub fn new(g: f64) -> Self {
16        Self { g }
17    }
18}
19
20impl TimeIntegrator for LieSplitting {
21    fn advance(
22        &mut self,
23        repr: &mut dyn PhaseSpaceRepr,
24        solver: &dyn PoissonSolver,
25        advector: &dyn Advector,
26        dt: f64,
27    ) {
28        let _span = tracing::info_span!("lie_advance").entered();
29
30        // 1. Drift full step
31        advector.drift(repr, dt);
32
33        // 2. Compute density → Poisson → acceleration → kick full step
34        let density = repr.compute_density();
35        let potential = solver.solve(&density, self.g);
36        let accel = solver.compute_acceleration(&potential);
37        advector.kick(repr, &accel, dt);
38    }
39
40    fn max_dt(&self, repr: &dyn PhaseSpaceRepr, cfl_factor: f64) -> f64 {
41        let density = repr.compute_density();
42        let rho_max = density.data.iter().cloned().fold(0.0_f64, f64::max);
43        if rho_max <= 0.0 || self.g <= 0.0 {
44            return 1e10;
45        }
46        let t_dyn = 1.0 / (self.g * rho_max).sqrt();
47        cfl_factor * t_dyn
48    }
49}