Code Monkey home page Code Monkey logo

pydmd's Introduction

Python Dynamic Mode Decomposition

Docs PyPI version Python versions Software License
CI Status Codacy Badge black code style
All Contributors GitHub Repo stars PyPI downloads per month JOSS DOI

Table of contents

Description

PyDMD is a Python package designed for Dynamic Mode Decomposition (DMD), a data-driven method used for analyzing and extracting spatiotemporal coherent structures from time-varying datasets. It provides a comprehensive and user-friendly interface for performing DMD analysis, making it a valuable tool for researchers, engineers, and data scientists working in various fields.

With PyDMD, users can easily decompose complex, high-dimensional datasets into a set of coherent spatial and temporal modes, capturing the underlying dynamics and extracting important features. The package implements both standard DMD algorithms and advanced variations, enabling users to choose the most suitable method for their specific needs. These extensions allow to deal with noisy data, big dataset, control variables, or to impose physical structures.

PyDMD offers a seamless integration with the scientific Python ecosystem, leveraging popular libraries such as NumPy and SciPy for efficient numerical computations and data manipulation. It also offers a variety of visualization tools, including mode reconstruction, energy spectrum analysis, and time evolution plotting. These capabilities enable users to gain insights into the dominant modes of the system, identify significant features, and understand the temporal evolution of the dynamics.

PyDMD promotes ease of use and customization, providing a well-documented API with intuitive function names and clear parameter descriptions. The package is actively maintained and updated, ensuring compatibility with the latest Python versions and incorporating user feedback to improve functionality and performance. We provide many tutorials showing the characteristics of the software. See the Examples section below and the Tutorials to have an idea of the potential of this package. Also see the diagram below for a summary of all available tools and functionalities. Currently in-progress contributions are represented by semi-transparent boxes.

Dependencies and installation

Installing via PIP

PyDMD is available on PyPI, therefore you can install the latest released version with:

> pip install pydmd

Installing from source

To install the bleeding edge version, clone this repository with:

> git clone https://github.com/PyDMD/PyDMD

and then install the package in development mode:

> pip install -e .

Dependencies

The core features of PyDMD depend on numpy and scipy. In order to use the plotting functionalities you will also need matplotlib.

Examples and Tutorials

You can find useful tutorials on how to use the package in the tutorials folder.

Here we show a simple application (taken from tutorial 2): we collect few snapshots from a toy system with some noise and reconstruct the entire system evolution.

The original snapshots used as input for the dynamic mode decomposition


The system evolution reconstructed with dynamic mode decomposition

Using PyDMD

To perform DMD, simply begin by initializing a PyDMD module that implements your DMD method of choice. Here, we demonstrate how a user might build a customized BOP-DMD model. Models may then be fitted by calling the fit() method and passing in the necessary data. This step performs the DMD algorithm, after which users may use PyDMD plotting tools in order to visualize their results.

from pydmd import BOPDMD
from pydmd.plotter import plot_summary

# Build a bagging, optimized DMD (BOP-DMD) model.
dmd = BOPDMD(
    svd_rank=15,  # rank of the DMD fit
    num_trials=100,  # number of bagging trials to perform
    trial_size=0.5,  # use 50% of the total number of snapshots per trial
    eig_constraints={"imag", "conjugate_pairs"},  # constrain the eigenvalue structure
    varpro_opts_dict={"tol":0.2, "verbose":True},  # set variable projection parameters
)

# Fit the DMD model.
# X = (n, m) numpy array of time-varying snapshot data
# t = (m,) numpy array of times of data collection
dmd.fit(X, t)

# Display a summary of the DMD results.
plot_summary(dmd)

Note that modules and functions may be parameterized by a variety of inputs for added customization, so we generally recommend that new users refer to module documentation, plotting tool documentation, and to our module-specific tutorials for more information.

For users who are unsure of which DMD method is best for them, we provide the following flow chart, which outlines how one might choose an appropriate DMD variant based on specific problem types or data sets.

Awards

First prize winner in DSWeb 2019 Contest Tutorials on Dynamical Systems Software (Junior Faculty Category). You can read the winner tutorial (PDF format) in the tutorials folder.

References

To implement the various versions of the DMD algorithm we follow these works:

General DMD References

  • Kutz, Brunton, Brunton, Proctor. Dynamic Mode Decomposition: Data-Driven Modeling of Complex Systems. SIAM Other Titles in Applied Mathematics, 2016. [DOI] [bibitem].
  • Brunton, Budišić, Kaiser, Kutz. Modern Koopman Theory for Dynamical Systems. SIAM Review, 2022. [DOI] [bibitem].

