use sciforge::hub::domain::common::constants::{G, K_B, SOLAR_MASS};
use crate::{
CONVECTIVE_ZONE_BASE_FRAC, PROTON_MASS, SOLAR_EFFECTIVE_TEMP,
SOLAR_OMEGA_EQUATORIAL, SOLAR_RADIUS, SECONDS_PER_DAY,
};
pub const CONVECTIVE_ZONE_BASE_TEMP: f64 = 2.0e6;
pub const CONVECTIVE_ZONE_TOP_TEMP: f64 = 5778.0;
pub const CONVECTIVE_ZONE_BASE_DENSITY: f64 = 200.0;
pub const CONVECTIVE_ZONE_TOP_DENSITY: f64 = 2e-4;
pub const MIXING_LENGTH_ALPHA: f64 = 1.7;
pub const CONVECTIVE_VELOCITY_DEEP: f64 = 100.0;
pub const CONVECTIVE_VELOCITY_SURFACE: f64 = 2000.0;
pub const CONVECTIVE_TURNOVER_TIME_S: f64 = 2.59e6;
pub const ROSSBY_NUMBER_SOLAR: f64 = 1.96;
pub struct ConvectiveZone {
pub inner_radius_frac: f64,
pub outer_radius_frac: f64,
pub base_temperature_k: f64,
pub top_temperature_k: f64,
pub base_density: f64,
pub top_density: f64,
}
impl Default for ConvectiveZone {
fn default() -> Self {
Self::new()
}
}
impl ConvectiveZone {
pub fn new() -> Self {
Self {
inner_radius_frac: CONVECTIVE_ZONE_BASE_FRAC,
outer_radius_frac: 1.0,
base_temperature_k: CONVECTIVE_ZONE_BASE_TEMP,
top_temperature_k: CONVECTIVE_ZONE_TOP_TEMP,
base_density: CONVECTIVE_ZONE_BASE_DENSITY,
top_density: CONVECTIVE_ZONE_TOP_DENSITY,
}
}
pub fn thickness_m(&self) -> f64 {
(self.outer_radius_frac - self.inner_radius_frac) * SOLAR_RADIUS
}
pub fn volume_m3(&self) -> f64 {
let r_out = self.outer_radius_frac * SOLAR_RADIUS;
let r_in = self.inner_radius_frac * SOLAR_RADIUS;
(4.0 / 3.0) * std::f64::consts::PI * (r_out.powi(3) - r_in.powi(3))
}
pub fn temperature_at_frac(&self, radius_frac: f64) -> f64 {
let f = ((radius_frac - self.inner_radius_frac)
/ (self.outer_radius_frac - self.inner_radius_frac))
.clamp(0.0, 1.0);
self.base_temperature_k * (1.0 - f) + self.top_temperature_k * f
}
pub fn density_at_frac(&self, radius_frac: f64) -> f64 {
let f = ((radius_frac - self.inner_radius_frac)
/ (self.outer_radius_frac - self.inner_radius_frac))
.clamp(0.0, 1.0);
(self.base_density.ln() * (1.0 - f) + self.top_density.ln() * f).exp()
}
pub fn pressure_scale_height(&self, radius_frac: f64) -> f64 {
let t = self.temperature_at_frac(radius_frac);
let r = radius_frac * SOLAR_RADIUS;
let g = G * SOLAR_MASS / (r * r);
K_B * t / (0.61 * PROTON_MASS * g)
}
pub fn mixing_length(&self, radius_frac: f64) -> f64 {
MIXING_LENGTH_ALPHA * self.pressure_scale_height(radius_frac)
}
pub fn convective_velocity(&self, radius_frac: f64) -> f64 {
let f = ((radius_frac - self.inner_radius_frac)
/ (self.outer_radius_frac - self.inner_radius_frac))
.clamp(0.0, 1.0);
CONVECTIVE_VELOCITY_DEEP * (1.0 - f) + CONVECTIVE_VELOCITY_SURFACE * f
}
pub fn convective_flux(&self, radius_frac: f64) -> f64 {
let rho = self.density_at_frac(radius_frac);
let v = self.convective_velocity(radius_frac);
let cp = 5.0 * K_B / (2.0 * 0.61 * PROTON_MASS);
let dt = 100.0;
rho * cp * v * dt
}
pub fn turnover_time(&self, radius_frac: f64) -> f64 {
let l = self.mixing_length(radius_frac);
let v = self.convective_velocity(radius_frac);
l / v.max(1e-10)
}
pub fn rossby_number(&self, radius_frac: f64) -> f64 {
let tau = self.turnover_time(radius_frac);
let omega = *SOLAR_OMEGA_EQUATORIAL;
2.0 * std::f64::consts::PI / (omega * tau)
}
pub fn superadiabaticity(&self) -> f64 {
1e-7
}
pub fn brunt_vaisala_frequency(&self, radius_frac: f64) -> f64 {
let g = G * SOLAR_MASS / ((radius_frac * SOLAR_RADIUS).powi(2));
let hp = self.pressure_scale_height(radius_frac);
let delta = self.superadiabaticity();
(g * delta / hp).sqrt()
}
pub fn total_kinetic_energy(&self) -> f64 {
let mean_v = (CONVECTIVE_VELOCITY_DEEP + CONVECTIVE_VELOCITY_SURFACE) / 2.0;
let mean_rho = (self.base_density + self.top_density) / 2.0;
0.5 * mean_rho * mean_v * mean_v * self.volume_m3()
}
}
pub fn differential_rotation_angular_velocity(latitude_deg: f64) -> f64 {
let a = 14.713;
let b = -2.396;
let c = -1.787;
let sin_lat = latitude_deg.to_radians().sin();
let sin2 = sin_lat * sin_lat;
(a + b * sin2 + c * sin2 * sin2) * std::f64::consts::PI / 180.0 / SECONDS_PER_DAY
}
pub fn meridional_flow_speed(latitude_deg: f64) -> f64 {
let max_speed = 15.0;
max_speed * (2.0 * latitude_deg.to_radians()).sin()
}
pub fn convective_overshoot_depth() -> f64 {
0.05 * SOLAR_RADIUS
}
pub fn entropy_rain_speed(temperature_deficit: f64) -> f64 {
let g = G * SOLAR_MASS / (SOLAR_RADIUS * SOLAR_RADIUS);
let hp = 1.5e5;
(g * temperature_deficit * hp / SOLAR_EFFECTIVE_TEMP).sqrt()
}