use crate::constants::physical::{C, G, SOLAR_MASS};
use std::f64::consts::PI;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct PrimordialBlackHole {
pub mass_kg: f64,
}
impl PrimordialBlackHole {
pub fn from_solar_masses(m_solar: f64) -> Self {
Self {
mass_kg: m_solar * SOLAR_MASS,
}
}
pub fn schwarzschild_radius(&self) -> f64 {
2.0 * G * self.mass_kg / (C * C)
}
pub fn hawking_temperature_gev(&self) -> f64 {
let hbar_si = 1.0546e-34;
let kb = 1.381e-23;
let t_kelvin = hbar_si * C * C * C / (8.0 * PI * G * self.mass_kg * kb);
t_kelvin * 8.617e-14 * 1e-9
}
pub fn hawking_luminosity(&self) -> f64 {
let hbar_si = 1.0546e-34;
hbar_si * C * C * C * C * C * C / (15360.0 * PI * G * G * self.mass_kg * self.mass_kg)
}
pub fn evaporation_time_seconds(&self) -> f64 {
let hbar_si = 1.0546e-34;
5120.0 * PI * G * G * self.mass_kg.powi(3) / (hbar_si * C * C * C * C)
}
pub fn is_stable_now(&self) -> bool {
self.evaporation_time_seconds() > 4.35e17
}
pub fn mass_solar(&self) -> f64 {
self.mass_kg / SOLAR_MASS
}
pub fn formation_mass_from_horizon(t_seconds: f64) -> f64 {
C * C * C * t_seconds / (2.0 * G)
}
pub fn microlensing_einstein_radius(&self, d_l: f64, d_s: f64) -> f64 {
let d_ls = d_s - d_l;
if d_ls <= 0.0 || d_s <= 0.0 {
return 0.0;
}
(4.0 * G * self.mass_kg * d_ls / (C * C * d_l * d_s)).sqrt()
}
pub fn microlensing_timescale(&self, d_l: f64, d_s: f64, v_transverse: f64) -> f64 {
let r_e = self.microlensing_einstein_radius(d_l, d_s);
if v_transverse <= 0.0 {
return f64::INFINITY;
}
r_e / v_transverse
}
pub fn accretion_luminosity(&self, accretion_rate_kg_s: f64, efficiency: f64) -> f64 {
efficiency * accretion_rate_kg_s * C * C
}
pub fn bondi_accretion_rate(&self, rho_gas: f64, cs_gas: f64) -> f64 {
4.0 * PI * G * G * self.mass_kg * self.mass_kg * rho_gas / (cs_gas * cs_gas * cs_gas)
}
}
pub fn pbh_dm_fraction_constraint_evaporation(mass_kg: f64) -> f64 {
let pbh = PrimordialBlackHole { mass_kg };
let t_evap = pbh.evaporation_time_seconds();
let age_universe = 4.35e17;
if t_evap < age_universe { 0.0 } else { 1.0 }
}
pub fn pbh_mass_range_dm_solar() -> (f64, f64) {
(1e-16, 1e3)
}
pub fn pbh_abundance_beta(mass_kg: f64, f_dm: f64) -> f64 {
let m_eq = 2.8e17 * SOLAR_MASS;
f_dm * (mass_kg / m_eq).sqrt()
}
pub fn extended_mass_function_lognormal(mass: f64, mass_c: f64, sigma: f64) -> f64 {
let log_ratio = (mass / mass_c).ln();
(-log_ratio * log_ratio / (2.0 * sigma * sigma)).exp() / (mass * sigma * (2.0 * PI).sqrt())
}
pub fn gravitational_wave_from_merger(m1_kg: f64, m2_kg: f64, distance: f64) -> f64 {
let m_total = m1_kg + m2_kg;
let mu = m1_kg * m2_kg / m_total;
let mc = mu.powf(3.0 / 5.0) * m_total.powf(2.0 / 5.0);
4.0 * G * mc / (C * C * distance) * (G * mc / (C * C * C)).powf(5.0 / 3.0)
}
pub fn pbh_merger_rate_per_gpc3_yr(f_dm: f64, mass_solar: f64) -> f64 {
let base_rate = 1.3e6;
base_rate * f_dm.powf(53.0 / 37.0) * mass_solar.powf(-32.0 / 37.0)
}