DMD Variants: Noise-robust Methods

  • Forward-backward DMD: Dawson, Hemati, Williams, Rowley. Characterizing and correcting for the effect of sensor noise in the dynamic mode decomposition. Experiments in Fluids, 2016. [DOI] [bibitem].
  • Total least-squares DMD: Hemati, Rowley, Deem, Cattafesta. De-biasing the dynamic mode decomposition for applied Koopman spectral analysis of noisy datasets. Theoretical and Computational Fluid Dynamics, 2017. [DOI] [bibitem].
  • Optimal closed-form DMD: Héas, Herzet. Low-rank dynamic mode decomposition: An exact and tractable solution. Journal of Nonlinear Science, 2022. [DOI] [bibitem].
  • Subspace DMD: Takeishi, Kawahara, Yairi. Subspace dynamic mode decomposition for stochastic Koopman analysis. Physical Review E, 2017. [DOI] [bibitem].
  • Physics-informed DMD: Baddoo, Herrmann, McKeon, Kutz, Brunton. Physics-informed dynamic mode decomposition. Proceedings of the Royal Society A, 2023. [DOI] [bibitem].
  • Optimized DMD: Askham, Kutz. Variable projection methods for an optimized dynamic mode decomposition. SIAM Journal on Applied Dynamical Systems, 2018. [DOI] [bibitem].
  • Bagging, optimized DMD: Sashidhar, Kutz. Bagging, optimized dynamic mode decomposition for robust, stable forecasting with spatial and temporal uncertainty quantification. Proceedings of the Royal Society A, 2022. [DOI] [bibitem].

DMD Variants: Additional Methods and Extensions

  • DMD with Control: Proctor, Brunton, Kutz. Dynamic mode decomposition with control. SIAM Journal on Applied Dynamical Systems, 2016. [DOI] [bibitem].
  • Multiresolution DMD: Kutz, Fu, Brunton. Multiresolution dynamic mode decomposition. SIAM Journal on Applied Dynamical Systems, 2016. [DOI] [bibitem].
  • Sparsity-promoting DMD: Jovanović, Schmid, Nichols Sparsity-promoting dynamic mode decomposition. Physics of Fluids, 2014. [DOI] [bibitem].
  • Compressed DMD: Erichson, Brunton, Kutz. Compressed dynamic mode decomposition for background modeling. Journal of Real-Time Image Processing, 2016. [DOI] [bibitem].
  • Randomized DMD: Erichson, Mathelin, Kutz, Brunton. Randomized dynamic mode decomposition. SIAM Journal on Applied Dynamical Systems, 2019. [DOI] [bibitem].
  • Higher Order DMD: Le Clainche, Vega. Higher order dynamic mode decomposition. Journal on Applied Dynamical Systems, 2017. [DOI] [bibitem].
  • HAVOK: Brunton, Brunton, Proctor, Kaiser, Kutz. Chaos as an intermittently forced linear system. Nature Communications, 2017. [DOI] [bibitem].
  • Parametric DMD: Andreuzzi, Demo, Rozza. A dynamic mode decomposition extension for the forecasting of parametric dynamical systems. SIAM Journal on Applied Dynamical Systems, 2023. [DOI] [bibitem].
  • Extended DMD: Williams, Rowley, Kevrekidis. A kernel-based method for data-driven koopman spectral analysis. Journal of Computational Dynamics, 2015. [DOI] [bibitem].
  • LANDO: Baddoo, Herrmann, McKeon, Brunton. Kernel learning for robust dynamic mode decomposition: linear and nonlinear disambiguation optimization. Proceedings of the Royal Society A, 2022. [DOI] [bibitem].

Implementation Tools and Preprocessing

  • Gavish, Donoho. The optimal hard threshold for singular values is 4/sqrt(3). IEEE Transactions on Information Theory, 2014. [DOI] [bibitem].
  • Matsumoto, Indinger. On-the-fly algorithm for dynamic mode decomposition using incremental singular value decomposition and total least squares. 2017. [arXiv] [bibitem].
  • Hirsh, Harris, Kutz, Brunton. Centering data improves the dynamic mode decomposition. SIAM Journal on Applied Dynamical Systems, 2020. [DOI] [bibitem]

Recent works using PyDMD

You can find a list of the scientific works using PyDMD here.

Developers and contributors

The main developers are

We warmly thank all the contributors that have supported PyDMD!

Do you want to join the team? Read the Contributing guidelines and the Tutorials for Developers before starting to play!

Made with contrib.rocks.

Testing

We use pytest to run our unit tests. You can run the whole test suite by using the following command in the base directory of the repository:

pytest

Funding

A significant part of PyDMD has been written either as a by-product for other projects people were funded for, or by people on university-funded positions. There are probably many of such projects that have led to some development of PyDMD. We are very grateful for this support!

Beyond this, PyDMD has also been supported by some dedicated projects that have allowed us to work on extensions, documentation, training and dissemination that would otherwise not have been possible. In particular, we acknowledge the following sources of support with great gratitude:

Affiliations

pydmd's People

Contributors

adam2392 avatar arfon avatar azzeddinetiba avatar chaous avatar doublonmousse avatar edonadini avatar eldan101 avatar fandreuz avatar fpichi avatar github-actions[bot] avatar greinerth avatar joshmyersdean avatar klapo avatar loiseaujc avatar mgirfogl avatar mphschmitt avatar mschmidt99 avatar mtezzele avatar ndem0 avatar nolanbrad avatar rfmiotto avatar robbystk avatar samadio avatar sichinaga avatar tianyikillua avatar twisterbboy avatar xmjiao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pydmd's Issues

