use crate::constants::*;
use crate::dynamics::components::Component;
#[derive(Debug, Clone)]
pub struct Universe {
pub h0: f64,
pub components: Vec<Component>,
}
impl Universe {
pub fn new(h0: f64) -> Self {
Universe {
h0,
components: Vec::new(),
}
}
pub fn add_component(&mut self, component: Component) {
self.components.push(component);
}
pub fn benchmark() -> Self {
let mut universe = Universe::new(67.66);
universe.add_component(Component::matter(0.3111));
universe.add_component(Component::radiation(9.3e-5));
universe.add_component(Component::dark_energy(0.6889));
universe
}
pub fn einstein_de_sitter(h0: f64) -> Self {
let mut universe = Universe::new(h0);
universe.add_component(Component::matter(1.0));
universe
}
pub fn omega_total(&self) -> f64 {
self.components.iter().map(|c| c.omega_0).sum()
}
pub fn hubble_normalized(&self, a: f64) -> f64 {
let sum: f64 = self.components
.iter()
.map(|c| c.density_evolution(a))
.sum();
sum.sqrt()
}
pub fn hubble(&self, a: f64) -> f64 {
self.h0 * self.hubble_normalized(a)
}
pub fn hubble_z(&self, z: f64) -> f64 {
let a = 1.0 / (1.0 + z);
self.hubble(a)
}
pub fn deceleration(&self, a: f64) -> f64 {
let mut sum_rho_1_w = 0.0;
let mut sum_rho = 0.0;
for component in &self.components {
let rho = component.density_evolution(a);
sum_rho += rho;
sum_rho_1_w += rho * (1.0 + component.w);
}
0.5 * sum_rho_1_w / sum_rho
}
pub fn age(&self, a: f64) -> f64 {
let n_steps = 1000;
let da = a / n_steps as f64;
let mut age = 0.0;
for i in 1..=n_steps {
let a_i = i as f64 * da;
let h = self.hubble(a_i); let h_si = h * 1e3 / (PARSEC * 1e6); let dt = da / (a_i * h_si); age += dt;
}
age / GYR }
pub fn age_today(&self) -> f64 {
self.age(1.0)
}
pub fn critical_density(&self) -> f64 {
critical_density(self.h0)
}
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn test_benchmark_universe() {
let universe = Universe::benchmark();
let omega_tot = universe.omega_total();
assert_relative_eq!(omega_tot, 1.0, epsilon = 1e-3);
}
#[test]
fn test_einstein_de_sitter() {
let universe = Universe::einstein_de_sitter(70.0);
assert_relative_eq!(universe.omega_total(), 1.0, epsilon = 1e-10);
assert_relative_eq!(universe.hubble_normalized(0.5), 2.828427, epsilon = 1e-5);
}
#[test]
fn test_age_calculation() {
let universe = Universe::benchmark();
let age = universe.age_today();
assert!(age > 13.0 && age < 14.5);
}
}