pub struct AtmosphericFlow {
pub name: &'static str,
pub lengthkm: f64,
pub widthm: f64,
pub depthm: f64,
pub velocityms: f64,
pub slopedegrees: f64,
pub manningroughness: f64,
}
impl AtmosphericFlow {
pub fn crosssectionaream2(&self) -> f64 {
self.widthm * self.depthm
}
pub fn dischargem3s(&self) -> f64 {
self.crosssectionaream2() * self.velocityms
}
pub fn hydraulicradiusm(&self) -> f64 {
let wetted = self.widthm + 2.0 * self.depthm;
if wetted.abs() < 1e-30 {
return 0.0;
}
self.crosssectionaream2() / wetted
}
pub fn manningvelocityms(&self) -> f64 {
if self.manningroughness.abs() < 1e-30 {
return 0.0;
}
let rh = self.hydraulicradiusm();
let s = self.slopedegrees.to_radians().sin();
if s < 0.0 {
return 0.0;
}
(1.0 / self.manningroughness) * rh.powf(2.0 / 3.0) * s.sqrt()
}
pub fn froudenumber(&self) -> f64 {
if self.depthm.abs() < 1e-30 {
return 0.0;
}
self.velocityms / (9.81 * self.depthm).sqrt()
}
pub fn reynoldsnumber(&self, kinematicviscositym2s: f64) -> f64 {
if kinematicviscositym2s.abs() < 1e-30 {
return 0.0;
}
self.velocityms * self.hydraulicradiusm() / kinematicviscositym2s
}
pub fn shearstressnm2(&self, densitykgm3: f64) -> f64 {
let s = self.slopedegrees.to_radians().sin();
densitykgm3 * 9.81 * self.hydraulicradiusm() * s
}
}
pub struct FlowNetwork {
pub flows: Vec<AtmosphericFlow>,
pub adjacency: Vec<(usize, usize)>,
}
impl FlowNetwork {
pub fn totaldischargem3s(&self) -> f64 {
self.flows.iter().map(|f| f.dischargem3s()).sum()
}
pub fn totallengthkm(&self) -> f64 {
self.flows.iter().map(|f| f.lengthkm).sum()
}
pub fn drainageorderstreams(&self) -> Vec<usize> {
let n = self.flows.len();
let mut indeg = vec![0usize; n];
for &(_, to) in &self.adjacency {
if to < n {
indeg[to] += 1;
}
}
let mut order = Vec::with_capacity(n);
let mut queue = std::collections::VecDeque::new();
for (i, °) in indeg.iter().enumerate().take(n) {
if deg == 0 {
queue.push_back(i);
}
}
while let Some(node) = queue.pop_front() {
order.push(node);
for &(from, to) in &self.adjacency {
if from == node && to < n {
indeg[to] -= 1;
if indeg[to] == 0 {
queue.push_back(to);
}
}
}
}
order
}
pub fn longestpathkm(&self) -> f64 {
let n = self.flows.len();
let mut dist = vec![0.0f64; n];
let order = self.drainageorderstreams();
for &node in &order {
for &(from, to) in &self.adjacency {
if from == node && to < n {
let candidate = dist[from] + self.flows[from].lengthkm;
if candidate > dist[to] {
dist[to] = candidate;
}
}
}
}
dist.iter().copied().fold(0.0f64, f64::max)
}
}
pub fn equatorialjet() -> AtmosphericFlow {
AtmosphericFlow {
name: "Equatorial Jet",
lengthkm: 440_000.0,
widthm: 10_000_000.0,
depthm: 3000.0,
velocityms: 140.0,
slopedegrees: 0.001,
manningroughness: 0.015,
}
}
pub fn polarjet() -> AtmosphericFlow {
AtmosphericFlow {
name: "Polar Jet",
lengthkm: 120_000.0,
widthm: 5_000_000.0,
depthm: 2000.0,
velocityms: 60.0,
slopedegrees: 0.0005,
manningroughness: 0.02,
}
}