Low-rank DMD: optimal solution in polynomial time

Hi guys,

I was wondering if you had seen this paper?

The authors have shown that all of the DMD algorithms proposed so far actually compute only a sub-optimal solution to the DMD minimization problem. More importantly, they come up with a closed-form solution that is actually the optimal solution.

Not sure how to proceed regarding its implementation. Do you think it would be worth adding a keyword to the DMD object to specify which algorithm to use (e.g. the original Schmid's algorithm or this optimal one) when fitting the model?

Regularization Enhancement?

Was wondering if an enhancement can be added when the input matrix is ill-conditioned. The warning saying the condition number is high certainly helps but I was wondering if it's possible to implement the regularization as described on page 8 of the Erichson et al paper attached below
Random-DMD_Erichson.pdf
. I think this will at least give a way to handle the case of an ill-conditioned input matrix.

MrDMD Changing timesteps not working

When I change the timesteps like:
dmd.dmd_time['dt']=0.1
dmd.dmd_time['tend'] *= 3

and then run the dmd.reconstructed_data, it returns the same array as before I changes the timestep size or endpoint in time. This does work for me with the DMD class like in your tutorial 2, but not with MrDMD. Am I doing something wrong?

Thanks,
Luke

Bad documentation link.

The README.md in the tutorials folder has a broken link to tutorial10: https://mathlab.github.io/PyDMD/tutorial10paramdmd.html
The filename seems ok, and the url is the same for all other tutorials in the same folder, so I am not quite sure why it doesn't work.

Here is what I have tried on my fork so far:

  • add the sphinx.ext.githubpages extension to conf.py
  • Add a config.yml file (usually for jekyll which should not be used here, but it was worth a try in case of a bug on github's side still using jekyll) including the docs/source/_tutorials folder (jekyll ignores files and folders whose name begins with an underscore).
  • I checked the logs of github action and everything seems to build without any error.

Computation error when having negative eigenvalues

There's a numerical issue at line 90-91 of the file dmdc.py (there are several other places having the same issue), such that when self.eigs are negative, np.log() will return nan.

omega = old_div(np.log(self.eigs), self.original_time['dt'])
eigs = np.exp(omega * self.dmd_time['dt'])

Mathematically these two lines can be merged together to avoid having negative value inside the logarithm.

I solved this by changing to
eigs = np.power(self.eigs, old_div(self.dmd_time['dt'], self.original_time['dt']))

Please let me know if there are better solutions, thanks!

Fix for mrDMD division by zero error during reconstruction

Dear,

I am using PyDMD package to analyze the data from my research in fluid dynamics. Particularly, with the multi-resolution DMD (mrDMD), I was obtaining a zero-division error when doing the reconstruction of the flow field. This issue was reported by other users (see #81 , for example)

zero-division-error

Debugging

I noticed that the problem was coming from the exception of the fit method. That is, in the current implementation, if the number of resolution levels (used-defined parameter) is large, the fit method would return an error. In order to fix this problem, a try-except approach was used, and the eigenvalues, DMD modes, etc. were set as zero if the exception was raised. These null values were causing the problem in the reconstruction.

I solved this problem by proposing a small refactor in the fit method and I would like to make a pull request with the solution.

Moreover, I noticed that at the end of the fit method, the dmd_time and original_time dictionaries were being overwritten. It seemed to me that this is because the mrDMD cannot handle predictions yet (as mentioned in #63). So the dmd_time was forced to be equal to the original_time.

Finally, a MemoryError exception was added for when reconstructing the solutions built from large matrices and with many resolution levels.

Possible future contributions

In my research, I am interested in isolating a given physical phenomenon that occurs at a specific time interval. Since the dynamics have different spatiotemporal scales, the mrDMD came in handy. I had to implement more stuff in the MrDMD class in order to extract the modes related to the isolated temporal phenomenon. I believe that it might help other users and so, I will be pleased to include this contribution to the main source. Unit tests of these new methods will also come along.

Please, let me know what do you think of it.

Best regards,
Renato Miotto

zero division error: tutorial 3

I was going through the tutorials trying different values for various parameters. I found an error. In tutorial 3 (cell 6):

dmd = MrDMD(svd_rank=6, max_level=7, max_cycles=1)

Instead of using svd_rank=-1, I used 6. I get a ZeroDivisionError.

I get a ZeroDivisionError for a dataset I am using as well. I was wondering if there are some guidelines on which parameters to use to avoid such errors, or is it the case that there is a bug in the code.

Thanks for making your package available.


ZeroDivisionError Traceback (most recent call last)
in
1 dmd = MrDMD(svd_rank=6, max_level=7, max_cycles=1)
2 dmd.fit(X=sample_data)
----> 3 make_plot(dmd.reconstructed_data.T, x=x, y=t)

~/anaconda3/envs/pydmd/lib/python3.7/site-packages/pydmd/mrdmd.py in reconstructed_data(self)
79 np.array([
80 self.partial_reconstructed_data(i)
---> 81 for i in range(self.max_level)
82 ]),
83 axis=0)

~/anaconda3/envs/pydmd/lib/python3.7/site-packages/pydmd/mrdmd.py in (.0)
79 np.array([
80 self.partial_reconstructed_data(i)
---> 81 for i in range(self.max_level)
82 ]),
83 axis=0)

~/anaconda3/envs/pydmd/lib/python3.7/site-packages/pydmd/mrdmd.py in partial_reconstructed_data(self, level, node)
208 level, self.max_level))
209 modes = self.partial_modes(level, node)
--> 210 dynamics = self.partial_dynamics(level, node)
211
212 return modes.dot(dynamics)

