Add diagram workbench UI with Modelica DoF coaching and ISO glyphs.
Ship the Next.js cycle editor with CAD chrome, technical HX symbols, Fixed/Free boundary guidance, and secondary water/air pressure drop support in the solver stack. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
190
crates/components/src/heat_exchanger/shell_and_tube.rs
Normal file
190
crates/components/src/heat_exchanger/shell_and_tube.rs
Normal file
@@ -0,0 +1,190 @@
|
||||
//! Shell-and-tube heat exchanger rating via Bell–Delaware shell-side factors.
|
||||
//!
|
||||
//! Computes shell-side HTC `h_s = h_ideal · J_C · J_L · J_B · J_R · J_S` and a
|
||||
//! combined UA with tube-side Gnielinski / Cooper / Shah as selected.
|
||||
|
||||
use super::bphx_correlation::{BphxCorrelation, CorrelationParams, FlowRegime};
|
||||
use super::correlation_registry::CorrelationId;
|
||||
use super::pool_boiling::{cooper_1984, PoolBoilingInput};
|
||||
|
||||
/// Geometric inputs for Bell–Delaware correction factors.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct BellDelawareGeometry {
|
||||
/// Fraction of tubes in cross-flow (F_C ≈ 1 − 2 F_W).
|
||||
pub f_c: f64,
|
||||
/// Leakage area ratio r_s = S_sb / (S_sb + S_tb).
|
||||
pub r_s: f64,
|
||||
/// Leakage/main stream area ratio r_lm = (S_sb + S_tb) / S_m.
|
||||
pub r_lm: f64,
|
||||
/// Bypass correction J_B (typical 0.7–0.9).
|
||||
pub j_b: f64,
|
||||
/// Laminar gradient correction J_R (1.0 if Re_s ≥ 100).
|
||||
pub j_r: f64,
|
||||
/// Unequal baffle spacing correction J_S (1.0 if uniform).
|
||||
pub j_s: f64,
|
||||
/// Ideal cross-flow HTC [W/(m²·K)] before corrections.
|
||||
pub h_ideal: f64,
|
||||
/// Shell-side area [m²].
|
||||
pub area_shell_m2: f64,
|
||||
/// Tube-side area [m²].
|
||||
pub area_tube_m2: f64,
|
||||
}
|
||||
|
||||
impl Default for BellDelawareGeometry {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
f_c: 0.9,
|
||||
r_s: 0.4,
|
||||
r_lm: 0.3,
|
||||
j_b: 0.8,
|
||||
j_r: 1.0,
|
||||
j_s: 1.0,
|
||||
h_ideal: 2500.0,
|
||||
area_shell_m2: 30.0,
|
||||
area_tube_m2: 25.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Bell–Delaware correction factors.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct BellDelawareFactors {
|
||||
/// Configuration factor J_C.
|
||||
pub j_c: f64,
|
||||
/// Leakage factor J_L.
|
||||
pub j_l: f64,
|
||||
/// Bypass factor J_B.
|
||||
pub j_b: f64,
|
||||
/// Laminar factor J_R.
|
||||
pub j_r: f64,
|
||||
/// Spacing factor J_S.
|
||||
pub j_s: f64,
|
||||
}
|
||||
|
||||
/// Computes J-factors from geometry (Taborek / Delaware handbook forms).
|
||||
pub fn bell_delaware_factors(geom: &BellDelawareGeometry) -> BellDelawareFactors {
|
||||
let j_c = 0.55 + 0.72 * geom.f_c.clamp(0.0, 1.0);
|
||||
let j_l = 0.44 * (1.0 - geom.r_s)
|
||||
+ (1.0 - 0.44 * (1.0 - geom.r_s)) * (-2.2 * geom.r_lm).exp();
|
||||
BellDelawareFactors {
|
||||
j_c: j_c.clamp(0.65, 1.15),
|
||||
j_l: j_l.clamp(0.2, 1.0),
|
||||
j_b: geom.j_b.clamp(0.7, 0.9),
|
||||
j_r: geom.j_r.clamp(0.7, 1.0),
|
||||
j_s: geom.j_s.clamp(0.8, 1.0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Shell-side HTC after Bell–Delaware corrections [W/(m²·K)].
|
||||
pub fn shell_side_htc(geom: &BellDelawareGeometry) -> f64 {
|
||||
let f = bell_delaware_factors(geom);
|
||||
geom.h_ideal * f.j_c * f.j_l * f.j_b * f.j_r * f.j_s
|
||||
}
|
||||
|
||||
/// Tube-side HTC using a registered correlation [W/(m²·K)].
|
||||
pub fn tube_side_htc(
|
||||
correlation: CorrelationId,
|
||||
params: &CorrelationParams,
|
||||
pool: Option<&PoolBoilingInput>,
|
||||
) -> f64 {
|
||||
match correlation {
|
||||
CorrelationId::Cooper1984 => pool
|
||||
.and_then(|p| cooper_1984(p).ok())
|
||||
.unwrap_or(3000.0),
|
||||
CorrelationId::Gnielinski1976 => BphxCorrelation::Gnielinski1976.compute_htc(params).h,
|
||||
CorrelationId::Shah2009 => BphxCorrelation::Shah2009.compute_htc(params).h,
|
||||
CorrelationId::Shah1979 => BphxCorrelation::Shah1979.compute_htc(params).h,
|
||||
CorrelationId::Cavallini2006 => BphxCorrelation::Cavallini2006.compute_htc(params).h,
|
||||
CorrelationId::Kandlikar1990 => BphxCorrelation::Kandlikar1990.compute_htc(params).h,
|
||||
_ => BphxCorrelation::Gnielinski1976.compute_htc(params).h,
|
||||
}
|
||||
}
|
||||
|
||||
/// Combined UA [W/K] from shell and tube sides (wall resistance neglected).
|
||||
pub fn shell_and_tube_ua(
|
||||
geom: &BellDelawareGeometry,
|
||||
h_tube: f64,
|
||||
) -> f64 {
|
||||
let h_shell = shell_side_htc(geom);
|
||||
let r = 1.0 / (h_shell.max(1.0) * geom.area_shell_m2.max(1e-9))
|
||||
+ 1.0 / (h_tube.max(1.0) * geom.area_tube_m2.max(1e-9));
|
||||
1.0 / r
|
||||
}
|
||||
|
||||
/// Rating helper wrapping Bell–Delaware + tube correlation.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ShellAndTubeHx {
|
||||
geom: BellDelawareGeometry,
|
||||
tube_correlation: CorrelationId,
|
||||
last_ua: f64,
|
||||
}
|
||||
|
||||
impl ShellAndTubeHx {
|
||||
/// Creates a shell-and-tube rater with default geometry.
|
||||
pub fn new(geom: BellDelawareGeometry) -> Self {
|
||||
Self {
|
||||
geom,
|
||||
tube_correlation: CorrelationId::Gnielinski1976,
|
||||
last_ua: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Selects tube-side correlation.
|
||||
pub fn with_tube_correlation(mut self, id: CorrelationId) -> Self {
|
||||
self.tube_correlation = id;
|
||||
self
|
||||
}
|
||||
|
||||
/// Rates UA from operating tube-side params.
|
||||
pub fn rate_ua(&mut self, params: &CorrelationParams) -> f64 {
|
||||
let h_tube = tube_side_htc(self.tube_correlation, params, None);
|
||||
self.last_ua = shell_and_tube_ua(&self.geom, h_tube);
|
||||
self.last_ua
|
||||
}
|
||||
|
||||
/// Last computed UA [W/K].
|
||||
pub fn ua(&self) -> f64 {
|
||||
self.last_ua
|
||||
}
|
||||
|
||||
/// Geometry accessor.
|
||||
pub fn geometry(&self) -> &BellDelawareGeometry {
|
||||
&self.geom
|
||||
}
|
||||
}
|
||||
|
||||
/// Default condensation CorrelationParams for tube-side rating.
|
||||
pub fn default_tube_params(regime: FlowRegime) -> CorrelationParams {
|
||||
CorrelationParams {
|
||||
regime,
|
||||
mass_flux: 200.0,
|
||||
..CorrelationParams::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn factors_in_expected_bands() {
|
||||
let f = bell_delaware_factors(&BellDelawareGeometry::default());
|
||||
assert!(f.j_c >= 0.65 && f.j_c <= 1.15);
|
||||
assert!(f.j_l >= 0.2 && f.j_l <= 1.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shell_htc_less_than_ideal() {
|
||||
let g = BellDelawareGeometry::default();
|
||||
let h = shell_side_htc(&g);
|
||||
assert!(h < g.h_ideal);
|
||||
assert!(h > 500.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rate_ua_positive() {
|
||||
let mut hx = ShellAndTubeHx::new(BellDelawareGeometry::default());
|
||||
let ua = hx.rate_ua(&default_tube_params(FlowRegime::SinglePhaseLiquid));
|
||||
assert!(ua.is_finite() && ua > 1000.0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user