use std::sync::Arc;
use std::time::Instant;
use super::super::{
advecator::Advector,
integrator::{StepProducts, StepTimings, TimeIntegrator},
phasespace::PhaseSpaceRepr,
progress::{StepPhase, StepProgress},
solver::PoissonSolver,
types::*,
};
use super::helpers;
use crate::CausticError;
pub struct LawsonRkIntegrator {
pub g: f64,
last_timings: StepTimings,
progress: Option<Arc<StepProgress>>,
}
impl LawsonRkIntegrator {
pub fn new(g: f64) -> Self {
Self {
g,
last_timings: StepTimings::default(),
progress: None,
}
}
fn compute_accel(
repr: &dyn PhaseSpaceRepr,
solver: &dyn PoissonSolver,
g: f64,
) -> AccelerationField {
let (_density, _potential, accel) = helpers::solve_poisson(repr, solver, g);
accel
}
}
impl TimeIntegrator for LawsonRkIntegrator {
fn advance(
&mut self,
repr: &mut dyn PhaseSpaceRepr,
solver: &dyn PoissonSolver,
advector: &dyn Advector,
dt: f64,
) -> Result<StepProducts, CausticError> {
let _span = tracing::info_span!("lawson_rk_advance").entered();
let mut timings = StepTimings::default();
if let Some(ref p) = self.progress {
p.start_step();
}
helpers::report_phase!(self.progress, StepPhase::DriftHalf1, 0, 7);
helpers::time_ms!(timings, drift_ms, advector.drift(repr, dt / 2.0));
let snap_after_drift = repr.to_snapshot(0.0).ok_or_else(|| {
CausticError::Solver("Lawson-RK integrator requires to_snapshot support".into())
})?;
helpers::report_phase!(self.progress, StepPhase::PoissonSolve, 1, 7);
let a1 = helpers::time_ms!(
timings,
poisson_ms,
Self::compute_accel(repr, solver, self.g)
);
helpers::report_phase!(self.progress, StepPhase::PoissonSolve, 2, 7);
let a2 = helpers::time_ms!(timings, poisson_ms, {
advector.kick(repr, &a1, dt / 2.0);
Self::compute_accel(repr, solver, self.g)
});
helpers::report_phase!(self.progress, StepPhase::PoissonSolve, 3, 7);
let PhaseSpaceSnapshot { data, shape, time } = snap_after_drift;
let a3 = helpers::time_ms!(timings, poisson_ms, {
repr.load_snapshot(PhaseSpaceSnapshot {
data: data.clone(),
shape,
time,
})
.expect("Lawson-RK snapshot restore failed");
advector.kick(repr, &a2, dt / 2.0);
Self::compute_accel(repr, solver, self.g)
});
helpers::report_phase!(self.progress, StepPhase::PoissonSolve, 4, 7);
let a4 = helpers::time_ms!(timings, poisson_ms, {
repr.load_snapshot(PhaseSpaceSnapshot {
data: data.clone(),
shape,
time,
})
.expect("Lawson-RK snapshot restore failed");
advector.kick(repr, &a3, dt);
Self::compute_accel(repr, solver, self.g)
});
helpers::report_phase!(self.progress, StepPhase::Kick, 5, 7);
repr.load_snapshot(PhaseSpaceSnapshot { data, shape, time })?;
helpers::time_ms!(timings, kick_ms, {
advector.kick(repr, &a1, dt / 6.0);
advector.kick(repr, &a2, dt / 3.0);
advector.kick(repr, &a3, dt / 3.0);
advector.kick(repr, &a4, dt / 6.0)
});
helpers::report_phase!(self.progress, StepPhase::DriftHalf2, 6, 7);
helpers::time_ms!(timings, drift_ms, advector.drift(repr, dt / 2.0));
helpers::report_phase!(self.progress, StepPhase::StepComplete, 7, 7);
let (density, potential, acceleration) = helpers::time_ms!(
timings,
density_ms,
helpers::solve_poisson(repr, solver, self.g)
);
self.last_timings = timings;
Ok(StepProducts {
density,
potential,
acceleration,
})
}
fn max_dt(&self, repr: &dyn PhaseSpaceRepr, cfl_factor: f64) -> f64 {
helpers::dynamical_timestep(repr, self.g, cfl_factor)
}
fn last_step_timings(&self) -> Option<&StepTimings> {
Some(&self.last_timings)
}
fn set_progress(&mut self, progress: Arc<StepProgress>) {
self.progress = Some(progress);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lawson_rk_construction() {
let integrator = LawsonRkIntegrator::new(1.0);
assert_eq!(integrator.g, 1.0);
}
}