~/anaconda3/envs/pydmd/lib/python3.7/site-packages/pydmd/mrdmd.py in partial_dynamics(self, level, node)
162 level_dynamics = [
163 dynamic(self._eigs[idx], self._b[idx], self._steps[idx],
--> 164 self._nsamples[idx]) for idx in indeces
165 ]
166 return scipy.linalg.block_diag(*level_dynamics)

~/anaconda3/envs/pydmd/lib/python3.7/site-packages/pydmd/mrdmd.py in (.0)
162 level_dynamics = [
163 dynamic(self._eigs[idx], self._b[idx], self._steps[idx],
--> 164 self._nsamples[idx]) for idx in indeces
165 ]
166 return scipy.linalg.block_diag(*level_dynamics)

~/anaconda3/envs/pydmd/lib/python3.7/site-packages/pydmd/mrdmd.py in dynamic(eigs, amplitudes, step, nsamples)
149 def dynamic(eigs, amplitudes, step, nsamples):
150 omega = old_div(
--> 151 np.log(np.power(eigs, old_div(1., step))),
152 self.original_time['dt'])
153 partial_timestep = np.arange(nsamples) * self.dmd_time['dt']

~/anaconda3/envs/pydmd/lib/python3.7/site-packages/past/utils/init.py in old_div(a, b)
93 return a // b
94 else:
---> 95 return a / b
96
97 all = ['PY3', 'PY2', 'PYPY', 'with_metaclass', 'native', 'old_div']

ZeroDivisionError: float division by zero

The funcion predict() from DMD class is deprecated or not?

The function predicti() can be find in https://mathlab.github.io/PyDMD/dmd.html#

My question is, that function is correct? because I'm using to predict one-step ahead on a univariate time series (airline passengers).

This is my code:

one-step ahead univariate forecasting using a DMD model

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from pydmd import DMD

load training dataset

training = pd.read_csv('airline_passengers_training.csv', index_col=0, header=None, parse_dates=True, squeeze=True)

create and fit a DMD model

dmd = DMD(svd_rank=-1,
opt=True,
exact=True,
rescale_mode=None,
forward_backward=True,
tlsq_rank=1,
sorted_eigs=False)
dmd.fit(training.values)

perform forecasts on training dataset

x = training.values
x = x.reshape((len(x),1))
forecasts = []
for i in range(len(x)):
x_i = x[i].reshape((1,1))
yhat = dmd.predict(x_i)
forecasts.append(yhat)
forecasts = np.array(forecasts).ravel()

plot predicted vs actuals on training dataset

plt.plot(training.values, label='Actuals')
plt.plot(forecasts, label='Predictions')
plt.legend()
plt.show()

The forecasts are very similar to the actuals points. I think that, there's something wrong on my code or in the function.

Best regards.

LinAlgError: Incompatible dimensions

dmd = DMD(svd_rank=1, tlsq_rank=2, exact=True, opt=True)
dmd.fit(Z[0])
print(Z[0])

[[  9.29641658  16.21852448  18.01832071 ...  16.21852448  18.01832071
    9.29641658]
 [  2.23071205  11.98353881  13.93900513 ...  11.98353881  13.93900513
    2.23071205]
 [ 13.50093531  24.19254382  25.31127805 ...  24.19254382  25.31127805
   13.50093531]
 ...
 [188.06647095 222.4888389  215.51700318 ... 222.4888389  215.51700318
  188.06647095]
 [178.20294582 211.87067288 200.97301622 ... 211.87067288 200.97301622
  178.20294582]
 [201.0606195  238.71759917 230.44923346 ... 238.71759917 230.44923346
  201.0606195 ]]
print(np.shape(Z[0]))

(4096, 9)

Error:

LinAlgError                               Traceback (most recent call last)
<ipython-input-1830-70e547dcb058> in <module>()
      1 dmd = DMD(svd_rank=1, tlsq_rank=2, exact=True, opt=True)
----> 2 dmd.fit(Z[0])
      3 lu_fish1_recons = dmd.reconstructed_data
      4 
      5 dmd = DMD(svd_rank=1, tlsq_rank=2, exact=True, opt=True)

/usr/local/lib/python2.7/dist-packages/pydmd/dmd.pyc in fit(self, X)
     46 
     47         self._b = self._compute_amplitudes(self._modes, self._snapshots,
---> 48                                            self._eigs, self.opt)
     49 
     50         # Default timesteps

