modulo-vki 2.0.7__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
modulo_vki/core/_dft.py CHANGED
@@ -6,27 +6,39 @@ from tqdm import tqdm
6
6
 
7
7
  def dft_fit(N_T, F_S, D, FOLDER_OUT, SAVE_DFT=False):
8
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
-
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.
30
42
  """
31
43
  n_t = int(N_T)
32
44
  Freqs = np.fft.fftfreq(n_t) * F_S # Compute the frequency bins
@@ -59,3 +71,62 @@ def dft_fit(N_T, F_S, D, FOLDER_OUT, SAVE_DFT=False):
59
71
  np.savez(FOLDER_OUT + 'DFT/dft_fitted', Freqs=Sorted_Freqs, Phis=Phi_F, Sigmas=SIGMA_F)
60
72
 
61
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
@@ -5,63 +5,72 @@ from ..utils._utils import switch_svds
5
5
 
6
6
 
7
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'):
8
+ SAVE_T_DMD: bool = False,
9
+ FOLDER_OUT: str = './',
10
+ svd_solver: str = 'svd_sklearn_truncated',
11
+ verbose=True):
11
12
  """
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
- """
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
+ """
43
47
 
44
48
  Phi_P, Psi_P, Sigma_P = switch_svds(D_1, n_Modes, svd_solver)
45
- print('SVD of D1 rdy')
49
+ if verbose:
50
+ print('SVD of D1 rdy')
46
51
  Sigma_inv = np.diag(1 / Sigma_P)
47
52
  dt = 1 / F_S
48
53
  # %% Step 3: Compute approximated propagator
49
54
  P_A = LA.multi_dot([np.transpose(Phi_P), D_2, Psi_P, Sigma_inv])
50
- print('reduced propagator rdy')
55
+ if verbose:
56
+ print('reduced propagator rdy')
51
57
 
52
58
  # %% Step 4: Compute eigenvalues of the system
53
59
  Lambda, Q = LA.eig(P_A) # not necessarily symmetric def pos! Avoid eigsh, eigh
54
60
  freqs = np.imag(np.log(Lambda)) / (2 * np.pi * dt)
55
- print(' lambdas and freqs rdy')
61
+ if verbose:
62
+ print(' lambdas and freqs rdy')
56
63
 
57
64
  # %% Step 5: Spatial structures of the DMD in the PIP style
58
65
  Phi_D = LA.multi_dot([D_2, Psi_P, Sigma_inv, Q])
59
- print('Phi_D rdy')
66
+ if verbose:
67
+ print('Phi_D rdy')
60
68
 
61
69
  # %% Step 6: Compute the initial coefficients
62
70
  # a0s=LA.lstsq(Phi_D, D_1[:,0],rcond=None)
63
71
  a0s = LA.pinv(Phi_D).dot(D_1[:, 0])
64
- print('Sigma_D rdy')
72
+ if verbose:
73
+ print('Sigma_D rdy')
65
74
 
66
75
  if SAVE_T_DMD:
67
76
  os.makedirs(FOLDER_OUT + "/DMD/", exist_ok=True)
@@ -2,32 +2,70 @@ import os
2
2
  from tqdm import tqdm
3
3
  import numpy as np
4
4
  import math
