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.

casessweepreduce_allrecordgatesverdict

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