/usr/local/lib/python2.7/dist-packages/pydmd/dmdbase.pyc in _compute_amplitudes(modes, snapshots, eigs, opt)
    337             b = np.reshape(snapshots, (-1, ), order='F')
    338 
--> 339             a = np.linalg.lstsq(L, b, rcond=None)[0]
    340         else:
    341             a = np.linalg.lstsq(modes, snapshots.T[0], rcond=None)[0]

/home/cen/.local/lib/python2.7/site-packages/numpy/linalg/linalg.pyc in lstsq(a, b, rcond)
   2203     m2, n_rhs = b.shape[-2:]
   2204     if m != m2:
-> 2205         raise LinAlgError('Incompatible dimensions')
   2206 
   2207     t, result_t = _commonType(a, b)

LinAlgError: Incompatible dimensions

Sort DMD modes by corresponding eigenvalues

It's convenient for several application (for instance when comparing DMD modes obtained from the same parameterized physical system) to sort DMD modes according to some (persistent) metric.

I propose to add a new optional flag to DMD to perform this task automatically.

New release

Great package! I was just wondering if you had plans to create a new release any time soon. I see that there have been lots of improvements since the current version 0.2.1 was released in 2018. It looks like the documentation is up-to-date with the GitHub repo, but the version on PyPI isn't.

I'm not sure if others have run into this, but it took me a little while to realize the reason I was getting an error when I tried to call DMD.predict was because the documentation was ahead of the current PyPI version.

Edit: I should also mention that I'm currently working on a package based on the Koopman operator and was planning to make PyDMD a dependency. I'd feel better about doing so if a new release was made which included the features added after the last release in 2018.

Use DMDc to just get the state transition matrix without a control input

Is possible for you guys to make the python dmdc to be able to just use the snapshots, not need to input a control, to just get the state transition matrix? This is as I tried to make the control input an array of zeros but it gave the error of "Array must not contain infs or NaNs." Thank you.

Edit: nevermind sorry I did not realize tutorial 4 had this, perhaps you guys should make it clear that in that way you can solve for A in xk = Axk+1

Edit2: Nevermind to evetything I said above as I now know that is what DMD is without DMDc. There I am going to close this issue

Rank selection issue in `_compute_svd`

Hi guys,

I have noted a small issue with the rank selection in _compute_svd(X, svd_rank) when user prescribes a desired cumulative energy (i.e. a truncation error). Line 242 of dmdbase.py, the code reads

cumulative_energy = np.cumsum(s / s.sum())

However, the energy in POD analysis is related to the square of the singular values, not the singular values themselves. The code should instead read

cumulative_energy = np.cumsum( s**2 / (s**2).sum() )

This is pretty straightforward to modify so should I send a PR or do you guys wanna handle it?

Adding a helper function to compute snapshots used in HODMD?

Main issue

I was wondering if it would be okay with developers to add in a public function to HoDMD to recompute the snapshots?

E.g.

def get_snapshots():
        snaps = np.concatenate(
            [
                self._snapshots[:, i:self._snapshots.shape[1] - self.d + i + 1]
                for i in range(self.d)
            ],
            axis=0)
      return snaps

The reason is, I am trying to rescale the DMD modes computed and some of the algorithms for rescaling want to do underlying computations on the original snapshots ran through HoDMD.

Issue about allowing different scaling strategies

With that being said a small side issue I was having is how to rescale the modes. For example, in this paper on page 5, authors have scaled the modes by the singular values of the corresponding SVD, so the eigenvectors are W = \Sigma^{1/2} \hat{W} instead of \hat{W}, which is then used to compute the DMD modes.

Would it be desirable to either i) add alternative scaling strategies on the DMD modes or ii) separate out the steps inside fit() a bit more such that, if someone wanted to alter say in between steps, they can start off there and call some private/public functions?

Wrong bibitem

readme/LeClainche2017.bib is wrong (coming from a copy/paste)

Type Error in MrDMD.fit

Hi, I started using the MrDMD class, but if I pass a real matrix to the function I get the next error:

TypeError:Cannot cast ufunc subtract output from dtype('complex128') to dtype('float64') with casting rule 'same_kind'

It seems to come form the fit function in line 288:

Xraw -= modes.dot(Psi)

I fixed it momentarily by adding imaginary zeros to my input matrix data, but it will be nice to let it be real.

questions about tutorial 5

Hello,
I am exploring this project, and even though I don't yet think I fathom the concepts, but the project seems great!

I have some questions about the tutorial 5:

  • The snapshots of data, as indicated, were taken from an OpenFOAM simulation. However, I can see that the solver used is simpleFoam which a steady-state solver so my guess is that the snapshots of data (in csv files) correspond to iterations?
  • If those are solution at several iterations, what is the purpose of using DMD?
  • [a meta question, just for curiosity] how did you generate the CSV files? is it via a functionObject or using Paraview or something else?

Thank you very much

Mrdmd can not make predictions

Hi,
I am experiencing the following problem:
Mrdmd is able to reconstruct just the data used to fit the model but if we manipulate the interval between the approximated states or extend the temporal window where the data is reconstructed (as shown in Tutorial 2) this does not have any effect on the shape of the reconstructed data.

