Blueprints
Sweep a parameter and get a table
A study is a family of cases run to a verdict. The table is written before judgment, so it survives a failed gate.
A study takes a list of cases, runs each one, reduces the runs to table rows, writes the table, judges it, and returns a verdict.
let verdict = CfdFlow::study("nozzle operating map")
.cases(back_pressure_ratios) // Vec<T>, one entry per row
.sweep(|case| march_one(case)) // runs concurrently under `parallel`
.reduce_all(|runs| rows_from(runs))? // needs the whole set -> sequential
.record("operating_map.csv") // table exists even if gates then fail
.gates(operating_map_gates())
.verdict()?;
Ordering is enforced at compile time
Each verb is defined only on the phase where it applies. No record or
gates before rows exist, and no verdict before a gating sequence is applied.
Four compile_fail doctests pin this, including a GateSeq<i32> applied to
f64 rows.
A mis-ordered study does not compile.
reduce versus reduce_all
reduce maps one run to one row and runs per case. reduce_all receives the whole
slice at once and therefore runs sequentially.
reduce_all applies when a row depends on the other rows, such as a
normalisation, a ranking, or a column identifying the selected case. reduce
does not serialise the fan-out.
Record precedes judgment
record precedes gates, so a failed gate still leaves the table that shows why
it failed.
The envelope placard inverts this on its negative path: a failing run exits nonzero and writes no table, so no artifact remains that could be mistaken for a valid one.
Concurrency
sweep runs cases concurrently under the parallel feature and inline
otherwise, reporting in case order in both modes. The VIV example records a
concurrent result bit-identical to its sequential run.
Worked examples using this