use crate::hamiltonian::*; use std::ops::{Add, Sub, Mul, Div, AddAssign}; #[derive(Clone, Copy, Debug)] pub struct Augmented { omega: f64, pub a: State, pub b: State, } impl Augmented { pub fn from(state: State, omega: f64) -> Self { Self { omega, a: state, b: state, } } } impl Augmented where T: Copy + Add + Mul { pub fn average(&self) -> State { (self.a + self.b) * 0.5 } } impl Augmented where T: Copy + Add + Sub + Mul + Div + AddAssign, State: Hamiltonian { pub fn evolve(&mut self, h: f64) { let cbrt2 = 2.0_f64.powf(1.0 / 3.0); let z0 = - cbrt2 / (2.0 - cbrt2); let z1 = 1.0 / (2.0 - cbrt2); self.strang(z1 * h); self.strang(z0 * h); self.strang(z1 * h); } fn strang(&mut self, h: f64) { self.evolve_a(h / 2.0); self.evolve_b(h / 2.0); self.evolve_c(h); self.evolve_b(h / 2.0); self.evolve_a(h / 2.0); } fn evolve_a(&mut self, h: f64) { let dots = State { q: self.a.q, p: self.b.p }.dots(); self.a.p += dots.p * h; self.b.q += dots.q * h; } fn evolve_b(&mut self, h: f64) { let dots = State { q: self.b.q, p: self.a.p }.dots(); self.a.q += dots.q * h; self.b.p += dots.p * h; } fn evolve_c(&mut self, h: f64) { let alpha = 2.0 * self.omega * h; let c = alpha.cos(); let s = alpha.sin(); let diff = self.a - self.b; let r = State { q: diff.q * c + diff.p * s, p: diff.p * c - diff.q * s, }; let sum = self.a + self.b; self.a = (sum + r) / 2.0; self.b = (sum - r) / 2.0; } } impl> Add for Augmented { type Output = Self; fn add(self, rhs: Self) -> Self { Self { omega: self.omega, a: self.a + rhs.a, b: self.b + rhs.b, } } } impl> Sub for Augmented { type Output = Self; fn sub(self, rhs: Self) -> Self { Self { omega: self.omega, a: self.a - rhs.a, b: self.b - rhs.b, } } } impl> Mul for Augmented { type Output = Self; fn mul(self, rhs: f64) -> Self { Self { omega: self.omega, a: self.a * rhs, b: self.b * rhs, } } } impl> Div for Augmented { type Output = Self; fn div(self, rhs: f64) -> Self { Self { omega: self.omega, a: self.a / rhs, b: self.b / rhs, } } }