use crate::config::parameters::*;
pub struct PotentiallyHazardousAsteroid {
pub radius: f64,
pub density: f64,
pub mass: f64,
pub semi_major_axis: f64,
pub eccentricity: f64,
pub inclination: f64,
pub moid: f64,
pub albedo: f64,
pub absolute_mag: f64,
pub velocity_infinity: f64,
}
impl PotentiallyHazardousAsteroid {
pub fn new(
radius_m: f64,
density: f64,
semi_major_au: f64,
eccentricity: f64,
moid_au: f64,
) -> Self {
let radius = radius_m.clamp(70.0, MAX_ASTEROID_RADIUS);
let density = density.clamp(500.0, 8000.0);
let mass = sphere_mass(radius, density);
let ecc = eccentricity.clamp(0.0, 0.999);
let moid = moid_au.clamp(0.0, 0.05);
let albedo: f64 = 0.15;
let diameter_km: f64 = 2.0 * radius / 1000.0;
let absolute_mag = 15.618 - 5.0 * diameter_km.log10() - 2.5 * albedo.log10();
let v_circ = (G * SOLAR_MASS / (1.0 * AU)).sqrt();
let v_ast = vis_viva(SOLAR_MASS, 1.0 * AU, semi_major_au * AU);
let velocity_infinity = (v_ast - v_circ).abs();
Self {
radius,
density,
mass,
semi_major_axis: semi_major_au,
eccentricity: ecc,
inclination: 0.0,
moid,
albedo,
absolute_mag,
velocity_infinity,
}
}
pub fn with_inclination(mut self, inc_deg: f64) -> Self {
self.inclination = inc_deg.to_radians();
self
}
pub fn with_albedo(mut self, a: f64) -> Self {
self.albedo = a.clamp(0.01, 0.99);
let diameter_km = 2.0 * self.radius / 1000.0;
self.absolute_mag = 15.618 - 5.0 * diameter_km.log10() - 2.5 * self.albedo.log10();
self
}
pub fn is_pha(&self) -> bool {
self.moid < 0.05 && self.absolute_mag < 22.0
}
pub fn impact_energy_joules(&self) -> f64 {
0.5 * self.mass * self.velocity_infinity * self.velocity_infinity
}
pub fn impact_energy_megatons(&self) -> f64 {
self.impact_energy_joules() / 4.184e15
}
pub fn torino_scale_estimate(&self) -> u8 {
let e_mt = self.impact_energy_megatons();
if self.moid > 0.05 {
0
} else if e_mt < 1.0 {
1
} else if e_mt < 100.0 {
3
} else if e_mt < 1e5 {
5
} else {
8
}
}
pub fn crater_diameter_estimate(&self) -> f64 {
let d = 2.0 * self.radius;
let v = self.velocity_infinity;
1.161 * d.powf(0.78) * v.powf(0.44) * self.density.powf(0.33) / 2500.0_f64.powf(0.33)
}
pub fn surface_gravity(&self) -> f64 {
surface_gravity(self.mass, self.radius)
}
pub fn escape_velocity(&self) -> f64 {
escape_velocity(self.mass, self.radius)
}
pub fn orbital_period(&self) -> f64 {
orbital_period(self.semi_major_axis, SOLAR_MASS)
}
pub fn orbital_period_years(&self) -> f64 {
self.orbital_period() / YEAR
}
pub fn perihelion_au(&self) -> f64 {
self.semi_major_axis * (1.0 - self.eccentricity)
}
pub fn aphelion_au(&self) -> f64 {
self.semi_major_axis * (1.0 + self.eccentricity)
}
pub fn warning_time_estimate(&self, detection_distance_au: f64) -> f64 {
let v_approach = self.velocity_infinity;
(detection_distance_au * AU) / v_approach
}
pub fn deflection_delta_v(&self, lead_time_years: f64) -> f64 {
let t = lead_time_years * YEAR;
if t < 1.0 {
return f64::INFINITY;
}
let miss = self.moid * AU;
miss / t
}
}