Skip to content

Commit f3ab889

Browse files
klapomtezzele
authored andcommitted
Clustering refactor, codacy compliance, doc updates
- Clustering now refactored into a protected _cluster method which does the actual clustering and then a clustering method and a hyperparameter sweep. - Added new private variable for the `svd_rank_preallocate` - Edited lines too long. - Completed many missing doc strings - Simplified some omega handling logic. - Tutorials use updated API, adjusted some documentation, added to README, edited titles to be more useful.
1 parent 5bad925 commit f3ab889

File tree

7 files changed

+519
-316
lines changed

7 files changed

+519
-316
lines changed

pydmd/costs.py

Lines changed: 261 additions & 138 deletions
Large diffs are not rendered by default.

pydmd/mrcosts.py

Lines changed: 123 additions & 70 deletions
Large diffs are not rendered by default.

tests/test_costs.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ def overlapping_oscillators():
1616
"""
1717

1818
def rhs_FNM(t, x, tau, a, b, Iext):
19-
# FitzHugh-Nagumo Model
19+
"""FitzHugh-Nagumo Model
20+
21+
See costs-tutorial_toy-data for details.
22+
"""
2023
v = x[0]
2124
w = x[1]
2225
vdot = v - (v**3) / 3 - w + Iext
@@ -26,7 +29,10 @@ def rhs_FNM(t, x, tau, a, b, Iext):
2629
return dx
2730

2831
def rhs_UFD(t, y, eta, epsilon, tau):
29-
# Unforced Duffing Oscillator
32+
"""Unforced Duffing Oscillator
33+
34+
See costs-tutorial_toy-data for details.
35+
"""
3036
p = y[0]
3137
q = y[1]
3238
pdot = q
@@ -121,7 +127,7 @@ def rhs_UFD(t, y, eta, epsilon, tau):
121127
)
122128
mrd.fit(data, np.atleast_2d(time), window, step, verbose=False)
123129
# Force the clustering to use two components due to the nature of the toy data.
124-
_ = mrd.cluster_omega(n_components=2, transform_method=transform_method)
130+
mrd.cluster_omega(n_components=2, transform_method=transform_method)
125131

126132

127133
def test_construction():
@@ -148,6 +154,7 @@ def test_construction():
148154

149155

150156
def test_bad_construction():
157+
"""Test bad fit and construction keywords and parameters."""
151158
mrd_alternative = COSTS()
152159
with raises(ValueError):
153160
mrd_alternative.fit(
@@ -156,6 +163,7 @@ def test_bad_construction():
156163

157164

158165
def test_window_construction():
166+
"""Determine that the correct number of windows were found."""
159167
assert mrd.build_windows(data, window, step, integer_windows=True) == 61
160168

161169

@@ -244,15 +252,16 @@ def test_omega_transforms():
244252

245253

246254
def test_to_xarray():
247-
""" """
255+
"""Tests the round trip conversion to and from xarray."""
248256
ds = mrd.to_xarray()
249257
mrd_convert = mrd.from_xarray(ds)
250258

251259
assert np.allclose(mrd.omega_array, mrd_convert.omega_array)
252260
assert np.allclose(mrd.modes_array, mrd_convert.modes_array)
253261
assert np.allclose(mrd.cluster_centroids, mrd_convert.cluster_centroids)
254262

255-
# The round trip of the pydmd_kwargs is sensitive to python and numpy version.
263+
# The round trip of the pydmd_kwargs is sensitive to python and numpy
264+
# version.
256265
assert np.allclose(
257266
mrd._pydmd_kwargs["proj_basis"], mrd_convert._pydmd_kwargs["proj_basis"]
258267
)
@@ -262,6 +271,7 @@ def test_to_xarray():
262271

263272

264273
def test_plotters():
274+
"""Determine no errors are triggered when plotting."""
265275
mrd.plot_reconstructions(data)
266276
mrd.plot_scale_separation(data)
267277
mrd.plot_error(data)

tests/test_mrcosts.py

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,23 @@
99

1010

1111
def build_multiscale_process():
12-
""" """
12+
"""
13+
Simulates a system with two oscillators with occasionally overlapping
14+
frequencies (adapted from Dylewsky et al., 2019) with a transient
15+
coherent wave packet constructive interfering with the system.
16+
17+
Oscillator #1: FitzHugh-Nagumo Model
18+
Oscillator #2: Unforced Duffing Oscillator
19+
20+
Data are sub-selected to reduce the computational load from minutes to
21+
10s of seconds. See costs-tutorial_toy-data for details.
22+
"""
1323

1424
def rhs_FNM(t, x, tau, a, b, Iext):
15-
# FitzHugh-Nagumo Model
25+
"""FitzHugh-Nagumo Model
26+
27+
See costs-tutorial_toy-data for details.
28+
"""
1629
v = x[0]
1730
w = x[1]
1831
vdot = v - (v**3) / 3 - w + Iext
@@ -22,7 +35,10 @@ def rhs_FNM(t, x, tau, a, b, Iext):
2235
return dx
2336

2437
def rhs_UFD(t, y, eta, epsilon, tau):
25-
# Unforced Duffing Oscillator
38+
"""Unforced Duffing Oscillator
39+
40+
See costs-tutorial_toy-data for details.
41+
"""
2642
p = y[0]
2743
q = y[1]
2844
pdot = q
@@ -269,7 +285,10 @@ def test_omega_transforms():
269285

270286

271287
def test_netcdf():
272-
""" """
288+
"""
289+
Test the round trip conversion of the mrCOSTS object to file in
290+
netcdf format and back to mrCOSTS.
291+
"""
273292
mrc.to_netcdf("tests")
274293
file_list = glob.glob("*tests*.nc")
275294
mrc_from_file = mrCOSTS()
@@ -283,6 +302,10 @@ def test_netcdf():
283302

284303

285304
def test_plot_local_reconstructions():
305+
"""
306+
Test that the local reconstruction plot works and raises the appropriate
307+
errors when trying to plot the first decomposition level without data.
308+
"""
286309
mrc.plot_local_reconstructions(0, data=data)
287310

288311
with raises(ValueError):
@@ -293,6 +316,10 @@ def test_plot_local_reconstructions():
293316

294317

295318
def test_plot_local_error():
319+
"""
320+
Test that the local error plot works and raises the appropriate
321+
errors when trying to plot the first decomposition level without data.
322+
"""
296323
mrc.plot_local_error(0, data=data)
297324

298325
with raises(ValueError):
@@ -303,6 +330,10 @@ def test_plot_local_error():
303330

304331

305332
def test_plot_local_scale_separation():
333+
"""
334+
Test that the local scale separation plot works and raises the appropriate
335+
errors when trying to plot the first decomposition level without data.
336+
"""
306337
_ = mrc.plot_local_scale_separation(0, data=data)
307338

308339
with raises(ValueError):
@@ -313,6 +344,11 @@ def test_plot_local_scale_separation():
313344

314345

315346
def test_plot_local_time_series():
347+
"""
348+
Test that the local time series of a point plot works and raises the
349+
appropriate errors when trying to plot the first decomposition level
350+
without data.
351+
"""
316352
_ = mrc.plot_local_time_series(0, 0, data=data)
317353

318354
with raises(ValueError):
@@ -323,6 +359,7 @@ def test_plot_local_time_series():
323359

324360

325361
def tear_down():
362+
"""Remove the files generated in `test_netcdf`"""
326363
file_list = glob.glob("*tests*.nc")
327364
for f in file_list:
328365
os.remove(f)

tutorials/README.md

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,29 @@ In this folder we collect several useful tutorials in order to understand the pr
44
An additional PDF tutorial ([DSWeb contest winner](https://dsweb.siam.org/The-Magazine/All-Issues/dsweb-2019-contest-tutorials-on-dynamical-systems-software)) is available [here](tutorial_dsweb.pdf).
55

66

7-
| Name | Description | PyDMD used classes |
8-
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|-----------------------|
9-
| Tutorial1 [[.ipynb](tutorial1/tutorial-1-dmd.ipynb), [.py](tutorial1/tutorial-1-dmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial1dmd.html)] | Analyzing real, simple data sets with PyDMD | `pydmd.DMD`, `pydmd.BOPDMD` |
10-
| Tutorial2 [[.ipynb](tutorial2/tutorial-2-adv-dmd.ipynb), [.py](tutorial2/tutorial-2-adv-dmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial2advdmd.html)] | advanced features of standard DMD | `pydmd.DMD` |
11-
| Tutorial3 [[.ipynb](tutorial3/tutorial-3-mrdmd.ipynb), [.py](tutorial3/tutorial-3-mrdmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial3mrdmd.html)] | multi-resolution DMD for transient phenomena | `pydmd.MrDMD` |
12-
| Tutorial4 [[.ipynb](tutorial4/tutorial-4-cdmd.ipynb), [.py](tutorial4/tutorial-4-cdmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial4cdmd.html)] | compress DMD for computation speedup | `pydmd.CDMD` |
13-
| Tutorial5 [[.ipynb](tutorial5/tutorial-5-fbdmd.ipynb), [.py](tutorial5/tutorial-5-fbdmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial5fbdmd.html)] | forward-backward DMD for CFD model analysis | `pydmd.FbDMD` |
14-
| Tutorial6 [[.ipynb](tutorial6/tutorial-6-hodmd.ipynb), [.py](tutorial6/tutorial-6-hodmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial6hodmd.html)] | higher-order DMD applied to scalar time-series | `pydmd.HODMD` |
15-
| Tutorial7 [[.ipynb](tutorial7/tutorial-7-dmdc.ipynb), [.py](tutorial7/tutorial-7-dmdc.py), [.html](http://pydmd.github.io/PyDMD/tutorial7dmdc.html)] | DMD with control | `pydmd.DMDC` |
16-
| Tutorial8 [[.ipynb](tutorial8/tutorial-8-comparisons.ipynb), [.py](tutorial8/tutorial-8-comparisons.py), [.html](http://pydmd.github.io/PyDMD/tutorial8comparison.html)] | comparison between DMD and optimal closed-form DMD | `pydmd.OptDMD` |
17-
| Tutorial9 [[.ipynb](tutorial9/tutorial-9-spdmd.ipynb), [.py](tutorial9/tutorial-9-spdmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial9spdmd.html)] | sparsity-promoting DMD | `pydmd.SpDMD` |
18-
| Tutorial10 [[.ipynb](tutorial10/tutorial-10-paramdmd.ipynb), [.py](tutorial10/tutorial-10-paramdmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial10paramdmd.html)] | parametric DMD | `pydmd.ParametricDMD` |
19-
| Tutorial11 [[.ipynb](tutorial10/tutorial-11-regularization.ipynb), [.py](tutorial11/tutorial-11-regularization.py), [.html](http://pydmd.github.io/PyDMD/tutorial11regularization.html)] | Tikhonov regularization | `pydmd.DMDBase` |
20-
| Tutorial12 [[.ipynb](tutorial12/tutorial-12-cdmd.ipynb), [.py](tutorial12/tutorial-12-cdmd.py)] | cDMD for background modeling | `pydmd.CDMD` |
21-
| Tutorial13 [[.ipynb](tutorial13/tutorial-13-subspacedmd.ipynb), [.py](tutorial13/tutorial-13-subspacedmd.py)] | SubspaceDMD for locating eigenvalues of stochastic systems | `pydmd.SubspaceDMD` |
22-
| Tutorial14 [[.ipynb](tutorial14/tutorial-14-bop-dmd.ipynb), [.py](tutorial14/tutorial-14-bop-dmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial14-bop-dmd.html)] | Comparison between Bagging-/ Optimized DMD and exact DMD | `pydmd.BOPDMD` |
23-
| Tutorial15 [[.ipynb](tutorial15/tutorial-15-pidmd.ipynb), [.py](tutorial15/tutorial-15-pidmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial15-pidmd.html)] | Physics-informed DMD for manifold enforcement | `pydmd.PiDMD` |
24-
| Tutorial16 [[.ipynb](tutorial16/tutorial-16-rdmd.ipynb), [.py](tutorial16/tutorial-16-rdmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial16-rdmd.html)] | Randomized DMD for greater computation speedup | `pydmd.RDMD` |
25-
| Tutorial17 [[.ipynb](tutorial17/tutorial-17-edmd.ipynb), [.py](tutorial17/tutorial-17-edmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial17-edmd.html)] | Extended DMD for nonlinear eigenfunction discovery | `pydmd.EDMD` |
26-
| Tutorial18 [[.ipynb](tutorial18/tutorial-18-lando.ipynb), [.py](tutorial18/tutorial-18-lando.py), [.html](http://pydmd.github.io/PyDMD/tutorial18-lando.html)] | LANDO for nonlinear system modeling | `pydmd.LANDO` |
27-
| Tutorial19 [[.ipynb](tutorial19/tutorial-19-havok.ipynb), [.py](tutorial19/tutorial-19-havok.py), [.html](http://pydmd.github.io/PyDMD/tutorial19-havok.html)] | HAVOK for modeling chaos with partial measurements | `pydmd.HAVOK` |
7+
| Name | Description | PyDMD used classes |
8+
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------|-----------------------------|
9+
| Tutorial1 [[.ipynb](tutorial1/tutorial-1-dmd.ipynb), [.py](tutorial1/tutorial-1-dmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial1dmd.html)] | Analyzing real, simple data sets with PyDMD | `pydmd.DMD`, `pydmd.BOPDMD` |
10+
| Tutorial2 [[.ipynb](tutorial2/tutorial-2-adv-dmd.ipynb), [.py](tutorial2/tutorial-2-adv-dmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial2advdmd.html)] | advanced features of standard DMD | `pydmd.DMD` |
11+
| Tutorial3 [[.ipynb](tutorial3/tutorial-3-mrdmd.ipynb), [.py](tutorial3/tutorial-3-mrdmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial3mrdmd.html)] | multi-resolution DMD for transient phenomena | `pydmd.MrDMD` |
12+
| Tutorial4 [[.ipynb](tutorial4/tutorial-4-cdmd.ipynb), [.py](tutorial4/tutorial-4-cdmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial4cdmd.html)] | compress DMD for computation speedup | `pydmd.CDMD` |
13+
| Tutorial5 [[.ipynb](tutorial5/tutorial-5-fbdmd.ipynb), [.py](tutorial5/tutorial-5-fbdmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial5fbdmd.html)] | forward-backward DMD for CFD model analysis | `pydmd.FbDMD` |
14+
| Tutorial6 [[.ipynb](tutorial6/tutorial-6-hodmd.ipynb), [.py](tutorial6/tutorial-6-hodmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial6hodmd.html)] | higher-order DMD applied to scalar time-series | `pydmd.HODMD` |
15+
| Tutorial7 [[.ipynb](tutorial7/tutorial-7-dmdc.ipynb), [.py](tutorial7/tutorial-7-dmdc.py), [.html](http://pydmd.github.io/PyDMD/tutorial7dmdc.html)] | DMD with control | `pydmd.DMDC` |
16+
| Tutorial8 [[.ipynb](tutorial8/tutorial-8-comparisons.ipynb), [.py](tutorial8/tutorial-8-comparisons.py), [.html](http://pydmd.github.io/PyDMD/tutorial8comparison.html)] | comparison between DMD and optimal closed-form DMD | `pydmd.OptDMD` |
17+
| Tutorial9 [[.ipynb](tutorial9/tutorial-9-spdmd.ipynb), [.py](tutorial9/tutorial-9-spdmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial9spdmd.html)] | sparsity-promoting DMD | `pydmd.SpDMD` |
18+
| Tutorial10 [[.ipynb](tutorial10/tutorial-10-paramdmd.ipynb), [.py](tutorial10/tutorial-10-paramdmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial10paramdmd.html)] | parametric DMD | `pydmd.ParametricDMD` |
19+
| Tutorial11 [[.ipynb](tutorial10/tutorial-11-regularization.ipynb), [.py](tutorial11/tutorial-11-regularization.py), [.html](http://pydmd.github.io/PyDMD/tutorial11regularization.html)] | Tikhonov regularization | `pydmd.DMDBase` |
20+
| Tutorial12 [[.ipynb](tutorial12/tutorial-12-cdmd.ipynb), [.py](tutorial12/tutorial-12-cdmd.py)] | cDMD for background modeling | `pydmd.CDMD` |
21+
| Tutorial13 [[.ipynb](tutorial13/tutorial-13-subspacedmd.ipynb), [.py](tutorial13/tutorial-13-subspacedmd.py)] | SubspaceDMD for locating eigenvalues of stochastic systems | `pydmd.SubspaceDMD` |
22+
| Tutorial14 [[.ipynb](tutorial14/tutorial-14-bop-dmd.ipynb), [.py](tutorial14/tutorial-14-bop-dmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial14-bop-dmd.html)] | Comparison between Bagging-/ Optimized DMD and exact DMD | `pydmd.BOPDMD` |
23+
| Tutorial15 [[.ipynb](tutorial15/tutorial-15-pidmd.ipynb), [.py](tutorial15/tutorial-15-pidmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial15-pidmd.html)] | Physics-informed DMD for manifold enforcement | `pydmd.PiDMD` |
24+
| Tutorial16 [[.ipynb](tutorial16/tutorial-16-rdmd.ipynb), [.py](tutorial16/tutorial-16-rdmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial16-rdmd.html)] | Randomized DMD for greater computation speedup | `pydmd.RDMD` |
25+
| Tutorial17 [[.ipynb](tutorial17/tutorial-17-edmd.ipynb), [.py](tutorial17/tutorial-17-edmd.py), [.html](http://pydmd.github.io/PyDMD/tutorial17-edmd.html)] | Extended DMD for nonlinear eigenfunction discovery | `pydmd.EDMD` |
26+
| Tutorial18 [[.ipynb](tutorial18/tutorial-18-lando.ipynb), [.py](tutorial18/tutorial-18-lando.py), [.html](http://pydmd.github.io/PyDMD/tutorial18-lando.html)] | LANDO for nonlinear system modeling | `pydmd.LANDO` |
27+
| Tutorial19 [[.ipynb](tutorial19/tutorial-19-havok.ipynb), [.py](tutorial19/tutorial-19-havok.py), [.html](http://pydmd.github.io/PyDMD/tutorial19-havok.html)] | HAVOK for modeling chaos with partial measurements | `pydmd.HAVOK` |
28+
| Tutorial20a&#160;[[.ipynb](tutorial20/costs-tutorial_toy-data.ipynb)] <br/><br/><br/><br/> | COSTS for decomposing toy data | `pydmd.COSTS` |
29+
| Tutorial20b&#160;[[.ipynb](tutorial20/costs-tutorial_real-data.ipynb)] <br/><br/><br/> | mrCOSTS for decomposing multi-scale physics of real, noisy data | `pydmd.mrCOSTS` |
2830

2931

3032

tutorials/tutorial20/costs-tutorial_real-data.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"cell_type": "markdown",
55
"metadata": {},
66
"source": [
7-
"# Multi-resolution Coherent Scale separation (mrCOSTS) using PyDMD\n",
7+
"# Tutorial 20b: Multi-resolution Coherent Scale separation (mrCOSTS) using real data\n",
88
"\n",
99
"This tutorial focuses on the real-world application the mrCOSTS object for multi-resolution coherent scale separation. In the toy-data example, the data include perfect oscillators as well as data engineered to be separable. Real world data is not so amiable. We provide this example with real data to illustrate how to use the mrCOSTS method on noisy, messy data. \n",
1010
"\n",

0 commit comments

Comments
 (0)