example:
Mrdmd.reconstructed_data.shape= (1000,200)
Mrdmd.dmd_time['dt'] *=1
Mrdmd.dmd_time['tend'] += 100
Mrdmd.reconstructed_data.shape= (1000,200)
where the last line should be:
Mrdmd.reconstructed_data.shape= (1000,300)

Thanks for your work,
Best regards

DOC for tlsq_rank

In the class DMDBase the DOC mentions that tlsq_rank=0 means no truncation. However, the corresponding private method _compute_tlsq(X, Y, tlsq_rank=0) returns both snapshots matrices without performing TLsq. Also the DOC of the private method might be confusing for such parameter is well.

MrDMD issue when fitting on non-complex data

Describe the bug
As I haven't found anyone else with the same issue with mrDMD, I'm not sure whether this is a bug or whether I just need help.
When applying mrDMD to real data I get an error indicating an unsuccessful complex value subtraction from real variables. If I Use complex data this issue doesn't happen.

To Reproduce
dmd = MrDMD(DMD(svd_rank=0),max_level=10, max_cycles=4)
dmd.fit(steady)

Expected behavior
As far as my understanding goes, I would've expected no errors as I used the same code from the mrDMD tutorial where I had no issues.

Output
Traceback (most recent call last):
File "/mrDMDPressureField.py", line 48, in
dmd.fit(steady)
File "\pydmd\pydmd\mrdmd.py", line 434, in fit
X -= newX
numpy.core._exceptions.UFuncTypeError: Cannot cast ufunc 'subtract' output from dtype('complex128') to dtype('float64') with casting rule 'same_kind'

Computing DmD amplitudes get Error: numpy.linalg.LinAlgError: Incompatible dimensions

Hi PyDMD team,

I am using PyDMD in my MSc Thesis at Imperial College.

I am experiencing issues when computing the amplitudes of the modes, my code is the following:

##Assign the array of the data containing the snapshots to the variable snapshots
snapshots = uvec_315_time.T

#Create dmd object using PyDMD library
dmd = DMD(svd_rank=0, tlsq_rank=0, exact=True, opt=True)
dmd.fit(snapshots)

#Spectral and spatial modes plot
eigs = dmd.eigs
modes = dmd.modes
amplitudes = DMDBase._compute_amplitudes(modes, snapshots, eigs, opt=True)

print(amplitudes)

I am getting the error of numpy.linalg.LinAlgError: Incompatible dimensions, should I change the code of the function or I have something wrong in my data.

Note that I want to reproduce the following plot:
https://www.researchgate.net/figure/Amplitude-distribution-of-the-averaged-dynamic-modes-as-a-function-of-Strouhal-number-of_fig3_278646580

Thank you in advance

application to a simple spring-mass system

I'm relatively new to the DMD method, so please point out the errors I may have made in applying PyDMD to the following simple spring-mass system (3 DoFs).

Construct the snapshot matrix

The response corresponds to a given linear combinaison of the normal modes.

M = np.array([
    [1, 0, 0],
    [0, 1, 0],
    [0, 0, 1]
])

K = np.array([
    [2, -1, 0],
    [-1, 2, -1],
    [0, -1, 1]
])
omega2, V = linalg.eigh(K, M)
omega = np.sqrt(omega2)
t = np.linspace(0, 50, 500)
q = np.vstack([
    10 * np.cos(omega[0] * t),  # given linear combination of normal modes
    2 * np.cos(omega[1] * t),
    3 * np.cos(omega[2] * t)
])
X = V @ q  # snapshot matrix

PyDMD

The obtained dynamics do not correspond to the given ones (at frequencies omega).

dmd = DMD(svd_rank=3)
dmd.fit(X)
for i, dynamic in enumerate(dmd.dynamics):
    plt.plot(t, dynamic.real, label=f"#{i:d}")
plt.legend()
plt.grid()
plt.tight_layout()

Also, the reconstructed response (e.g., the 1st DoF) agrees poorly with the original one.

plt.plot(t, X[0], label="original")
plt.plot(t, dmd.reconstructed_data[0].real, label="DMD")
plt.legend()
plt.grid()
plt.tight_layout()

Where am I doing wrong?

Large 3D data set

Dear PyDMD team,

I am working with 600 snapshots of a fluid data set and each snapshot is a [415x145x145] (Nx, Ny, Nz) array. When I want to find the power spectrum, I am having memory error problem when trying to compute a large number of modes.

I was thinking to use the compressed dmd method available, but this method is built for 2d arrays. Will work also with my data or I would have to modify it?

I would like to know what will be your advice to work with a large data set using PyDMD.

Thanks for your time and help,

Ismael

Support for separate X and Y inputs

As far as I could understand, currently pydmd takes input as a single X matrix, from which the X and Y matrices are formed.

Sometimes it is convenient to sample real data non-uniformly, e.g. in short batches from the original dynamics. This would mean that the columns of X are not necessarily contiguous in time, but the corresponding X-Y pairs are.

