chore: sync project state and current artifacts
This commit is contained in:
@@ -74,7 +74,7 @@
|
||||
//! ```
|
||||
|
||||
use crate::{
|
||||
Component, ComponentError, ConnectedPort, JacobianBuilder, ResidualVector, SystemState,
|
||||
Component, ComponentError, ConnectedPort, JacobianBuilder, ResidualVector, StateSlice,
|
||||
};
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
@@ -195,7 +195,12 @@ impl FlowSplitter {
|
||||
"FlowSplitter with 1 outlet is just a pipe — use a Pipe component instead".into(),
|
||||
));
|
||||
}
|
||||
Ok(Self { kind, fluid_id: fluid, inlet, outlets })
|
||||
Ok(Self {
|
||||
kind,
|
||||
fluid_id: fluid,
|
||||
inlet,
|
||||
outlets,
|
||||
})
|
||||
}
|
||||
|
||||
// ── Accessors ─────────────────────────────────────────────────────────────
|
||||
@@ -238,7 +243,7 @@ impl Component for FlowSplitter {
|
||||
|
||||
fn compute_residuals(
|
||||
&self,
|
||||
_state: &SystemState,
|
||||
_state: &StateSlice,
|
||||
residuals: &mut ResidualVector,
|
||||
) -> Result<(), ComponentError> {
|
||||
let n_eqs = self.n_equations();
|
||||
@@ -286,7 +291,7 @@ impl Component for FlowSplitter {
|
||||
|
||||
fn jacobian_entries(
|
||||
&self,
|
||||
_state: &SystemState,
|
||||
_state: &StateSlice,
|
||||
jacobian: &mut JacobianBuilder,
|
||||
) -> Result<(), ComponentError> {
|
||||
// All residuals are linear differences → constant Jacobian.
|
||||
@@ -312,6 +317,65 @@ impl Component for FlowSplitter {
|
||||
// the actual solver coupling is via the System graph edges.
|
||||
&[]
|
||||
}
|
||||
|
||||
fn port_mass_flows(
|
||||
&self,
|
||||
state: &StateSlice,
|
||||
) -> Result<Vec<entropyk_core::MassFlow>, ComponentError> {
|
||||
// FlowSplitter: 1 inlet → N outlets
|
||||
// Mass balance: inlet = sum of outlets
|
||||
// State layout: [m_in, m_out_1, m_out_2, ...]
|
||||
let n_outlets = self.n_outlets();
|
||||
if state.len() < 1 + n_outlets {
|
||||
return Err(ComponentError::InvalidStateDimensions {
|
||||
expected: 1 + n_outlets,
|
||||
actual: state.len(),
|
||||
});
|
||||
}
|
||||
|
||||
let mut flows = Vec::with_capacity(1 + n_outlets);
|
||||
// Inlet (positive = entering)
|
||||
flows.push(entropyk_core::MassFlow::from_kg_per_s(state[0]));
|
||||
// Outlets (negative = leaving)
|
||||
for i in 0..n_outlets {
|
||||
flows.push(entropyk_core::MassFlow::from_kg_per_s(-state[1 + i]));
|
||||
}
|
||||
Ok(flows)
|
||||
}
|
||||
|
||||
/// Returns the enthalpies of all ports (inlet first, then outlets).
|
||||
///
|
||||
/// For a flow splitter, the enthalpy is conserved across branches:
|
||||
/// `h_in = h_out_1 = h_out_2 = ...` (isenthalpic split).
|
||||
fn port_enthalpies(
|
||||
&self,
|
||||
_state: &StateSlice,
|
||||
) -> Result<Vec<entropyk_core::Enthalpy>, ComponentError> {
|
||||
let mut enthalpies = Vec::with_capacity(1 + self.outlets.len());
|
||||
|
||||
enthalpies.push(self.inlet.enthalpy());
|
||||
|
||||
for outlet in &self.outlets {
|
||||
enthalpies.push(outlet.enthalpy());
|
||||
}
|
||||
|
||||
Ok(enthalpies)
|
||||
}
|
||||
|
||||
/// Returns the energy transfers for the flow splitter.
|
||||
///
|
||||
/// A flow splitter is adiabatic:
|
||||
/// - **Heat (Q)**: 0 W (no heat exchange with environment)
|
||||
/// - **Work (W)**: 0 W (no mechanical work)
|
||||
fn energy_transfers(
|
||||
&self,
|
||||
_state: &StateSlice,
|
||||
) -> Option<(entropyk_core::Power, entropyk_core::Power)> {
|
||||
Some((
|
||||
entropyk_core::Power::from_watts(0.0),
|
||||
entropyk_core::Power::from_watts(0.0),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
@@ -462,7 +526,10 @@ impl FlowMerger {
|
||||
let total_flow: f64 = weights.iter().sum();
|
||||
if total_flow <= 0.0 {
|
||||
// Fall back to equal weighting
|
||||
self.inlets.iter().map(|p| p.enthalpy().to_joules_per_kg()).sum::<f64>()
|
||||
self.inlets
|
||||
.iter()
|
||||
.map(|p| p.enthalpy().to_joules_per_kg())
|
||||
.sum::<f64>()
|
||||
/ n as f64
|
||||
} else {
|
||||
self.inlets
|
||||
@@ -475,7 +542,10 @@ impl FlowMerger {
|
||||
}
|
||||
None => {
|
||||
// Equal weighting
|
||||
self.inlets.iter().map(|p| p.enthalpy().to_joules_per_kg()).sum::<f64>()
|
||||
self.inlets
|
||||
.iter()
|
||||
.map(|p| p.enthalpy().to_joules_per_kg())
|
||||
.sum::<f64>()
|
||||
/ n as f64
|
||||
}
|
||||
}
|
||||
@@ -493,7 +563,7 @@ impl Component for FlowMerger {
|
||||
|
||||
fn compute_residuals(
|
||||
&self,
|
||||
_state: &SystemState,
|
||||
_state: &StateSlice,
|
||||
residuals: &mut ResidualVector,
|
||||
) -> Result<(), ComponentError> {
|
||||
let n_eqs = self.n_equations();
|
||||
@@ -529,7 +599,7 @@ impl Component for FlowMerger {
|
||||
|
||||
fn jacobian_entries(
|
||||
&self,
|
||||
_state: &SystemState,
|
||||
_state: &StateSlice,
|
||||
jacobian: &mut JacobianBuilder,
|
||||
) -> Result<(), ComponentError> {
|
||||
// Diagonal approximation — the full coupling is resolved by the System
|
||||
@@ -544,6 +614,65 @@ impl Component for FlowMerger {
|
||||
fn get_ports(&self) -> &[ConnectedPort] {
|
||||
&[]
|
||||
}
|
||||
|
||||
fn port_mass_flows(
|
||||
&self,
|
||||
state: &StateSlice,
|
||||
) -> Result<Vec<entropyk_core::MassFlow>, ComponentError> {
|
||||
// FlowMerger: N inlets → 1 outlet
|
||||
// Mass balance: sum of inlets = outlet
|
||||
// State layout: [m_in_1, m_in_2, ..., m_out]
|
||||
let n_inlets = self.n_inlets();
|
||||
if state.len() < n_inlets + 1 {
|
||||
return Err(ComponentError::InvalidStateDimensions {
|
||||
expected: n_inlets + 1,
|
||||
actual: state.len(),
|
||||
});
|
||||
}
|
||||
|
||||
let mut flows = Vec::with_capacity(n_inlets + 1);
|
||||
// Inlets (positive = entering)
|
||||
for i in 0..n_inlets {
|
||||
flows.push(entropyk_core::MassFlow::from_kg_per_s(state[i]));
|
||||
}
|
||||
// Outlet (negative = leaving)
|
||||
flows.push(entropyk_core::MassFlow::from_kg_per_s(-state[n_inlets]));
|
||||
Ok(flows)
|
||||
}
|
||||
|
||||
/// Returns the enthalpies of all ports (inlets first, then outlet).
|
||||
///
|
||||
/// For a flow merger, the outlet enthalpy is determined by
|
||||
/// the mixing of inlet streams (mass-weighted average).
|
||||
fn port_enthalpies(
|
||||
&self,
|
||||
_state: &StateSlice,
|
||||
) -> Result<Vec<entropyk_core::Enthalpy>, ComponentError> {
|
||||
let mut enthalpies = Vec::with_capacity(self.inlets.len() + 1);
|
||||
|
||||
for inlet in &self.inlets {
|
||||
enthalpies.push(inlet.enthalpy());
|
||||
}
|
||||
|
||||
enthalpies.push(self.outlet.enthalpy());
|
||||
|
||||
Ok(enthalpies)
|
||||
}
|
||||
|
||||
/// Returns the energy transfers for the flow merger.
|
||||
///
|
||||
/// A flow merger is adiabatic:
|
||||
/// - **Heat (Q)**: 0 W (no heat exchange with environment)
|
||||
/// - **Work (W)**: 0 W (no mechanical work)
|
||||
fn energy_transfers(
|
||||
&self,
|
||||
_state: &StateSlice,
|
||||
) -> Option<(entropyk_core::Power, entropyk_core::Power)> {
|
||||
Some((
|
||||
entropyk_core::Power::from_watts(0.0),
|
||||
entropyk_core::Power::from_watts(0.0),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
@@ -599,8 +728,8 @@ mod tests {
|
||||
#[test]
|
||||
fn test_splitter_incompressible_creation() {
|
||||
let inlet = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_a = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_b = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_a = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_b = make_port("Water", 3.0e5, 2.0e5);
|
||||
|
||||
let s = FlowSplitter::incompressible("Water", inlet, vec![out_a, out_b]).unwrap();
|
||||
assert_eq!(s.n_outlets(), 2);
|
||||
@@ -612,9 +741,9 @@ mod tests {
|
||||
#[test]
|
||||
fn test_splitter_compressible_creation() {
|
||||
let inlet = make_port("R410A", 24.0e5, 4.65e5);
|
||||
let out_a = make_port("R410A", 24.0e5, 4.65e5);
|
||||
let out_b = make_port("R410A", 24.0e5, 4.65e5);
|
||||
let out_c = make_port("R410A", 24.0e5, 4.65e5);
|
||||
let out_a = make_port("R410A", 24.0e5, 4.65e5);
|
||||
let out_b = make_port("R410A", 24.0e5, 4.65e5);
|
||||
let out_c = make_port("R410A", 24.0e5, 4.65e5);
|
||||
|
||||
let s = FlowSplitter::compressible("R410A", inlet, vec![out_a, out_b, out_c]).unwrap();
|
||||
assert_eq!(s.n_outlets(), 3);
|
||||
@@ -626,16 +755,19 @@ mod tests {
|
||||
#[test]
|
||||
fn test_splitter_rejects_refrigerant_as_incompressible() {
|
||||
let inlet = make_port("R410A", 24.0e5, 4.65e5);
|
||||
let out_a = make_port("R410A", 24.0e5, 4.65e5);
|
||||
let out_b = make_port("R410A", 24.0e5, 4.65e5);
|
||||
let out_a = make_port("R410A", 24.0e5, 4.65e5);
|
||||
let out_b = make_port("R410A", 24.0e5, 4.65e5);
|
||||
let result = FlowSplitter::incompressible("R410A", inlet, vec![out_a, out_b]);
|
||||
assert!(result.is_err(), "R410A should not be accepted as incompressible");
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"R410A should not be accepted as incompressible"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_splitter_rejects_single_outlet() {
|
||||
let inlet = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out = make_port("Water", 3.0e5, 2.0e5);
|
||||
let result = FlowSplitter::incompressible("Water", inlet, vec![out]);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
@@ -644,8 +776,8 @@ mod tests {
|
||||
fn test_splitter_residuals_zero_at_consistent_state() {
|
||||
// Consistent state: all pressures and enthalpies equal
|
||||
let inlet = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_a = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_b = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_a = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_b = make_port("Water", 3.0e5, 2.0e5);
|
||||
|
||||
let s = FlowSplitter::incompressible("Water", inlet, vec![out_a, out_b]).unwrap();
|
||||
let state = vec![0.0; 6]; // dummy, not used by current impl
|
||||
@@ -656,7 +788,8 @@ mod tests {
|
||||
assert!(
|
||||
r.abs() < 1.0,
|
||||
"residual[{}] = {} should be ≈ 0 for consistent state",
|
||||
i, r
|
||||
i,
|
||||
r
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -664,8 +797,8 @@ mod tests {
|
||||
#[test]
|
||||
fn test_splitter_residuals_nonzero_on_pressure_mismatch() {
|
||||
let inlet = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_a = make_port("Water", 2.5e5, 2.0e5); // lower pressure!
|
||||
let out_b = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_a = make_port("Water", 2.5e5, 2.0e5); // lower pressure!
|
||||
let out_b = make_port("Water", 3.0e5, 2.0e5);
|
||||
|
||||
let s = FlowSplitter::incompressible("Water", inlet, vec![out_a, out_b]).unwrap();
|
||||
let state = vec![0.0; 6];
|
||||
@@ -673,7 +806,11 @@ mod tests {
|
||||
s.compute_residuals(&state, &mut res).unwrap();
|
||||
|
||||
// r[0] = P_out_a - P_in = 2.5e5 - 3.0e5 = -0.5e5
|
||||
assert!((res[0] - (-0.5e5)).abs() < 1.0, "expected -0.5e5, got {}", res[0]);
|
||||
assert!(
|
||||
(res[0] - (-0.5e5)).abs() < 1.0,
|
||||
"expected -0.5e5, got {}",
|
||||
res[0]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -688,8 +825,8 @@ mod tests {
|
||||
#[test]
|
||||
fn test_splitter_water_type_aliases() {
|
||||
let inlet = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_a = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_b = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_a = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_b = make_port("Water", 3.0e5, 2.0e5);
|
||||
|
||||
// IncompressibleSplitter is a type alias for FlowSplitter
|
||||
let _s: IncompressibleSplitter =
|
||||
@@ -700,8 +837,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_merger_incompressible_creation() {
|
||||
let in_a = make_port("Water", 3.0e5, 2.0e5);
|
||||
let in_b = make_port("Water", 3.0e5, 2.4e5);
|
||||
let in_a = make_port("Water", 3.0e5, 2.0e5);
|
||||
let in_b = make_port("Water", 3.0e5, 2.4e5);
|
||||
let outlet = make_port("Water", 3.0e5, 2.2e5);
|
||||
|
||||
let m = FlowMerger::incompressible("Water", vec![in_a, in_b], outlet).unwrap();
|
||||
@@ -713,9 +850,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_merger_compressible_creation() {
|
||||
let in_a = make_port("R134a", 8.0e5, 4.0e5);
|
||||
let in_b = make_port("R134a", 8.0e5, 4.2e5);
|
||||
let in_c = make_port("R134a", 8.0e5, 3.8e5);
|
||||
let in_a = make_port("R134a", 8.0e5, 4.0e5);
|
||||
let in_b = make_port("R134a", 8.0e5, 4.2e5);
|
||||
let in_c = make_port("R134a", 8.0e5, 3.8e5);
|
||||
let outlet = make_port("R134a", 8.0e5, 4.0e5);
|
||||
|
||||
let m = FlowMerger::compressible("R134a", vec![in_a, in_b, in_c], outlet).unwrap();
|
||||
@@ -727,7 +864,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_merger_rejects_single_inlet() {
|
||||
let in_a = make_port("Water", 3.0e5, 2.0e5);
|
||||
let in_a = make_port("Water", 3.0e5, 2.0e5);
|
||||
let outlet = make_port("Water", 3.0e5, 2.0e5);
|
||||
let result = FlowMerger::incompressible("Water", vec![in_a], outlet);
|
||||
assert!(result.is_err());
|
||||
@@ -738,8 +875,8 @@ mod tests {
|
||||
// Equal branches → mixed enthalpy = inlet enthalpy
|
||||
let h = 2.0e5_f64;
|
||||
let p = 3.0e5_f64;
|
||||
let in_a = make_port("Water", p, h);
|
||||
let in_b = make_port("Water", p, h);
|
||||
let in_a = make_port("Water", p, h);
|
||||
let in_b = make_port("Water", p, h);
|
||||
let outlet = make_port("Water", p, h); // h_mixed = (h+h)/2 = h
|
||||
|
||||
let m = FlowMerger::incompressible("Water", vec![in_a, in_b], outlet).unwrap();
|
||||
@@ -759,8 +896,8 @@ mod tests {
|
||||
let h_expected = (h_a + h_b) / 2.0; // equal-weight average
|
||||
let p = 3.0e5_f64;
|
||||
|
||||
let in_a = make_port("Water", p, h_a);
|
||||
let in_b = make_port("Water", p, h_b);
|
||||
let in_a = make_port("Water", p, h_a);
|
||||
let in_b = make_port("Water", p, h_b);
|
||||
let outlet = make_port("Water", p, h_expected);
|
||||
|
||||
let m = FlowMerger::incompressible("Water", vec![in_a, in_b], outlet).unwrap();
|
||||
@@ -779,8 +916,8 @@ mod tests {
|
||||
// ṁ_b = 0.7 kg/s, h_b = 3e5 J/kg
|
||||
// h_mix = (0.3*2e5 + 0.7*3e5) / 1.0 = (6e4 + 21e4) = 2.7e5 J/kg
|
||||
let p = 3.0e5_f64;
|
||||
let in_a = make_port("Water", p, 2.0e5);
|
||||
let in_b = make_port("Water", p, 3.0e5);
|
||||
let in_a = make_port("Water", p, 2.0e5);
|
||||
let in_b = make_port("Water", p, 3.0e5);
|
||||
let outlet = make_port("Water", p, 2.7e5);
|
||||
|
||||
let m = FlowMerger::incompressible("Water", vec![in_a, in_b], outlet)
|
||||
@@ -802,25 +939,130 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_merger_as_trait_object() {
|
||||
let in_a = make_port("Water", 3.0e5, 2.0e5);
|
||||
let in_b = make_port("Water", 3.0e5, 2.0e5);
|
||||
let in_a = make_port("Water", 3.0e5, 2.0e5);
|
||||
let in_b = make_port("Water", 3.0e5, 2.0e5);
|
||||
let outlet = make_port("Water", 3.0e5, 2.0e5);
|
||||
|
||||
let merger: Box<dyn Component> = Box::new(
|
||||
FlowMerger::incompressible("Water", vec![in_a, in_b], outlet).unwrap()
|
||||
);
|
||||
let merger: Box<dyn Component> =
|
||||
Box::new(FlowMerger::incompressible("Water", vec![in_a, in_b], outlet).unwrap());
|
||||
assert_eq!(merger.n_equations(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_splitter_as_trait_object() {
|
||||
let inlet = make_port("R410A", 24.0e5, 4.65e5);
|
||||
let out_a = make_port("R410A", 24.0e5, 4.65e5);
|
||||
let out_b = make_port("R410A", 24.0e5, 4.65e5);
|
||||
let out_a = make_port("R410A", 24.0e5, 4.65e5);
|
||||
let out_b = make_port("R410A", 24.0e5, 4.65e5);
|
||||
|
||||
let splitter: Box<dyn Component> = Box::new(
|
||||
FlowSplitter::compressible("R410A", inlet, vec![out_a, out_b]).unwrap()
|
||||
);
|
||||
let splitter: Box<dyn Component> =
|
||||
Box::new(FlowSplitter::compressible("R410A", inlet, vec![out_a, out_b]).unwrap());
|
||||
assert_eq!(splitter.n_equations(), 3);
|
||||
}
|
||||
|
||||
// ── energy_transfers tests ─────────────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn test_splitter_energy_transfers_zero() {
|
||||
let inlet = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_a = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_b = make_port("Water", 3.0e5, 2.0e5);
|
||||
|
||||
let splitter = FlowSplitter::incompressible("Water", inlet, vec![out_a, out_b]).unwrap();
|
||||
let state = vec![0.0; 6];
|
||||
|
||||
let (heat, work) = splitter.energy_transfers(&state).unwrap();
|
||||
|
||||
assert_eq!(heat.to_watts(), 0.0);
|
||||
assert_eq!(work.to_watts(), 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merger_energy_transfers_zero() {
|
||||
let in_a = make_port("Water", 3.0e5, 2.0e5);
|
||||
let in_b = make_port("Water", 3.0e5, 2.4e5);
|
||||
let outlet = make_port("Water", 3.0e5, 2.2e5);
|
||||
|
||||
let merger = FlowMerger::incompressible("Water", vec![in_a, in_b], outlet).unwrap();
|
||||
let state = vec![0.0; 6];
|
||||
|
||||
let (heat, work) = merger.energy_transfers(&state).unwrap();
|
||||
|
||||
assert_eq!(heat.to_watts(), 0.0);
|
||||
assert_eq!(work.to_watts(), 0.0);
|
||||
}
|
||||
|
||||
// ── port_enthalpies tests ──────────────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn test_splitter_port_enthalpies_count() {
|
||||
let inlet = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_a = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_b = make_port("Water", 3.0e5, 2.0e5);
|
||||
let out_c = make_port("Water", 3.0e5, 2.0e5);
|
||||
|
||||
let splitter =
|
||||
FlowSplitter::incompressible("Water", inlet, vec![out_a, out_b, out_c]).unwrap();
|
||||
let state = vec![0.0; 8];
|
||||
|
||||
let enthalpies = splitter.port_enthalpies(&state).unwrap();
|
||||
|
||||
// 1 inlet + 3 outlets = 4 enthalpies
|
||||
assert_eq!(enthalpies.len(), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merger_port_enthalpies_count() {
|
||||
let in_a = make_port("Water", 3.0e5, 2.0e5);
|
||||
let in_b = make_port("Water", 3.0e5, 2.4e5);
|
||||
let in_c = make_port("Water", 3.0e5, 2.2e5);
|
||||
let outlet = make_port("Water", 3.0e5, 2.2e5);
|
||||
|
||||
let merger = FlowMerger::incompressible("Water", vec![in_a, in_b, in_c], outlet).unwrap();
|
||||
let state = vec![0.0; 8];
|
||||
|
||||
let enthalpies = merger.port_enthalpies(&state).unwrap();
|
||||
|
||||
// 3 inlets + 1 outlet = 4 enthalpies
|
||||
assert_eq!(enthalpies.len(), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_splitter_port_enthalpies_values() {
|
||||
let h_in = 2.5e5_f64;
|
||||
let h_out_a = 2.5e5_f64;
|
||||
let h_out_b = 2.5e5_f64;
|
||||
|
||||
let inlet = make_port("Water", 3.0e5, h_in);
|
||||
let out_a = make_port("Water", 3.0e5, h_out_a);
|
||||
let out_b = make_port("Water", 3.0e5, h_out_b);
|
||||
|
||||
let splitter = FlowSplitter::incompressible("Water", inlet, vec![out_a, out_b]).unwrap();
|
||||
let state = vec![0.0; 6];
|
||||
|
||||
let enthalpies = splitter.port_enthalpies(&state).unwrap();
|
||||
|
||||
assert_eq!(enthalpies[0].to_joules_per_kg(), h_in);
|
||||
assert_eq!(enthalpies[1].to_joules_per_kg(), h_out_a);
|
||||
assert_eq!(enthalpies[2].to_joules_per_kg(), h_out_b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merger_port_enthalpies_values() {
|
||||
let h_in_a = 2.0e5_f64;
|
||||
let h_in_b = 3.0e5_f64;
|
||||
let h_out = 2.5e5_f64;
|
||||
|
||||
let in_a = make_port("Water", 3.0e5, h_in_a);
|
||||
let in_b = make_port("Water", 3.0e5, h_in_b);
|
||||
let outlet = make_port("Water", 3.0e5, h_out);
|
||||
|
||||
let merger = FlowMerger::incompressible("Water", vec![in_a, in_b], outlet).unwrap();
|
||||
let state = vec![0.0; 6];
|
||||
|
||||
let enthalpies = merger.port_enthalpies(&state).unwrap();
|
||||
|
||||
assert_eq!(enthalpies[0].to_joules_per_kg(), h_in_a);
|
||||
assert_eq!(enthalpies[1].to_joules_per_kg(), h_in_b);
|
||||
assert_eq!(enthalpies[2].to_joules_per_kg(), h_out);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user