modulo-vki 2.0.6__py3-none-any.whl → 2.0.7__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 -341
- modulo_vki/utils/others.py +452 -452
- modulo_vki/utils/read_db.py +339 -339
- {modulo_vki-2.0.6.dist-info → modulo_vki-2.0.7.dist-info}/LICENSE +21 -21
- {modulo_vki-2.0.6.dist-info → modulo_vki-2.0.7.dist-info}/METADATA +304 -304
- modulo_vki-2.0.7.dist-info/RECORD +22 -0
- modulo_vki-2.0.6.dist-info/RECORD +0 -22
- {modulo_vki-2.0.6.dist-info → modulo_vki-2.0.7.dist-info}/WHEEL +0 -0
- {modulo_vki-2.0.6.dist-info → modulo_vki-2.0.7.dist-info}/top_level.txt +0 -0
modulo_vki/core/_pod_space.py
CHANGED
|
@@ -1,184 +1,184 @@
|
|
|
1
|
-
import math
|
|
2
|
-
import numpy as np
|
|
3
|
-
from tqdm import tqdm
|
|
4
|
-
import os
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def Spatial_basis_POD(D, PSI_P, Sigma_P, MEMORY_SAVING, N_T, FOLDER_OUT='./', N_PARTITIONS=1, SAVE_SPATIAL_POD=False,
|
|
8
|
-
rescale=False):
|
|
9
|
-
"""
|
|
10
|
-
This function computs the POD spatial basis from the temporal basis,
|
|
11
|
-
|
|
12
|
-
:param D: np.array.
|
|
13
|
-
matrix on which to project the temporal basis
|
|
14
|
-
:param PSI_P: np.array.
|
|
15
|
-
POD's Psis
|
|
16
|
-
:param Sigma_P: np.array.
|
|
17
|
-
POD's Sigmas
|
|
18
|
-
:param MEMORY_SAVING: bool.
|
|
19
|
-
Inherited from main class, if True turns on the MEMORY_SAVING feature, loading the partitions and starting the proper algorithm
|
|
20
|
-
:param N_T: int.
|
|
21
|
-
Number of temporal snapshots
|
|
22
|
-
:param FOLDER_OUT: str.
|
|
23
|
-
Folder in which the results are saved if SAVE_SPATIAL_POD = True
|
|
24
|
-
:param N_PARTITIONS: int.
|
|
25
|
-
Number of partitions to be loaded. If D has been partitioned using MODULO, this parameter is automatically inherited from the main class. To be specified otherwise.
|
|
26
|
-
|
|
27
|
-
:param SAVE_SPATIAL_POD: bool.
|
|
28
|
-
If True, results are saved on disk and released from memory
|
|
29
|
-
|
|
30
|
-
:param rescale: bool.
|
|
31
|
-
If False, the Sigmas are used for the normalization. If True, these are ignored and the normalization is carried out.
|
|
32
|
-
For the standard POD, False is the way to go.
|
|
33
|
-
However, for other decompositions (eg. the SPOD_s) you must use rescale=True
|
|
34
|
-
|
|
35
|
-
:return Phi_P: np.array.
|
|
36
|
-
POD's Phis
|
|
37
|
-
"""
|
|
38
|
-
|
|
39
|
-
R = PSI_P.shape[1]
|
|
40
|
-
|
|
41
|
-
if not MEMORY_SAVING:
|
|
42
|
-
N_S = D.shape[0]
|
|
43
|
-
|
|
44
|
-
if rescale:
|
|
45
|
-
# The following is the general normalization approach.
|
|
46
|
-
# not needed for POD for required for SPOD
|
|
47
|
-
Phi_P = np.zeros((N_S, R))
|
|
48
|
-
# N_S = D.shape[0] unused variable
|
|
49
|
-
PHI_P_SIGMA_P = np.dot(D, PSI_P)
|
|
50
|
-
print("Completing Spatial Structures Modes: \n")
|
|
51
|
-
|
|
52
|
-
for i in tqdm(range(0, R)):
|
|
53
|
-
# Normalize the columns of C to get spatial modes
|
|
54
|
-
Phi_P[:, i] = PHI_P_SIGMA_P[:, i] / Sigma_P[i]
|
|
55
|
-
|
|
56
|
-
else:
|
|
57
|
-
# We take only the first R modes.
|
|
58
|
-
Sigma_P_t = Sigma_P[0:R];
|
|
59
|
-
Sigma_P_Inv_V = 1 / Sigma_P_t
|
|
60
|
-
# So we have the inverse
|
|
61
|
-
Sigma_P_Inv = np.diag(Sigma_P_Inv_V)
|
|
62
|
-
# Here is the one shot projection:
|
|
63
|
-
Phi_P = np.linalg.multi_dot([D, PSI_P[:, 0:R], Sigma_P_Inv])
|
|
64
|
-
|
|
65
|
-
if SAVE_SPATIAL_POD:
|
|
66
|
-
os.makedirs(FOLDER_OUT + 'POD', exist_ok=True)
|
|
67
|
-
np.savez(FOLDER_OUT + '/POD/pod_spatial_basis', phis=Phi_P)
|
|
68
|
-
# removed PHI_P_SIGMA_P=PHI_P_SIGMA_P, not present if not rescale and not needed (?)
|
|
69
|
-
|
|
70
|
-
return Phi_P
|
|
71
|
-
|
|
72
|
-
else:
|
|
73
|
-
|
|
74
|
-
N_S = np.shape(np.load(FOLDER_OUT + "/data_partitions/di_1.npz")['di'])[0]
|
|
75
|
-
dim_col = math.floor(N_T / N_PARTITIONS)
|
|
76
|
-
dim_row = math.floor(N_S / N_PARTITIONS)
|
|
77
|
-
dr = np.zeros((dim_row, N_T))
|
|
78
|
-
|
|
79
|
-
# 1 -- Converting partitions dC to dR
|
|
80
|
-
if N_S % N_PARTITIONS != 0:
|
|
81
|
-
tot_blocks_row = N_PARTITIONS + 1
|
|
82
|
-
else:
|
|
83
|
-
tot_blocks_row = N_PARTITIONS
|
|
84
|
-
|
|
85
|
-
if N_T % N_PARTITIONS != 0:
|
|
86
|
-
tot_blocks_col = N_PARTITIONS + 1
|
|
87
|
-
else:
|
|
88
|
-
tot_blocks_col = N_PARTITIONS
|
|
89
|
-
|
|
90
|
-
# --- Loading Psi_P
|
|
91
|
-
fixed = 0
|
|
92
|
-
R1 = 0
|
|
93
|
-
R2 = 0
|
|
94
|
-
C1 = 0
|
|
95
|
-
C2 = 0
|
|
96
|
-
|
|
97
|
-
for i in range(1, tot_blocks_row + 1):
|
|
98
|
-
|
|
99
|
-
if (i == tot_blocks_row) and (N_S - dim_row * N_PARTITIONS > 0):
|
|
100
|
-
dim_row_fix = N_S - dim_row * N_PARTITIONS
|
|
101
|
-
dr = np.zeros((dim_row_fix, N_T))
|
|
102
|
-
|
|
103
|
-
for b in range(1, tot_blocks_col + 1):
|
|
104
|
-
di = np.load(FOLDER_OUT + f"/data_partitions/di_{b}.npz")['di']
|
|
105
|
-
if (i == tot_blocks_row) and (N_S - dim_row * N_PARTITIONS > 0) and fixed == 0:
|
|
106
|
-
R1 = R2
|
|
107
|
-
R2 = R1 + (N_S - dim_row * N_PARTITIONS)
|
|
108
|
-
fixed = 1
|
|
109
|
-
elif fixed == 0:
|
|
110
|
-
R1 = (i - 1) * dim_row
|
|
111
|
-
R2 = i * dim_row
|
|
112
|
-
|
|
113
|
-
if (b == tot_blocks_col) and (N_T - dim_col * N_PARTITIONS > 0):
|
|
114
|
-
C1 = C2
|
|
115
|
-
C2 = C1 + (N_T - dim_col * N_PARTITIONS)
|
|
116
|
-
else:
|
|
117
|
-
C1 = (b - 1) * dim_col
|
|
118
|
-
C2 = b * dim_col
|
|
119
|
-
|
|
120
|
-
np.copyto(dr[:, C1:C2], di[R1:R2, :])
|
|
121
|
-
|
|
122
|
-
PHI_SIGMA_BLOCK = np.dot(dr, PSI_P)
|
|
123
|
-
np.savez(FOLDER_OUT + f"/PHI_SIGMA_{i}",
|
|
124
|
-
phi_sigma=PHI_SIGMA_BLOCK)
|
|
125
|
-
|
|
126
|
-
# 3 - Converting partitions R to partitions C and get Sigmas
|
|
127
|
-
dim_col = math.floor(R / N_PARTITIONS)
|
|
128
|
-
dim_row = math.floor(N_S / N_PARTITIONS)
|
|
129
|
-
dps = np.zeros((N_S, dim_col))
|
|
130
|
-
Phi_P = np.zeros((N_S, R))
|
|
131
|
-
|
|
132
|
-
if R % N_PARTITIONS != 0:
|
|
133
|
-
tot_blocks_col = N_PARTITIONS + 1
|
|
134
|
-
else:
|
|
135
|
-
tot_blocks_col = N_PARTITIONS
|
|
136
|
-
|
|
137
|
-
fixed = 0
|
|
138
|
-
|
|
139
|
-
for i in range(1, tot_blocks_col + 1):
|
|
140
|
-
|
|
141
|
-
if (i == tot_blocks_col) and (R - dim_col * N_PARTITIONS > 0):
|
|
142
|
-
dim_col_fix = R - dim_col * N_PARTITIONS
|
|
143
|
-
dps = np.zeros((N_S, dim_col_fix))
|
|
144
|
-
|
|
145
|
-
for b in range(1, tot_blocks_row + 1):
|
|
146
|
-
|
|
147
|
-
PHI_SIGMA_BLOCK = np.load(FOLDER_OUT + f"/PHI_SIGMA_{b}.npz")['phi_sigma']
|
|
148
|
-
|
|
149
|
-
if (i == tot_blocks_col) and (R - dim_col * N_PARTITIONS > 0) and fixed == 0:
|
|
150
|
-
R1 = R2
|
|
151
|
-
R2 = R1 + (R - dim_col * N_PARTITIONS)
|
|
152
|
-
fixed = 1
|
|
153
|
-
elif fixed == 0:
|
|
154
|
-
R1 = (i - 1) * dim_col
|
|
155
|
-
R2 = i * dim_col
|
|
156
|
-
|
|
157
|
-
if (b == tot_blocks_row) and (N_S - dim_row * N_PARTITIONS > 0): # Change here
|
|
158
|
-
C1 = C2
|
|
159
|
-
C2 = C1 + (N_S - dim_row * N_PARTITIONS)
|
|
160
|
-
else:
|
|
161
|
-
C1 = (b - 1) * dim_row
|
|
162
|
-
C2 = b * dim_row
|
|
163
|
-
|
|
164
|
-
dps[C1:C2, :] = PHI_SIGMA_BLOCK[:, R1:R2]
|
|
165
|
-
|
|
166
|
-
# Computing Sigmas and Phis
|
|
167
|
-
if rescale:
|
|
168
|
-
for j in range(R1, R2):
|
|
169
|
-
jj = j - R1
|
|
170
|
-
Sigma_P[jj] = np.linalg.norm(dps[:, jj])
|
|
171
|
-
Phi_P = dps[:, jj] / Sigma_P[jj]
|
|
172
|
-
np.savez(FOLDER_OUT + f"/phi_{j + 1}", phi_p=Phi_P)
|
|
173
|
-
else:
|
|
174
|
-
for j in range(R1, R2):
|
|
175
|
-
jj = j - R1
|
|
176
|
-
Phi_P = dps[:, jj] / Sigma_P[
|
|
177
|
-
np.savez(FOLDER_OUT + f"/phi_{j + 1}", phi_p=Phi_P)
|
|
178
|
-
|
|
179
|
-
Phi_P_M = np.zeros((N_S, R))
|
|
180
|
-
for j in range(R):
|
|
181
|
-
Phi_P_V = np.load(FOLDER_OUT + f"/phi_{j + 1}.npz")['phi_p']
|
|
182
|
-
Phi_P_M[:, j] = Phi_P_V
|
|
183
|
-
|
|
184
|
-
return Phi_P_M
|
|
1
|
+
import math
|
|
2
|
+
import numpy as np
|
|
3
|
+
from tqdm import tqdm
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def Spatial_basis_POD(D, PSI_P, Sigma_P, MEMORY_SAVING, N_T, FOLDER_OUT='./', N_PARTITIONS=1, SAVE_SPATIAL_POD=False,
|
|
8
|
+
rescale=False):
|
|
9
|
+
"""
|
|
10
|
+
This function computs the POD spatial basis from the temporal basis,
|
|
11
|
+
|
|
12
|
+
:param D: np.array.
|
|
13
|
+
matrix on which to project the temporal basis
|
|
14
|
+
:param PSI_P: np.array.
|
|
15
|
+
POD's Psis
|
|
16
|
+
:param Sigma_P: np.array.
|
|
17
|
+
POD's Sigmas
|
|
18
|
+
:param MEMORY_SAVING: bool.
|
|
19
|
+
Inherited from main class, if True turns on the MEMORY_SAVING feature, loading the partitions and starting the proper algorithm
|
|
20
|
+
:param N_T: int.
|
|
21
|
+
Number of temporal snapshots
|
|
22
|
+
:param FOLDER_OUT: str.
|
|
23
|
+
Folder in which the results are saved if SAVE_SPATIAL_POD = True
|
|
24
|
+
:param N_PARTITIONS: int.
|
|
25
|
+
Number of partitions to be loaded. If D has been partitioned using MODULO, this parameter is automatically inherited from the main class. To be specified otherwise.
|
|
26
|
+
|
|
27
|
+
:param SAVE_SPATIAL_POD: bool.
|
|
28
|
+
If True, results are saved on disk and released from memory
|
|
29
|
+
|
|
30
|
+
:param rescale: bool.
|
|
31
|
+
If False, the Sigmas are used for the normalization. If True, these are ignored and the normalization is carried out.
|
|
32
|
+
For the standard POD, False is the way to go.
|
|
33
|
+
However, for other decompositions (eg. the SPOD_s) you must use rescale=True
|
|
34
|
+
|
|
35
|
+
:return Phi_P: np.array.
|
|
36
|
+
POD's Phis
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
R = PSI_P.shape[1]
|
|
40
|
+
|
|
41
|
+
if not MEMORY_SAVING:
|
|
42
|
+
N_S = D.shape[0]
|
|
43
|
+
|
|
44
|
+
if rescale:
|
|
45
|
+
# The following is the general normalization approach.
|
|
46
|
+
# not needed for POD for required for SPOD
|
|
47
|
+
Phi_P = np.zeros((N_S, R))
|
|
48
|
+
# N_S = D.shape[0] unused variable
|
|
49
|
+
PHI_P_SIGMA_P = np.dot(D, PSI_P)
|
|
50
|
+
print("Completing Spatial Structures Modes: \n")
|
|
51
|
+
|
|
52
|
+
for i in tqdm(range(0, R)):
|
|
53
|
+
# Normalize the columns of C to get spatial modes
|
|
54
|
+
Phi_P[:, i] = PHI_P_SIGMA_P[:, i] / Sigma_P[i]
|
|
55
|
+
|
|
56
|
+
else:
|
|
57
|
+
# We take only the first R modes.
|
|
58
|
+
Sigma_P_t = Sigma_P[0:R];
|
|
59
|
+
Sigma_P_Inv_V = 1 / Sigma_P_t
|
|
60
|
+
# So we have the inverse
|
|
61
|
+
Sigma_P_Inv = np.diag(Sigma_P_Inv_V)
|
|
62
|
+
# Here is the one shot projection:
|
|
63
|
+
Phi_P = np.linalg.multi_dot([D, PSI_P[:, 0:R], Sigma_P_Inv])
|
|
64
|
+
|
|
65
|
+
if SAVE_SPATIAL_POD:
|
|
66
|
+
os.makedirs(FOLDER_OUT + 'POD', exist_ok=True)
|
|
67
|
+
np.savez(FOLDER_OUT + '/POD/pod_spatial_basis', phis=Phi_P)
|
|
68
|
+
# removed PHI_P_SIGMA_P=PHI_P_SIGMA_P, not present if not rescale and not needed (?)
|
|
69
|
+
|
|
70
|
+
return Phi_P
|
|
71
|
+
|
|
72
|
+
else:
|
|
73
|
+
|
|
74
|
+
N_S = np.shape(np.load(FOLDER_OUT + "/data_partitions/di_1.npz")['di'])[0]
|
|
75
|
+
dim_col = math.floor(N_T / N_PARTITIONS)
|
|
76
|
+
dim_row = math.floor(N_S / N_PARTITIONS)
|
|
77
|
+
dr = np.zeros((dim_row, N_T))
|
|
78
|
+
|
|
79
|
+
# 1 -- Converting partitions dC to dR
|
|
80
|
+
if N_S % N_PARTITIONS != 0:
|
|
81
|
+
tot_blocks_row = N_PARTITIONS + 1
|
|
82
|
+
else:
|
|
83
|
+
tot_blocks_row = N_PARTITIONS
|
|
84
|
+
|
|
85
|
+
if N_T % N_PARTITIONS != 0:
|
|
86
|
+
tot_blocks_col = N_PARTITIONS + 1
|
|
87
|
+
else:
|
|
88
|
+
tot_blocks_col = N_PARTITIONS
|
|
89
|
+
|
|
90
|
+
# --- Loading Psi_P
|
|
91
|
+
fixed = 0
|
|
92
|
+
R1 = 0
|
|
93
|
+
R2 = 0
|
|
94
|
+
C1 = 0
|
|
95
|
+
C2 = 0
|
|
96
|
+
|
|
97
|
+
for i in range(1, tot_blocks_row + 1):
|
|
98
|
+
|
|
99
|
+
if (i == tot_blocks_row) and (N_S - dim_row * N_PARTITIONS > 0):
|
|
100
|
+
dim_row_fix = N_S - dim_row * N_PARTITIONS
|
|
101
|
+
dr = np.zeros((dim_row_fix, N_T))
|
|
102
|
+
|
|
103
|
+
for b in range(1, tot_blocks_col + 1):
|
|
104
|
+
di = np.load(FOLDER_OUT + f"/data_partitions/di_{b}.npz")['di']
|
|
105
|
+
if (i == tot_blocks_row) and (N_S - dim_row * N_PARTITIONS > 0) and fixed == 0:
|
|
106
|
+
R1 = R2
|
|
107
|
+
R2 = R1 + (N_S - dim_row * N_PARTITIONS)
|
|
108
|
+
fixed = 1
|
|
109
|
+
elif fixed == 0:
|
|
110
|
+
R1 = (i - 1) * dim_row
|
|
111
|
+
R2 = i * dim_row
|
|
112
|
+
|
|
113
|
+
if (b == tot_blocks_col) and (N_T - dim_col * N_PARTITIONS > 0):
|
|
114
|
+
C1 = C2
|
|
115
|
+
C2 = C1 + (N_T - dim_col * N_PARTITIONS)
|
|
116
|
+
else:
|
|
117
|
+
C1 = (b - 1) * dim_col
|
|
118
|
+
C2 = b * dim_col
|
|
119
|
+
|
|
120
|
+
np.copyto(dr[:, C1:C2], di[R1:R2, :])
|
|
121
|
+
|
|
122
|
+
PHI_SIGMA_BLOCK = np.dot(dr, PSI_P)
|
|
123
|
+
np.savez(FOLDER_OUT + f"/PHI_SIGMA_{i}",
|
|
124
|
+
phi_sigma=PHI_SIGMA_BLOCK)
|
|
125
|
+
|
|
126
|
+
# 3 - Converting partitions R to partitions C and get Sigmas
|
|
127
|
+
dim_col = math.floor(R / N_PARTITIONS)
|
|
128
|
+
dim_row = math.floor(N_S / N_PARTITIONS)
|
|
129
|
+
dps = np.zeros((N_S, dim_col))
|
|
130
|
+
Phi_P = np.zeros((N_S, R))
|
|
131
|
+
|
|
132
|
+
if R % N_PARTITIONS != 0:
|
|
133
|
+
tot_blocks_col = N_PARTITIONS + 1
|
|
134
|
+
else:
|
|
135
|
+
tot_blocks_col = N_PARTITIONS
|
|
136
|
+
|
|
137
|
+
fixed = 0
|
|
138
|
+
|
|
139
|
+
for i in range(1, tot_blocks_col + 1):
|
|
140
|
+
|
|
141
|
+
if (i == tot_blocks_col) and (R - dim_col * N_PARTITIONS > 0):
|
|
142
|
+
dim_col_fix = R - dim_col * N_PARTITIONS
|
|
143
|
+
dps = np.zeros((N_S, dim_col_fix))
|
|
144
|
+
|
|
145
|
+
for b in range(1, tot_blocks_row + 1):
|
|
146
|
+
|
|
147
|
+
PHI_SIGMA_BLOCK = np.load(FOLDER_OUT + f"/PHI_SIGMA_{b}.npz")['phi_sigma']
|
|
148
|
+
|
|
149
|
+
if (i == tot_blocks_col) and (R - dim_col * N_PARTITIONS > 0) and fixed == 0:
|
|
150
|
+
R1 = R2
|
|
151
|
+
R2 = R1 + (R - dim_col * N_PARTITIONS)
|
|
152
|
+
fixed = 1
|
|
153
|
+
elif fixed == 0:
|
|
154
|
+
R1 = (i - 1) * dim_col
|
|
155
|
+
R2 = i * dim_col
|
|
156
|
+
|
|
157
|
+
if (b == tot_blocks_row) and (N_S - dim_row * N_PARTITIONS > 0): # Change here
|
|
158
|
+
C1 = C2
|
|
159
|
+
C2 = C1 + (N_S - dim_row * N_PARTITIONS)
|
|
160
|
+
else:
|
|
161
|
+
C1 = (b - 1) * dim_row
|
|
162
|
+
C2 = b * dim_row
|
|
163
|
+
|
|
164
|
+
dps[C1:C2, :] = PHI_SIGMA_BLOCK[:, R1:R2]
|
|
165
|
+
|
|
166
|
+
# Computing Sigmas and Phis
|
|
167
|
+
if rescale:
|
|
168
|
+
for j in range(R1, R2):
|
|
169
|
+
jj = j - R1
|
|
170
|
+
Sigma_P[jj] = np.linalg.norm(dps[:, jj])
|
|
171
|
+
Phi_P = dps[:, jj] / Sigma_P[jj]
|
|
172
|
+
np.savez(FOLDER_OUT + f"/phi_{j + 1}", phi_p=Phi_P)
|
|
173
|
+
else:
|
|
174
|
+
for j in range(R1, R2):
|
|
175
|
+
jj = j - R1
|
|
176
|
+
Phi_P = dps[:, jj] / Sigma_P[j] # Change here
|
|
177
|
+
np.savez(FOLDER_OUT + f"/phi_{j + 1}", phi_p=Phi_P)
|
|
178
|
+
|
|
179
|
+
Phi_P_M = np.zeros((N_S, R))
|
|
180
|
+
for j in range(R):
|
|
181
|
+
Phi_P_V = np.load(FOLDER_OUT + f"/phi_{j + 1}.npz")['phi_p']
|
|
182
|
+
Phi_P_M[:, j] = Phi_P_V
|
|
183
|
+
|
|
184
|
+
return Phi_P_M
|
modulo_vki/core/_pod_time.py
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import numpy as np
|
|
3
|
-
from ..utils._utils import switch_eigs
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def Temporal_basis_POD(K, SAVE_T_POD=False, FOLDER_OUT='./', n_Modes=10,eig_solver: str = 'eigh'):
|
|
7
|
-
"""
|
|
8
|
-
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
|
-
:param FOLDER_OUT: str. Folder in which the results will be saved (if SAVE_T_POD=True)
|
|
11
|
-
:param K: np.array. Temporal correlation matrix
|
|
12
|
-
:param SAVE_T_POD: bool. 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.
|
|
13
|
-
:param n_Modes: int. Number of modes that will be computed
|
|
14
|
-
:param svd_solver: str. Svd solver to be used throughout the computation
|
|
15
|
-
:return: Psi_P: np.array. POD's Psis
|
|
16
|
-
:return: Sigma_P: np.array. POD's Sigmas
|
|
17
|
-
"""
|
|
18
|
-
# Solver 1: Use the standard SVD
|
|
19
|
-
# Psi_P, Lambda_P, _ = np.linalg.svd(K)
|
|
20
|
-
# Sigma_P = np.sqrt(Lambda_P)
|
|
21
|
-
|
|
22
|
-
# Solver 2: Use randomized SVD ############## WARNING #################
|
|
23
|
-
# if svd_solver.lower() == 'svd_sklearn_truncated':
|
|
24
|
-
# svd = TruncatedSVD(n_Modes)
|
|
25
|
-
# svd.fit_transform(K)
|
|
26
|
-
# Psi_P = svd.components_.T
|
|
27
|
-
# Lambda_P = svd.singular_values_
|
|
28
|
-
# Sigma_P = np.sqrt(Lambda_P)
|
|
29
|
-
# elif svd_solver.lower() == 'svd_numpy':
|
|
30
|
-
# Psi_P, Lambda_P, _ = np.linalg.svd(K)
|
|
31
|
-
# Sigma_P = np.sqrt(Lambda_P)
|
|
32
|
-
# elif svd_solver.lower() == 'svd_sklearn_randomized':
|
|
33
|
-
# Psi_P, Lambda_P, _ = svds_RND(K, n_Modes)
|
|
34
|
-
# Sigma_P = np.sqrt(Lambda_P)
|
|
35
|
-
# elif svd_solver.lower() == 'svd_scipy_sparse':
|
|
36
|
-
# Psi_P, Lambda_P, _ = svds(K, k=n_Modes)
|
|
37
|
-
# Sigma_P = np.sqrt(Lambda_P)
|
|
38
|
-
|
|
39
|
-
print("diagonalizing K....")
|
|
40
|
-
Psi_P, Sigma_P = switch_eigs(K, n_Modes, eig_solver)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if SAVE_T_POD:
|
|
44
|
-
os.makedirs(FOLDER_OUT + "/POD/", exist_ok=True)
|
|
45
|
-
print("Saving POD temporal basis")
|
|
46
|
-
np.savez(FOLDER_OUT + '/POD/temporal_basis', Psis=Psi_P, Sigmas=Sigma_P)
|
|
47
|
-
|
|
48
|
-
return Psi_P, Sigma_P
|
|
1
|
+
import os
|
|
2
|
+
import numpy as np
|
|
3
|
+
from ..utils._utils import switch_eigs
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def Temporal_basis_POD(K, SAVE_T_POD=False, FOLDER_OUT='./', n_Modes=10,eig_solver: str = 'eigh'):
|
|
7
|
+
"""
|
|
8
|
+
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
|
+
:param FOLDER_OUT: str. Folder in which the results will be saved (if SAVE_T_POD=True)
|
|
11
|
+
:param K: np.array. Temporal correlation matrix
|
|
12
|
+
:param SAVE_T_POD: bool. 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.
|
|
13
|
+
:param n_Modes: int. Number of modes that will be computed
|
|
14
|
+
:param svd_solver: str. Svd solver to be used throughout the computation
|
|
15
|
+
:return: Psi_P: np.array. POD's Psis
|
|
16
|
+
:return: Sigma_P: np.array. POD's Sigmas
|
|
17
|
+
"""
|
|
18
|
+
# Solver 1: Use the standard SVD
|
|
19
|
+
# Psi_P, Lambda_P, _ = np.linalg.svd(K)
|
|
20
|
+
# Sigma_P = np.sqrt(Lambda_P)
|
|
21
|
+
|
|
22
|
+
# Solver 2: Use randomized SVD ############## WARNING #################
|
|
23
|
+
# if svd_solver.lower() == 'svd_sklearn_truncated':
|
|
24
|
+
# svd = TruncatedSVD(n_Modes)
|
|
25
|
+
# svd.fit_transform(K)
|
|
26
|
+
# Psi_P = svd.components_.T
|
|
27
|
+
# Lambda_P = svd.singular_values_
|
|
28
|
+
# Sigma_P = np.sqrt(Lambda_P)
|
|
29
|
+
# elif svd_solver.lower() == 'svd_numpy':
|
|
30
|
+
# Psi_P, Lambda_P, _ = np.linalg.svd(K)
|
|
31
|
+
# Sigma_P = np.sqrt(Lambda_P)
|
|
32
|
+
# elif svd_solver.lower() == 'svd_sklearn_randomized':
|
|
33
|
+
# Psi_P, Lambda_P, _ = svds_RND(K, n_Modes)
|
|
34
|
+
# Sigma_P = np.sqrt(Lambda_P)
|
|
35
|
+
# elif svd_solver.lower() == 'svd_scipy_sparse':
|
|
36
|
+
# Psi_P, Lambda_P, _ = svds(K, k=n_Modes)
|
|
37
|
+
# Sigma_P = np.sqrt(Lambda_P)
|
|
38
|
+
|
|
39
|
+
print("diagonalizing K....")
|
|
40
|
+
Psi_P, Sigma_P = switch_eigs(K, n_Modes, eig_solver)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if SAVE_T_POD:
|
|
44
|
+
os.makedirs(FOLDER_OUT + "/POD/", exist_ok=True)
|
|
45
|
+
print("Saving POD temporal basis")
|
|
46
|
+
np.savez(FOLDER_OUT + '/POD/temporal_basis', Psis=Psi_P, Sigmas=Sigma_P)
|
|
47
|
+
|
|
48
|
+
return Psi_P, Sigma_P
|