///|
/// Heat-transfer balances for preliminary equipment sizing.
pub struct WallLayer {
name : String
thickness_m : Float
conductivity_w_mk : Float
}
///|
pub fn wall_layer(
name : String,
thickness_m : Float,
conductivity_w_mk : Float,
) -> WallLayer {
{ name, thickness_m, conductivity_w_mk }
}
///|
pub fn WallLayer::resistance(self : WallLayer, area_m2 : Float) -> Float {
if area_m2 == 0.0 || self.conductivity_w_mk == 0.0 {
0.0
} else {
self.thickness_m / (self.conductivity_w_mk * area_m2)
}
}
///|
pub fn conduction_resistance(
thickness_m : Float,
conductivity_w_mk : Float,
area_m2 : Float,
) -> Float {
if conductivity_w_mk == 0.0 || area_m2 == 0.0 {
0.0
} else {
thickness_m / (conductivity_w_mk * area_m2)
}
}
///|
pub fn convection_resistance(
coefficient_w_m2k : Float,
area_m2 : Float,
) -> Float {
if coefficient_w_m2k == 0.0 || area_m2 == 0.0 {
0.0
} else {
1.0 / (coefficient_w_m2k * area_m2)
}
}
///|
pub fn radiation_coefficient(
emissivity : Float,
hot_k : Float,
cold_k : Float,
) -> Float {
5.670374419e-8 *
emissivity *
(hot_k + cold_k) *
(hot_k * hot_k + cold_k * cold_k)
}
///|
pub fn heat_duty(
mass_flow_kg_h : Float,
heat_capacity_kj_kgk : Float,
delta_temperature_k : Float,
) -> Float {
mass_flow_kg_h * heat_capacity_kj_kgk * delta_temperature_k
}
///|
pub fn heat_duty_with_phase(
mass_flow_kg_h : Float,
heat_capacity_kj_kgk : Float,
delta_temperature_k : Float,
latent_kj_kg : Float,
) -> Float {
heat_duty(mass_flow_kg_h, heat_capacity_kj_kgk, delta_temperature_k) +
mass_flow_kg_h * latent_kj_kg
}
///|
pub fn lmtd(
hot_in : Float,
hot_out : Float,
cold_in : Float,
cold_out : Float,
) -> Float {
let d1 = hot_in - cold_out
let d2 = hot_out - cold_in
if d1 == d2 {
d1
} else if d1 <= 0.0 || d2 <= 0.0 {
0.0
} else {
2.0 * d1 * d2 / (d1 + d2)
}
}
///|
pub fn exchanger_area(
duty_kw : Float,
coefficient_kw_m2k : Float,
driving_force_k : Float,
correction : Float,
) -> Float {
if coefficient_kw_m2k == 0.0 || driving_force_k == 0.0 || correction == 0.0 {
0.0
} else {
duty_kw / (coefficient_kw_m2k * driving_force_k * correction)
}
}
///|
pub struct HeatExchangerCheck {
area_m2 : Float
required_m2 : Float
duty_kw : Float
pressure_drop_bar : Float
max_pressure_drop_bar : Float
}
///|
pub fn heat_exchanger_check(
area_m2 : Float,
required_m2 : Float,
duty_kw : Float,
pressure_drop_bar : Float,
max_pressure_drop_bar : Float,
) -> HeatExchangerCheck {
{ area_m2, required_m2, duty_kw, pressure_drop_bar, max_pressure_drop_bar }
}
///|
pub fn HeatExchangerCheck::area_margin(self : HeatExchangerCheck) -> Float {
self.area_m2 - self.required_m2
}
///|
pub fn HeatExchangerCheck::acceptable(self : HeatExchangerCheck) -> Bool {
self.area_margin() >= 0.0 &&
self.pressure_drop_bar <= self.max_pressure_drop_bar
}
///|
pub struct InsulationDesign {
thickness_m : Float
conductivity_w_mk : Float
area_m2 : Float
ambient_c : Float
process_c : Float
}
///|
pub fn insulation_design(
thickness_m : Float,
conductivity_w_mk : Float,
area_m2 : Float,
ambient_c : Float,
process_c : Float,
) -> InsulationDesign {
{ thickness_m, conductivity_w_mk, area_m2, ambient_c, process_c }
}
///|
pub fn InsulationDesign::loss_w(self : InsulationDesign) -> Float {
let r = conduction_resistance(
self.thickness_m,
self.conductivity_w_mk,
self.area_m2,
)
if r == 0.0 {
0.0
} else {
(self.process_c - self.ambient_c) / r
}
}
///|
pub fn InsulationDesign::surface_load(self : InsulationDesign) -> Float {
if self.area_m2 == 0.0 {
0.0
} else {
self.loss_w() / self.area_m2
}
}
///|
pub fn InsulationDesign::acceptable(
self : InsulationDesign,
limit_w_m2 : Float,
) -> Bool {
self.surface_load() <= limit_w_m2
}
///|
pub fn heat_balance(
inlet_kw : Float,
reaction_kw : Float,
utility_kw : Float,
outlet_kw : Float,
) -> Float {
inlet_kw + reaction_kw + utility_kw - outlet_kw
}
///|
pub fn heat_balance_gate(error_kw : Float, tolerance_kw : Float) -> Bool {
error_kw.abs() <= tolerance_kw
}
///|
pub fn heat_transfer_table(checks : Array[HeatExchangerCheck]) -> ReportTable {
let rows : Array[Array[String]] = []
for c in checks {
rows.push([
"\{c.area_m2}",
"\{c.required_m2}",
"\{c.duty_kw}",
"\{c.pressure_drop_bar}",
"\{c.acceptable()}",
])
}
table(["area", "required", "duty", "pressure drop", "acceptable"], rows)
}