qlroms.intrusive_qlroms — qlGalerkin and the data pipelines
The intrusive family: qlGalerkin is the compilation of Galerkin-projected members, and
the three cases define the members it compiles. Every case package has the same shape —
config.py (TEST_CASES + the torch-side grids/operators), fom.py (the full-order
model, a dynamodels Model), rom.py (the single-cluster ROM class and
build_local_model, which caches itself). The offline data pipelines sit next to them:
build_ks (KS FOM + cached trajectory) and build_pinball (snapshot loading).
The cases have their own pages: KS 1-D · KS 2-D · fluidic pinball.
At a glance
| Name | One-liner |
|---|---|
galerkin.qlGalerkin |
Compilation of intrusively-projected members, one GalerkinROM per chart (isinstance tells the family apart); from_operators reloads stacked (b, A, B). |
build_ks |
KS offline data pipeline: build_fom (a case's FOM + merged run config), get_full_trajectory (the physical trajectory, generated in chunks and cached), build_sensor_indices (sensor placement on the KS grid). |
build_pinball |
load_snapshots: stack velocity_*.npy / pressure_*.npy into an (Ndof, Nt) matrix plus the snapshot spacing. |
qlroms.intrusive_qlroms.galerkin
qlGalerkin: the intrusive model family.
A qlGalerkin is simply the compilation (qlroms.base.qlROM) of single-cluster
ROMs whose operators come from an intrusive Galerkin projection of a known
governing-equation operator -- the case ROM classes (ks1d.rom.ROM,
ks2d.rom.ROM, pinball.rom.ROM) own those operators and step_reduced;
compiling K of them yields the quantized-local model. The name records the family,
so isinstance(model, qlGalerkin) distinguishes intrusive compilations from
non-intrusive ones (OpInf/ESN) in family-agnostic code.
GalerkinROM
Bases: QuadROM
One cluster's intrusive quadratic ROM: the family-neutral QuadROM member (qlroms.charts.QuadROM -- geometry + (b, A, B) + ETDRK4 step), labeled as INTRUSIVE: its operators come from a Galerkin projection of a known governing-equation operator, never from a regression.
Source code in qlroms/intrusive_qlroms/galerkin.py
16 17 18 19 20 | |
qlGalerkin
Bases: qlROM
Compilation of intrusively-projected (Galerkin) single-cluster ROMs.
Source code in qlroms/intrusive_qlroms/galerkin.py
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | |
from_operators(centroids, Phi_all, b_all, A_all, B_all, dt=1.0, Mw=None, Mcontour=32, Rcontour=15.0)
classmethod
Build a qlGalerkin from already-projected reduced operators, skipping any fit -- e.g. to reload stacked (b, A, B) from disk (tests/test_qlgalerkin_bridge.py); the case builders compile their own ROM classes directly.
The reduced continuous quadratic ODE da/dt = b + A a + B(a, a) is the same compute as the OpInf family once reduced, so both members subclass the shared qlroms.charts.QuadROM; GalerkinROM records the intrusive provenance. centroids (K, N), Phi_all (N, r, K), b/A/B stacked (K, ...); Mw is the chart inner-product weight (e.g. the FEM mass matrix; None for M = I).
Source code in qlroms/intrusive_qlroms/galerkin.py
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | |
qlroms.intrusive_qlroms.build_ks
Offline KS build pipeline (ks1d / ks2d): the case FOM (build_fom) and its cached full physical trajectory (get_full_trajectory), which feed the case rom.build_local_model -- see qlroms.utils.builder.build_case for the config-driven orchestration. Also the sensor-placement helper build_sensor_indices.
The full-order models are the cases' own FOM classes (module.FOM: a dynamodels.physical.KS / KS2D subclass); the ROM machinery stays torch. build_fom constructs module.FOM for a case, get_full_trajectory drives model.time_integrate and caches the physical snapshot matrix in the exact same file format/layout as the old torch FOMs, so existing full_trajectory.pth caches keep hitting.
state_dim(model)
Flattened PHYSICAL state length of a KS FOM or config (1D: Nx, 2D: Nx*Ny).
Do not use model.N for dynamodels models: dynamodels.Model.N is the analysis-augmented size (Nphi + Na + Nq), not the physical grid size.
Source code in qlroms/intrusive_qlroms/build_ks.py
25 26 27 28 29 30 31 32 33 | |
build_fom(module, case=None, overrides=None)
Build the case's full-order model and return (fom, cfg).
The FOM is module.FOM(case=...) -- a dynamodels Model subclass
(ks1d.FOM(physical.KS) / ks2d.FOM(physical.KS2D)) that reads the case's
PHYSICAL parameters straight out of its own torch-side config, which it
keeps as fom.cfg. There is no rescaling and nothing is attached after
construction: fom.dt IS the case's physical time step, and the case-side
quantities the ROM stack reads (visc/Lx/lamb1/device/rdtype/cdtype, 2-D
wt) are properties on the class delegating to fom.cfg.
Per-case model params (Nx/Ny/dt/visc/nu/lamb1) live in module.TEST_CASES[case].
Dataset params (Ntrain/Ntest/i0) come from TEST_CASES[case] (1D) or
module.TIME_DEFAULTS (2D). overrides (CLI flags; None values ignored)
win over both and, because the torch ROM configs read their params from
TEST_CASES, are written there before construction.
cfg is the merged dict the scripts run on: TIME_DEFAULTS < TEST_CASES[case] < overrides, plus case/module.
Source code in qlroms/intrusive_qlroms/build_ks.py
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | |
get_full_trajectory(Ntot, model, i0=0)
Compute or load the full physical trajectory of a KS FOM.
Works for both 1D and 2D KS: model is the CONSTRUCTED dynamodels model
returned by build_fom (physical.KS or physical.KS2D). Generation runs
model.time_integrate in chunks; ks1d spectral history is converted to
physical snapshots via the model's own transforms. The cache file format
and layout are identical to the old torch-FOM pipeline -- a torch-saved
float64 tensor of POST-burn-in physical snapshots, (state_dim, Ncols), at
get_simulation_path(model)/full_trajectory.pth -- so existing caches hit.
Cache-hit rule unchanged: cached_cols >= Ntot -> last Ntot columns.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
Ntot
|
int
|
Number of kept snapshots to return after discarding i0 transient steps. |
required |
model
|
dynamodels FOM (from build_fom). |
required | |
i0
|
int
|
Number of initial transient steps to skip (default 0). Only used when generating from scratch; the cache stores post-burn-in states. |
0
|
Returns:
| Type | Description |
|---|---|
Tensor
|
Trajectory tensor with shape (state_dim, Ntot), float64, CPU. |
Source code in qlroms/intrusive_qlroms/build_ks.py
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | |
qlroms.intrusive_qlroms.build_pinball
Pinball snapshot loading -- the build_ks.get_full_trajectory analog.
Snapshots are written by PinballFOM.run() (scripts/pinball/run_pinball_fom.py) as
load_snapshots(snapshot_dir=None, quantity='velocity', device=None, rdtype=torch.float64)
Stack <quantity>_*.npy snapshots into an (Ndof, Nt) matrix, chronological.
Returns:
| Type | Description |
|---|---|
(X, dt)
|
snapshot matrix and the saved-snapshot time spacing from |
float
|
snapshot_metadata.npz (dt * snapshot_interval). |
Source code in qlroms/intrusive_qlroms/build_pinball.py
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | |