///|
fn template_source(label : String) -> DataSource {
source("template", "MoonBit chemreport engineering template: \{label}")
}
///|
pub fn heat_exchanger_report() -> ChemReport {
report(
"Heat Exchanger Duty Summary",
summary="Sensible-duty report for a single-phase exchanger.",
inputs=[
input("mass flow", quantity("2.0", "kg/s")),
input("heat capacity", quantity("4.18", "kJ/(kg K)")),
input("temperature rise", quantity("25", "K")),
],
assumptions=[assumption("single phase", "no latent heat is represented")],
formulas=[
formula("duty", "Q = m_dot * Cp * DeltaT", ["m_dot", "Cp", "DeltaT"]),
],
results=[
result("duty", quantity("209.0", "kW"), procedure="2.0 * 4.18 * 25"),
],
sources=[template_source("heat exchanger")],
)
}
///|
pub fn pump_power_report() -> ChemReport {
report(
"Pump Hydraulic Power Summary",
summary="Hydraulic power before pump efficiency correction.",
inputs=[
input("density", quantity("998", "kg/m3")),
input("flow", quantity("0.01", "m3/s")),
input("head", quantity("30", "m")),
],
assumptions=[assumption("incompressible liquid", "density is fixed")],
formulas=[
formula("hydraulic power", "P = rho * g * Q * H", ["rho", "g", "Q", "H"]),
],
results=[
result(
"hydraulic power",
quantity("2.934", "kW"),
procedure="998 * 9.81 * 0.01 * 30",
),
],
sources=[template_source("pump power")],
)
}
///|
pub fn flash_split_report() -> ChemReport {
report(
"Flash Split Summary",
summary="Two-phase split record with component-free recovery figures.",
inputs=[
input("feed", quantity("100", "kmol/h")),
input("vapor fraction", quantity("0.35", "1")),
input("liquid fraction", quantity("0.65", "1")),
],
assumptions=[assumption("single feed", "no side draw is recorded")],
formulas=[formula("split", "V = beta F; L = (1-beta) F", ["beta", "F"])],
results=[
result("vapor flow", quantity("35", "kmol/h"), procedure="0.35 * 100"),
result("liquid flow", quantity("65", "kmol/h"), procedure="0.65 * 100"),
],
sources=[template_source("flash split")],
)
}
///|
pub fn stoichiometric_yield_report() -> ChemReport {
report(
"Stoichiometric Yield Summary",
summary="Single-reaction yield record with explicit limiting-feed basis.",
inputs=[
input("limiting reactant", quantity("10", "mol")),
input("theoretical product", quantity("8", "mol")),
input("actual product", quantity("7.2", "mol")),
],
assumptions=[
assumption(
"single reaction", "selectivity losses are represented by yield only",
),
],
formulas=[
formula("yield", "Y = actual / theoretical", ["actual", "theoretical"]),
],
results=[result("yield", quantity("90", "%"), procedure="7.2 / 8 * 100")],
warnings=[
caution(
"selectivity and impurity profile require a reaction-specific report",
),
],
sources=[template_source("stoichiometric yield")],
)
}
///|
pub fn mixing_report() -> ChemReport {
report(
"Adiabatic Mixing Temperature",
summary="A two-stream mixing record with an explicit enthalpy-basis equation.",
inputs=[
input("stream one", quantity("10", "kg/s")),
input("stream one temperature", quantity("300", "K")),
input("stream two", quantity("5", "kg/s")),
input("stream two temperature", quantity("360", "K")),
input("heat capacity", quantity("4.18", "kJ/(kg K)")),
],
assumptions=[
assumption(
"adiabatic mixing", "heat loss is excluded from the enthalpy closure",
),
],
formulas=[
formula("mixed temperature", "sum(m Cp T)_in / sum(m Cp)_in", [
"m", "Cp", "T",
]),
],
results=[
result(
"mixed temperature",
quantity("320.0", "K"),
procedure="(10 * 300 + 5 * 360) / 15",
),
],
sources=[template_source("mixing temperature")],
)
}
///|
pub fn pressure_drop_report() -> ChemReport {
report(
"Pipe Pressure-Drop Summary",
summary="A friction-loss record for a single pipe segment.",
inputs=[
input("friction factor", quantity("0.020", "1")),
input("pipe length", quantity("100", "m")),
input("pipe diameter", quantity("0.050", "m")),
input("density", quantity("998", "kg/m3")),
input("velocity", quantity("2.0", "m/s")),
],
assumptions=[
assumption("Darcy-Weisbach basis", "minor losses are reported separately"),
],
formulas=[
formula("friction loss", "DeltaP = f L/D rho v^2/2", [
"f", "L", "D", "rho", "v",
]),
],
results=[
result(
"friction pressure drop",
quantity("39920", "Pa"),
procedure="0.020 * 100 / 0.050 * 998 * 2^2 / 2",
),
],
warnings=[
caution(
"include fittings, elevation, and pump margin before equipment selection",
),
],
sources=[template_source("pipe pressure drop")],
)
}
///|
pub fn reaction_rate_report() -> ChemReport {
report(
"Reaction-Rate Snapshot",
summary="A rate-law record that keeps kinetics assumptions beside the calculated rate.",
inputs=[
input("rate constant", quantity("0.12", "1/h")),
input("reactant concentration", quantity("2.0", "kmol/m3")),
input("reaction order", quantity("1", "1")),
],
assumptions=[
assumption(
"power-law kinetics", "the rate law is valid only over the cited operating window",
),
],
formulas=[formula("rate law", "r = k C_A^n", ["k", "C_A", "n"])],
results=[
result(
"reaction rate",
quantity("0.24", "kmol/m3/h"),
procedure="0.12 * 2.0^1",
),
],
warnings=[
caution(
"attach fitted-data uncertainty and temperature dependence for production use",
),
],
sources=[template_source("reaction rate")],
)
}
///|
pub fn distillation_stage_report() -> ChemReport {
report(
"Distillation Stage Efficiency",
summary="A single-stage efficiency record with equilibrium composition traceability.",
inputs=[
input("inlet vapor composition", quantity("0.40", "mol/mol")),
input("outlet vapor composition", quantity("0.72", "mol/mol")),
input("equilibrium composition", quantity("0.80", "mol/mol")),
],
assumptions=[
assumption(
"Murphree vapor efficiency", "the reference equilibrium value is evaluated at the stage condition",
),
],
formulas=[
formula("stage efficiency", "E_M = (y_out-y_in)/(y_star-y_in)", [
"y_out", "y_in", "y_star",
]),
],
results=[
result(
"Murphree efficiency",
quantity("80", "%"),
procedure="(0.72 - 0.40) / (0.80 - 0.40) * 100",
),
],
sources=[template_source("distillation stage")],
)
}
///|
pub fn drying_report() -> ChemReport {
report(
"Solid Drying Rate Summary",
summary="A drying-rate record that distinguishes the measured surface basis.",
inputs=[
input("mass-transfer coefficient", quantity("0.004", "kg/m2/h")),
input("area", quantity("20", "m2")),
input("driving force", quantity("0.30", "1")),
],
assumptions=[
assumption(
"constant-rate region", "the reported driving force is treated as constant",
),
],
formulas=[
formula("drying rate", "N_A = k_y a (Y-Y*)", ["k_y", "a", "Y", "Y*"]),
],
results=[
result(
"water removal rate",
quantity("0.024", "kg/h"),
procedure="0.004 * 20 * 0.30",
),
],
warnings=[
caution(
"falling-rate behavior and equilibrium moisture need a dedicated drying model",
),
],
sources=[template_source("drying rate")],
)
}
///|
pub fn filtration_report() -> ChemReport {
report(
"Cake Filtration Rate Summary",
summary="A pressure-driven filtration record with medium and cake resistance terms.",
inputs=[
input("pressure difference", quantity("100000", "Pa")),
input("filter area", quantity("2", "m2")),
input("viscosity", quantity("0.001", "Pa s")),
input("total resistance", quantity("100000000", "1/m")),
],
assumptions=[
assumption(
"constant pressure", "the pressure difference is held over the reported interval",
),
],
formulas=[
formula("filtration rate", "dV/dt = DeltaP A / (mu R_total)", [
"DeltaP", "A", "mu", "R_total",
]),
],
results=[
result(
"filtrate rate",
quantity("2", "m3/s"),
procedure="100000 * 2 / (0.001 * 100000000)",
),
],
warnings=[
caution(
"cake compressibility and solids loading require plant data before scale-up",
),
],
sources=[template_source("filtration rate")],
)
}