use sciforge::hub::domain::common::constants::DEGREE_TO_RAD;
pub const SIDEREAL_DAY_S: f64 = crate::SIDEREAL_DAY_S;
pub const SOL_S: f64 = crate::SOL_S;
pub const AXIAL_TILT_DEG: f64 = crate::AXIAL_TILT_DEG;
pub const AXIAL_TILT_RAD: f64 = AXIAL_TILT_DEG * DEGREE_TO_RAD;
pub const PRECESSION_PERIOD_YEARS: f64 = 170_000.0;
pub struct MarsRotation {
pub angular_velocity_rad_s: f64,
pub axial_tilt_rad: f64,
}
impl Default for MarsRotation {
fn default() -> Self {
Self::new()
}
}
impl MarsRotation {
pub fn new() -> Self {
Self {
angular_velocity_rad_s: 2.0 * std::f64::consts::PI / SIDEREAL_DAY_S,
axial_tilt_rad: AXIAL_TILT_RAD,
}
}
pub fn surface_velocity_at_latitude(&self, latitude_deg: f64) -> f64 {
let lat_rad = latitude_deg.to_radians();
self.angular_velocity_rad_s * crate::MARS_EQUATORIAL_RADIUS * lat_rad.cos()
}
pub fn coriolis_parameter(&self, latitude_deg: f64) -> f64 {
let lat_rad = latitude_deg.to_radians();
2.0 * self.angular_velocity_rad_s * lat_rad.sin()
}
pub fn moment_of_inertia(&self) -> f64 {
crate::MOI_FACTOR * crate::MARS_MASS * crate::MARS_RADIUS * crate::MARS_RADIUS
}
pub fn rotational_kinetic_energy(&self) -> f64 {
0.5 * self.moment_of_inertia() * self.angular_velocity_rad_s.powi(2)
}
pub fn angular_momentum(&self) -> f64 {
self.moment_of_inertia() * self.angular_velocity_rad_s
}
pub fn precession_rate_rad_per_year(&self) -> f64 {
2.0 * std::f64::consts::PI / PRECESSION_PERIOD_YEARS
}
pub fn solar_declination(&self, areocentric_longitude_deg: f64) -> f64 {
let ls_rad = areocentric_longitude_deg.to_radians();
(self.axial_tilt_rad.sin() * ls_rad.sin()).asin()
}
pub fn day_length_hours(&self, latitude_deg: f64, areocentric_longitude_deg: f64) -> f64 {
let lat_rad = latitude_deg.to_radians();
let decl = self.solar_declination(areocentric_longitude_deg);
let cos_ha = -(lat_rad.tan() * decl.tan());
if cos_ha > 1.0 {
return 0.0;
}
if cos_ha < -1.0 {
return 24.0 * SOL_S / 86400.0;
}
2.0 * cos_ha.acos() / (2.0 * std::f64::consts::PI) * SOL_S / 3600.0
}
}