use sciforge::hub::prelude::biology::population::logistic_growth;
pub struct Population {
pub species_name: &'static str,
pub count: f64,
pub carrying_capacity: f64,
pub intrinsic_growth_rate: f64,
pub body_mass_kg: f64,
}
impl Population {
pub fn growth_rate(&self) -> f64 {
logistic_growth(
self.intrinsic_growth_rate,
self.count,
self.carrying_capacity,
)
}
pub fn project_forward(&self, dt_years: f64) -> f64 {
let r = self.intrinsic_growth_rate;
let k = self.carrying_capacity;
let n = self.count;
k / (1.0 + ((k - n) / n) * (-r * dt_years).exp())
}
pub fn metabolic_rate_w(&self) -> f64 {
crate::KLEIBER_A * self.body_mass_kg.powf(0.75)
}
pub fn home_range_km2(&self) -> f64 {
crate::MCNAB_A * self.body_mass_kg.powf(1.0)
}
pub fn generation_time_years(&self) -> f64 {
crate::GEN_TIME_A * self.body_mass_kg.powf(0.25)
}
pub fn max_lifespan_years(&self) -> f64 {
crate::LIFESPAN_A * self.body_mass_kg.powf(0.20)
}
}
pub struct PredatorPrey {
pub prey: Population,
pub predator: Population,
pub attack_rate: f64,
pub conversion_efficiency: f64,
pub predator_death_rate: f64,
}
impl PredatorPrey {
pub fn prey_growth_rate(&self) -> f64 {
let prey_logistic = self.prey.growth_rate();
let predation = self.attack_rate * self.prey.count * self.predator.count;
prey_logistic - predation
}
pub fn predator_growth_rate(&self) -> f64 {
let births =
self.conversion_efficiency * self.attack_rate * self.prey.count * self.predator.count;
let deaths = self.predator_death_rate * self.predator.count;
births - deaths
}
pub fn step(&mut self, dt: f64) {
let (n, p) = (self.prey.count, self.predator.count);
let deriv = |prey: f64, pred: f64| -> (f64, f64) {
let prey_logistic =
self.prey.intrinsic_growth_rate * prey * (1.0 - prey / self.prey.carrying_capacity);
let predation = self.attack_rate * prey * pred;
let dn = prey_logistic - predation;
let dp = self.conversion_efficiency * self.attack_rate * prey * pred
- self.predator_death_rate * pred;
(dn, dp)
};
let (k1n, k1p) = deriv(n, p);
let (k2n, k2p) = deriv(n + 0.5 * dt * k1n, p + 0.5 * dt * k1p);
let (k3n, k3p) = deriv(n + 0.5 * dt * k2n, p + 0.5 * dt * k2p);
let (k4n, k4p) = deriv(n + dt * k3n, p + dt * k3p);
self.prey.count = (n + dt / 6.0 * (k1n + 2.0 * k2n + 2.0 * k3n + k4n)).max(0.0);
self.predator.count = (p + dt / 6.0 * (k1p + 2.0 * k2p + 2.0 * k3p + k4p)).max(0.0);
}
}
pub fn african_elephant() -> Population {
Population {
species_name: "African Elephant",
count: 415_000.0,
carrying_capacity: 1_000_000.0,
intrinsic_growth_rate: 0.05,
body_mass_kg: 6000.0,
}
}
pub fn blue_whale() -> Population {
Population {
species_name: "Blue Whale",
count: 25_000.0,
carrying_capacity: 350_000.0,
intrinsic_growth_rate: 0.04,
body_mass_kg: 150_000.0,
}
}