Skip to content

Config-driven builds

One YAML file per model: which test case and window, the family (rom.kind: qlgalerkin, the intrusive family this package carries), how many charts and modes, and what to measure once it is fitted.

python -m qlroms.utils.builder configs/ks1d_chaotic.yml   # [--set rom.K=20] [--set case.params='{"Ntrain": 5000}']
case: {model: ks1d chaos}          # a qlroms.utils.builder.KS_CASES name, or ks1d/chaotic
rom:  {kind: qlgalerkin, seed: 0, clustering: {kmeans_method: minibatch}}
check: {n_steps: 1000, compare_global: true}

A case is defined in exactly one place — its own module's TEST_CASES entry, which holds the physics, the windows it is generated with, the \((K, r)\) its ql-ROMs are built at and the timescales its characterization needs. qlroms.utils.builder.KS_CASES only maps a readable name onto one of those entries (read live at build time), and a config restates none of it: leave rom.K / rom.r or case.params out and the case's own values stand, set them and this run overrides them. Unknown keys fail loudly, dotted --set beats the file, and both the trajectory and the fitted ROM come from the case's cached pipeline. The run prints a JSON summary: representation error, closed-loop mean error and prediction horizon, against the global (\(K=1\)) ROM of the same family when compare_global is on.

There is no key for the inner product: Mw comes from the case (none for the uniform KS grids, the FEM velocity mass matrix for the pinball, read without dolfinx from the file written next to the mesh), and the clustering, the chart affiliation, the transitions and the reported errors all use it.

From Python the same pipeline is qlroms.utils.builder.load_config → build_case → run_build; see the qlroms.utils reference.