use std::marker::PhantomData;
use crate::support::hx::{
CapacitanceRate, Effectiveness, Ntu,
effectiveness_ntu::{EffectivenessRelation, NtuRelation, effectiveness_via, ntu_via},
};
#[derive(Debug, Clone, Copy, Default)]
pub struct CrossFlow<T: MixState, U: MixState> {
_marker: PhantomData<(T, U)>,
}
impl<T: MixState, U: MixState> CrossFlow<T, U> {
#[must_use]
pub const fn new() -> Self {
Self {
_marker: PhantomData,
}
}
}
pub struct Mixed;
pub struct Unmixed;
pub trait MixState {}
impl MixState for Mixed {}
impl MixState for Unmixed {}
impl EffectivenessRelation for CrossFlow<Unmixed, Unmixed> {
fn effectiveness(&self, ntu: Ntu, capacitance_rates: [CapacitanceRate; 2]) -> Effectiveness {
effectiveness_via(ntu, capacitance_rates, |ntu, cr| {
1. - ((ntu.powf(0.22) / cr) * ((-cr * ntu.powf(0.78)).exp() - 1.)).exp()
})
}
}
impl EffectivenessRelation for CrossFlow<Mixed, Mixed> {
fn effectiveness(&self, ntu: Ntu, capacitance_rates: [CapacitanceRate; 2]) -> Effectiveness {
effectiveness_via(ntu, capacitance_rates, |ntu, cr| {
1. / (1. / (1. - (-ntu).exp()) + cr / (1. - (-cr * ntu).exp()) - 1. / ntu)
})
}
}
impl EffectivenessRelation for CrossFlow<Mixed, Unmixed> {
fn effectiveness(&self, ntu: Ntu, capacitance_rates: [CapacitanceRate; 2]) -> Effectiveness {
if capacitance_rates[0] >= capacitance_rates[1] {
effectiveness_via(ntu, capacitance_rates, |ntu, cr| {
(1. - (cr * ((-ntu).exp() - 1.)).exp()) / cr
})
} else {
effectiveness_via(ntu, capacitance_rates, |ntu, cr| {
1. - (-((1. - (-cr * ntu).exp()) / cr)).exp()
})
}
}
}
impl EffectivenessRelation for CrossFlow<Unmixed, Mixed> {
fn effectiveness(&self, ntu: Ntu, capacitance_rates: [CapacitanceRate; 2]) -> Effectiveness {
CrossFlow::<Mixed, Unmixed>::new()
.effectiveness(ntu, [capacitance_rates[1], capacitance_rates[0]])
}
}
impl NtuRelation for CrossFlow<Mixed, Unmixed> {
fn ntu(&self, effectiveness: Effectiveness, capacitance_rates: [CapacitanceRate; 2]) -> Ntu {
if capacitance_rates[0] >= capacitance_rates[1] {
ntu_via(effectiveness, capacitance_rates, |eff, cr| {
-(1. + (1. - eff * cr).ln() / cr).ln()
})
} else {
ntu_via(effectiveness, capacitance_rates, |eff, cr| {
-(cr * (1. - eff).ln() + 1.).ln() / cr
})
}
}
}
impl NtuRelation for CrossFlow<Unmixed, Mixed> {
fn ntu(&self, effectiveness: Effectiveness, capacitance_rates: [CapacitanceRate; 2]) -> Ntu {
CrossFlow::<Mixed, Unmixed>::new()
.ntu(effectiveness, [capacitance_rates[1], capacitance_rates[0]])
}
}
#[cfg(test)]
mod tests {
use crate::support::constraint::ConstraintResult;
use approx::assert_relative_eq;
use uom::si::{ratio::ratio, thermal_conductance::watt_per_kelvin};
use super::*;
#[test]
fn roundtrip() -> ConstraintResult<()> {
let ntus = [0., 0.1, 0.5, 1., 5.];
let capacitance_rates = [
[1., f64::INFINITY],
[1., 4.],
[1., 2.],
[1., 1.],
[2., 1.],
[4., 1.],
[f64::INFINITY, 1.],
];
for ntu in ntus {
for pair in capacitance_rates {
let rates = [
CapacitanceRate::new::<watt_per_kelvin>(pair[0])?,
CapacitanceRate::new::<watt_per_kelvin>(pair[1])?,
];
let mixed_unmixed = CrossFlow::<Mixed, Unmixed>::new();
let eff = mixed_unmixed.effectiveness(Ntu::new(ntu)?, rates);
let back = mixed_unmixed.ntu(eff, rates);
assert_relative_eq!(back.get::<ratio>(), ntu, max_relative = 1e-12);
}
}
Ok(())
}
}