use crate::temporal::calendar::SECONDSPERDAY;
use sciforge::hub::domain::common::constants::{DEGREE_TO_RAD, EARTH_MASS, EARTH_RADIUS};
pub const SIDEREALDAYS: f64 = 86164.0905;
pub const SOLARDAYS: f64 = SECONDSPERDAY;
pub const AXIALTILTDEG: f64 = 23.4392811;
pub const AXIALTILTRAD: f64 = AXIALTILTDEG * DEGREE_TO_RAD;
pub const PRECESSIONPERIODYEARS: f64 = 25772.0;
pub const NUTATIONAMPLITUDEARCSEC: f64 = 9.2;
pub struct EarthRotation {
pub angularvelocityrads: f64,
pub axialtiltrad: f64,
}
impl Default for EarthRotation {
fn default() -> Self {
Self::new()
}
}
impl EarthRotation {
pub fn new() -> Self {
Self {
angularvelocityrads: 2.0 * std::f64::consts::PI / SIDEREALDAYS,
axialtiltrad: AXIALTILTRAD,
}
}
pub fn surfacevelocityatlatitude(&self, latitudedeg: f64) -> f64 {
let latrad = latitudedeg.to_radians();
self.angularvelocityrads * EARTH_RADIUS * latrad.cos()
}
pub fn centripetalaccelerationatlatitude(&self, latitudedeg: f64) -> f64 {
let latrad = latitudedeg.to_radians();
let omega = self.angularvelocityrads;
omega * omega * EARTH_RADIUS * latrad.cos()
}
pub fn coriolisparameter(&self, latitudedeg: f64) -> f64 {
let latrad = latitudedeg.to_radians();
2.0 * self.angularvelocityrads * latrad.sin()
}
pub fn momentofinertia(&self) -> f64 {
0.3307 * EARTH_MASS * EARTH_RADIUS * EARTH_RADIUS
}
pub fn rotationalkineticenergy(&self) -> f64 {
0.5 * self.momentofinertia() * self.angularvelocityrads.powi(2)
}
pub fn angular_momentum(&self) -> f64 {
self.momentofinertia() * self.angularvelocityrads
}
pub fn precession_rate_rad_per_year(&self) -> f64 {
2.0 * std::f64::consts::PI / PRECESSIONPERIODYEARS
}
pub fn nutation_obliquity_rad(&self, juliancenturiessincej2000: f64) -> f64 {
let t = juliancenturiessincej2000;
let omegadeg = 125.04452 - 1934.136261 * t;
let omegarad = omegadeg.to_radians();
let deltaepsilonarcsec = NUTATIONAMPLITUDEARCSEC * omegarad.cos();
deltaepsilonarcsec / 3600.0 * sciforge::hub::prelude::constants::DEGREE_TO_RAD
}
pub fn effective_tilt_rad(&self, juliancenturiessincej2000: f64) -> f64 {
self.axialtiltrad + self.nutation_obliquity_rad(juliancenturiessincej2000)
}
pub fn day_length_variation_due_to_tilt(&self, dayofyear: u32, latitudedeg: f64) -> f64 {
let latrad = latitudedeg.to_radians();
let declination = self.axialtiltrad
* (2.0 * std::f64::consts::PI * (dayofyear as f64 - 81.0)
/ crate::lighting::seasons::TROPICALYEARDAYS)
.sin();
let coshourangle = -(latrad.tan() * declination.tan());
if coshourangle > 1.0 {
return 0.0;
}
if coshourangle < -1.0 {
return 24.0;
}
2.0 * coshourangle.acos() * 12.0 / std::f64::consts::PI
}
}