///|
pub fn BenchmarkCategory::to_string(category : BenchmarkCategory) -> String {
match category {
Analytical => "analytical"
LiteratureKinetics => "literature-kinetics"
MeasuredProperty => "measured-property"
Screening => "screening"
}
}
///|
fn benchmark_actual(id : String) -> Double {
if id == "first-order-pfr-da-1" {
let reaction = Reaction::new(name="A -> B", order=First, k_ref=1.0)
let feed = Feed::new(
concentration=1.0,
volumetric_flow=1.0,
temperature=298.15,
)
design_pfr(reaction, feed, 1.0).conversion
} else if id == "first-order-cstr-da-1" {
let reaction = Reaction::new(name="A -> B", order=First, k_ref=1.0)
let feed = Feed::new(
concentration=1.0,
volumetric_flow=1.0,
temperature=298.15,
)
design_cstr(reaction, feed, 1.0).conversion
} else if id == "ethyl-acetate-saponification-25c" {
let reaction = Reaction::new(
name="ethyl acetate + NaOH",
order=Second,
k_ref=6.523,
)
let feed = Feed::new(
concentration=0.0100,
volumetric_flow=1.0,
temperature=298.15,
)
design_batch(reaction, feed, 20.0).conversion
} else if id == "ethyl-acetate-molecular-weight" {
88.1051
} else if id == "series-first-order-selectivity" {
series_first_order_batch(1.0, 1.0, 0.2, 1.0).intermediate_selectivity
} else if id == "exothermic-cstr-screening" {
let reaction = Reaction::new(
name="screening exothermic",
order=First,
k_ref=0.03,
reaction_enthalpy=-50000.0,
)
let feed = Feed::new(
concentration=0.8,
volumetric_flow=1.0,
temperature=315.0,
heat_capacity_flow=5000.0,
)
design_cstr(reaction, feed, 20.0, thermal_mode=Adiabatic).outlet_temperature
} else {
let reaction = Reaction::new(name="A -> B", order=First, k_ref=0.5)
let feed = Feed::new(
concentration=1.0,
volumetric_flow=1.0,
temperature=298.15,
)
design_batch(reaction, feed, 2.0).conversion
}
}
///|
pub fn run_benchmark(case : BenchmarkCase) -> BenchmarkResult {
let actual = benchmark_actual(case.id)
let absolute_error = (actual - case.expected).abs()
{
id: case.id,
expected: case.expected,
actual,
absolute_error,
tolerance: case.tolerance,
passed: absolute_error <= case.tolerance,
source_url: case.source_url,
}
}
///|
pub fn benchmark_results() -> Array[BenchmarkResult] {
let results : Array[BenchmarkResult] = []
for case in curated_benchmarks {
results.push(run_benchmark(case))
}
results
}
///|
pub fn benchmark_report_markdown() -> String {
let builder = StringBuilder()
builder.write_string("# moonbit-reactor benchmark report\n\n")
builder.write_string(
"| id | actual | expected | absolute error | tolerance | status |\n",
)
builder.write_string("| --- | ---: | ---: | ---: | ---: | --- |\n")
for result in benchmark_results() {
builder.write_string("| ")
builder.write_string(result.id)
builder.write_string(" | ")
builder.write_string(format_double(result.actual, digits=10))
builder.write_string(" | ")
builder.write_string(format_double(result.expected, digits=10))
builder.write_string(" | ")
builder.write_string(format_double(result.absolute_error, digits=10))
builder.write_string(" | ")
builder.write_string(format_double(result.tolerance, digits=10))
builder.write_string(" | ")
builder.write_string(if result.passed { "PASS" } else { "FAIL" })
builder.write_string(" |\n")
}
builder.to_string()
}
///|
pub fn benchmark_report_csv() -> String {
let builder = StringBuilder()
builder.write_string(
"id,actual,expected,absolute_error,tolerance,passed,source_url\n",
)
for result in benchmark_results() {
builder.write_string(result.to_csv_row())
builder.write_string("\n")
}
builder.to_string()
}