Metadata-Version: 2.4
Name: qlroms
Version: 0.1.1a2
Summary: Quantized-local reduced-order models: chart atlases with local POD-Galerkin models.
Author-email: Andrea Nóvoa <a.novoa@imperial.ac.uk>
License-Expression: MIT
Project-URL: Homepage, https://github.com/andreanovoa/qlroms
Project-URL: Repository, https://github.com/andreanovoa/qlroms
Project-URL: Issues, https://github.com/andreanovoa/qlroms/issues
Keywords: reduced-order-modelling,operator-inference,reservoir-computing,dynamical-systems
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: dynamodels<1.0,>=0.3.3
Requires-Dist: echostatenetwork<1.0,>=0.1
Requires-Dist: matplotlib<4.0,>=3.9
Requires-Dist: numpy<3.0,>=2.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: scikit-learn<2.0,>=1.3
Requires-Dist: scipy<2.0,>=1.13
Requires-Dist: torch>=2.2
Provides-Extra: esn
Requires-Dist: scikit-optimize>=0.9; extra == "esn"
Provides-Extra: dev
Requires-Dist: pytest>=8.4; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Requires-Dist: scikit-optimize>=0.9; extra == "dev"
Requires-Dist: ntsa>=0.1; extra == "dev"
Dynamic: license-file

# qlroms

[![PyPI](https://img.shields.io/pypi/v/qlroms.svg)](https://pypi.org/project/qlroms/)
[![Docs](https://img.shields.io/badge/docs-andreanovoa.github.io%2Fqlroms-blue)](https://andreanovoa.github.io/qlroms)

Quantized-local reduced-order models (qlROMs). The state space is partitioned into
charts by k-means, each chart gets its own local POD basis, and an exact shared atlas
stitches the charts into one global coordinate system. On that geometry, this package
advances the local dynamics with **qlGalerkin**: an intrusive projection of the
governing equations, one quadratic reduced system $\dot{\bm{a}} = \bm{b}_k +
\mathbf{A}_k\bm{a} + \mathsf{B}_k(\bm{a},\bm{a})$ per chart, plus the transition maps
that carry coordinates across chart boundaries. The `QLModel` adapter wraps a qlROM as
a [`dynamodels`](https://github.com/andreanovoa/dynamodels) `Model`, so it plugs
directly into `romda` estimators and [`ntsa`](https://github.com/andreanovoa/ntsa) analysis.


## Install

```bash
conda create -n qlroms python=3.11   # >=3.10
conda activate qlroms
pip install qlroms
pip install -e ".[dev]"   # development
```

## Quickstart

```python
import numpy as np
from qlroms import free_run
from qlroms.intrusive_qlroms import ks1d
from qlroms.intrusive_qlroms.build_ks import build_fom, get_full_trajectory

# A case FOM and its (cached) trajectory: the 1-D KS chaotic regime, short window
fom, cfg = build_fom(ks1d, case="chaotic", overrides={"Ntrain": 20_000, "Ntest": 2_000})
traj = get_full_trajectory(Ntot=cfg["i0"] + cfg["Ntrain"] + cfg["Ntest"], model=fom, i0=cfg["i0"])
Xtrain, x0 = traj[:, :cfg["Ntrain"]], traj[:, cfg["Ntrain"]]

# Charts (k-means + local POD + atlas) and one projected (b, A, B) per chart
rom = ks1d.build_local_model(Xtrain, fom, K=10, r=30, save_dir=".")

# Closed-loop forecast through the shared step(apod) interface
X_rec, cluster_path = free_run(rom, x0, n_steps=500)

# Run it as a dynamodels Model (romda estimators, ntsa analysis)
from qlroms.model import QLModel
model = QLModel(rom, obs_idx=np.arange(0, fom.Nx, 8), psi0=x0)
```

## Building a qlROM from a config

One YAML file per model: which test case and window, which family, how many charts
and modes, and what to measure once it is fitted.

```bash
python -m qlroms.utils.builder configs/ks1d_chaotic.yml   # [--set rom.K=20] [--set case.params='{"Ntrain": 5000}']
```

```yaml
case: {model: ks1d chaos}          # a qlroms.utils.config.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.config` only maps a
readable name onto one of those entries (`get_case("ks1d chaos")` reads it back live),
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.

## Theory

Derivations (local POD with the mass-weighted inner product, OpInf regression with
$\lambda_1$/$\lambda_2$ regularization, ESN training) live in `docs/theory/`; full
documentation is published at https://andreanovoa.github.io/qlroms.

## References

If you use this package, please cite the papers the method comes from:

- Colanera, A., & Magri, L. (2025). Quantized local reduced-order modeling in time
  (ql-ROM). *Computer Methods in Applied Mechanics and Engineering*, **447**, 118393.
- Colanera, A., & Magri, L. (2026). Towards extreme event prediction of turbulent flows
  with quantized local reduced-order models. *Journal of Physics: Conference Series*,
  **3230**(1), 012003. IOP Publishing.
