use crate::temporal::calendar::SECONDS_PER_DAY;
use sciforge::hub::domain::common::constants::{DEGREE_TO_RAD, EARTH_MASS, EARTH_RADIUS};
pub const SIDEREAL_DAY_S: f64 = 86164.0905;
pub const SOLAR_DAY_S: f64 = SECONDS_PER_DAY;
pub const AXIAL_TILT_DEG: f64 = 23.4392811;
pub const AXIAL_TILT_RAD: f64 = AXIAL_TILT_DEG * DEGREE_TO_RAD;
pub const PRECESSION_PERIOD_YEARS: f64 = 25_772.0;
pub const NUTATION_AMPLITUDE_ARCSEC: f64 = 9.2;
pub struct EarthRotation {
pub angular_velocity_rad_s: f64,
pub axial_tilt_rad: f64,
}
impl Default for EarthRotation {
fn default() -> Self {
Self::new()
}
}
impl EarthRotation {
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 * EARTH_RADIUS * lat_rad.cos()
}
pub fn centripetal_acceleration_at_latitude(&self, latitude_deg: f64) -> f64 {
let lat_rad = latitude_deg.to_radians();
let omega = self.angular_velocity_rad_s;
omega * omega * EARTH_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 {
0.3307 * EARTH_MASS * EARTH_RADIUS * EARTH_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 nutation_obliquity_rad(&self, julian_centuries_since_j2000: f64) -> f64 {
let t = julian_centuries_since_j2000;
let omega_deg = 125.04452 - 1934.136261 * t;
let omega_rad = omega_deg.to_radians();
let delta_epsilon_arcsec = NUTATION_AMPLITUDE_ARCSEC * omega_rad.cos();
delta_epsilon_arcsec / 3600.0 * sciforge::hub::prelude::constants::DEGREE_TO_RAD
}
pub fn effective_tilt_rad(&self, julian_centuries_since_j2000: f64) -> f64 {
self.axial_tilt_rad + self.nutation_obliquity_rad(julian_centuries_since_j2000)
}
pub fn day_length_variation_due_to_tilt(&self, day_of_year: u32, latitude_deg: f64) -> f64 {
let lat_rad = latitude_deg.to_radians();
let declination = self.axial_tilt_rad
* (2.0 * std::f64::consts::PI * (day_of_year as f64 - 81.0)
/ crate::lighting::seasons::TROPICAL_YEAR_DAYS)
.sin();
let cos_hour_angle = -(lat_rad.tan() * declination.tan());
if cos_hour_angle > 1.0 {
return 0.0;
}
if cos_hour_angle < -1.0 {
return 24.0;
}
2.0 * cos_hour_angle.acos() * 12.0 / std::f64::consts::PI
}
}