use crate::symmetry::Symmetry;
#[derive(Debug, Clone)]
pub struct ConservationLaw {
pub symmetry: Symmetry,
pub name: String,
pub initial_value: f64,
pub tolerance: f64,
}
impl ConservationLaw {
pub fn new(symmetry: Symmetry, initial_value: f64, tolerance: f64) -> Self {
Self {
name: symmetry.conserved_quantity().to_string(),
symmetry,
initial_value,
tolerance,
}
}
pub fn is_conserved(&self, value: f64) -> bool {
(value - self.initial_value).abs() <= self.tolerance
}
pub fn drift(&self, value: f64) -> f64 {
(value - self.initial_value).abs()
}
pub fn drift_rate(&self, previous_drift: f64, dt: f64) -> f64 {
if dt > 0.0 {
(self.initial_value - previous_drift).abs() / dt
} else {
0.0
}
}
}
#[derive(Debug, Clone)]
pub struct ConservedQuantity {
pub name: String,
pub values: Vec<(f64, f64)>,
pub drift_rate: f64,
}
impl ConservedQuantity {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
values: Vec::new(),
drift_rate: 0.0,
}
}
pub fn record(&mut self, time: f64, value: f64) {
self.values.push((time, value));
if self.values.len() >= 2 {
let (t0, v0) = self.values[self.values.len() - 2];
let (t1, v1) = self.values[self.values.len() - 1];
let dt = t1 - t0;
if dt > 0.0 {
self.drift_rate = (v1 - v0) / dt;
}
}
}
pub fn current_drift_rate(&self) -> f64 {
self.drift_rate
}
pub fn total_drift(&self) -> f64 {
if self.values.len() < 2 {
return 0.0;
}
let first = self.values.first().unwrap().1;
let last = self.values.last().unwrap().1;
(last - first).abs()
}
pub fn len(&self) -> usize {
self.values.len()
}
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
}