pub struct CloudLayer {
pub name: &'static str,
pub composition: &'static str,
pub base_altitude_m: f64,
pub top_altitude_m: f64,
pub optical_depth: f64,
}
pub struct CloudSystemEndpoint {
pub layers: Vec<CloudLayer>,
}
impl CloudSystemEndpoint {
pub fn titan_default() -> Self {
Self {
layers: vec![
CloudLayer {
name: "stratospheric_haze",
composition: "C4N2 + HCN aerosols",
base_altitude_m: 300_000.0,
top_altitude_m: 500_000.0,
optical_depth: 0.5,
},
CloudLayer {
name: "detached_haze",
composition: "tholin aerosols",
base_altitude_m: 400_000.0,
top_altitude_m: 520_000.0,
optical_depth: 0.3,
},
CloudLayer {
name: "main_haze",
composition: "tholin + nitrile aerosols",
base_altitude_m: 100_000.0,
top_altitude_m: 300_000.0,
optical_depth: 3.0,
},
CloudLayer {
name: "tropospheric_methane",
composition: "CH4 droplets",
base_altitude_m: 8_000.0,
top_altitude_m: 30_000.0,
optical_depth: 1.5,
},
CloudLayer {
name: "low_ethane_fog",
composition: "C2H6 + CH4 condensate",
base_altitude_m: 0.0,
top_altitude_m: 5_000.0,
optical_depth: 0.8,
},
],
}
}
pub fn cloud_top_altitude_m(&self) -> f64 {
self.layers
.iter()
.map(|l| l.top_altitude_m)
.fold(0.0_f64, f64::max)
}
pub fn cloud_base_altitude_m(&self) -> f64 {
self.layers
.iter()
.map(|l| l.base_altitude_m)
.fold(f64::INFINITY, f64::min)
}
pub fn total_optical_depth(&self) -> f64 {
self.layers.iter().map(|l| l.optical_depth).sum()
}
pub fn transmission(&self) -> f64 {
(-self.total_optical_depth()).exp()
}
pub fn layer_at_altitude(&self, altitude_m: f64) -> Option<&CloudLayer> {
self.layers
.iter()
.find(|l| altitude_m >= l.base_altitude_m && altitude_m <= l.top_altitude_m)
}
}