Skip to main content

twine_thermo/
stream.rs

1use twine_core::constraint::{Constrained, ConstraintError, StrictlyPositive};
2use uom::si::f64::{MassRate, Power};
3
4use crate::{
5    PropertyError, State,
6    capability::{HasEnthalpy, ThermoModel},
7};
8
9/// A stream of fluid at a thermodynamic state.
10///
11/// A `Stream` represents steady-state transport of mass and energy without
12/// storing either. For transient systems with mass or energy storage, use a
13/// [`ControlVolume`](crate::ControlVolume).
14///
15/// Zero-flow streams are not physically meaningful.
16/// Use `Option<Stream<Fluid>>` to represent an optional or inactive stream.
17#[derive(Debug, Clone, Copy, PartialEq)]
18pub struct Stream<Fluid> {
19    pub rate: Constrained<MassRate, StrictlyPositive>,
20    pub state: State<Fluid>,
21}
22
23impl<Fluid> Stream<Fluid> {
24    /// Creates a new [`Stream`] from a mass rate and thermodynamic state.
25    ///
26    /// # Errors
27    ///
28    /// Returns a [`ConstraintError`] if `rate` is not strictly positive.
29    pub fn new(rate: MassRate, state: State<Fluid>) -> Result<Self, ConstraintError> {
30        let rate = Constrained::new(rate)?;
31        Ok(Self::from_constrained(rate, state))
32    }
33
34    /// Creates a new [`Stream`] from a pre-validated positive mass rate and state.
35    pub fn from_constrained(
36        rate: Constrained<MassRate, StrictlyPositive>,
37        state: State<Fluid>,
38    ) -> Self {
39        Self { rate, state }
40    }
41
42    /// Returns the enthalpy flow rate of this stream.
43    ///
44    /// This method computes the energy flow carried by the stream as `ṁ · h`,
45    /// where `ṁ` is the mass flow rate and `h` is the enthalpy of its state.
46    ///
47    /// # Errors
48    ///
49    /// Returns a [`PropertyError`] if enthalpy cannot be computed.
50    pub fn enthalpy_flow<Model>(&self, model: &Model) -> Result<Power, PropertyError>
51    where
52        Model: ThermoModel<Fluid = Fluid> + HasEnthalpy,
53    {
54        let m_dot = self.rate.into_inner();
55        let h = model.enthalpy(&self.state)?;
56        Ok(m_dot * h)
57    }
58}