#[test]
fn conservation_laws() {
use crate::tooling::core::init::{
domain::{Domain, SpatialBoundType, VelocityBoundType},
isolated::{PlummerIC, sample_on_grid},
};
use crate::tooling::validation::helpers::{build_standard_sim, relative_drift};
let domain = Domain::builder()
.spatial_extent(8.0) .velocity_extent(2.5) .spatial_resolution(8)
.velocity_resolution(8)
.t_final(4.0) .spatial_bc(SpatialBoundType::Periodic)
.velocity_bc(VelocityBoundType::Truncated) .build()
.unwrap();
let ic = PlummerIC::new(1.0, 1.0, 1.0);
let snap = sample_on_grid(&ic, &domain);
let mut sim = build_standard_sim(domain, snap, 4.0);
let pkg = sim.run().unwrap();
let history = &pkg.diagnostics_history;
assert!(history.len() >= 2, "Need at least 2 diagnostic entries");
let e0 = history[0].total_energy;
let c2_0 = history[0].casimir_c2;
let max_e_drift = history
.iter()
.map(|d| relative_drift(d.total_energy, e0))
.fold(0.0f64, f64::max);
let max_c2_drift = history
.iter()
.map(|d| relative_drift(d.casimir_c2, c2_0))
.fold(0.0f64, f64::max);
println!(
"Conservation: E0={:.4}, max_dE/E={:.2e}; C2_0={:.4}, max_dC2/C2={:.2e}; steps={}",
e0, max_e_drift, c2_0, max_c2_drift, pkg.total_steps
);
assert!(!e0.is_nan(), "Initial energy must not be NaN");
assert!(!max_e_drift.is_nan(), "Energy drift must not be NaN");
assert!(
max_e_drift < 0.5,
"Energy drift {:.2e} exceeds 50% threshold over {} steps",
max_e_drift,
pkg.total_steps
);
}