How about adding the option to the DMD.fit method to provide separate X and Y matrices?

Something of the kind:

def fit(self, X, Y=None):
    if Y is None:
        X = X[:,:-1]
        Y = X[:,1:]

HODMD doesn't agree with the reference

By looking at the code, the current HODMD seems to be a "Hankel-DMD"-- first stack the staggered data, next perform DMD on the new data.

But I found the code and paper for the original HODMD are different than the pydmd. Their first step is to reduce the data.

I think they are not equivalent.

DMDc horizon

Hi all,

When trying to reconstruct output data with DMDc, and when the reconstruction control input have a different length than the fitting data, an error is raised:
'The number of control inputs and the number of snapshots to reconstruct has to be the same'
from https://github.com/mathLab/PyDMD/blob/a6277fa594e041cdb992559287b77165e1e3f3fc/pydmd/dmdc.py#L88

I don't think this restriction needs to be enforced. On top of that, I think you usually need as much data as possible for your fitting, and reconstruct fewer data for short term prediction.

What is your take on that ?

Thanks

Ill conditioned data matrices - Checks and Regularization

Hi,

so I ran into an issue w/ my data matrices being fed in and there is are numerical issues when your X is ill-conditioned (e.g. > 10^4), then the SVD approach will surely fail. My runs give me basically useless A matrices.

Had two questions:

  1. Any suggestions on how we might incorporate regularization into the code elegantly? I'm thinking something like L2 regularization should be sufficient, with a passed in parameter.
  2. I plan on incorporating a few lines just to check the condition number of the X matrix. Any concerns on me doing this? Thinking something along the lines of

"if cond > THRESHOLD: raise warning."

How do I use DMD for prediction\extrapolation?

I've tried exactly like in the tutorial 2 to learn on the beginning of time series to make prediction about the future:

T_LEARN = 1000

snapshots = data_vec[:,:T_LEARN]
dmd = MrDMD(svd_rank=50, max_level=3, max_cycles=3)
dmd.fit(X = np.complex128(snapshots))

tend = 3604

dmd.dmd_time['tend'] = tend

print(np.shape(dmd.reconstructed_data))
print(np.shape(dmd.dmd_timesteps))
print(np.shape(snapshots))

and I'm getting

(28800, 1000)
(3605,)
(28800, 1000)

So, the size of dmd.dmd_timesteps is still of the initial time series I've used for learning.

So, I just have some kind of low-rank approximation to beginning of the time series I've used for learning, but not the extrapolation I've seen in this picture

index

My code is very similar to code from tutorial, although I don't understand why you needed to compute integral (and twice!).

compute_integral = scipy.integrate.trapz

original_int = [compute_integral(compute_integral(snapshot)).real for snapshot in snapshots]
dmd_int = [compute_integral(compute_integral(state)).real for state in dmd_states]

figure = plt.figure(figsize=(18, 5))
plt.plot(dmd.original_timesteps, original_int, 'bo', label='original snapshots')
plt.plot(dmd.dmd_timesteps, dmd_int, 'r.', label='dmd states')
plt.ylabel('Integral')
plt.xlabel('Time')
plt.grid()
leg = plt.legend()

Adding a DMD bounding box (probing/window) function in DMDBase class

Hi,
I am an active CFD user and I use DMD to understand turbulence in environmental flows. I recently wrote a function using pyDMD and my own bound box (window) function. The function chooses the data values within a box (min X coord, max X coord) and (min Y coord, max Y coord) from the snapshot matrix (my snapshot matrix has X and Y coordinates as the first 2 columns followed by the data) and can perform any of the DMD methods on this bound box.
This can be added to the DMDBase class and can be called by any of the DMD methods. Is it alright if I incorporate this with the said class. I use it quite frequently with numerical and experimental data and found it very useful writing this function. I would like to contribute and can also create the test cases for this function.

Kindly do consider.

Regards
Edwin Rajeev

Plot modes in 3D

Dear team,

I am wondering if there is an implemented option to plot the modes in 3D. If not, could you give a small guidance of how to change the dmd._plot_modes_2D function to make it 3D.
Adding a third component of the domain to lines listed below would be enough?

    # If domain dimensions have not been passed as argument,
    # use the snapshots dimensions
    if x is None and y is None:
        x = np.arange(self._snapshots_shape[0])
        y = np.arange(self._snapshots_shape[1])

    xgrid, ygrid = np.meshgrid(x, y)

    if index_mode is None:
        index_mode = list(range(self._modes.shape[1]))
    elif isinstance(index_mode, int):
        index_mode = [index_mode]

Thanks for your time and attention

Cheers

Ismael

More states than just one for the snapshot input for DMDc

Hi PyDMD support, my snapshot input has 6 state variables (x, y, z, and the velocities of those three), there is about 3000 iterations of the state evolving over time, and one snapshot of the system I want to use. After running many tests and looking through your guys source code I was wondering if it is possible to have this kind of input into your guys DMDc library? Thank you.

