jupiters 0.0.3

Jupiter celestial simulation crate for the MilkyWay SolarSystem workspace
Documentation
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, &deg) 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,
    }
}