use sciforge::hub::domain::common::constants::{K_B, SIGMA_SB};
use sciforge::hub::domain::meteorology::radiation::stefan_boltzmann_flux;
use crate::{
PHOTOSPHERE_THICKNESS, PROTON_MASS, SOLAR_EFFECTIVE_TEMP, SOLAR_RADIUS, SPEED_OF_LIGHT,
};
pub const PHOTOSPHERE_BASE_DENSITY: f64 = 2e-4;
pub const PHOTOSPHERE_BASE_PRESSURE: f64 = 1.25e4;
pub const PHOTOSPHERE_SCALE_HEIGHT: f64 = 1.5e5;
pub const GRANULATION_CELL_SIZE_M: f64 = 1e6;
pub const GRANULATION_VELOCITY_MS: f64 = 1000.0;
pub const SUPERGRANULATION_CELL_SIZE_M: f64 = 3e7;
pub const SUPERGRANULATION_VELOCITY_MS: f64 = 300.0;
pub const PHOTOSPHERIC_OPACITY_CM2G: f64 = 0.264;
pub const LIMB_DARKENING_COEFF_U: f64 = 0.6;
pub struct Photosphere {
pub temperature_k: f64,
pub density_kgm3: f64,
pub pressure_pa: f64,
pub thickness_m: f64,
}
impl Default for Photosphere {
fn default() -> Self {
Self::new()
}
}
impl Photosphere {
pub fn new() -> Self {
Self {
temperature_k: SOLAR_EFFECTIVE_TEMP,
density_kgm3: PHOTOSPHERE_BASE_DENSITY,
pressure_pa: PHOTOSPHERE_BASE_PRESSURE,
thickness_m: PHOTOSPHERE_THICKNESS,
}
}
pub fn surface_flux(&self) -> f64 {
stefan_boltzmann_flux(self.temperature_k)
}
pub fn luminosity(&self) -> f64 {
4.0 * std::f64::consts::PI * SOLAR_RADIUS * SOLAR_RADIUS * self.surface_flux()
}
pub fn opacity(&self) -> f64 {
PHOTOSPHERIC_OPACITY_CM2G * 0.1 * self.density_kgm3
}
pub fn optical_depth_at_height(&self, height_m: f64) -> f64 {
let kappa = self.opacity();
kappa
* self.density_kgm3
* (-height_m / PHOTOSPHERE_SCALE_HEIGHT).exp()
* PHOTOSPHERE_SCALE_HEIGHT
}
pub fn temperature_at_optical_depth(&self, tau: f64) -> f64 {
self.temperature_k * (0.75 * (tau + 2.0 / 3.0)).powf(0.25)
}
pub fn limb_darkening_intensity(&self, theta: f64) -> f64 {
1.0 - LIMB_DARKENING_COEFF_U * (1.0 - theta.cos())
}
pub fn density_at_height(&self, height_m: f64) -> f64 {
self.density_kgm3 * (-height_m / PHOTOSPHERE_SCALE_HEIGHT).exp()
}
pub fn pressure_at_height(&self, height_m: f64) -> f64 {
self.pressure_pa * (-height_m / PHOTOSPHERE_SCALE_HEIGHT).exp()
}
pub fn sound_speed(&self) -> f64 {
let gamma = 5.0 / 3.0;
let mu = 0.61;
(gamma * K_B * self.temperature_k / (mu * PROTON_MASS)).sqrt()
}
pub fn thermal_velocity(&self) -> f64 {
(2.0 * K_B * self.temperature_k / PROTON_MASS).sqrt()
}
pub fn spectral_peak_wavelength_m(&self) -> f64 {
2.898e-3 / self.temperature_k
}
pub fn radiation_pressure(&self) -> f64 {
4.0 * SIGMA_SB * self.temperature_k.powi(4) / (3.0 * SPEED_OF_LIGHT)
}
pub fn mean_molecular_weight(&self) -> f64 {
let mu_ion = 1.26;
let ionization_frac = 0.5;
mu_ion / (1.0 + ionization_frac)
}
}
pub fn granulation_lifetime() -> f64 {
GRANULATION_CELL_SIZE_M / GRANULATION_VELOCITY_MS
}
pub fn supergranulation_lifetime() -> f64 {
SUPERGRANULATION_CELL_SIZE_M / SUPERGRANULATION_VELOCITY_MS
}
pub fn effective_temperature_from_luminosity(luminosity: f64) -> f64 {
(luminosity / (4.0 * std::f64::consts::PI * SOLAR_RADIUS * SOLAR_RADIUS * SIGMA_SB)).powf(0.25)
}
pub fn spectral_irradiance_planck(wavelength_m: f64, temperature_k: f64) -> f64 {
let h = crate::PLANCK_H;
let c = SPEED_OF_LIGHT;
let k = K_B;
let a = 2.0 * h * c * c / wavelength_m.powi(5);
let b = (h * c / (wavelength_m * k * temperature_k)).exp() - 1.0;
a / b
}
pub fn bolometric_correction(temperature_k: f64) -> f64 {
let log_t = temperature_k.log10();
if log_t < 3.7 {
-0.4 * (log_t - 3.7)
} else {
-0.09 * (log_t - 3.76).powi(2)
}
}
pub fn wilson_depression_depth(field_t: f64) -> f64 {
let beta = crate::MU_0;
let p_mag = field_t.powi(2) / (2.0 * beta);
p_mag / (PHOTOSPHERE_BASE_DENSITY * crate::SOLAR_SURFACE_GRAVITY)
}