use crate::config::parameters::*;
use std::f64::consts::PI;
pub struct BlackHoleShadow {
pub mass: f64,
pub spin: f64,
pub inclination: f64,
}
impl BlackHoleShadow {
pub fn new(mass: f64, spin: f64, inclination: f64) -> Self {
Self {
mass,
spin: spin.clamp(-1.0, 1.0),
inclination,
}
}
pub fn photon_ring_radius(&self) -> f64 {
photon_sphere_radius(self.mass)
}
pub fn critical_impact_parameter(&self) -> f64 {
let rph = self.photon_ring_radius();
let rs = schwarzschild_radius(self.mass);
rph / (1.0 - rs / rph).max(1e-30).sqrt()
}
pub fn shadow_radius(&self) -> f64 {
let rg = gravitational_radius(self.mass);
let a = self.spin;
let base = 3.0 * 3.0_f64.sqrt() * rg;
let spin_correction = 1.0 - 0.07 * a * a - 0.04 * a * a * self.inclination.cos().powi(2);
base * spin_correction
}
pub fn shadow_diameter_uas(&self, distance: f64) -> f64 {
let r_shadow = self.shadow_radius();
let angle = 2.0 * r_shadow / distance;
angle * 180.0 / PI * 3.6e9
}
pub fn asymmetry_parameter(&self) -> f64 {
self.spin.abs() * self.inclination.sin()
}
pub fn shadow_area(&self) -> f64 {
let r = self.shadow_radius();
PI * r * r * (1.0 + 0.5 * self.asymmetry_parameter().powi(2))
}
pub fn shadow_contour(&self, n_points: usize) -> Vec<(f64, f64)> {
let r = self.shadow_radius();
let asym = self.asymmetry_parameter();
(0..n_points)
.map(|i| {
let phi = 2.0 * PI * i as f64 / n_points as f64;
let r_local = r * (1.0 + 0.1 * asym * phi.cos());
(r_local * phi.cos(), r_local * phi.sin())
})
.collect()
}
}
pub fn eht_m87_expected_diameter_uas() -> f64 {
let mass = M87_MASS_SOLAR * SOLAR_MASS;
let shadow = BlackHoleShadow::new(mass, M87_SPIN, 0.3);
shadow.shadow_diameter_uas(M87_DISTANCE)
}