Edit: Sorry nevermind I did not see https://github.com/mathLab/PyDMD/issues/116 and this clarified my understanding of the python dmdc as the iterations are the snapshots. Hope you guys also clear up tutorial 7 as according to issue 116.

DMDc tutorial #7

Hi all,
I reckon there is a mistake in DMD with control tutorial 7.
The tutorial says there are 25 snapshots created with 10 state variables, however the length of x0 is 25, so I'd say there are 25 state variables with 10 snapshots. Is that right ?

Thanks for your help

Use FBDMD for control

Is there a way to extedn FBDMD for control? I have noisy measurements so want to cancel that out. Not sure how to get the matrices to work out with different sizes. i.e X has states and controls while Y has only states. Any suggestions?

`OptDMD.predict` does not work with default argument `factorization='evd'`

If I run OptDMD with default argument factorization='evd', the error 'OptDMD' object has no attribute '_eigs' is raised. This is an easy fix, replace self._eigs with self.eigs. However, doing so introduces a new bug.

Running OptDMD with factorization='svd' works fine.

Describe the bug

dmd = OptDMD(svd_rank=7)
dmd.fit(X)
dmd.predict(X)

The last statement causes an error.

To Reproduce
see previous code snippet.

Expected behavior
There shouldn't be an exception.

Output

Traceback (most recent call last):
  ...
  File "/home/user/anaconda3/envs/test/lib/python3.9/site-packages/pydmd/optdmd.py", line 235, in predict
    Y = np.linalg.multi_dot(
  File "<__array_function__ internals>", line 5, in multi_dot
  File "/home/user/anaconda3/envs/test/lib/python3.9/site-packages/numpy/linalg/linalg.py", line 2724, in multi_dot
    _assert_2d(*arrays)
  File "/home/user/anaconda3/envs/test/lib/python3.9/site-packages/numpy/linalg/linalg.py", line 190, in _assert_2d
    raise LinAlgError('%d-dimensional array given. Array must be '
numpy.linalg.LinAlgError: 1-dimensional array given. Array must be two-dimensional

Additional context
I looked into what causes this bug and there seems to be a mismatch in dimensions:

Y = np.linalg.multi_dot(
    [
        self._output_space,
        np.diag(self.eigs),
        self._input_space.T.conj(),
        X,
    ]
)

We have the following shapes:

self._output_space.shape = (128, 7)
np.diag(self.eigs).shape = (7, 7)
self._input_space.T.conj().shape = (7, )
X.shape = (128, )

This does not match. My best guess is, that the shape of the third matrix should be self._input_space.shape == (128, 7) so that the result after the multiplication has a shape of (128, ).

DMD with control

Hi guys,

I have been working with DMD for quite a while, essentially on very large-scale dynamical systems from fluid dynamics for which I needed to implement the algorithms directly within my flow solver. I am now moving on to smaller problems, for which using pre-existing libraries is much more suited and yours comes as a natural choice.

One of these problems is that of the nonlinear control of a two-dimensional flow. For that purpose, I plan to use DMD with Control (see Ref. [1]). Do you guys already have plans to implement DMDc?

Regards,
JC

[1] Proctor, Joshua L., Steven L. Brunton, and J. Nathan Kutz. "Dynamic mode decomposition with control." SIAM Journal on Applied Dynamical Systems 15.1 (2016): 142-161.

Incorrect `DMD.reconstructed_data` compared to `dmd.predict`

When t0 (0 here) is a multiple of the period (3 here), DMD.reconstructed gives correct results

t = np.linspace(0, 5, 100)
X = np.sin(1 / 3 * 2 * np.pi * t).reshape((1, -1))  # frequency = 1 / 3
X_embedded = np.vstack([X[:, :-1], X[:, 1:]])

dmd = pydmd.DMD(svd_rank=2, exact=True, opt=True).fit(X_embedded)

dmd.original_time["dt"] = t[1] - t[0]
dmd.dmd_time["t0"] = t[0]
dmd.dmd_time["tend"] = t[-1]
dmd.dmd_time["dt"] = t[1] - t[0]

def dmd_predict(dmd, X0, n):
    Y = np.empty((X0.shape[0], n), dtype=np.complex)
    Y[:, 0] = X0
    for i in range(n - 1):
        Y[:, i + 1] = dmd.predict(Y[:, i])
    return Y

plt.plot(t, X[0], "k", alpha=0.5, linewidth=3, label="Original")
plt.plot(dmd.dmd_timesteps, dmd.reconstructed_data.real[0], "--", label="DMD reconstructed")
plt.plot(dmd.dmd_timesteps, dmd_predict(dmd, X_embedded[:, 0], len(dmd.dmd_timesteps)).real[0], "-.", label="DMD predicted")
plt.grid()
plt.legend()
plt.tight_layout()

Screenshot 2020-02-15 at 14 19 48

However when t0 = 1, DMD.predict is correct, not DMD.reconstructed_data

Screenshot 2020-02-15 at 14 20 51

When t0 = 3 which is the signal period here, again DMD.reconstructed_data is correct

Screenshot 2020-02-15 at 14 21 50

We need to check in DMD.reconstructed_data how time translation affects the result.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.