sr-opinf 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sr_opinf-0.1.0/LICENSE +21 -0
- sr_opinf-0.1.0/PKG-INFO +211 -0
- sr_opinf-0.1.0/README.md +177 -0
- sr_opinf-0.1.0/pyproject.toml +53 -0
- sr_opinf-0.1.0/setup.cfg +4 -0
- sr_opinf-0.1.0/src/SROpInf/__init__.py +1 -0
- sr_opinf-0.1.0/src/SROpInf/dataloader.py +50 -0
- sr_opinf-0.1.0/src/SROpInf/grids/__init__.py +0 -0
- sr_opinf-0.1.0/src/SROpInf/grids/grid1d.py +348 -0
- sr_opinf-0.1.0/src/SROpInf/mode_decomposition.py +85 -0
- sr_opinf-0.1.0/src/SROpInf/models/__init__.py +0 -0
- sr_opinf-0.1.0/src/SROpInf/models/ks.py +71 -0
- sr_opinf-0.1.0/src/SROpInf/models/model.py +544 -0
- sr_opinf-0.1.0/src/SROpInf/sr_tools.py +368 -0
- sr_opinf-0.1.0/src/SROpInf/timestepper.py +178 -0
- sr_opinf-0.1.0/src/SROpInf/typing.py +18 -0
- sr_opinf-0.1.0/src/sr_opinf.egg-info/PKG-INFO +211 -0
- sr_opinf-0.1.0/src/sr_opinf.egg-info/SOURCES.txt +23 -0
- sr_opinf-0.1.0/src/sr_opinf.egg-info/dependency_links.txt +1 -0
- sr_opinf-0.1.0/src/sr_opinf.egg-info/requires.txt +8 -0
- sr_opinf-0.1.0/src/sr_opinf.egg-info/top_level.txt +1 -0
- sr_opinf-0.1.0/test/test_grid1d_compare.py +187 -0
- sr_opinf-0.1.0/test/test_grid1d_cubicspline.py +206 -0
- sr_opinf-0.1.0/test/test_grid1d_demo.py +439 -0
- sr_opinf-0.1.0/test/test_model_poly_comp.py +362 -0
sr_opinf-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Yu Shuai and Clarence W. Rowley
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
sr_opinf-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sr-opinf
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: SR-OpInf: Symmetry-Reduced Operator Inference for Shift-Equivariant Systems
|
|
5
|
+
Author: Clarence W. Rowley
|
|
6
|
+
Author-email: Yu Shuai <yu_shuai@princeton.edu>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/Yu-Shuai-PU/sr-opinf
|
|
9
|
+
Project-URL: Repository, https://github.com/Yu-Shuai-PU/sr-opinf
|
|
10
|
+
Project-URL: Paper (arXiv), https://arxiv.org/abs/2507.18780
|
|
11
|
+
Keywords: operator-inference,reduced-order-model,model-order-reduction,symmetry-reduction,shift-equivariant,Kuramoto-Sivashinsky,POD,ROM
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
22
|
+
Classifier: Operating System :: OS Independent
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: numpy>=1.23
|
|
27
|
+
Requires-Dist: scipy>=1.10
|
|
28
|
+
Requires-Dist: matplotlib>=3.6
|
|
29
|
+
Requires-Dist: tqdm>=4.65
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
32
|
+
Requires-Dist: ipywidgets>=8.0; extra == "dev"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# SROpInf — Symmetry-Reduced Operator Inference
|
|
36
|
+
|
|
37
|
+
`SROpInf` is a Python package for **symmetry-reduced model reduction of shift-equivariant
|
|
38
|
+
systems via operator inference**. For a 1D periodic PDE whose solutions are dominated by a
|
|
39
|
+
travelling / drifting structure (e.g. a travelling wave), it builds a reduced-order model (ROM)
|
|
40
|
+
that first factors out the continuous translation symmetry and then learns the reduced dynamics in
|
|
41
|
+
the co-moving frame — either **intrusively** (symmetry-reduced POD–Galerkin projection) or
|
|
42
|
+
**non-intrusively** from snapshot data (symmetry-reduced operator inference, S-R OpInf).
|
|
43
|
+
|
|
44
|
+
The package accompanies the paper
|
|
45
|
+
|
|
46
|
+
> Yu Shuai and Clarence W. Rowley,
|
|
47
|
+
> *Symmetry-reduced model reduction of shift-equivariant systems via operator inference*,
|
|
48
|
+
> arXiv:[2507.18780](https://arxiv.org/abs/2507.18780) (2025).
|
|
49
|
+
> Submitted to *Advances in Computational Mathematics* (in revision).
|
|
50
|
+
|
|
51
|
+
and reproduces all of its Kuramoto–Sivashinsky (KS) numerical experiments.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Method at a glance
|
|
56
|
+
|
|
57
|
+
For a shift-equivariant system the solution `q(x, t)` is decomposed into a **shift amount** `c(t)`
|
|
58
|
+
(the location of the travelling structure) and a **co-moving profile** obtained by aligning each
|
|
59
|
+
snapshot to a fixed template `q_template = cos(2πx/L)` (template fitting). The reduced model then
|
|
60
|
+
evolves
|
|
61
|
+
|
|
62
|
+
* the reduced co-moving state `z(t)` (POD coefficients of the template-fitted, scaled snapshots), and
|
|
63
|
+
* the scalar shift amount `c(t)` via a reconstruction equation `dc/dt = numerator / denominator`.
|
|
64
|
+
|
|
65
|
+
Two ways to obtain the reduced operators are provided:
|
|
66
|
+
|
|
67
|
+
| ROM | Intrusive? | How the reduced operators are obtained |
|
|
68
|
+
|-----|------------|----------------------------------------|
|
|
69
|
+
| **S-R POD–Galerkin** | yes | Galerkin projection of the (scaled, symmetry-reduced) FOM right-hand side onto the POD subspace. |
|
|
70
|
+
| **S-R OpInf** | no | Ridge-regression of reduced polynomial operators to the data; optional **re-projection** for consistency and **penalty (Tikhonov) regularization** for stability. |
|
|
71
|
+
|
|
72
|
+
Two spatial discretizations are supported, which lets the shift-induced interpolation error be
|
|
73
|
+
assessed directly:
|
|
74
|
+
|
|
75
|
+
* `Grid1DUniformSpectral` — equispaced spectral grid; the shift and spatial derivatives are **exact**
|
|
76
|
+
(Fourier), with 3/2-rule dealiasing for the quadratic nonlinearity.
|
|
77
|
+
* `Grid1DCubicSpline` — grid-based discretization; the shift, derivative, and inner-product
|
|
78
|
+
operators are realized via **periodic cubic-spline interpolation** (hence an additional
|
|
79
|
+
interpolation error, as encountered when non-intrusiveness is actually relevant).
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Repository structure
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
SROpInf/
|
|
87
|
+
├── pyproject.toml # package metadata + dependencies (installable, src-layout)
|
|
88
|
+
├── requirements.txt # runtime deps (see also pyproject.toml)
|
|
89
|
+
├── requirements-dev.txt # dev/test deps
|
|
90
|
+
├── src/SROpInf/
|
|
91
|
+
│ ├── grids/grid1d.py # Grid1D base + Grid1DUniformSpectral + Grid1DCubicSpline
|
|
92
|
+
│ │ # (inner product, sqrt-mass map R, shift_x, diff_x, fft/ifft)
|
|
93
|
+
│ ├── models/
|
|
94
|
+
│ │ ├── model.py # FullOrderModel, SymmetryReducedScaledFullOrderModel (.project),
|
|
95
|
+
│ │ │ # SymmetryReducedScaledReducedOrderModel (.solve, .sample_and_compare)
|
|
96
|
+
│ │ └── ks.py # KuramotoSivashinsky equation (polynomial operators)
|
|
97
|
+
│ ├── sr_tools.py # template_fitting (shift amount c(t)); sropinf (the S-R OpInf
|
|
98
|
+
│ │ # regression, with re-projection / grid-search / cross-validation)
|
|
99
|
+
│ ├── mode_decomposition.py # pod (energy-truncated POD of the symmetry-reduced snapshots)
|
|
100
|
+
│ ├── timestepper.py # explicit (Euler/RK2/RK4) and semi-implicit (RK2CN/RK3CN) steppers
|
|
101
|
+
│ ├── dataloader.py # FOMDataloader (loads trajectories / shift amounts from disk)
|
|
102
|
+
│ └── typing.py # array type aliases
|
|
103
|
+
├── example/ks/
|
|
104
|
+
│ ├── configs.py # all KS parameters and file paths (single source of truth)
|
|
105
|
+
│ ├── plot.py # figure helpers (x–t contours, spatial profiles, error bands, ...)
|
|
106
|
+
│ ├── ks_base_solution.ipynb # experiment 1: single base travelling-wave solution
|
|
107
|
+
│ └── ks_perturbed_solutions.ipynb # experiment 2: family of perturbed solutions (+ amplitude sweep)
|
|
108
|
+
└── test/ # pytest suite (grids + model polynomial composition)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
> `output/` (generated trajectories, data, and figures) is **not** tracked — it is fully
|
|
112
|
+
> regenerated by running the example notebooks.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Installation
|
|
117
|
+
|
|
118
|
+
Requires **Python ≥ 3.10** (developed and tested with Python 3.13).
|
|
119
|
+
|
|
120
|
+
### From PyPI (recommended)
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
python3 -m pip install sr-opinf
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The package is then importable as `SROpInf`:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
import SROpInf
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
> The install name and the import name differ on purpose: you **install** the distribution
|
|
133
|
+
> `sr-opinf` but **import** the package `SROpInf` — the same pattern as
|
|
134
|
+
> `pip install scikit-learn` / `import sklearn`.
|
|
135
|
+
|
|
136
|
+
### From source (for development / reproducing the experiments)
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# from the repository root
|
|
140
|
+
python3 -m pip install -e . # runtime install (numpy, scipy, matplotlib, tqdm)
|
|
141
|
+
python3 -m pip install -e ".[dev]" # + dev/test extras (pytest, ipywidgets)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The `-e` (editable) install puts the `SROpInf` package on the path so the example notebooks can
|
|
145
|
+
`import SROpInf...` directly. Exact dependency versions are declared in
|
|
146
|
+
[`pyproject.toml`](pyproject.toml).
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Reproducing the paper experiments
|
|
151
|
+
|
|
152
|
+
The experiments live in [`example/ks/`](example/ks/). Run the notebooks top-to-bottom:
|
|
153
|
+
|
|
154
|
+
### 1. Base travelling-wave solution — `ks_base_solution.ipynb`
|
|
155
|
+
Reconstruction (train = test) of a single KS travelling-wave solution. Builds the symmetry-reduced
|
|
156
|
+
POD subspace and compares **S-R POD–Galerkin** against **S-R OpInf** (plain, re-projected, and
|
|
157
|
+
penalty-regularized), on **both** the spectral and the cubic-spline grids — quantifying the effect
|
|
158
|
+
of the shift-induced interpolation error.
|
|
159
|
+
|
|
160
|
+
### 2. Perturbed solutions — `ks_perturbed_solutions.ipynb`
|
|
161
|
+
Generalization across a family of solutions: trains on perturbed initial conditions and evaluates on
|
|
162
|
+
a disjoint, held-out testing set. Includes a **perturbation-amplitude sweep**: per-trajectory testing
|
|
163
|
+
errors are written to `output/<case>/sweep_rRMSE/` and the final cell aggregates them into a box-plot
|
|
164
|
+
of testing error vs. perturbation amplitude.
|
|
165
|
+
|
|
166
|
+
### Configuration
|
|
167
|
+
All parameters and paths are centralized in [`example/ks/configs.py`](example/ks/configs.py):
|
|
168
|
+
|
|
169
|
+
* `type_traj_training` — `"base_solution"` or `"perturbed_solutions"`.
|
|
170
|
+
* physical / discretization — `Lx = 2π`, `nx = 256`, `nu = 4/87`, `T = 10`, `dt = 1e-3`.
|
|
171
|
+
* ROM — `poly_comp = [1, 2]` (linear + quadratic), `pod_energy_threshold`, the OpInf
|
|
172
|
+
`penalty_weight_*` (Tikhonov penalties on the inferred operators), and
|
|
173
|
+
`shift_speed_denom_threshold` (regularizes the shift-reconstruction denominator).
|
|
174
|
+
|
|
175
|
+
The output directory defaults to `output/ks_multiple_solutions/` and can be overridden with the
|
|
176
|
+
`NISRH_OUTPUT_DIR` environment variable. Each notebook's first cell `assert`s that `configs` points
|
|
177
|
+
at the matching output folder and trajectory type, to prevent accidentally mixing cases.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Tests
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
python3 -m pytest # from the SROpInf/ directory
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The suite checks the grid operators (spectral vs. cubic-spline shift / derivative, inner products)
|
|
188
|
+
and the polynomial-composition machinery of the model class.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Citation
|
|
193
|
+
|
|
194
|
+
If you use this code, please cite the accompanying paper:
|
|
195
|
+
|
|
196
|
+
```bibtex
|
|
197
|
+
@misc{shuai2025symmetryreduced,
|
|
198
|
+
title = {Symmetry-reduced model reduction of shift-equivariant systems via operator inference},
|
|
199
|
+
author = {Shuai, Yu and Rowley, Clarence W.},
|
|
200
|
+
year = {2025},
|
|
201
|
+
eprint = {2507.18780},
|
|
202
|
+
archivePrefix = {arXiv},
|
|
203
|
+
primaryClass = {math.NA},
|
|
204
|
+
note = {Submitted to Advances in Computational Mathematics (in revision)},
|
|
205
|
+
url = {https://arxiv.org/abs/2507.18780}
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## License
|
|
210
|
+
|
|
211
|
+
Released under the MIT License (see [LICENSE](LICENSE)).
|
sr_opinf-0.1.0/README.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# SROpInf — Symmetry-Reduced Operator Inference
|
|
2
|
+
|
|
3
|
+
`SROpInf` is a Python package for **symmetry-reduced model reduction of shift-equivariant
|
|
4
|
+
systems via operator inference**. For a 1D periodic PDE whose solutions are dominated by a
|
|
5
|
+
travelling / drifting structure (e.g. a travelling wave), it builds a reduced-order model (ROM)
|
|
6
|
+
that first factors out the continuous translation symmetry and then learns the reduced dynamics in
|
|
7
|
+
the co-moving frame — either **intrusively** (symmetry-reduced POD–Galerkin projection) or
|
|
8
|
+
**non-intrusively** from snapshot data (symmetry-reduced operator inference, S-R OpInf).
|
|
9
|
+
|
|
10
|
+
The package accompanies the paper
|
|
11
|
+
|
|
12
|
+
> Yu Shuai and Clarence W. Rowley,
|
|
13
|
+
> *Symmetry-reduced model reduction of shift-equivariant systems via operator inference*,
|
|
14
|
+
> arXiv:[2507.18780](https://arxiv.org/abs/2507.18780) (2025).
|
|
15
|
+
> Submitted to *Advances in Computational Mathematics* (in revision).
|
|
16
|
+
|
|
17
|
+
and reproduces all of its Kuramoto–Sivashinsky (KS) numerical experiments.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Method at a glance
|
|
22
|
+
|
|
23
|
+
For a shift-equivariant system the solution `q(x, t)` is decomposed into a **shift amount** `c(t)`
|
|
24
|
+
(the location of the travelling structure) and a **co-moving profile** obtained by aligning each
|
|
25
|
+
snapshot to a fixed template `q_template = cos(2πx/L)` (template fitting). The reduced model then
|
|
26
|
+
evolves
|
|
27
|
+
|
|
28
|
+
* the reduced co-moving state `z(t)` (POD coefficients of the template-fitted, scaled snapshots), and
|
|
29
|
+
* the scalar shift amount `c(t)` via a reconstruction equation `dc/dt = numerator / denominator`.
|
|
30
|
+
|
|
31
|
+
Two ways to obtain the reduced operators are provided:
|
|
32
|
+
|
|
33
|
+
| ROM | Intrusive? | How the reduced operators are obtained |
|
|
34
|
+
|-----|------------|----------------------------------------|
|
|
35
|
+
| **S-R POD–Galerkin** | yes | Galerkin projection of the (scaled, symmetry-reduced) FOM right-hand side onto the POD subspace. |
|
|
36
|
+
| **S-R OpInf** | no | Ridge-regression of reduced polynomial operators to the data; optional **re-projection** for consistency and **penalty (Tikhonov) regularization** for stability. |
|
|
37
|
+
|
|
38
|
+
Two spatial discretizations are supported, which lets the shift-induced interpolation error be
|
|
39
|
+
assessed directly:
|
|
40
|
+
|
|
41
|
+
* `Grid1DUniformSpectral` — equispaced spectral grid; the shift and spatial derivatives are **exact**
|
|
42
|
+
(Fourier), with 3/2-rule dealiasing for the quadratic nonlinearity.
|
|
43
|
+
* `Grid1DCubicSpline` — grid-based discretization; the shift, derivative, and inner-product
|
|
44
|
+
operators are realized via **periodic cubic-spline interpolation** (hence an additional
|
|
45
|
+
interpolation error, as encountered when non-intrusiveness is actually relevant).
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Repository structure
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
SROpInf/
|
|
53
|
+
├── pyproject.toml # package metadata + dependencies (installable, src-layout)
|
|
54
|
+
├── requirements.txt # runtime deps (see also pyproject.toml)
|
|
55
|
+
├── requirements-dev.txt # dev/test deps
|
|
56
|
+
├── src/SROpInf/
|
|
57
|
+
│ ├── grids/grid1d.py # Grid1D base + Grid1DUniformSpectral + Grid1DCubicSpline
|
|
58
|
+
│ │ # (inner product, sqrt-mass map R, shift_x, diff_x, fft/ifft)
|
|
59
|
+
│ ├── models/
|
|
60
|
+
│ │ ├── model.py # FullOrderModel, SymmetryReducedScaledFullOrderModel (.project),
|
|
61
|
+
│ │ │ # SymmetryReducedScaledReducedOrderModel (.solve, .sample_and_compare)
|
|
62
|
+
│ │ └── ks.py # KuramotoSivashinsky equation (polynomial operators)
|
|
63
|
+
│ ├── sr_tools.py # template_fitting (shift amount c(t)); sropinf (the S-R OpInf
|
|
64
|
+
│ │ # regression, with re-projection / grid-search / cross-validation)
|
|
65
|
+
│ ├── mode_decomposition.py # pod (energy-truncated POD of the symmetry-reduced snapshots)
|
|
66
|
+
│ ├── timestepper.py # explicit (Euler/RK2/RK4) and semi-implicit (RK2CN/RK3CN) steppers
|
|
67
|
+
│ ├── dataloader.py # FOMDataloader (loads trajectories / shift amounts from disk)
|
|
68
|
+
│ └── typing.py # array type aliases
|
|
69
|
+
├── example/ks/
|
|
70
|
+
│ ├── configs.py # all KS parameters and file paths (single source of truth)
|
|
71
|
+
│ ├── plot.py # figure helpers (x–t contours, spatial profiles, error bands, ...)
|
|
72
|
+
│ ├── ks_base_solution.ipynb # experiment 1: single base travelling-wave solution
|
|
73
|
+
│ └── ks_perturbed_solutions.ipynb # experiment 2: family of perturbed solutions (+ amplitude sweep)
|
|
74
|
+
└── test/ # pytest suite (grids + model polynomial composition)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
> `output/` (generated trajectories, data, and figures) is **not** tracked — it is fully
|
|
78
|
+
> regenerated by running the example notebooks.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Installation
|
|
83
|
+
|
|
84
|
+
Requires **Python ≥ 3.10** (developed and tested with Python 3.13).
|
|
85
|
+
|
|
86
|
+
### From PyPI (recommended)
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
python3 -m pip install sr-opinf
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The package is then importable as `SROpInf`:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
import SROpInf
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
> The install name and the import name differ on purpose: you **install** the distribution
|
|
99
|
+
> `sr-opinf` but **import** the package `SROpInf` — the same pattern as
|
|
100
|
+
> `pip install scikit-learn` / `import sklearn`.
|
|
101
|
+
|
|
102
|
+
### From source (for development / reproducing the experiments)
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# from the repository root
|
|
106
|
+
python3 -m pip install -e . # runtime install (numpy, scipy, matplotlib, tqdm)
|
|
107
|
+
python3 -m pip install -e ".[dev]" # + dev/test extras (pytest, ipywidgets)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The `-e` (editable) install puts the `SROpInf` package on the path so the example notebooks can
|
|
111
|
+
`import SROpInf...` directly. Exact dependency versions are declared in
|
|
112
|
+
[`pyproject.toml`](pyproject.toml).
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Reproducing the paper experiments
|
|
117
|
+
|
|
118
|
+
The experiments live in [`example/ks/`](example/ks/). Run the notebooks top-to-bottom:
|
|
119
|
+
|
|
120
|
+
### 1. Base travelling-wave solution — `ks_base_solution.ipynb`
|
|
121
|
+
Reconstruction (train = test) of a single KS travelling-wave solution. Builds the symmetry-reduced
|
|
122
|
+
POD subspace and compares **S-R POD–Galerkin** against **S-R OpInf** (plain, re-projected, and
|
|
123
|
+
penalty-regularized), on **both** the spectral and the cubic-spline grids — quantifying the effect
|
|
124
|
+
of the shift-induced interpolation error.
|
|
125
|
+
|
|
126
|
+
### 2. Perturbed solutions — `ks_perturbed_solutions.ipynb`
|
|
127
|
+
Generalization across a family of solutions: trains on perturbed initial conditions and evaluates on
|
|
128
|
+
a disjoint, held-out testing set. Includes a **perturbation-amplitude sweep**: per-trajectory testing
|
|
129
|
+
errors are written to `output/<case>/sweep_rRMSE/` and the final cell aggregates them into a box-plot
|
|
130
|
+
of testing error vs. perturbation amplitude.
|
|
131
|
+
|
|
132
|
+
### Configuration
|
|
133
|
+
All parameters and paths are centralized in [`example/ks/configs.py`](example/ks/configs.py):
|
|
134
|
+
|
|
135
|
+
* `type_traj_training` — `"base_solution"` or `"perturbed_solutions"`.
|
|
136
|
+
* physical / discretization — `Lx = 2π`, `nx = 256`, `nu = 4/87`, `T = 10`, `dt = 1e-3`.
|
|
137
|
+
* ROM — `poly_comp = [1, 2]` (linear + quadratic), `pod_energy_threshold`, the OpInf
|
|
138
|
+
`penalty_weight_*` (Tikhonov penalties on the inferred operators), and
|
|
139
|
+
`shift_speed_denom_threshold` (regularizes the shift-reconstruction denominator).
|
|
140
|
+
|
|
141
|
+
The output directory defaults to `output/ks_multiple_solutions/` and can be overridden with the
|
|
142
|
+
`NISRH_OUTPUT_DIR` environment variable. Each notebook's first cell `assert`s that `configs` points
|
|
143
|
+
at the matching output folder and trajectory type, to prevent accidentally mixing cases.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Tests
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
python3 -m pytest # from the SROpInf/ directory
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The suite checks the grid operators (spectral vs. cubic-spline shift / derivative, inner products)
|
|
154
|
+
and the polynomial-composition machinery of the model class.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Citation
|
|
159
|
+
|
|
160
|
+
If you use this code, please cite the accompanying paper:
|
|
161
|
+
|
|
162
|
+
```bibtex
|
|
163
|
+
@misc{shuai2025symmetryreduced,
|
|
164
|
+
title = {Symmetry-reduced model reduction of shift-equivariant systems via operator inference},
|
|
165
|
+
author = {Shuai, Yu and Rowley, Clarence W.},
|
|
166
|
+
year = {2025},
|
|
167
|
+
eprint = {2507.18780},
|
|
168
|
+
archivePrefix = {arXiv},
|
|
169
|
+
primaryClass = {math.NA},
|
|
170
|
+
note = {Submitted to Advances in Computational Mathematics (in revision)},
|
|
171
|
+
url = {https://arxiv.org/abs/2507.18780}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## License
|
|
176
|
+
|
|
177
|
+
Released under the MIT License (see [LICENSE](LICENSE)).
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "sr-opinf"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "SR-OpInf: Symmetry-Reduced Operator Inference for Shift-Equivariant Systems"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Yu Shuai", email = "yu_shuai@princeton.edu" },
|
|
14
|
+
{ name = "Clarence W. Rowley" },
|
|
15
|
+
]
|
|
16
|
+
keywords = [
|
|
17
|
+
"operator-inference", "reduced-order-model", "model-order-reduction",
|
|
18
|
+
"symmetry-reduction", "shift-equivariant", "Kuramoto-Sivashinsky", "POD", "ROM",
|
|
19
|
+
]
|
|
20
|
+
classifiers = [
|
|
21
|
+
"Development Status :: 4 - Beta",
|
|
22
|
+
"Intended Audience :: Science/Research",
|
|
23
|
+
"License :: OSI Approved :: MIT License",
|
|
24
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
25
|
+
"Programming Language :: Python :: 3.10",
|
|
26
|
+
"Programming Language :: Python :: 3.11",
|
|
27
|
+
"Programming Language :: Python :: 3.12",
|
|
28
|
+
"Programming Language :: Python :: 3.13",
|
|
29
|
+
"Topic :: Scientific/Engineering :: Mathematics",
|
|
30
|
+
"Topic :: Scientific/Engineering :: Physics",
|
|
31
|
+
"Operating System :: OS Independent",
|
|
32
|
+
]
|
|
33
|
+
dependencies = [
|
|
34
|
+
"numpy>=1.23",
|
|
35
|
+
"scipy>=1.10",
|
|
36
|
+
"matplotlib>=3.6",
|
|
37
|
+
"tqdm>=4.65",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.optional-dependencies]
|
|
41
|
+
dev = [
|
|
42
|
+
"pytest>=7.0",
|
|
43
|
+
"ipywidgets>=8.0",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[project.urls]
|
|
47
|
+
Homepage = "https://github.com/Yu-Shuai-PU/sr-opinf"
|
|
48
|
+
Repository = "https://github.com/Yu-Shuai-PU/sr-opinf"
|
|
49
|
+
"Paper (arXiv)" = "https://arxiv.org/abs/2507.18780"
|
|
50
|
+
|
|
51
|
+
[tool.setuptools.packages.find]
|
|
52
|
+
where = ["src"]
|
|
53
|
+
include = ["SROpInf*"]
|
sr_opinf-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""SROpInf: Symmetry-Reduced Operator Inference for 1D periodic PDEs."""
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Data loader for loading data and do POD or streaming SVD or balanced POD to generate reduced subspaces or preliminarily reduce the dimensionality of the FOM before official training."""
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
class FOMDataloader:
|
|
5
|
+
def __init__(self, params):
|
|
6
|
+
self.params = params
|
|
7
|
+
|
|
8
|
+
def get_traj(self, which_traj, which_snapshot, is_scaled=False, is_template_fitted=False):
|
|
9
|
+
"""Return the scaled data (R)q (N, T, M) of trajectories"""
|
|
10
|
+
which_traj = np.atleast_1d(which_traj)
|
|
11
|
+
which_snapshot = np.atleast_1d(which_snapshot)
|
|
12
|
+
if is_scaled:
|
|
13
|
+
if is_template_fitted:
|
|
14
|
+
fname_Q = self.params.fname_traj_fitted_scaled
|
|
15
|
+
else:
|
|
16
|
+
fname_Q = self.params.fname_traj_scaled
|
|
17
|
+
else:
|
|
18
|
+
if is_template_fitted:
|
|
19
|
+
fname_Q = self.params.fname_traj_fitted
|
|
20
|
+
else:
|
|
21
|
+
fname_Q = self.params.fname_traj
|
|
22
|
+
num_traj, num_snapshot = len(which_traj), len(which_snapshot)
|
|
23
|
+
|
|
24
|
+
Q0 = np.load(fname_Q % ("fom", which_traj[0]), mmap_mode='r') # shape (n_states, n_snapshots)
|
|
25
|
+
num_states = Q0.shape[0]
|
|
26
|
+
Q = np.empty((num_states, num_snapshot, num_traj))
|
|
27
|
+
for i, traj_idx in enumerate(which_traj):
|
|
28
|
+
Q[:,:,i] = np.load(fname_Q % ("fom", traj_idx), mmap_mode='r')[:, which_snapshot]
|
|
29
|
+
|
|
30
|
+
return Q.squeeze() # shape (N, T, M) or (N, T)
|
|
31
|
+
|
|
32
|
+
def get_shift_amount(self, which_traj, which_snapshot):
|
|
33
|
+
"""Return the shift amount c (T, M)"""
|
|
34
|
+
which_traj = np.atleast_1d(which_traj)
|
|
35
|
+
which_snapshot = np.atleast_1d(which_snapshot)
|
|
36
|
+
fname_shift_amount = self.params.fname_shift_amount
|
|
37
|
+
num_traj, num_snapshot = len(which_traj), len(which_snapshot)
|
|
38
|
+
c = np.empty((num_snapshot, num_traj))
|
|
39
|
+
|
|
40
|
+
for i, traj_idx in enumerate(which_traj):
|
|
41
|
+
c[:,i] = np.load(fname_shift_amount % ("fom", traj_idx))[which_snapshot]
|
|
42
|
+
|
|
43
|
+
return c.squeeze() # shape (T, M) or (T,)
|
|
44
|
+
|
|
45
|
+
def get_time(self, which_snapshot):
|
|
46
|
+
"""Return the time vector (T, M)"""
|
|
47
|
+
which_snapshot = np.atleast_1d(which_snapshot)
|
|
48
|
+
fname_time = self.params.fname_time
|
|
49
|
+
time = np.load(fname_time)[which_snapshot]
|
|
50
|
+
return time
|
|
File without changes
|