///|
/// Thresholds for a numerical benchmark gate.
pub(all) struct BenchmarkGate {
max_l2 : Double
max_linf : Double
max_mass_drift : Double
} derive(Debug)
///|
/// Construct a benchmark gate.
pub fn BenchmarkGate::new(
max_l2~ : Double,
max_linf~ : Double,
max_mass_drift~ : Double,
) -> BenchmarkGate {
{ max_l2, max_linf, max_mass_drift }
}
///|
/// Check a benchmark result against configured thresholds.
pub fn BenchmarkGate::accepts(
self : BenchmarkGate,
report : BenchmarkReport,
) -> Bool {
report.l2_error <= self.max_l2 &&
report.linf_error <= self.max_linf &&
report.mass_drift <= self.max_mass_drift &&
report.stable
}
///|
/// Comparison between two measured benchmark results.
pub(all) struct BenchmarkComparison {
l2_delta : Double
relative_l2 : Double
linf_delta : Double
mass_delta : Double
} derive(Debug)
///|
/// Compare the error and conservation fields of two reports.
pub fn compare_reports(
left : BenchmarkReport,
right : BenchmarkReport,
) -> BenchmarkComparison {
let l2_delta = left.l2_error - right.l2_error
let reference = abs_double(right.l2_error)
{
l2_delta,
relative_l2: if reference == 0.0 {
abs_double(l2_delta)
} else {
abs_double(l2_delta) / reference
},
linf_delta: left.linf_error - right.linf_error,
mass_delta: left.mass_drift - right.mass_drift,
}
}
///|
/// Return the better of two stable reports by L2 error.
pub fn better_report(
left : BenchmarkReport,
right : BenchmarkReport,
) -> BenchmarkReport {
if left.stable && (!right.stable || left.l2_error <= right.l2_error) {
left
} else {
right
}
}
///|
/// Run a small resolution study for Poiseuille flow.
pub fn run_resolution_study(
resolutions~ : Array[Int],
steps~ : Int,
) -> Array[BenchmarkReport] {
let result = Array::new()
for resolution in resolutions {
let height = (resolution / 3).max(4)
result.push(
run_poiseuille_benchmark(width=resolution.max(8), height~, steps~),
)
}
result
}
///|
/// Return the report with the smallest L2 error.
pub fn best_benchmark(reports : ArrayView[BenchmarkReport]) -> BenchmarkReport? {
let mut best : BenchmarkReport? = None
for report in reports {
match best {
None => best = Some(report)
Some(current) => best = Some(better_report(current, report))
}
}
best
}
///|
/// Return the largest mass drift in a report set.
pub fn maximum_mass_drift(reports : ArrayView[BenchmarkReport]) -> Double {
let mut result = 0.0
for report in reports {
result = result.max(report.mass_drift)
}
result
}
///|
/// Return true when every report is stable and finite.
pub fn benchmark_suite_is_usable(reports : ArrayView[BenchmarkReport]) -> Bool {
let mut result = true
for report in reports {
result = result &&
report.stable &&
!report.l2_error.is_nan() &&
!report.linf_error.is_nan()
}
result
}