Added energy conservation test
This commit is contained in:
@@ -764,4 +764,59 @@ mod tests {
|
||||
// 7th order interpolation should be very accurate
|
||||
assert_relative_eq!(y_interp[0], exact, epsilon = 1e-8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vern7_long_term_energy_conservation() {
|
||||
// Test energy conservation over 1000 periods of harmonic oscillator
|
||||
// This verifies that Vern7 maintains accuracy over long integrations
|
||||
type Params = ();
|
||||
|
||||
fn derivative(_t: f64, y: Vector2<f64>, _p: &Params) -> Vector2<f64> {
|
||||
// Harmonic oscillator: y'' + y = 0
|
||||
// As system: y1' = y2, y2' = -y1
|
||||
Vector2::new(y[1], -y[0])
|
||||
}
|
||||
|
||||
let y0 = Vector2::new(1.0, 0.0); // Start at maximum displacement, zero velocity
|
||||
|
||||
// Period of harmonic oscillator is 2π
|
||||
let period = 2.0 * std::f64::consts::PI;
|
||||
let num_periods = 1000.0;
|
||||
let t_end = num_periods * period;
|
||||
|
||||
let ode = ODE::new(&derivative, 0.0, t_end, y0, ());
|
||||
let vern7 = Vern7::new().a_tol(1e-10).r_tol(1e-10);
|
||||
let controller = PIController::default();
|
||||
|
||||
let mut problem = Problem::new(ode, vern7, controller);
|
||||
let solution = problem.solve();
|
||||
|
||||
// Check solution at the end
|
||||
let y_final = solution.states.last().unwrap();
|
||||
|
||||
// Energy of harmonic oscillator: E = 0.5 * (y1^2 + y2^2)
|
||||
let energy_initial = 0.5 * (y0[0] * y0[0] + y0[1] * y0[1]);
|
||||
let energy_final = 0.5 * (y_final[0] * y_final[0] + y_final[1] * y_final[1]);
|
||||
|
||||
// After 1000 periods, energy drift should be minimal
|
||||
let energy_drift = (energy_final - energy_initial).abs() / energy_initial;
|
||||
|
||||
println!("Initial energy: {}", energy_initial);
|
||||
println!("Final energy: {}", energy_final);
|
||||
println!("Energy drift after {} periods: {:.2e}", num_periods, energy_drift);
|
||||
println!("Number of steps: {}", solution.times.len());
|
||||
|
||||
// Energy should be conserved to high precision (< 1e-7 relative error over 1000 periods)
|
||||
// This is excellent for a non-symplectic method!
|
||||
assert!(
|
||||
energy_drift < 1e-7,
|
||||
"Energy drift too large: {:.2e}",
|
||||
energy_drift
|
||||
);
|
||||
|
||||
// Also check that we return near the initial position after 1000 periods
|
||||
// (should be back at (1, 0))
|
||||
assert_relative_eq!(y_final[0], 1.0, epsilon = 1e-6);
|
||||
assert_relative_eq!(y_final[1], 0.0, epsilon = 1e-6);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user