///|
pub fn summarize_pressure_benchmarks(
points : Array[PurePressureBenchmark],
predicted_pressures_bar : Array[Double],
) -> BenchmarkSummary raise VleError {
assert_same_length(points.length(), predicted_pressures_bar.length())
if points.length() == 0 {
raise VleError::EmptyMixture
}
let (passed, total_error, maximum_error) = for i = 0, passed = 0, total_error = 0.0, maximum_error = 0.0; i <
points.length(); {
let error = abs_double(predicted_pressures_bar[i] - points[i].pressure_bar)
let next_passed = if error <= points[i].tolerance {
passed + 1
} else {
passed
}
let next_maximum = if error > maximum_error { error } else { maximum_error }
continue i + 1, next_passed, total_error + error, next_maximum
} nobreak {
(passed, total_error, maximum_error)
}
let total = points.length()
BenchmarkSummary::{
total,
passed,
failed: total - passed,
pass_rate: passed.to_double() / total.to_double(),
mean_error: total_error / total.to_double(),
max_error: maximum_error,
}
}
///|
pub fn summarize_vle_benchmarks(
points : Array[BenchmarkPoint],
predicted_pressures_bar : Array[Double],
) -> BenchmarkSummary raise VleError {
assert_same_length(points.length(), predicted_pressures_bar.length())
if points.length() == 0 {
raise VleError::EmptyMixture
}
let (passed, total_error, maximum_error) = for i = 0, passed = 0, total_error = 0.0, maximum_error = 0.0; i <
points.length(); {
let error = benchmark_pressure_error(points[i], predicted_pressures_bar[i])
let next_passed = if error <= points[i].tolerance {
passed + 1
} else {
passed
}
let next_maximum = if error > maximum_error { error } else { maximum_error }
continue i + 1, next_passed, total_error + error, next_maximum
} nobreak {
(passed, total_error, maximum_error)
}
let total = points.length()
BenchmarkSummary::{
total,
passed,
failed: total - passed,
pass_rate: passed.to_double() / total.to_double(),
mean_error: total_error / total.to_double(),
max_error: maximum_error,
}
}
///|
pub fn benchmark_summary_is_successful(
summary : BenchmarkSummary,
required_pass_rate : Double,
) -> Bool raise VleError {
if required_pass_rate < 0.0 || required_pass_rate > 1.0 {
raise VleError::InvalidParameter(
"required pass rate must be between zero and one",
)
}
summary.pass_rate >= required_pass_rate
}
///|
pub fn benchmark_summary_error_budget(
summary : BenchmarkSummary,
maximum_allowed_error : Double,
) -> Bool raise VleError {
if maximum_allowed_error < 0.0 {
raise VleError::InvalidParameter("error budget cannot be negative")
}
summary.max_error <= maximum_allowed_error
}
///|
pub fn benchmark_prediction_from_component(
component : Component,
point : PurePressureBenchmark,
) -> Double raise VleError {
if component.name != point.component {
raise VleError::InvalidParameter(
"benchmark component does not match prediction",
)
}
component.saturation_pressure_bar(point.temperature_k)
}
///|
pub fn evaluate_pure_pressure_catalog(
components : Array[Component],
points : Array[PurePressureBenchmark],
) -> BenchmarkSummary raise VleError {
assert_same_length(components.length(), points.length())
let predictions = [
for i in 0.. {
benchmark_prediction_from_component(components[i], points[i])
}
]
summarize_pressure_benchmarks(points, predictions)
}
///|
pub fn benchmark_error_percent(
reference : Double,
predicted : Double,
) -> Double raise VleError {
relative_error(reference, predicted) * 100.0
}
///|
pub fn pressure_catalog_components() -> Array[Component] {
[water(), benzene(), toluene(), ethanol(), methanol()]
}
///|
pub fn pressure_catalog_summary() -> BenchmarkSummary raise VleError {
evaluate_pure_pressure_catalog(
pressure_catalog_components(),
pure_pressure_benchmarks(),
)
}