5
+ from scipy.signal import firwin
6
+ from scipy import signal
7
+ from sklearn.metrics.pairwise import pairwise_kernels
8
+
9
+ def CorrelationMatrix(N_T,
10
+ N_PARTITIONS=1,
11
+ MEMORY_SAVING=False,
12
+ FOLDER_OUT='./',
13
+ SAVE_K=False,
14
+ D=None,
15
+ weights=np.array([]),
16
+ verbose=True):
17
+ """
18
+ Computes the temporal correlation matrix from the provided data matrix.
5
19
 
20
+ If MEMORY_SAVING is active, computation is split into partitions to reduce memory load.
21
+ If data matrix D has been computed using MODULO, parameters like dimensions and number of partitions
22
+ will automatically be inferred.
6
23
 
7
- def CorrelationMatrix(N_T, N_PARTITIONS=1, MEMORY_SAVING=False, FOLDER_OUT='./', SAVE_K=False, D=None,weights = np.array([])):
8
- """
9
- This method computes the temporal correlation matrix, given a data matrix as input. It's possible to use memory saving
10
- then splitting the computing in different tranches if computationally heavy. If D has been computed using MODULO
11
- then the dimension dim_col and N_PARTITIONS is automatically loaded
12
-
13
- :param N_T: int. Number of temporal snapshots
14
- :param D: np.array. Data matrix
15
- :param SAVE_K: bool. If SAVE_K=True, the matrix K is saved on disk. If the MEMORY_SAVING feature is active, this is done by default.
16
- :param MEMORY_SAVING: bool. If MEMORY_SAVING = True, the computation of the correlation matrix is done by steps. It requires the data matrix to be partitioned, following algorithm in MODULO._data_processing.
17
- :param FOLDER_OUT: str. Folder in which the temporal correlation matrix will be stored
18
- :param N_PARTITIONS: int. Number of partitions to be read in computing the correlation matrix. If _data_processing is used to partition the data matrix, this is inherited from the main class
19
- :param weights: weight vector [w_i,....,w_{N_s}] where w_i = area_cell_i/area_grid. Only needed if grid is non-uniform & MEMORY_SAVING== True
20
- :return: K (: np.array) if the memory saving is not active. None type otherwise.
24
+ Parameters
25
+ ----------
26
+ N_T : int
27
+ Number of temporal snapshots.
28
+
29
+ N_PARTITIONS : int, default=1
30
+ Number of partitions for memory-saving computation.
31
+ Inherited automatically if using MODULO's partitioning.
32
+
33
+ MEMORY_SAVING : bool, default=False
34
+ Activates partitioned computation of the correlation matrix to reduce memory usage.
35
+ Requires pre-partitioned data according to MODULO's `_data_processing`.
36
+
37
+ FOLDER_OUT : str, default='./'
38
+ Output directory where the temporal correlation matrix will be saved if required.
39
+
40
+ SAVE_K : bool, default=False
41
+ Flag to save the computed correlation matrix K to disk. Automatically enforced
42
+ if MEMORY_SAVING is active.
43
+
44
+ D : np.ndarray, optional
45
+ Data matrix used to compute the correlation matrix. Required if MEMORY_SAVING is False.
46
+
47
+ weights : np.ndarray, default=np.array([])
48
+ Weight vector `[w_1, w_2, ..., w_Ns]` defined as `w_i = area_cell_i / area_grid`.
49
+ Needed only for non-uniform grids when MEMORY_SAVING is True.
50
+
51
+ Returns
52
+ -------
53
+ K : np.ndarray or None
54
+ Temporal correlation matrix if MEMORY_SAVING is False; otherwise returns None,
55
+ as matrix is managed via disk storage in partitioned computations.
21
56
  """
22
57
 
23
58
  if not MEMORY_SAVING:
24
- print("\n Computing Temporal correlation matrix K ...")
59
+ if verbose:
60
+ print("Computing Temporal correlation matrix K ...")
25
61
  K = np.dot(D.T, D)
26
- print("\n Done.")
62
+ if verbose:
63
+ print("Done.")
27
64
 
28
65
  else:
29
66
  SAVE_K = True
30
- print("\n Using Memory Saving feature...")
67
+ if verbose:
68
+ print("\n Using Memory Saving feature...")
31
69
  K = np.zeros((N_T, N_T))
32
70
  dim_col = math.floor(N_T / N_PARTITIONS)
33
71
 
@@ -79,3 +117,93 @@ def CorrelationMatrix(N_T, N_PARTITIONS=1, MEMORY_SAVING=False, FOLDER_OUT='./',
79
117
  np.savez(FOLDER_OUT + "/correlation_matrix/k_matrix", K=K)
80
118
 
81
119
  return K if not MEMORY_SAVING else None
120
+
121
+
122
+ def spectral_filter(K: np.ndarray, N_o:int, f_c: float) -> np.ndarray:
123
+ """
124
+ Zero‐phase band‐pass filter of the correlation matrix K along its diagonals.
125
+ Used for the SPOD proposed by Sieber et al.
126
+
127
+ Parameters
128
+ ----------
129
+ K : (n_t, n_t) array
130
+ Original temporal correlation matrix.
131
+ N_o : int
132
+ Semi‐order of the FIR filter (true filter length = 2*N_o+1).
133
+ f_c : float
134
+ Normalized cutoff frequency (0 < f_c < 0.5).
135
+
136
+ Returns
137
+ -------
138
+ K_F : (n_t, n_t) array
139
+ The filtered correlation matrix.
140
+ """
141
+ n_t = K.shape[0]
142
+
143
+ # extend K for edge-padding
144
+ K_ext = np.pad(
145
+ K,
146
+ pad_width=((N_o, N_o), (N_o, N_o)),
147
+ mode='constant', # or 'edge', 'reflect', etc.
148
+ constant_values=0
149
+ )
150
+
151
+ # Fill the edges ( a bit of repetition but ok.. )
152
+ # Row-wise, Upper part
153
+ for i in range(0, N_o):
154
+ K_ext[i, i:i + n_t] = K[0, :]
155
+
156
+ # Row-wise, bottom part
157
+ for i in range(N_o + n_t, n_t + 2 * N_o):
158
+ K_ext[i, i - n_t + 1:i + 1] = K[-1, :]
159
+
160
+ # Column-wise, left part
161
+ for j in range(0, N_o):
162
+ K_ext[j:j + n_t, j] = K[:, 0]
163
+
164
+ # Column-wise, right part
165
+ for j in range(N_o + n_t, 2 * N_o + n_t):
166
+ K_ext[j - n_t + 1:j + 1, j] = K[:, -1]
167
+
168
+ # K_e = np.zeros((n_t + 2 * N_o, n_t + 2 * N_o))
169
+ # From which we clearly know that:
170
+ # K_e[N_o:n_t + N_o, N_o:n_t + N_o] = K
171
+
172
+ # create 2D kernel for FIR
173
+ h1d = firwin(N_o, f_c)
174
+ L = K_ext.shape[0]
175
+
176
+ pad_l = (L - N_o) // 2
177
+ pad_r = L - N_o - pad_l
178
+
179
+ # symmetrically padded kernel in 1D
180
+ h1d_pad = np.pad(h1d, (pad_l, pad_r))
181
+
182
+ # we make it 2D diagonal
183
+ h2d = np.diag(h1d_pad)
184
+
185
+ # finally filter K_ext and return the trimmed filtered without boundaries
186
+ K_ext_filt = signal.fftconvolve(K_ext, h2d, mode='same')
187
+ K_F = K_ext_filt[N_o : N_o + n_t, N_o : N_o + n_t]
188
+
189
+ return K_F
190
+
191
+ def kernelized_K(D, M_ij, k_m, metric, cent, alpha):
192
+
193
+ n_s, n_t = D.shape
194
+
195
+ gamma = - np.log(k_m) / M_ij
196
+ K_zeta = pairwise_kernels(D.T, metric=metric, gamma=gamma) # kernel substitute of the inner product
197
+
198
+ # Center the Kernel Matrix (if cent is True):
199
+ if cent:
200
+ H = np.eye(n_t) - 1 / n_t * np.ones_like(K_zeta)
201
+ K_zeta = H @ K_zeta @ H.T
202
+
203
+ # add `Ridge term` to enforce strictly pos. def. eigs and well-conditioning
204
+ K_r = K_zeta + alpha * np.eye(n_t)
205
+
206
+ return K_r
207
+
208
+
209
+
@@ -4,8 +4,11 @@ from scipy.signal import firwin # To create FIR kernels
4
4
  from tqdm import tqdm
5
5
  from modulo_vki.utils._utils import conv_m, switch_eigs
6
6
 
7
+ # TODO: instead of computing the min of modes between SAT and the number of frequencies, we should compute the number of modes between SAT and the number of requested modes by the user.
7
8
 
8
- def temporal_basis_mPOD(K, Nf, Ex, F_V, Keep, boundaries, MODE='reduced', dt=1,FOLDER_OUT: str = "./", MEMORY_SAVING: bool = False,SAT: int = 100,n_Modes=10, eig_solver: str = 'svd_sklearn_randomized'):
9
+ def temporal_basis_mPOD(K, Nf, Ex, F_V, Keep, boundaries, MODE='reduced',
10
+ dt=1,FOLDER_OUT: str = "./", MEMORY_SAVING: bool = False,SAT: int = 100,
11
+ n_Modes=10, eig_solver: str = 'svd_sklearn_randomized'):
9
12
  '''
10
13
  This function computes the PSIs for the mPOD. In this implementation, a "dft-trick" is proposed, in order to avoid
11
14
  expansive SVDs. Randomized SVD is used by default for the diagonalization.
@@ -15,9 +18,11 @@ def temporal_basis_mPOD(K, Nf, Ex, F_V, Keep, boundaries, MODE='reduced', dt=1,F
15
18
  :param dt: float.
16
19
  1/fs, the dt between snapshots. Units in seconds.
17
20
  :param Nf:
18
- np.array. Vector collecting the order of the FIR filters used in each scale.
21
+ np.array. Vector collecting the order of the FIR filters used in each scale. It must be of size len(F_V) + 1, where the first element defines
22
+ the low pass filter, and the last one is the high pass filter. The rest are for the band-pass filters.
19
23
  :param Ex: int.
20
- Extension at the boundaries of K to impose the boundary conditions (see boundaries). It must be at least as Nf.
24
+ Extension at the boundaries of K to impose the boundary conditions (see boundaries). It must be at least as Nf, and of size len(F_V) + 1, where the first
25
+ element is the low pass filter, and the last one is the high pass filter. The rest are band-pass filters.
21
26
  :param F_V: np.array.
22
27
  Frequency splitting vector, containing the frequencies of each scale (see article). If the time axis is in seconds, these frequencies are in Hz.
23
28
  :param Keep: np.array.
@@ -51,6 +56,16 @@ def temporal_basis_mPOD(K, Nf, Ex, F_V, Keep, boundaries, MODE='reduced', dt=1,F
51
56
  #Converting F_V in radiants and initialise number of scales M
52
57
  Fs = 1 / dt
53
58
  F_Bank_r = F_V * 2 / Fs
59
+
60
+ # repeat first entry to ensure all scales are covered
61
+ F_Bank_r = np.concatenate(([F_Bank_r[0]], F_Bank_r))
62
+ # TODO: update tutorials to reflect this change!
63
+
64
+ assert len(F_Bank_r) == len(Nf), "Frequencies and filter orders must have the same length. Remember that given M scales, Nf must have M+1 elements"
65
+ assert len(F_Bank_r) == len(Keep), "Frequencies and keep must have the same length. Remember that given M scales, keep must have M+1 elements"
66
+ # Nf = np.concatenate(([Nf[0]], Nf))
67
+ # Keep = np.concatenate(([Keep[0]], Keep))
68
+
54
69
  M = len(F_Bank_r)
55
70
 
56
71
  # Loop over the scales to show the transfer functions
@@ -72,26 +87,29 @@ def temporal_basis_mPOD(K, Nf, Ex, F_V, Keep, boundaries, MODE='reduced', dt=1,F
72
87
  # Generate the 1d filter for this
73
88
  if m < 1:
74
89
  if Keep[m] == 1:
75
- # Low Pass Filter
76
- h_A = firwin(Nf[m], F_Bank_r[m], window='hamming')
77
- # Filter K_LP
78
- print('\n Filtering Largest Scale')
79
- K_L = conv_m(K=K, h=h_A, Ex=Ex, boundaries=boundaries)
80
- # R_K = np.linalg.matrix_rank(K_L, tol=None, hermitian=True)
81
- '''We replace it with an estimation based on the non-zero freqs the cut off frequency of the scale is '''
82
- F_CUT = F_Bank_r[m] * Fs / 2
83
- Indices = np.argwhere(np.abs(Freqs) < F_CUT)
84
- R_K = np.min([len(Indices), SAT])
85
- print(str(len(Indices)) + ' Modes Estimated')
86
- print('\n Diagonalizing Largest Scale')
87
- Psi_P, Lambda_P = switch_eigs(K_L, R_K, eig_solver) #svds_RND(K_L, R_K)
88
- Psi_M=Psi_P; Lambda_M=Lambda_P
90
+ # Low Pass Filter
91
+ h_A = firwin(Nf[m], F_Bank_r[m], window='hamming')
92
+ # Filter K_LP
93
+ print('\n Filtering Largest Scale')
94
+ K_L = conv_m(K=K, h=h_A, Ex=Ex, boundaries=boundaries)
95
+ # R_K = np.linalg.matrix_rank(K_L, tol=None, hermitian=True)
96
+ '''We replace it with an estimation based on the non-zero freqs the cut off frequency of the scale is '''
97
+ F_CUT = F_Bank_r[m] * Fs / 2
98
+ Indices = np.argwhere(np.abs(Freqs) < F_CUT)
99
+
100
+ # R_K = np.min([len(Indices), SAT])
101
+ # R_K = np.min(R_K, n_Modes) # we take the min between the number of frequencies and the number of modes requested
102
+ R_K = min(len(Indices), SAT, n_Modes)
103
+
104
+ print(str(len(Indices)) + ' Modes Estimated')
105
+ print('\n Diagonalizing Largest Scale')
106
+
107
+ Psi_P, Lambda_P = switch_eigs(K_L, R_K, eig_solver) #svds_RND(K_L, R_K)
108
+ Psi_M=Psi_P
109
+ Lambda_M=Lambda_P
89
110
  else:
90
- print('\n Scale '+str(m)+' jumped (keep['+str(m)+']=0)')
91
- # if K_S:
92
- # Ks[:, :, m] = K_L # First large scale
93
-
94
- # method = signal.choose_conv_method(K, h2d, mode='same')
111
+ print('\n Scale '+str(m)+' jumped (keep['+str(m)+']=0)')
112
+
95
113
  elif m > 0 and m < M - 1:
96
114
  if Keep[m] == 1:
97
115
  # print(m)
@@ -109,11 +127,14 @@ def temporal_basis_mPOD(K, Nf, Ex, F_V, Keep, boundaries, MODE='reduced', dt=1,F
109
127
  print('Diagonalizing H Scale ' + str(m + 1) + '/' + str(M))
110
128
  # R_K = np.linalg.matrix_rank(K_H, tol=None, hermitian=True)
111
129
  Psi_P, Lambda_P = switch_eigs(K_H, R_K, eig_solver) #svds_RND(K_H, R_K) # Diagonalize scale
130
+
112
131
  if np.shape(Psi_M)[0]==0: # if this is the first contribute to the basis
113
- Psi_M=Psi_P; Lambda_M=Lambda_P
132
+ Psi_M=Psi_P
133
+ Lambda_M=Lambda_P
114
134
  else:
115
- Psi_M = np.concatenate((Psi_M, Psi_P), axis=1) # append to the previous
116
- Lambda_M = np.concatenate((Lambda_M, Lambda_P), axis=0)
135
+ Psi_M = np.concatenate((Psi_M, Psi_P), axis=1) # append to the previous
136
+ Lambda_M = np.concatenate((Lambda_M, Lambda_P), axis=0)
137
+
117
138
  else:
118
139
  print('\n Scale '+str(m)+' jumped (keep['+str(m)+']=0)')
119
140
 
@@ -4,7 +4,8 @@ from tqdm import tqdm
4
4
  import os
5
5
 
6
6
 
7
- def Spatial_basis_POD(D, PSI_P, Sigma_P, MEMORY_SAVING, N_T, FOLDER_OUT='./', N_PARTITIONS=1, SAVE_SPATIAL_POD=False,
7
+ def Spatial_basis_POD(D, PSI_P, Sigma_P, MEMORY_SAVING,
8
+ N_T, FOLDER_OUT='./', N_PARTITIONS=1, SAVE_SPATIAL_POD=False,
8
9
  rescale=False):
9
10
  """
