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