modulo-vki 2.0.5__py3-none-any.whl → 2.0.6__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 +22 -22
- modulo_vki/core/__init__.py +9 -9
- modulo_vki/core/_dft.py +61 -61
- modulo_vki/core/_dmd_s.py +72 -72
- modulo_vki/core/_k_matrix.py +81 -81
- modulo_vki/core/_mpod_space.py +180 -180
- modulo_vki/core/_mpod_time.py +154 -154
- modulo_vki/core/_pod_space.py +184 -184
- modulo_vki/core/_pod_time.py +48 -48
- modulo_vki/core/_spod_s.py +101 -101
- modulo_vki/core/_spod_t.py +104 -104
- modulo_vki/modulo.py +828 -828
- modulo_vki/utils/__init__.py +4 -4
- modulo_vki/utils/_plots.py +51 -51
- modulo_vki/utils/_utils.py +341 -339
- modulo_vki/utils/others.py +452 -449
- modulo_vki/utils/read_db.py +339 -339
- {modulo_vki-2.0.5.dist-info → modulo_vki-2.0.6.dist-info}/LICENSE +21 -21
- modulo_vki-2.0.6.dist-info/METADATA +304 -0
- modulo_vki-2.0.6.dist-info/RECORD +22 -0
- {modulo_vki-2.0.5.dist-info → modulo_vki-2.0.6.dist-info}/WHEEL +1 -1
- modulo_vki-2.0.5.dist-info/METADATA +0 -96
- modulo_vki-2.0.5.dist-info/RECORD +0 -22
- {modulo_vki-2.0.5.dist-info → modulo_vki-2.0.6.dist-info}/top_level.txt +0 -0
modulo_vki/core/_mpod_time.py
CHANGED
|
@@ -1,154 +1,154 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import numpy as np
|
|
3
|
-
from scipy.signal import firwin # To create FIR kernels
|
|
4
|
-
from tqdm import tqdm
|
|
5
|
-
from modulo_vki.utils._utils import conv_m, switch_eigs
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
'''
|
|
10
|
-
This function computes the PSIs for the mPOD. In this implementation, a "dft-trick" is proposed, in order to avoid
|
|
11
|
-
expansive SVDs. Randomized SVD is used by default for the diagonalization.
|
|
12
|
-
|
|
13
|
-
:param K:
|
|
14
|
-
np.array Temporal correlation matrix
|
|
15
|
-
:param dt: float.
|
|
16
|
-
1/fs, the dt between snapshots. Units in seconds.
|
|
17
|
-
:param Nf:
|
|
18
|
-
np.array. Vector collecting the order of the FIR filters used in each scale.
|
|
19
|
-
:param Ex: int.
|
|
20
|
-
Extension at the boundaries of K to impose the boundary conditions (see boundaries). It must be at least as Nf.
|
|
21
|
-
:param F_V: np.array.
|
|
22
|
-
Frequency splitting vector, containing the frequencies of each scale (see article). If the time axis is in seconds, these frequencies are in Hz.
|
|
23
|
-
:param Keep: np.array.
|
|
24
|
-
Vector defining which scale to keep.
|
|
25
|
-
:param boundaries: str -> {'nearest', 'reflect', 'wrap' or 'extrap'}.
|
|
26
|
-
In order to avoid 'edge effects' if the time correlation matrix is not periodic, several boundary conditions can be used. Options are (from scipy.ndimage.convolve):
|
|
27
|
-
‘reflect’ (d c b a | a b c d | d c b a) The input is extended by reflecting about the edge of the last pixel.
|
|
28
|
-
‘nearest’ (a a a a | a b c d | d d d d) The input is extended by replicating the last pixel.
|
|
29
|
-
‘wrap’ (a b c d | a b c d | a b c d) The input is extended by wrapping around to the opposite edge.
|
|
30
|
-
:param MODE: tr -> {‘reduced’, ‘complete’, ‘r’, ‘raw’}
|
|
31
|
-
As a final step of this algorithm, the orthogonality is imposed via a QR-factorization. This parameterd define how to perform such factorization, according to numpy.
|
|
32
|
-
Options: this is a wrapper to np.linalg.qr(_, mode=MODE). Check numpy's documentation.
|
|
33
|
-
if ‘reduced’ The final basis will not necessarely be full. If ‘complete’ The final basis will always be full
|
|
34
|
-
:param FOLDER_OUT: str.
|
|
35
|
-
This is the directory where intermediate results will be stored if the memory saving is active.It will be ignored if MEMORY_SAVING=False.
|
|
36
|
-
:param MEMORY_SAVING: Bool.
|
|
37
|
-
If memory saving is active, the results will be saved locally. Nevertheless, since Psi_M is usually not expensive, it will be returned.
|
|
38
|
-
:param SAT: int.
|
|
39
|
-
Maximum number of modes per scale. The user can decide how many modes to compute; otherwise, modulo set the default SAT=100.
|
|
40
|
-
:param n_Modes: int.
|
|
41
|
-
Total number of modes that will be finally exported
|
|
42
|
-
:param eig_solver: str.
|
|
43
|
-
This is the eigenvalue solver that will be used. Refer to eigs_swith for the options.
|
|
44
|
-
:return PSI_M: np.array.
|
|
45
|
-
The mPOD PSIs. Yet to be sorted !
|
|
46
|
-
'''
|
|
47
|
-
|
|
48
|
-
if Ex < np.max(Nf):
|
|
49
|
-
raise RuntimeError("For the mPOD temporal basis computation Ex must be larger than or equal to Nf")
|
|
50
|
-
|
|
51
|
-
#Converting F_V in radiants and initialise number of scales M
|
|
52
|
-
Fs = 1 / dt
|
|
53
|
-
F_Bank_r = F_V * 2 / Fs
|
|
54
|
-
M = len(F_Bank_r)
|
|
55
|
-
|
|
56
|
-
# Loop over the scales to show the transfer functions
|
|
57
|
-
Psi_M = np.array([])
|
|
58
|
-
Lambda_M = np.array([])
|
|
59
|
-
n_t = K.shape[1]
|
|
60
|
-
|
|
61
|
-
# if K_S:
|
|
62
|
-
# Ks = np.zeros((n_t, n_t, M + 1))
|
|
63
|
-
|
|
64
|
-
#DFT-trick below: computing frequency bins.
|
|
65
|
-
Freqs = np.fft.fftfreq(n_t) * Fs
|
|
66
|
-
|
|
67
|
-
print("Filtering and Diagonalizing H scale: \n")
|
|
68
|
-
|
|
69
|
-
#Filtering and computing eigenvectors
|
|
70
|
-
|
|
71
|
-
for m in tqdm(range(0, M)):
|
|
72
|
-
# Generate the 1d filter for this
|
|
73
|
-
if m < 1:
|
|
74
|
-
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
|
|
89
|
-
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')
|
|
95
|
-
elif m > 0 and m < M - 1:
|
|
96
|
-
if Keep[m] == 1:
|
|
97
|
-
# print(m)
|
|
98
|
-
print('\n Working on Scale '+str(m)+'/'+str(M))
|
|
99
|
-
# This is the 1d Kernel for Band pass
|
|
100
|
-
h1d_H = firwin(Nf[m], [F_Bank_r[m], F_Bank_r[m + 1]], pass_zero=False) # Band-pass
|
|
101
|
-
F_CUT1 = F_Bank_r[m] * Fs / 2
|
|
102
|
-
F_CUT2 = F_Bank_r[m + 1] * Fs / 2
|
|
103
|
-
Indices = np.argwhere((np.abs(Freqs) > F_CUT1) & (np.abs(Freqs) < F_CUT2))
|
|
104
|
-
R_K = np.min([len(Indices), SAT]) # number of frequencies here
|
|
105
|
-
print(str(len(Indices)) + ' Modes Estimated')
|
|
106
|
-
# print('Filtering H Scale ' + str(m + 1) + '/' + str(M))
|
|
107
|
-
K_H = conv_m(K, h1d_H, Ex, boundaries)
|
|
108
|
-
# Ks[:, :, m + 1] = K_H # Intermediate band-pass
|
|
109
|
-
print('Diagonalizing H Scale ' + str(m + 1) + '/' + str(M))
|
|
110
|
-
# R_K = np.linalg.matrix_rank(K_H, tol=None, hermitian=True)
|
|
111
|
-
Psi_P, Lambda_P = switch_eigs(K_H, R_K, eig_solver) #svds_RND(K_H, R_K) # Diagonalize scale
|
|
112
|
-
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
|
|
114
|
-
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)
|
|
117
|
-
else:
|
|
118
|
-
print('\n Scale '+str(m)+' jumped (keep['+str(m)+']=0)')
|
|
119
|
-
|
|
120
|
-
else: # this is the case m=M: this is a high pass
|
|
121
|
-
if Keep[m] == 1:
|
|
122
|
-
print('Working on Scale '+str(m)+'/'+str(M))
|
|
123
|
-
# This is the 1d Kernel for High Pass (last scale)
|
|
124
|
-
h1d_H = firwin(Nf[m], F_Bank_r[m], pass_zero=False)
|
|
125
|
-
F_CUT1 = F_Bank_r[m] * Fs / 2
|
|
126
|
-
Indices = np.argwhere((np.abs(Freqs) > F_CUT1))
|
|
127
|
-
R_K = len(Indices)
|
|
128
|
-
R_K = np.min([len(Indices), SAT]) # number of frequencies here
|
|
129
|
-
print(str(len(Indices)) + ' Modes Estimated')
|
|
130
|
-
print('Filtering H Scale ' + str(m + 1) + '/ ' + str(M))
|
|
131
|
-
K_H = conv_m(K, h1d_H, Ex, boundaries)
|
|
132
|
-
# Ks[:, :, m + 1] = K_H # Last (high pass) scale
|
|
133
|
-
print('Diagonalizing H Scale ' + str(m + 1) + '/ ' + str(M))
|
|
134
|
-
# R_K = np.linalg.matrix_rank(K_H, tol=None, hermitian=True)
|
|
135
|
-
Psi_P, Lambda_P = switch_eigs(K_H, R_K, eig_solver) #svds_RND(K_H, R_K) # Diagonalize scale
|
|
136
|
-
Psi_M = np.concatenate((Psi_M, Psi_P), axis=1) # append to the previous
|
|
137
|
-
Lambda_M = np.concatenate((Lambda_M, Lambda_P), axis=0)
|
|
138
|
-
else:
|
|
139
|
-
print('\n Scale '+str(m)+' jumped (keep['+str(m)+']=0)')
|
|
140
|
-
|
|
141
|
-
# Now Order the Scales
|
|
142
|
-
Indices = np.flip(np.argsort(Lambda_M)) # find indices for sorting in decreasing order
|
|
143
|
-
Psi_M = Psi_M[:, Indices] # Sort the temporal structures
|
|
144
|
-
#print(f"Size psis in mpodtime = {np.shape(Psi_M)}")
|
|
145
|
-
# Now we complete the basis via re-orghotonalization
|
|
146
|
-
print('\n QR Polishing...')
|
|
147
|
-
PSI_M, R = np.linalg.qr(Psi_M, mode=MODE)
|
|
148
|
-
print('Done!')
|
|
149
|
-
|
|
150
|
-
if MEMORY_SAVING:
|
|
151
|
-
os.makedirs(FOLDER_OUT + '/mPOD', exist_ok=True)
|
|
152
|
-
np.savez(FOLDER_OUT + '/mPOD/Psis', Psis=PSI_M)
|
|
153
|
-
|
|
154
|
-
return PSI_M[:,0:n_Modes]
|
|
1
|
+
import os
|
|
2
|
+
import numpy as np
|
|
3
|
+
from scipy.signal import firwin # To create FIR kernels
|
|
4
|
+
from tqdm import tqdm
|
|
5
|
+
from modulo_vki.utils._utils import conv_m, switch_eigs
|
|
6
|
+
|
|
7
|
+
|
|
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
|
+
'''
|
|
10
|
+
This function computes the PSIs for the mPOD. In this implementation, a "dft-trick" is proposed, in order to avoid
|
|
11
|
+
expansive SVDs. Randomized SVD is used by default for the diagonalization.
|
|
12
|
+
|
|
13
|
+
:param K:
|
|
14
|
+
np.array Temporal correlation matrix
|
|
15
|
+
:param dt: float.
|
|
16
|
+
1/fs, the dt between snapshots. Units in seconds.
|
|
17
|
+
:param Nf:
|
|
18
|
+
np.array. Vector collecting the order of the FIR filters used in each scale.
|
|
19
|
+
:param Ex: int.
|
|
20
|
+
Extension at the boundaries of K to impose the boundary conditions (see boundaries). It must be at least as Nf.
|
|
21
|
+
:param F_V: np.array.
|
|
22
|
+
Frequency splitting vector, containing the frequencies of each scale (see article). If the time axis is in seconds, these frequencies are in Hz.
|
|
23
|
+
:param Keep: np.array.
|
|
24
|
+
Vector defining which scale to keep.
|
|
25
|
+
:param boundaries: str -> {'nearest', 'reflect', 'wrap' or 'extrap'}.
|
|
26
|
+
In order to avoid 'edge effects' if the time correlation matrix is not periodic, several boundary conditions can be used. Options are (from scipy.ndimage.convolve):
|
|
27
|
+
‘reflect’ (d c b a | a b c d | d c b a) The input is extended by reflecting about the edge of the last pixel.
|
|
28
|
+
‘nearest’ (a a a a | a b c d | d d d d) The input is extended by replicating the last pixel.
|
|
29
|
+
‘wrap’ (a b c d | a b c d | a b c d) The input is extended by wrapping around to the opposite edge.
|
|
30
|
+
:param MODE: tr -> {‘reduced’, ‘complete’, ‘r’, ‘raw’}
|
|
31
|
+
As a final step of this algorithm, the orthogonality is imposed via a QR-factorization. This parameterd define how to perform such factorization, according to numpy.
|
|
32
|
+
Options: this is a wrapper to np.linalg.qr(_, mode=MODE). Check numpy's documentation.
|
|
33
|
+
if ‘reduced’ The final basis will not necessarely be full. If ‘complete’ The final basis will always be full
|
|
34
|
+
:param FOLDER_OUT: str.
|
|
35
|
+
This is the directory where intermediate results will be stored if the memory saving is active.It will be ignored if MEMORY_SAVING=False.
|
|
36
|
+
:param MEMORY_SAVING: Bool.
|
|
37
|
+
If memory saving is active, the results will be saved locally. Nevertheless, since Psi_M is usually not expensive, it will be returned.
|
|
38
|
+
:param SAT: int.
|
|
39
|
+
Maximum number of modes per scale. The user can decide how many modes to compute; otherwise, modulo set the default SAT=100.
|
|
40
|
+
:param n_Modes: int.
|
|
41
|
+
Total number of modes that will be finally exported
|
|
42
|
+
:param eig_solver: str.
|
|
43
|
+
This is the eigenvalue solver that will be used. Refer to eigs_swith for the options.
|
|
44
|
+
:return PSI_M: np.array.
|
|
45
|
+
The mPOD PSIs. Yet to be sorted !
|
|
46
|
+
'''
|
|
47
|
+
|
|
48
|
+
if Ex < np.max(Nf):
|
|
49
|
+
raise RuntimeError("For the mPOD temporal basis computation Ex must be larger than or equal to Nf")
|
|
50
|
+
|
|
51
|
+
#Converting F_V in radiants and initialise number of scales M
|
|
52
|
+
Fs = 1 / dt
|
|
53
|
+
F_Bank_r = F_V * 2 / Fs
|
|
54
|
+
M = len(F_Bank_r)
|
|
55
|
+
|
|
56
|
+
# Loop over the scales to show the transfer functions
|
|
57
|
+
Psi_M = np.array([])
|
|
58
|
+
Lambda_M = np.array([])
|
|
59
|
+
n_t = K.shape[1]
|
|
60
|
+
|
|
61
|
+
# if K_S:
|
|
62
|
+
# Ks = np.zeros((n_t, n_t, M + 1))
|
|
63
|
+
|
|
64
|
+
#DFT-trick below: computing frequency bins.
|
|
65
|
+
Freqs = np.fft.fftfreq(n_t) * Fs
|
|
66
|
+
|
|
67
|
+
print("Filtering and Diagonalizing H scale: \n")
|
|
68
|
+
|
|
69
|
+
#Filtering and computing eigenvectors
|
|
70
|
+
|
|
71
|
+
for m in tqdm(range(0, M)):
|
|
72
|
+
# Generate the 1d filter for this
|
|
73
|
+
if m < 1:
|
|
74
|
+
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
|
|
89
|
+
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')
|
|
95
|
+
elif m > 0 and m < M - 1:
|
|
96
|
+
if Keep[m] == 1:
|
|
97
|
+
# print(m)
|
|
98
|
+
print('\n Working on Scale '+str(m)+'/'+str(M))
|
|
99
|
+
# This is the 1d Kernel for Band pass
|
|
100
|
+
h1d_H = firwin(Nf[m], [F_Bank_r[m], F_Bank_r[m + 1]], pass_zero=False) # Band-pass
|
|
101
|
+
F_CUT1 = F_Bank_r[m] * Fs / 2
|
|
102
|
+
F_CUT2 = F_Bank_r[m + 1] * Fs / 2
|
|
103
|
+
Indices = np.argwhere((np.abs(Freqs) > F_CUT1) & (np.abs(Freqs) < F_CUT2))
|
|
104
|
+
R_K = np.min([len(Indices), SAT]) # number of frequencies here
|
|
105
|
+
print(str(len(Indices)) + ' Modes Estimated')
|
|
106
|
+
# print('Filtering H Scale ' + str(m + 1) + '/' + str(M))
|
|
107
|
+
K_H = conv_m(K, h1d_H, Ex, boundaries)
|
|
108
|
+
# Ks[:, :, m + 1] = K_H # Intermediate band-pass
|
|
109
|
+
print('Diagonalizing H Scale ' + str(m + 1) + '/' + str(M))
|
|
110
|
+
# R_K = np.linalg.matrix_rank(K_H, tol=None, hermitian=True)
|
|
111
|
+
Psi_P, Lambda_P = switch_eigs(K_H, R_K, eig_solver) #svds_RND(K_H, R_K) # Diagonalize scale
|
|
112
|
+
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
|
|
114
|
+
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)
|
|
117
|
+
else:
|
|
118
|
+
print('\n Scale '+str(m)+' jumped (keep['+str(m)+']=0)')
|
|
119
|
+
|
|
120
|
+
else: # this is the case m=M: this is a high pass
|
|
121
|
+
if Keep[m] == 1:
|
|
122
|
+
print('Working on Scale '+str(m)+'/'+str(M))
|
|
123
|
+
# This is the 1d Kernel for High Pass (last scale)
|
|
124
|
+
h1d_H = firwin(Nf[m], F_Bank_r[m], pass_zero=False)
|
|
125
|
+
F_CUT1 = F_Bank_r[m] * Fs / 2
|
|
126
|
+
Indices = np.argwhere((np.abs(Freqs) > F_CUT1))
|
|
127
|
+
R_K = len(Indices)
|
|
128
|
+
R_K = np.min([len(Indices), SAT]) # number of frequencies here
|
|
129
|
+
print(str(len(Indices)) + ' Modes Estimated')
|
|
130
|
+
print('Filtering H Scale ' + str(m + 1) + '/ ' + str(M))
|
|
131
|
+
K_H = conv_m(K, h1d_H, Ex, boundaries)
|
|
132
|
+
# Ks[:, :, m + 1] = K_H # Last (high pass) scale
|
|
133
|
+
print('Diagonalizing H Scale ' + str(m + 1) + '/ ' + str(M))
|
|
134
|
+
# R_K = np.linalg.matrix_rank(K_H, tol=None, hermitian=True)
|
|
135
|
+
Psi_P, Lambda_P = switch_eigs(K_H, R_K, eig_solver) #svds_RND(K_H, R_K) # Diagonalize scale
|
|
136
|
+
Psi_M = np.concatenate((Psi_M, Psi_P), axis=1) # append to the previous
|
|
137
|
+
Lambda_M = np.concatenate((Lambda_M, Lambda_P), axis=0)
|
|
138
|
+
else:
|
|
139
|
+
print('\n Scale '+str(m)+' jumped (keep['+str(m)+']=0)')
|
|
140
|
+
|
|
141
|
+
# Now Order the Scales
|
|
142
|
+
Indices = np.flip(np.argsort(Lambda_M)) # find indices for sorting in decreasing order
|
|
143
|
+
Psi_M = Psi_M[:, Indices] # Sort the temporal structures
|
|
144
|
+
#print(f"Size psis in mpodtime = {np.shape(Psi_M)}")
|
|
145
|
+
# Now we complete the basis via re-orghotonalization
|
|
146
|
+
print('\n QR Polishing...')
|
|
147
|
+
PSI_M, R = np.linalg.qr(Psi_M, mode=MODE)
|
|
148
|
+
print('Done!')
|
|
149
|
+
|
|
150
|
+
if MEMORY_SAVING:
|
|
151
|
+
os.makedirs(FOLDER_OUT + '/mPOD', exist_ok=True)
|
|
152
|
+
np.savez(FOLDER_OUT + '/mPOD/Psis', Psis=PSI_M)
|
|
153
|
+
|
|
154
|
+
return PSI_M[:,0:n_Modes]
|