use crate::config::parameters::{AU, G, PI, SOLAR_MASS, YEAR};
pub fn mean_motion(semi_major_au: f64) -> f64 {
let a = semi_major_au * AU;
if a < 1.0 {
return 0.0;
}
(G * SOLAR_MASS / a.powi(3)).sqrt()
}
pub fn orbital_period(semi_major_au: f64) -> f64 {
let n = mean_motion(semi_major_au);
if n < 1.0e-30 {
return f64::INFINITY;
}
2.0 * PI / n
}
pub fn tisserand(semi_major_au: f64, eccentricity: f64, inclination_deg: f64, a_p: f64) -> f64 {
let ratio = a_p / semi_major_au;
let inc_rad = inclination_deg.to_radians();
ratio
+ 2.0 * ((1.0 - eccentricity * eccentricity) * (semi_major_au / a_p)).sqrt() * inc_rad.cos()
}
pub fn eccentric_anomaly(mean_anomaly: f64, eccentricity: f64) -> f64 {
let mut ea = mean_anomaly;
for _i in 0..50 {
let delta = (ea - eccentricity * ea.sin() - mean_anomaly) / (1.0 - eccentricity * ea.cos());
ea -= delta;
if delta.abs() < 1.0e-12 {
break;
}
}
ea
}
pub fn heliocentric_distance(semi_major_au: f64, eccentricity: f64, true_anomaly: f64) -> f64 {
semi_major_au * (1.0 - eccentricity * eccentricity) / (1.0 + eccentricity * true_anomaly.cos())
}
pub fn velocity_at_distance(semi_major_au: f64, r_au: f64) -> f64 {
let a = semi_major_au * AU;
let r = r_au * AU;
if r < 1.0 || a < 1.0 {
return 0.0;
}
(G * SOLAR_MASS * (2.0 / r - 1.0 / a)).sqrt()
}
pub fn synodic_period(a1_au: f64, a2_au: f64) -> f64 {
let n1 = mean_motion(a1_au);
let n2 = mean_motion(a2_au);
let diff = (n1 - n2).abs();
if diff < 1.0e-30 {
return f64::INFINITY;
}
2.0 * PI / diff
}
pub fn time_from_perihelion(semi_major_au: f64, eccentricity: f64, true_anomaly: f64) -> f64 {
let ea = 2.0
* ((1.0 - eccentricity).sqrt() * (true_anomaly / 2.0).sin())
.atan2((1.0 + eccentricity).sqrt() * (true_anomaly / 2.0).cos());
let ma = ea - eccentricity * ea.sin();
let n = mean_motion(semi_major_au);
if n < 1.0e-30 {
return f64::INFINITY;
}
ma / n
}
pub fn perihelion_passages(semi_major_au: f64, duration_years: f64) -> f64 {
let period_s = orbital_period(semi_major_au);
let duration_s = duration_years * YEAR;
duration_s / period_s
}