earths 0.0.4

High-fidelity Earth simulation engine — orbit, atmosphere, geology, hydrology, biosphere, terrain, lighting, rendering, satellites, and temporal systems with full scientific coupling
Documentation
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))
}