modulo-vki 2.0.6__py3-none-any.whl → 2.1.0__py3-none-any.whl

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.
modulo_vki/__init__.py CHANGED
@@ -1,23 +1 @@
1
-
2
- #from ._version import get_versions
3
- #__version__ = get_versions()['version']
4
- #del get_versions
5
-
6
-
7
- # from .utils.read_db import *
8
- # from .utils._utils import *
9
- # from .utils._plots import *
10
- # from .utils.others import *
11
-
12
- # from .core._k_matrix import *
13
- # from .core._dft import *
14
- # from .core._dmd_s import *
15
- # from .core._k_matrix import *
16
- # from .core._mpod_time import *
17
- # from .core._mpod_space import *
18
- # from .core._pod_time import *
19
- # from .core._pod_space import *
20
- # from .core._spod_s import *
21
- # from .core._spod_t import *
22
-
23
1
  from modulo_vki.modulo import ModuloVKI
@@ -1,9 +1,9 @@
1
- from ._dft import *
2
- from ._dmd_s import *
3
- from ._k_matrix import *
4
- from ._mpod_space import *
5
- from ._mpod_time import *
6
- from ._pod_space import *
7
- from ._pod_time import *
8
- from ._spod_s import *
9
- from ._spod_t import *
1
+ from ._dft import *
2
+ from ._dmd_s import *
3
+ from ._k_matrix import *
4
+ from ._mpod_space import *
5
+ from ._mpod_time import *
6
+ from ._pod_space import *
7
+ from ._pod_time import *
8
+ from ._spod_s import *
9
+ from ._spod_t import *
modulo_vki/core/_dft.py CHANGED
@@ -1,61 +1,132 @@
1
- import os
2
-
3
- import numpy as np
4
- from tqdm import tqdm
5
-
6
-
7
- def dft_fit(N_T, F_S, D, FOLDER_OUT, SAVE_DFT=False):
8
- """
9
- This function computes the DFT form the dataset D.
10
- Currently, this does not handle the memory saving feature.
11
-
12
- :param N_T: int.
13
- number of snapshots
14
- :param F_S:
15
- Sampling frequency (in Hz)
16
- :param D:
17
- Snapshot matrix
18
- :param FOLDER_OUT:
19
- Folder in which the results are saved if SAVE_SPATIAL_POD = True
20
- :param SAVE_DFT:
21
- If True, results are saved on disk and released from memory
22
-
23
- :return: Sorted_Freqs, np.array
24
- Frequency bins, in Hz.
25
- :return: Phi_F, np.array
26
- (Complex) Spatial structures for each mode
27
- :return: SIGMA_F, np.array
28
- (real) amplitude of each modes
29
-
30
- """
31
- n_t = int(N_T)
32
- Freqs = np.fft.fftfreq(n_t) * F_S # Compute the frequency bins
33
- # PSI_F = np.conj(np.fft.fft(np.eye(n_t)) / np.sqrt(n_t)) # Prepare the Fourier Matrix.
34
-
35
- # Method 1 (didactic!)
36
- # PHI_SIGMA = np.dot(D, np.conj(PSI_F)) # This is PHI * SIGMA
37
-
38
- # Method 2
39
- PHI_SIGMA = (np.fft.fft(D, n_t, 1)) / (n_t ** 0.5)
40
-
41
- PHI_F = np.zeros((D.shape[0], n_t), dtype=complex) # Initialize the PHI_F MATRIX
42
- SIGMA_F = np.zeros(n_t) # Initialize the SIGMA_F MATRIX
43
-
44
- # Now we proceed with the normalization. This is also intense so we time it
45
- for r in tqdm(range(0, n_t)): # Loop over the PHI_SIGMA to normalize
46
- # MEX = 'Proj ' + str(r + 1) + ' /' + str(n_t)
47
- # print(MEX)
48
- SIGMA_F[r] = abs(np.vdot(PHI_SIGMA[:, r], PHI_SIGMA[:, r])) ** 0.5
49
- PHI_F[:, r] = PHI_SIGMA[:, r] / SIGMA_F[r]
50
-
51
- Indices = np.flipud(np.argsort(SIGMA_F)) # find indices for sorting in decreasing order
52
- Sorted_Sigmas = SIGMA_F[Indices] # Sort all the sigmas
53
- Sorted_Freqs = Freqs[Indices] # Sort all the frequencies accordingly.
54
- Phi_F = PHI_F[:, Indices] # Sorted Spatial Structures Matrix
55
- SIGMA_F = Sorted_Sigmas # Sorted Amplitude Matrix (vector)
56
-
57
- if SAVE_DFT:
58
- os.makedirs(FOLDER_OUT + 'DFT', exist_ok=True)
59
- np.savez(FOLDER_OUT + 'DFT/dft_fitted', Freqs=Sorted_Freqs, Phis=Phi_F, Sigmas=SIGMA_F)
60
-
61
- return Sorted_Freqs, Phi_F, SIGMA_F
1
+ import os
2
+
3
+ import numpy as np
4
+ from tqdm import tqdm
5
+
6
+
7
+ def dft_fit(N_T, F_S, D, FOLDER_OUT, SAVE_DFT=False):
8
+ """
9
+ Computes the Discrete Fourier Transform (DFT) from the provided dataset.
10
+
11
+ Note
12
+ ----
13
+ Memory saving feature is currently not supported by this function.
14
+
15
+ Parameters
16
+ ----------
17
+ N_T : int
18
+ Number of temporal snapshots.
19
+
20
+ F_S : float
21
+ Sampling frequency in Hz.
22
+
23
+ D : np.ndarray
24
+ Snapshot matrix.
25
+
26
+ FOLDER_OUT : str
27
+ Directory path where results are saved if `SAVE_DFT` is True.
28
+
29
+ SAVE_DFT : bool, default=False
30
+ If True, computed results are saved to disk and released from memory.
31
+
32
+ Returns
33
+ -------
34
+ Sorted_Freqs : np.ndarray
35
+ Frequency bins in Hz, sorted in ascending order.
36
+
37
+ Phi_F : np.ndarray
38
+ Complex spatial structures corresponding to each frequency mode.
39
+
40
+ SIGMA_F : np.ndarray
41
+ Real amplitudes associated with each frequency mode.
42
+ """
43
+ n_t = int(N_T)
44
+ Freqs = np.fft.fftfreq(n_t) * F_S # Compute the frequency bins
45
+ # PSI_F = np.conj(np.fft.fft(np.eye(n_t)) / np.sqrt(n_t)) # Prepare the Fourier Matrix.
46
+
47
+ # Method 1 (didactic!)
48
+ # PHI_SIGMA = np.dot(D, np.conj(PSI_F)) # This is PHI * SIGMA
49
+
50
+ # Method 2
51
+ PHI_SIGMA = (np.fft.fft(D, n_t, 1)) / (n_t ** 0.5)
52
+
53
+ PHI_F = np.zeros((D.shape[0], n_t), dtype=complex) # Initialize the PHI_F MATRIX
54
+ SIGMA_F = np.zeros(n_t) # Initialize the SIGMA_F MATRIX
55
+
56
+ # Now we proceed with the normalization. This is also intense so we time it
57
+ for r in tqdm(range(0, n_t)): # Loop over the PHI_SIGMA to normalize
58
+ # MEX = 'Proj ' + str(r + 1) + ' /' + str(n_t)
59
+ # print(MEX)
60
+ SIGMA_F[r] = abs(np.vdot(PHI_SIGMA[:, r], PHI_SIGMA[:, r])) ** 0.5
61
+ PHI_F[:, r] = PHI_SIGMA[:, r] / SIGMA_F[r]
62
+
63
+ Indices = np.flipud(np.argsort(SIGMA_F)) # find indices for sorting in decreasing order
64
+ Sorted_Sigmas = SIGMA_F[Indices] # Sort all the sigmas
65
+ Sorted_Freqs = Freqs[Indices] # Sort all the frequencies accordingly.
66
+ Phi_F = PHI_F[:, Indices] # Sorted Spatial Structures Matrix
67
+ SIGMA_F = Sorted_Sigmas # Sorted Amplitude Matrix (vector)
68
+
69
+ if SAVE_DFT:
70
+ os.makedirs(FOLDER_OUT + 'DFT', exist_ok=True)
71
+ np.savez(FOLDER_OUT + 'DFT/dft_fitted', Freqs=Sorted_Freqs, Phis=Phi_F, Sigmas=SIGMA_F)
72
+
73
+ return Sorted_Freqs, Phi_F, SIGMA_F
74
+
75
+ def dft(N_T, F_S, D, FOLDER_OUT, SAVE_DFT=False):
76
+ """
77
+ Computes the Discrete Fourier Transform (DFT) from the provided dataset.
78
+
79
+ Note
80
+ ----
81
+ Memory saving feature is currently not supported by this function.
82
+
83
+ Parameters
84
+ ----------
85
+ N_T : int
86
+ Number of temporal snapshots.
87
+
88
+ F_S : float
89
+ Sampling frequency in Hz.
90
+
91
+ D : np.ndarray
92
+ Snapshot matrix.
93
+
94
+ FOLDER_OUT : str
95
+ Directory path where results are saved if `SAVE_DFT` is True.
96
+
97
+ SAVE_DFT : bool, default=False
98
+ If True, computed results are saved to disk and released from memory.
99
+
100
+ Returns
101
+ -------
102
+ Phi_F : np.ndarray
103
+ Complex spatial structures corresponding to each frequency mode.
104
+
105
+ Sorted_Freqs : np.ndarray
106
+ Frequency bins in Hz, sorted in ascending order.
107
+
108
+ SIGMA_F : np.ndarray
109
+ Real amplitudes associated with each frequency mode.
110
+ """
111
+ n_t = int(N_T)
112
+ Freqs = np.fft.fftfreq(n_t) * F_S # Compute the frequency bins
113
+
114
+ # FFT along the snapshot axis
115
+ PHI_SIGMA = np.fft.fft(D, axis=1) / np.sqrt(n_t)
116
+ sigma_F = np.linalg.norm(PHI_SIGMA, axis=0) # Compute the norm of each column
117
+
118
+ # make phi_F orthonormal
119
+ Phi_F = PHI_SIGMA / sigma_F
120
+
121
+ # Sort
122
+ Indices = np.flipud(np.argsort(sigma_F)) # find indices for sorting in decreasing order
123
+ Sorted_Sigmas = sigma_F[Indices] # Sort all the sigmas
124
+ Sorted_Freqs = Freqs[Indices] # Sort all the frequencies accordingly.
125
+ Phi_F = Phi_F[:, Indices] # Sorted Spatial Structures Matrix
126
+ sigma_F = Sorted_Sigmas # Sorted Amplitude Matrix (vector)
127
+
128
+ if SAVE_DFT:
129
+ os.makedirs(FOLDER_OUT + 'DFT', exist_ok=True)
130
+ np.savez(FOLDER_OUT + 'DFT/dft_fitted', Freqs=Sorted_Freqs, Phis=Phi_F, Sigmas=SIGMA_F)
131
+
132
+ return Phi_F, Sorted_Freqs, sigma_F
modulo_vki/core/_dmd_s.py CHANGED
@@ -1,72 +1,81 @@
1
- import os
2
- import numpy as np
3
- from numpy import linalg as LA
4
- from ..utils._utils import switch_svds
5
-
6
-
7
- def dmd_s(D_1, D_2, n_Modes, F_S,
8
- SAVE_T_DMD=False,
9
- FOLDER_OUT='./',
10
- svd_solver: str = 'svd_sklearn_truncated'):
11
- """
12
- This method computes the Dynamic Mode Decomposition (DMD) using hte PIP algorithm from Penland.
13
-
14
- :param D_1: np.array
15
- First portion of the data, i.e. D[:,0:n_t-1]
16
- :param D_2: np.array
17
- Second portion of the data, i.e. D[:,1:n_t]
18
- :param Phi_P, Psi_P, Sigma_P: np.arrays
19
- POD decomposition of D1
20
- :param F_S: float
21
- Sampling frequency in Hz
22
- :param FOLDER_OUT: str
23
- Folder in which the results will be saved (if SAVE_T_DMD=True)
24
- :param K: np.array
25
- Temporal correlation matrix
26
- :param SAVE_T_POD: bool
27
- A flag deciding whether the results are saved on disk or not. If the MEMORY_SAVING feature is active, it is switched True by default.
28
- :param n_Modes: int
29
- number of modes that will be computed
30
- :param svd_solver: str,
31
- svd solver to be used
32
-
33
-
34
- :return1 Phi_D: np.array.
35
- DMD's complex spatial structures
36
- :return2 Lambda_D: np.array.
37
- DMD Eigenvalues (of the reduced propagator)
38
- :return3 freqs: np.array.
39
- Frequencies (in Hz, associated to the DMD modes)
40
- :return4 a0s: np.array.
41
- Initial Coefficients of the Modes
42
- """
43
-
44
- Phi_P, Psi_P, Sigma_P = switch_svds(D_1, n_Modes, svd_solver)
45
- print('SVD of D1 rdy')
46
- Sigma_inv = np.diag(1 / Sigma_P)
47
- dt = 1 / F_S
48
- # %% Step 3: Compute approximated propagator
49
- P_A = LA.multi_dot([np.transpose(Phi_P), D_2, Psi_P, Sigma_inv])
50
- print('reduced propagator rdy')
51
-
52
- # %% Step 4: Compute eigenvalues of the system
53
- Lambda, Q = LA.eig(P_A) # not necessarily symmetric def pos! Avoid eigsh, eigh
54
- freqs = np.imag(np.log(Lambda)) / (2 * np.pi * dt)
55
- print(' lambdas and freqs rdy')
56
-
57
- # %% Step 5: Spatial structures of the DMD in the PIP style
58
- Phi_D = LA.multi_dot([D_2, Psi_P, Sigma_inv, Q])
59
- print('Phi_D rdy')
60
-
61
- # %% Step 6: Compute the initial coefficients
62
- # a0s=LA.lstsq(Phi_D, D_1[:,0],rcond=None)
63
- a0s = LA.pinv(Phi_D).dot(D_1[:, 0])
64
- print('Sigma_D rdy')
65
-
66
- if SAVE_T_DMD:
67
- os.makedirs(FOLDER_OUT + "/DMD/", exist_ok=True)
68
- print("Saving DMD results")
69
- np.savez(FOLDER_OUT + '/DMD/dmd_decomposition',
70
- Phi_D=Phi_D, Lambda=Lambda, freqs=freqs, a0s=a0s)
71
-
72
- return Phi_D, Lambda, freqs, a0s
1
+ import os
2
+ import numpy as np
3
+ from numpy import linalg as LA
4
+ from ..utils._utils import switch_svds
5
+
6
+
7
+ def dmd_s(D_1, D_2, n_Modes, F_S,
8
+ SAVE_T_DMD: bool = False,
9
+ FOLDER_OUT: str = './',
10
+ svd_solver: str = 'svd_sklearn_truncated',
11
+ verbose=True):
12
+ """
13
+ Compute the Dynamic Mode Decomposition (DMD) using the PIP algorithm.
14
+
15
+ This implementation follows the Penland & Sardeshmukh PIP approach and
16
+ recovers the same modes as the exact DMD of Tu et al. (2014).
17
+
18
+ Parameters
19
+ ----------
20
+ D_1 : ndarray, shape (n_features, n_time-1)
21
+ First snapshot matrix (columns 0 to n_t-2 of the full data).
22
+ D_2 : ndarray, shape (n_features, n_time-1)
23
+ Second snapshot matrix (columns 1 to n_t-1 of the full data).
24
+ n_Modes : int
25
+ Number of DMD modes to compute.
26
+ F_S : float
27
+ Sampling frequency in Hz.
28
+ SAVE_T_DMD : bool, optional
29
+ If True, save time‐series DMD results to disk. Default is False.
30
+ FOLDER_OUT : str, optional
31
+ Directory in which to save outputs when SAVE_T_DMD is True. Default is './'.
32
+ svd_solver : str, optional
33
+ SVD solver to use for the low‐rank approximation. Default is
34
+ 'svd_sklearn_truncated'.
35
+
36
+ Returns
37
+ -------
38
+ Phi_D : ndarray, shape (n_features, n_Modes)
39
+ Complex spatial DMD modes.
40
+ Lambda_D : ndarray, shape (n_Modes,)
41
+ Complex eigenvalues of the reduced propagator.
42
+ freqs : ndarray, shape (n_Modes,)
43
+ Frequencies (Hz) associated with each DMD mode.
44
+ a0s : ndarray, shape (n_Modes,)
45
+ Initial amplitudes (coefficients) of the DMD modes.
46
+ """
47
+
48
+ Phi_P, Psi_P, Sigma_P = switch_svds(D_1, n_Modes, svd_solver)
49
+ if verbose:
50
+ print('SVD of D1 rdy')
51
+ Sigma_inv = np.diag(1 / Sigma_P)
52
+ dt = 1 / F_S
53
+ # %% Step 3: Compute approximated propagator
54
+ P_A = LA.multi_dot([np.transpose(Phi_P), D_2, Psi_P, Sigma_inv])
55
+ if verbose:
56
+ print('reduced propagator rdy')
57
+
58
+ # %% Step 4: Compute eigenvalues of the system
59
+ Lambda, Q = LA.eig(P_A) # not necessarily symmetric def pos! Avoid eigsh, eigh
60
+ freqs = np.imag(np.log(Lambda)) / (2 * np.pi * dt)
61
+ if verbose:
62
+ print(' lambdas and freqs rdy')
63
+
64
+ # %% Step 5: Spatial structures of the DMD in the PIP style
65
+ Phi_D = LA.multi_dot([D_2, Psi_P, Sigma_inv, Q])
66
+ if verbose:
67
+ print('Phi_D rdy')
68
+
69
+ # %% Step 6: Compute the initial coefficients
70
+ # a0s=LA.lstsq(Phi_D, D_1[:,0],rcond=None)
71
+ a0s = LA.pinv(Phi_D).dot(D_1[:, 0])
72
+ if verbose:
73
+ print('Sigma_D rdy')
74
+
75
+ if SAVE_T_DMD:
76
+ os.makedirs(FOLDER_OUT + "/DMD/", exist_ok=True)
77
+ print("Saving DMD results")
78
+ np.savez(FOLDER_OUT + '/DMD/dmd_decomposition',
79
+ Phi_D=Phi_D, Lambda=Lambda, freqs=freqs, a0s=a0s)
80
+
81
+ return Phi_D, Lambda, freqs, a0s