///|
pub struct VesselDesign {
volume : Float
liquid_volume : Float
design_pressure : Float
allowable_pressure : Float
design_temperature : Float
allowable_temperature : Float
} derive(Debug, Eq)
///|
pub fn vessel_design(
volume : Float,
liquid_volume : Float,
design_pressure : Float,
allowable_pressure : Float,
design_temperature : Float,
allowable_temperature : Float,
) -> VesselDesign {
{
volume,
liquid_volume,
design_pressure,
allowable_pressure,
design_temperature,
allowable_temperature,
}
}
///|
pub fn VesselDesign::volume_margin(self : VesselDesign) -> Float {
self.volume - self.liquid_volume
}
///|
pub fn VesselDesign::pressure_margin(self : VesselDesign) -> Float {
self.allowable_pressure - self.design_pressure
}
///|
pub fn VesselDesign::temperature_margin(self : VesselDesign) -> Float {
self.allowable_temperature - self.design_temperature
}
///|
pub fn VesselDesign::fill_fraction(self : VesselDesign) -> Float {
if self.volume <= 0.0 {
0.0
} else {
self.liquid_volume / self.volume
}
}
///|
pub fn VesselDesign::is_acceptable(self : VesselDesign) -> Bool {
self.volume > 0.0 &&
self.liquid_volume >= 0.0 &&
self.volume_margin() >= 0.0 &&
self.pressure_margin() >= 0.0 &&
self.temperature_margin() >= 0.0
}
///|
pub fn VesselDesign::recommended_relief_pressure(
self : VesselDesign,
factor : Float,
) -> Float {
self.allowable_pressure * clamp(factor, 0.1, 0.95)
}
///|
pub struct TankDesign {
diameter : Float
height : Float
working_level : Float
dead_volume : Float
overflow_level : Float
} derive(Debug, Eq)
///|
pub fn tank_design(
diameter : Float,
height : Float,
working_level : Float,
dead_volume : Float,
overflow_level : Float,
) -> TankDesign {
{ diameter, height, working_level, dead_volume, overflow_level }
}
///|
pub fn TankDesign::cross_section(self : TankDesign) -> Float {
3.141592653589793 * self.diameter * self.diameter / 4.0
}
///|
pub fn TankDesign::working_volume(self : TankDesign) -> Float {
self.cross_section() * self.working_level
}
///|
pub fn TankDesign::overflow_volume(self : TankDesign) -> Float {
self.cross_section() * self.overflow_level
}
///|
pub fn TankDesign::usable_volume(self : TankDesign) -> Float {
self.working_volume() - self.dead_volume
}
///|
pub fn TankDesign::is_acceptable(self : TankDesign) -> Bool {
self.diameter > 0.0 &&
self.height > 0.0 &&
self.working_level >= 0.0 &&
self.working_level <= self.height &&
self.overflow_level >= self.working_level
}
///|
pub fn TankDesign::residence_time(
self : TankDesign,
flow_rate : Float,
) -> Float {
residence_time(self.usable_volume(), flow_rate)
}
///|
pub struct ExchangerDesign {
area : Float
overall_u : Float
hot_inlet : Float
hot_outlet : Float
cold_inlet : Float
cold_outlet : Float
hot_capacity : Float
cold_capacity : Float
} derive(Debug, Eq)
///|
pub fn exchanger_design(
area : Float,
overall_u : Float,
hot_inlet : Float,
hot_outlet : Float,
cold_inlet : Float,
cold_outlet : Float,
hot_capacity : Float,
cold_capacity : Float,
) -> ExchangerDesign {
{
area,
overall_u,
hot_inlet,
hot_outlet,
cold_inlet,
cold_outlet,
hot_capacity,
cold_capacity,
}
}
///|
pub fn ExchangerDesign::delta_hot(self : ExchangerDesign) -> Float {
self.hot_inlet - self.hot_outlet
}
///|
pub fn ExchangerDesign::delta_cold(self : ExchangerDesign) -> Float {
self.cold_outlet - self.cold_inlet
}
///|
pub fn ExchangerDesign::hot_duty(self : ExchangerDesign) -> Float {
self.hot_capacity * self.delta_hot()
}
///|
pub fn ExchangerDesign::cold_duty(self : ExchangerDesign) -> Float {
self.cold_capacity * self.delta_cold()
}
///|
pub fn ExchangerDesign::duty_error(self : ExchangerDesign) -> Float {
normalized_error(self.hot_duty(), self.cold_duty())
}
///|
pub fn ExchangerDesign::lmtd(self : ExchangerDesign) -> Float {
log_mean_temperature_difference(
self.hot_inlet - self.cold_outlet,
self.hot_outlet - self.cold_inlet,
)
}
///|
pub fn ExchangerDesign::required_area(self : ExchangerDesign) -> Float {
if self.overall_u <= 0.0 || self.lmtd() <= 0.0 {
0.0
} else {
self.hot_duty() / (self.overall_u * self.lmtd())
}
}
///|
pub fn ExchangerDesign::area_margin(self : ExchangerDesign) -> Float {
self.area - self.required_area()
}
///|
pub fn ExchangerDesign::effectiveness(self : ExchangerDesign) -> Float {
let minimum = if self.hot_capacity < self.cold_capacity {
self.hot_capacity
} else {
self.cold_capacity
}
if minimum <= 0.0 || self.hot_inlet <= self.cold_inlet {
0.0
} else {
clamp(
self.cold_duty() / (minimum * (self.hot_inlet - self.cold_inlet)),
0.0,
1.0,
)
}
}
///|
pub fn ExchangerDesign::is_acceptable(self : ExchangerDesign) -> Bool {
self.area > 0.0 &&
self.overall_u > 0.0 &&
self.area_margin() >= 0.0 &&
self.duty_error() <= 0.05
}
///|
pub struct CompressorDesign {
suction_pressure : Float
discharge_pressure : Float
inlet_temperature : Float
flow_rate : Float
efficiency : Float
gas_constant : Float
heat_capacity_ratio : Float
} derive(Debug, Eq)
///|
pub fn compressor_design(
suction_pressure : Float,
discharge_pressure : Float,
inlet_temperature : Float,
flow_rate : Float,
efficiency : Float,
gas_constant : Float,
heat_capacity_ratio : Float,
) -> CompressorDesign {
{
suction_pressure,
discharge_pressure,
inlet_temperature,
flow_rate,
efficiency,
gas_constant,
heat_capacity_ratio,
}
}
///|
pub fn CompressorDesign::pressure_ratio(self : CompressorDesign) -> Float {
if self.suction_pressure <= 0.0 {
0.0
} else {
self.discharge_pressure / self.suction_pressure
}
}
///|
pub fn CompressorDesign::specific_work(self : CompressorDesign) -> Float {
if self.efficiency <= 0.0 ||
self.heat_capacity_ratio <= 1.0 ||
self.inlet_temperature <= 0.0 {
0.0
} else {
self.gas_constant *
self.inlet_temperature /
self.efficiency *
(self.pressure_ratio().sqrt() - 1.0)
}
}
///|
pub fn CompressorDesign::power(self : CompressorDesign) -> Float {
self.flow_rate * self.specific_work()
}
///|
pub fn CompressorDesign::discharge_temperature(
self : CompressorDesign,
) -> Float {
if self.inlet_temperature <= 0.0 {
0.0
} else {
self.inlet_temperature * self.pressure_ratio().sqrt()
}
}
///|
pub fn CompressorDesign::is_acceptable(
self : CompressorDesign,
maximum_temperature : Float,
) -> Bool {
self.pressure_ratio() >= 1.0 &&
self.efficiency > 0.0 &&
self.efficiency <= 1.0 &&
self.discharge_temperature() <= maximum_temperature
}
///|
pub struct ValveDesign {
flow_coefficient : Float
pressure_drop : Float
density : Float
opening : Float
maximum_flow : Float
} derive(Debug, Eq)
///|
pub fn valve_design(
flow_coefficient : Float,
pressure_drop : Float,
density : Float,
opening : Float,
maximum_flow : Float,
) -> ValveDesign {
{ flow_coefficient, pressure_drop, density, opening, maximum_flow }
}
///|
pub fn ValveDesign::estimated_flow(self : ValveDesign) -> Float {
if self.density <= 0.0 || self.pressure_drop <= 0.0 {
0.0
} else {
self.flow_coefficient *
self.opening *
(self.pressure_drop / self.density).sqrt()
}
}
///|
pub fn ValveDesign::capacity_margin(self : ValveDesign) -> Float {
self.maximum_flow - self.estimated_flow()
}
///|
pub fn ValveDesign::is_acceptable(self : ValveDesign) -> Bool {
self.flow_coefficient > 0.0 &&
self.opening >= 0.0 &&
self.opening <= 1.0 &&
self.capacity_margin() >= 0.0
}
///|
pub struct PipeDesign {
length : Float
diameter : Float
roughness : Float
flow_rate : Float
density : Float
viscosity : Float
allowable_drop : Float
} derive(Debug, Eq)
///|
pub fn pipe_design(
length : Float,
diameter : Float,
roughness : Float,
flow_rate : Float,
density : Float,
viscosity : Float,
allowable_drop : Float,
) -> PipeDesign {
{ length, diameter, roughness, flow_rate, density, viscosity, allowable_drop }
}
///|
pub fn PipeDesign::area(self : PipeDesign) -> Float {
3.141592653589793 * self.diameter * self.diameter / 4.0
}
///|
pub fn PipeDesign::velocity(self : PipeDesign) -> Float {
if self.area() <= 0.0 {
0.0
} else {
self.flow_rate / self.area()
}
}
///|
pub fn PipeDesign::reynolds(self : PipeDesign) -> Float {
reynolds_number(self.density, self.velocity(), self.diameter, self.viscosity)
}
///|
pub fn PipeDesign::friction_factor(self : PipeDesign) -> Float {
pressure_drop_case(
self.length,
self.diameter,
self.velocity(),
self.density,
self.viscosity,
self.roughness,
0.0,
).friction_factor()
}
///|
pub fn PipeDesign::pressure_drop(self : PipeDesign) -> Float {
pressure_drop_case(
self.length,
self.diameter,
self.velocity(),
self.density,
self.viscosity,
self.roughness,
0.0,
).major_loss()
}
///|
pub fn PipeDesign::pressure_margin(self : PipeDesign) -> Float {
self.allowable_drop - self.pressure_drop()
}
///|
pub fn PipeDesign::is_acceptable(self : PipeDesign) -> Bool {
self.length > 0.0 &&
self.diameter > 0.0 &&
self.density > 0.0 &&
self.viscosity > 0.0 &&
self.pressure_margin() >= 0.0
}
///|
pub struct UtilityLoad {
name : String
demand : Float
availability : Float
priority : Int
} derive(Debug, Eq)
///|
pub fn utility_load(
name : String,
demand : Float,
availability : Float,
priority : Int,
) -> UtilityLoad {
{ name, demand, availability, priority }
}
///|
pub fn UtilityLoad::margin(self : UtilityLoad) -> Float {
self.availability - self.demand
}
///|
pub fn UtilityLoad::is_supplied(self : UtilityLoad) -> Bool {
self.demand >= 0.0 && self.margin() >= 0.0
}
///|
pub fn UtilityLoad::utilization(self : UtilityLoad) -> Float {
if self.availability <= 0.0 {
0.0
} else {
self.demand / self.availability
}
}
///|
pub fn sort_loads_by_priority(loads : Array[UtilityLoad]) -> Array[UtilityLoad] {
let result = loads.copy()
result.sort_by(fn(left, right) { left.priority - right.priority })
result
}
///|
pub fn total_utility_demand(loads : Array[UtilityLoad]) -> Float {
let mut total : Float = 0.0
for load in loads {
total = total + load.demand
}
total
}
///|
pub fn total_utility_availability(loads : Array[UtilityLoad]) -> Float {
let mut total : Float = 0.0
for load in loads {
total = total + load.availability
}
total
}
///|
pub fn utility_margin(loads : Array[UtilityLoad]) -> Float {
total_utility_availability(loads) - total_utility_demand(loads)
}
///|
pub fn utility_load_table(loads : Array[UtilityLoad]) -> ReportTable {
let rows : Array[Array[String]] = []
for load in loads {
rows.push([
load.name,
"{load.demand}",
"{load.availability}",
"{load.margin()}",
"{load.priority}",
])
}
table(["utility", "demand", "availability", "margin", "priority"], rows)
}