use std::sync::Arc;
use super::super::{
advecator::Advector,
integrator::{StepProducts, StepTimings, TimeIntegrator},
phasespace::PhaseSpaceRepr,
progress::{StepPhase, StepProgress},
solver::PoissonSolver,
types::*,
};
use super::helpers;
use crate::CausticError;
const S1: f64 = 1.1746881100325735;
const S2: f64 = -1.349_376_220_065_147;
const YOSHIDA_W1: f64 = 1.3512071919596578;
const YOSHIDA_W0: f64 = -1.7024143839193153;
pub struct Rkn6Splitting {
pub g: f64,
last_timings: StepTimings,
progress: Option<Arc<StepProgress>>,
}
impl Rkn6Splitting {
pub fn new(g: f64) -> Self {
Self {
g,
last_timings: StepTimings::default(),
progress: None,
}
}
#[inline]
fn rkn6_drift(
repr: &mut dyn PhaseSpaceRepr,
advector: &dyn Advector,
coeff: f64,
timings: &mut StepTimings,
progress: &Option<Arc<StepProgress>>,
phase: StepPhase,
sub: u8,
) {
helpers::report_phase!(progress, phase, sub, 19);
let _s = tracing::info_span!("rkn6_drift").entered();
helpers::time_ms!(timings, drift_ms, advector.drift(repr, coeff));
}
#[inline]
#[allow(clippy::too_many_arguments)]
fn rkn6_kick(
g: f64,
repr: &mut dyn PhaseSpaceRepr,
solver: &dyn PoissonSolver,
advector: &dyn Advector,
coeff: f64,
timings: &mut StepTimings,
progress: &Option<Arc<StepProgress>>,
sub: u8,
) {
helpers::report_phase!(progress, StepPhase::Kick, sub, 19);
let _s = tracing::info_span!("rkn6_kick").entered();
let (_density, _potential, accel) =
helpers::time_ms!(timings, poisson_ms, helpers::solve_poisson(repr, solver, g));
helpers::time_ms!(timings, kick_ms, advector.kick(repr, &accel, coeff));
}
#[allow(clippy::too_many_arguments)]
fn yoshida_step(
&self,
repr: &mut dyn PhaseSpaceRepr,
solver: &dyn PoissonSolver,
advector: &dyn Advector,
dt: f64,
timings: &mut StepTimings,
progress: &Option<Arc<StepProgress>>,
base_sub: u8,
total_sub: u8,
) {
helpers::report_phase!(progress, StepPhase::DriftHalf1, base_sub, total_sub);
{
let _s = tracing::info_span!("rkn6_drift").entered();
helpers::time_ms!(
timings,
drift_ms,
advector.drift(repr, YOSHIDA_W1 * dt / 2.0)
);
}
helpers::report_phase!(progress, StepPhase::Kick, base_sub + 1, total_sub);
{
let _s = tracing::info_span!("rkn6_kick").entered();
let (_density, _potential, accel) = helpers::time_ms!(
timings,
poisson_ms,
helpers::solve_poisson(repr, solver, self.g)
);
helpers::time_ms!(
timings,
kick_ms,
advector.kick(repr, &accel, YOSHIDA_W1 * dt)
);
}
helpers::report_phase!(progress, StepPhase::DriftHalf2, base_sub + 2, total_sub);
{
let _s = tracing::info_span!("rkn6_drift").entered();
helpers::time_ms!(
timings,
drift_ms,
advector.drift(repr, (YOSHIDA_W1 + YOSHIDA_W0) * dt / 2.0)
);
}
helpers::report_phase!(progress, StepPhase::Kick, base_sub + 3, total_sub);
{
let _s = tracing::info_span!("rkn6_kick").entered();
let (_density, _potential, accel) = helpers::time_ms!(
timings,
poisson_ms,
helpers::solve_poisson(repr, solver, self.g)
);
helpers::time_ms!(
timings,
kick_ms,
advector.kick(repr, &accel, YOSHIDA_W0 * dt)
);
}
helpers::report_phase!(progress, StepPhase::DriftHalf1, base_sub + 4, total_sub);
{
let _s = tracing::info_span!("rkn6_drift").entered();
helpers::time_ms!(
timings,
drift_ms,
advector.drift(repr, (YOSHIDA_W0 + YOSHIDA_W1) * dt / 2.0)
);
}
helpers::report_phase!(progress, StepPhase::Kick, base_sub + 5, total_sub);
{
let _s = tracing::info_span!("rkn6_kick").entered();
let (_density, _potential, accel) = helpers::time_ms!(
timings,
poisson_ms,
helpers::solve_poisson(repr, solver, self.g)
);
helpers::time_ms!(
timings,
kick_ms,
advector.kick(repr, &accel, YOSHIDA_W1 * dt)
);
}
helpers::report_phase!(progress, StepPhase::DriftHalf2, base_sub + 6, total_sub);
{
let _s = tracing::info_span!("rkn6_drift").entered();
helpers::time_ms!(
timings,
drift_ms,
advector.drift(repr, YOSHIDA_W1 * dt / 2.0)
);
}
}
}
impl TimeIntegrator for Rkn6Splitting {
fn advance(
&mut self,
repr: &mut dyn PhaseSpaceRepr,
solver: &dyn PoissonSolver,
advector: &dyn Advector,
dt: f64,
) -> Result<StepProducts, CausticError> {
let _span = tracing::info_span!("rkn6_advance").entered();
let mut timings = StepTimings::default();
let g = self.g;
let progress = self.progress.clone();
if let Some(ref p) = progress {
p.start_step();
}
let s1dt = S1 * dt;
let s2dt = S2 * dt;
let d_half_w1_s1 = YOSHIDA_W1 * s1dt / 2.0;
let d_half_w01_s1 = (YOSHIDA_W1 + YOSHIDA_W0) * s1dt / 2.0;
let d_half_w01_s2 = (YOSHIDA_W1 + YOSHIDA_W0) * s2dt / 2.0;
let d_seam = YOSHIDA_W1 * (S1 + S2) * dt / 2.0;
let k_w1_s1 = YOSHIDA_W1 * s1dt;
let k_w0_s1 = YOSHIDA_W0 * s1dt;
let k_w1_s2 = YOSHIDA_W1 * s2dt;
let k_w0_s2 = YOSHIDA_W0 * s2dt;
Self::rkn6_drift(
repr,
advector,
d_half_w1_s1,
&mut timings,
&progress,
StepPhase::DriftHalf1,
0,
);
Self::rkn6_kick(
g,
repr,
solver,
advector,
k_w1_s1,
&mut timings,
&progress,
1,
);
Self::rkn6_drift(
repr,
advector,
d_half_w01_s1,
&mut timings,
&progress,
StepPhase::DriftHalf2,
2,
);
Self::rkn6_kick(
g,
repr,
solver,
advector,
k_w0_s1,
&mut timings,
&progress,
3,
);
Self::rkn6_drift(
repr,
advector,
d_half_w01_s1,
&mut timings,
&progress,
StepPhase::DriftHalf1,
4,
);
Self::rkn6_kick(
g,
repr,
solver,
advector,
k_w1_s1,
&mut timings,
&progress,
5,
);
Self::rkn6_drift(
repr,
advector,
d_seam,
&mut timings,
&progress,
StepPhase::DriftHalf2,
6,
);
Self::rkn6_kick(
g,
repr,
solver,
advector,
k_w1_s2,
&mut timings,
&progress,
7,
);
Self::rkn6_drift(
repr,
advector,
d_half_w01_s2,
&mut timings,
&progress,
StepPhase::DriftHalf1,
8,
);
Self::rkn6_kick(
g,
repr,
solver,
advector,
k_w0_s2,
&mut timings,
&progress,
9,
);
Self::rkn6_drift(
repr,
advector,
d_half_w01_s2,
&mut timings,
&progress,
StepPhase::DriftHalf2,
10,
);
Self::rkn6_kick(
g,
repr,
solver,
advector,
k_w1_s2,
&mut timings,
&progress,
11,
);
Self::rkn6_drift(
repr,
advector,
d_seam,
&mut timings,
&progress,
StepPhase::DriftHalf1,
12,
);
Self::rkn6_kick(
g,
repr,
solver,
advector,
k_w1_s1,
&mut timings,
&progress,
13,
);
Self::rkn6_drift(
repr,
advector,
d_half_w01_s1,
&mut timings,
&progress,
StepPhase::DriftHalf2,
14,
);
Self::rkn6_kick(
g,
repr,
solver,
advector,
k_w0_s1,
&mut timings,
&progress,
15,
);
Self::rkn6_drift(
repr,
advector,
d_half_w01_s1,
&mut timings,
&progress,
StepPhase::DriftHalf1,
16,
);
Self::rkn6_kick(
g,
repr,
solver,
advector,
k_w1_s1,
&mut timings,
&progress,
17,
);
Self::rkn6_drift(
repr,
advector,
d_half_w1_s1,
&mut timings,
&progress,
StepPhase::DriftHalf2,
18,
);
helpers::report_phase!(progress, StepPhase::StepComplete, 19, 19);
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);
}
}