use sciforge::hub::domain::meteorology::radiation::{solar_constant, stefan_boltzmann_flux};
use sciforge::hub::prelude::constants::{ATM_TO_PASCAL, EARTH_MASS, EARTH_RADIUS, G, R_GAS};
pub const SEALEVELPRESSURE: f64 = ATM_TO_PASCAL;
pub const SEALEVELTEMPERATURE: f64 = 288.15;
pub fn dryairmolarmass() -> f64 {
crate::mdryair()
}
pub const LAPSERATETROPOSPHERE: f64 = 0.0065;
pub struct AtmosphericLayer {
pub name: &'static str,
pub basealtitudem: f64,
pub topaltitudem: f64,
pub basetemperaturek: f64,
pub lapseratekperm: f64,
}
impl AtmosphericLayer {
pub fn temperatureat(&self, altitudem: f64) -> f64 {
let h = (altitudem - self.basealtitudem)
.max(0.0)
.min(self.topaltitudem - self.basealtitudem);
self.basetemperaturek - self.lapseratekperm * h
}
pub fn pressureat(&self, altitudem: f64) -> f64 {
let t = self.temperatureat(altitudem);
let h = altitudem - self.basealtitudem;
let g0 = G * EARTH_MASS / (EARTH_RADIUS * EARTH_RADIUS);
if self.lapseratekperm.abs() < 1e-10 {
let pbase = barometricpressure(self.basealtitudem);
pbase * (-g0 * dryairmolarmass() * h / (R_GAS * self.basetemperaturek)).exp()
} else {
let pbase = barometricpressure(self.basealtitudem);
pbase
* (t / self.basetemperaturek)
.powf(g0 * dryairmolarmass() / (R_GAS * self.lapseratekperm))
}
}
pub fn densityat(&self, altitudem: f64) -> f64 {
let p = self.pressureat(altitudem);
let t = self.temperatureat(altitudem);
p * dryairmolarmass() / (R_GAS * t)
}
}
pub fn troposphere() -> AtmosphericLayer {
AtmosphericLayer {
name: "Troposphere",
basealtitudem: 0.0,
topaltitudem: 12000.0,
basetemperaturek: 288.15,
lapseratekperm: 0.0065,
}
}
pub fn stratosphere() -> AtmosphericLayer {
AtmosphericLayer {
name: "Stratosphere",
basealtitudem: 12000.0,
topaltitudem: 50000.0,
basetemperaturek: 216.65,
lapseratekperm: -0.001,
}
}
pub fn mesosphere() -> AtmosphericLayer {
AtmosphericLayer {
name: "Mesosphere",
basealtitudem: 50000.0,
topaltitudem: 85000.0,
basetemperaturek: 270.65,
lapseratekperm: 0.0028,
}
}
pub fn thermosphere() -> AtmosphericLayer {
AtmosphericLayer {
name: "Thermosphere",
basealtitudem: 85000.0,
topaltitudem: 600000.0,
basetemperaturek: 186.87,
lapseratekperm: -0.0017,
}
}
pub fn barometricpressure(altitudem: f64) -> f64 {
let g0 = G * EARTH_MASS / (EARTH_RADIUS * EARTH_RADIUS);
if altitudem <= 12000.0 {
let t = SEALEVELTEMPERATURE - LAPSERATETROPOSPHERE * altitudem;
SEALEVELPRESSURE
* (t / SEALEVELTEMPERATURE)
.powf(g0 * dryairmolarmass() / (R_GAS * LAPSERATETROPOSPHERE))
} else {
let ptropo = barometricpressure(12000.0);
let ttropo = 216.65;
ptropo * (-g0 * dryairmolarmass() * (altitudem - 12000.0) / (R_GAS * ttropo)).exp()
}
}
pub fn scaleheight() -> f64 {
let g0 = G * EARTH_MASS / (EARTH_RADIUS * EARTH_RADIUS);
R_GAS * SEALEVELTEMPERATURE / (dryairmolarmass() * g0)
}
pub fn meansolarirradiance() -> f64 {
solar_constant()
}
pub fn effectivetemperaturek() -> f64 {
let s = solar_constant();
let albedo = 0.306;
stefan_boltzmann_flux(((s * (1.0 - albedo)) / 4.0).powf(0.25))
}