10
11
  This function computs the POD spatial basis from the temporal basis,
@@ -55,7 +56,7 @@ def Spatial_basis_POD(D, PSI_P, Sigma_P, MEMORY_SAVING, N_T, FOLDER_OUT='./', N_
55
56
 
56
57
  else:
57
58
  # We take only the first R modes.
58
- Sigma_P_t = Sigma_P[0:R];
59
+ Sigma_P_t = Sigma_P[0:R]
59
60
  Sigma_P_Inv_V = 1 / Sigma_P_t
60
61
  # So we have the inverse
61
62
  Sigma_P_Inv = np.diag(Sigma_P_Inv_V)
@@ -3,7 +3,8 @@ import numpy as np
3
3
  from ..utils._utils import switch_eigs
4
4
 
5
5
 
6
- def Temporal_basis_POD(K, SAVE_T_POD=False, FOLDER_OUT='./', n_Modes=10,eig_solver: str = 'eigh'):
6
+ def Temporal_basis_POD(K, SAVE_T_POD=False, FOLDER_OUT='./',
7
+ n_Modes=10,eig_solver: str = 'eigh'):
7
8
  """
8
9
  This method computes the POD basis. For some theoretical insights, you can find the theoretical background of the proper orthogonal decomposition in a nutshell here: https://youtu.be/8fhupzhAR_M
9
10