turbx 1.0.2__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.
- turbx/__init__.py +52 -0
- turbx/bl.py +620 -0
- turbx/blasius.py +64 -0
- turbx/cli.py +19 -0
- turbx/composite_profile.py +243 -0
- turbx/confidence_interval.py +64 -0
- turbx/eas3.py +420 -0
- turbx/eas4.py +567 -0
- turbx/fig_ax_constructor.py +52 -0
- turbx/freestream_parameters.py +268 -0
- turbx/gradient.py +391 -0
- turbx/grid_metric.py +272 -0
- turbx/h5.py +236 -0
- turbx/mvp.py +385 -0
- turbx/rgd.py +2693 -0
- turbx/rgd_mean.py +523 -0
- turbx/rgd_testing.py +354 -0
- turbx/rgd_xpln_ccor.py +701 -0
- turbx/rgd_xpln_coh.py +992 -0
- turbx/rgd_xpln_mean_dim.py +336 -0
- turbx/rgd_xpln_spectrum.py +940 -0
- turbx/rgd_xpln_stats.py +738 -0
- turbx/rgd_xpln_turb_budget.py +1193 -0
- turbx/set_mpl_env.py +85 -0
- turbx/signal.py +277 -0
- turbx/spd.py +1206 -0
- turbx/spd_wall_ccor.py +629 -0
- turbx/spd_wall_ci.py +406 -0
- turbx/spd_wall_import.py +676 -0
- turbx/spd_wall_spectrum.py +638 -0
- turbx/spd_wall_stats.py +618 -0
- turbx/utils.py +84 -0
- turbx/ztmd.py +2224 -0
- turbx/ztmd_analysis.py +2337 -0
- turbx/ztmd_loader.py +56 -0
- turbx-1.0.2.dist-info/LICENSE +21 -0
- turbx-1.0.2.dist-info/METADATA +120 -0
- turbx-1.0.2.dist-info/RECORD +41 -0
- turbx-1.0.2.dist-info/WHEEL +5 -0
- turbx-1.0.2.dist-info/entry_points.txt +2 -0
- turbx-1.0.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,638 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import timeit
|
|
4
|
+
from pathlib import Path, PurePosixPath
|
|
5
|
+
|
|
6
|
+
import h5py
|
|
7
|
+
import numpy as np
|
|
8
|
+
import scipy as sp
|
|
9
|
+
from scipy.signal import csd
|
|
10
|
+
from tqdm import tqdm
|
|
11
|
+
|
|
12
|
+
from .h5 import h5_print_contents
|
|
13
|
+
from .utils import even_print, format_time_string
|
|
14
|
+
|
|
15
|
+
# ======================================================================
|
|
16
|
+
|
|
17
|
+
def _calc_turb_cospectrum_wall(self, **kwargs):
|
|
18
|
+
'''
|
|
19
|
+
Calculate FFT cospectrum in [z,t] at every [x]
|
|
20
|
+
- designed for analyzing unsteady, pre-computed wall quantities ([y] plane)
|
|
21
|
+
'''
|
|
22
|
+
|
|
23
|
+
if (self.rank==0):
|
|
24
|
+
verbose = True
|
|
25
|
+
else:
|
|
26
|
+
verbose = False
|
|
27
|
+
|
|
28
|
+
if verbose: print('\n'+'spd.calc_turb_cospectrum_wall()'+'\n'+72*'-')
|
|
29
|
+
t_start_func = timeit.default_timer()
|
|
30
|
+
|
|
31
|
+
if not self.usingmpi:
|
|
32
|
+
raise NotImplementedError('function is not implemented for non-MPI usage')
|
|
33
|
+
|
|
34
|
+
h5py_is_mpi_build = h5py.h5.get_config().mpi
|
|
35
|
+
if not h5py_is_mpi_build:
|
|
36
|
+
if verbose: print('h5py was not compiled for parallel usage! exiting.')
|
|
37
|
+
sys.exit(1)
|
|
38
|
+
|
|
39
|
+
ri = kwargs.get('ri',1)
|
|
40
|
+
rj = kwargs.get('rj',1)
|
|
41
|
+
rt = kwargs.get('rt',1)
|
|
42
|
+
|
|
43
|
+
fn_h5_out = kwargs.get('fn_h5_out',None) ## filename for output HDF5 (.h5) file
|
|
44
|
+
overlap_fac_nom = kwargs.get('overlap_fac_nom',0.50) ## nominal windows overlap factor
|
|
45
|
+
n_win = kwargs.get('n_win',8) ## number of segment windows for [t] PSD calc
|
|
46
|
+
|
|
47
|
+
## check data distribution (only distribute data in [i]/[x])
|
|
48
|
+
if (rj!=1):
|
|
49
|
+
raise AssertionError('rj!=1')
|
|
50
|
+
if (rt!=1):
|
|
51
|
+
raise AssertionError('rt!=1')
|
|
52
|
+
|
|
53
|
+
if not isinstance(ri,int) or (ri<1):
|
|
54
|
+
raise ValueError('ri should be a positive non-zero int')
|
|
55
|
+
|
|
56
|
+
if (ri*rj*rt != self.n_ranks):
|
|
57
|
+
raise AssertionError('ri*rj*rt != self.n_ranks')
|
|
58
|
+
if (ri>self.ni):
|
|
59
|
+
raise AssertionError('ri>self.ni')
|
|
60
|
+
if (self.ni%ri!=0):
|
|
61
|
+
raise AssertionError('ni currently needs to be divisible by the n ranks')
|
|
62
|
+
|
|
63
|
+
## distribute data over [i]/[x]
|
|
64
|
+
ril_ = np.array_split(np.arange(self.ni,dtype=np.int64),min(ri,self.ni))
|
|
65
|
+
ril = [[b[0],b[-1]+1] for b in ril_ ]
|
|
66
|
+
ri1,ri2 = ril[self.rank]
|
|
67
|
+
nir = ri2 - ri1
|
|
68
|
+
|
|
69
|
+
## output filename : HDF5 (.h5)
|
|
70
|
+
if (fn_h5_out is None): ## automatically determine name
|
|
71
|
+
fname_path = os.path.dirname(self.fname)
|
|
72
|
+
fname_base = os.path.basename(self.fname)
|
|
73
|
+
fname_root, fname_ext = os.path.splitext(fname_base)
|
|
74
|
+
#fname_root = re.findall(r'io\S+_mpi_[0-9]+', fname_root)[0]
|
|
75
|
+
fn_h5_out_base = fname_root+'_fft.h5'
|
|
76
|
+
fn_h5_out = str(PurePosixPath(fname_path, fn_h5_out_base))
|
|
77
|
+
if (Path(fn_h5_out).suffix != '.h5'):
|
|
78
|
+
raise ValueError(f"fn_h5_out='{str(fn_h5_out)}' must end in .h5")
|
|
79
|
+
if os.path.isfile(fn_h5_out):
|
|
80
|
+
if (fn_h5_out == self.fname):
|
|
81
|
+
raise ValueError(f"fn_h5_out='{str(fn_h5_out)}' cannot be same as input filename.")
|
|
82
|
+
|
|
83
|
+
if verbose: even_print( 'fn_h5' , self.fname )
|
|
84
|
+
if verbose: even_print( 'fn_h5_out' , fn_h5_out )
|
|
85
|
+
if verbose: print(72*'-')
|
|
86
|
+
self.comm.Barrier()
|
|
87
|
+
|
|
88
|
+
# ===
|
|
89
|
+
|
|
90
|
+
## the data dictionary to be written to .h5 later
|
|
91
|
+
data = {}
|
|
92
|
+
|
|
93
|
+
## infile
|
|
94
|
+
fsize = os.path.getsize(self.fname)/1024**3
|
|
95
|
+
if verbose: even_print(os.path.basename(self.fname),'%0.1f [GB]'%fsize)
|
|
96
|
+
if verbose: even_print('ni',f'{self.ni:d}')
|
|
97
|
+
if verbose: even_print('nj',f'{self.nj:d}')
|
|
98
|
+
if verbose: even_print('nt',f'{self.nt:d}')
|
|
99
|
+
if verbose: even_print('n_pts',f'{self.n_pts/1e6:0.1f} [M]')
|
|
100
|
+
if verbose: even_print('n_ranks',f'{self.n_ranks:d}')
|
|
101
|
+
if verbose: print(72*'-')
|
|
102
|
+
|
|
103
|
+
## 0D freestream scalars
|
|
104
|
+
#lchar = self.lchar ; data['lchar'] = self.lchar
|
|
105
|
+
U_inf = self.U_inf ; data['U_inf'] = self.U_inf
|
|
106
|
+
rho_inf = self.rho_inf ; data['rho_inf'] = self.rho_inf
|
|
107
|
+
T_inf = self.T_inf ; data['T_inf'] = self.T_inf
|
|
108
|
+
#mu_inf = self.mu_inf ; data['mu_inf'] = self.mu_inf
|
|
109
|
+
data['p_inf'] = self.p_inf
|
|
110
|
+
#data['M_inf'] = self.M_inf
|
|
111
|
+
data['Ma'] = self.Ma
|
|
112
|
+
data['Pr'] = self.Pr
|
|
113
|
+
|
|
114
|
+
## read in 1D coordinate arrays & re-dimensionalize
|
|
115
|
+
x = np.copy( self['dims/x'][()] * self.lchar )
|
|
116
|
+
z = np.copy( self['dims/z'][()] * self.lchar )
|
|
117
|
+
t = np.copy( self['dims/t'][()] * self.tchar )
|
|
118
|
+
data['x'] = x
|
|
119
|
+
data['z'] = z
|
|
120
|
+
data['t'] = t
|
|
121
|
+
|
|
122
|
+
nx = self.ni
|
|
123
|
+
ni = self.ni
|
|
124
|
+
nz = self.nj
|
|
125
|
+
nj = self.nj
|
|
126
|
+
data['ni'] = ni
|
|
127
|
+
data['nx'] = nx
|
|
128
|
+
data['nj'] = nj
|
|
129
|
+
data['nz'] = nz
|
|
130
|
+
|
|
131
|
+
nt = self.nt
|
|
132
|
+
data['nt'] = nt
|
|
133
|
+
|
|
134
|
+
## assert constant Δz
|
|
135
|
+
dz0 = np.diff(z)[0]
|
|
136
|
+
if not np.all(np.isclose(np.diff(z), dz0, rtol=1e-6)):
|
|
137
|
+
raise NotImplementedError('Δz not constant')
|
|
138
|
+
|
|
139
|
+
## get Δt, dimensional [s]
|
|
140
|
+
if hasattr(self,'dt'):
|
|
141
|
+
dt = self.dt * self.tchar
|
|
142
|
+
np.testing.assert_allclose(dt, t[1]-t[0], rtol=1e-12, atol=1e-12)
|
|
143
|
+
else:
|
|
144
|
+
dt = t[1] - t[0] ## already dimensional
|
|
145
|
+
|
|
146
|
+
if hasattr(self,'duration'):
|
|
147
|
+
t_meas = self.duration * self.tchar
|
|
148
|
+
np.testing.assert_allclose(t_meas, t.max()-t.min(), rtol=1e-12, atol=1e-12)
|
|
149
|
+
else:
|
|
150
|
+
t_meas = t[-1] - t[0] ## already dimensional
|
|
151
|
+
self.duration = t_meas / self.tchar ## non-dimensionalize for attribute
|
|
152
|
+
|
|
153
|
+
zrange = z.max() - z.min()
|
|
154
|
+
|
|
155
|
+
data['t'] = t
|
|
156
|
+
data['dt'] = dt
|
|
157
|
+
data['dz'] = dz0
|
|
158
|
+
data['zrange'] = zrange
|
|
159
|
+
|
|
160
|
+
if verbose: even_print( 'Δt/tchar' , f'{dt/self.tchar:0.8f}' )
|
|
161
|
+
if verbose: even_print( 'Δt' , f'{dt:0.3e} [s]' )
|
|
162
|
+
if verbose: even_print( 'duration/tchar' , f'{self.duration:0.1f}' )
|
|
163
|
+
if verbose: even_print( 'duration' , f'{self.duration*self.tchar:0.3e} [s]' )
|
|
164
|
+
if verbose: print(72*'-')
|
|
165
|
+
|
|
166
|
+
## report
|
|
167
|
+
if verbose:
|
|
168
|
+
even_print('Δt' , f'{dt :0.5e} [s]' )
|
|
169
|
+
even_print('t_meas' , f'{t_meas:0.5e} [s]' )
|
|
170
|
+
even_print('Δz' , f'{dz0 :0.5e} [m]' )
|
|
171
|
+
even_print('zrange' , f'{zrange:0.5e} [m]' )
|
|
172
|
+
print(72*'-')
|
|
173
|
+
|
|
174
|
+
## establish [t] windowing & get frequency
|
|
175
|
+
nperseg = nt // n_win
|
|
176
|
+
noverlap = int(round(nperseg*overlap_fac_nom))
|
|
177
|
+
overlap_fac = noverlap / nperseg
|
|
178
|
+
fs = 1./dt ## dimensional [1/s]
|
|
179
|
+
|
|
180
|
+
## get [freq] vector
|
|
181
|
+
freq,_ = csd(
|
|
182
|
+
np.zeros((nt,),dtype=np.float64),
|
|
183
|
+
np.zeros((nt,),dtype=np.float64),
|
|
184
|
+
fs=fs,
|
|
185
|
+
nperseg=nperseg,
|
|
186
|
+
noverlap=noverlap,
|
|
187
|
+
window='hann',
|
|
188
|
+
detrend='constant',
|
|
189
|
+
scaling='density',
|
|
190
|
+
return_onesided=True,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
nf = freq.shape[0]
|
|
194
|
+
df = np.diff(freq)[0]
|
|
195
|
+
|
|
196
|
+
data['nperseg'] = nperseg
|
|
197
|
+
data['noverlap'] = noverlap
|
|
198
|
+
data['freq'] = freq
|
|
199
|
+
data['df'] = df
|
|
200
|
+
data['nf'] = nf
|
|
201
|
+
|
|
202
|
+
if verbose:
|
|
203
|
+
even_print('overlap_fac (nominal)' , f'{overlap_fac_nom:0.5f}' )
|
|
204
|
+
even_print('n_win' , f'{n_win:d}' )
|
|
205
|
+
even_print('nperseg' , f'{nperseg:d}' )
|
|
206
|
+
even_print('noverlap' , f'{noverlap:d}' )
|
|
207
|
+
even_print('overlap_fac' , f'{overlap_fac:0.5f}' )
|
|
208
|
+
print(72*'-')
|
|
209
|
+
|
|
210
|
+
if verbose:
|
|
211
|
+
even_print('freq min',f'{freq.min():0.1f} [Hz]')
|
|
212
|
+
even_print('freq max',f'{freq.max():0.1f} [Hz]')
|
|
213
|
+
even_print('df',f'{df:0.1f} [Hz]')
|
|
214
|
+
even_print('nf',f'{nf:d}')
|
|
215
|
+
print(72*'-')
|
|
216
|
+
|
|
217
|
+
## spatial [z] wavenumber (kz) vector
|
|
218
|
+
kz_full = sp.fft.fftfreq(n=nz, d=dz0) * ( 2 * np.pi )
|
|
219
|
+
kzp = np.where(kz_full>0) ## indices of positive values
|
|
220
|
+
kz = np.copy(kz_full[kzp])
|
|
221
|
+
dkz = kz[1] - kz[0]
|
|
222
|
+
nkz = kz.shape[0]
|
|
223
|
+
|
|
224
|
+
## wavenumber vector should be size nz//2-1
|
|
225
|
+
if (nkz!=nz//2-1):
|
|
226
|
+
raise ValueError
|
|
227
|
+
|
|
228
|
+
data['kz'] = kz
|
|
229
|
+
data['dkz'] = dkz
|
|
230
|
+
data['nkz'] = nkz
|
|
231
|
+
|
|
232
|
+
if verbose:
|
|
233
|
+
even_print('kz min',f'{kz.min():0.1f} [1/m]')
|
|
234
|
+
even_print('kz max',f'{kz.max():0.1f} [1/m]')
|
|
235
|
+
even_print('dkz',f'{dkz:0.1f} [1/m]')
|
|
236
|
+
even_print('nkz',f'{nkz:d}')
|
|
237
|
+
print(72*'-')
|
|
238
|
+
|
|
239
|
+
## wavelength λz = (2·π)/kz
|
|
240
|
+
lz = np.copy( 2 * np.pi / kz )
|
|
241
|
+
data['lz'] = lz
|
|
242
|
+
|
|
243
|
+
# ==============================================================
|
|
244
|
+
# prepare buffers, etc.
|
|
245
|
+
# ==============================================================
|
|
246
|
+
|
|
247
|
+
do_density_weighting = False ## deactivated for now... would need implementation
|
|
248
|
+
|
|
249
|
+
## cospectrum pairs
|
|
250
|
+
## [ str:var1, str:var2 ]
|
|
251
|
+
fft_combis = [
|
|
252
|
+
|
|
253
|
+
[ 'u_tau' , 'u_tau' ], ## [ uτ , uτ ] --> FFT[ uτ′ , uτ′ ]
|
|
254
|
+
[ 'v_tau' , 'v_tau' ], ## [ vτ , vτ ] --> FFT[ vτ′ , vτ′ ]
|
|
255
|
+
[ 'w_tau' , 'w_tau' ], ## [ wτ , wτ ] --> FFT[ wτ′ , wτ′ ]
|
|
256
|
+
|
|
257
|
+
#[ 'u_tau' , 'v_tau' ], ## [ uτ , vτ ] --> FFT[ uτ′ , vτ′ ]
|
|
258
|
+
#[ 'u_tau' , 'w_tau' ], ## [ uτ , wτ ] --> FFT[ uτ′ , wτ′ ]
|
|
259
|
+
#[ 'v_tau' , 'w_tau' ], ## [ vτ , wτ ] --> FFT[ vτ′ , wτ′ ]
|
|
260
|
+
|
|
261
|
+
[ 'tau_uy' , 'tau_uy' ], ## [ τuy , τuy ] --> FFT[ τuy′ , τuy′ ]
|
|
262
|
+
[ 'tau_vy' , 'tau_vy' ], ## [ τvy , τvy ] --> FFT[ τvy′ , τvy′ ]
|
|
263
|
+
[ 'tau_wy' , 'tau_wy' ], ## [ τwy , τwy ] --> FFT[ τwy′ , τwy′ ]
|
|
264
|
+
|
|
265
|
+
#[ 'tau_uy' , 'tau_vy' ], ## [ τuy , τvy ] --> FFT[ τuy′ , τvy′ ]
|
|
266
|
+
#[ 'tau_uy' , 'tau_wy' ], ## [ τuy , τwy ] --> FFT[ τuy′ , τwy′ ]
|
|
267
|
+
#[ 'tau_vy' , 'tau_wy' ], ## [ τvy , τwy ] --> FFT[ τvy′ , τwy′ ]
|
|
268
|
+
|
|
269
|
+
[ 'p' , 'p' ], ## [p,p] --> FFT[ p′ , p′ ]
|
|
270
|
+
[ 'T' , 'T' ], ## [T,T] --> FFT[ T′ , T′ ]
|
|
271
|
+
[ 'rho' , 'rho' ], ## [ρ,ρ] --> FFT[ ρ′ , ρ′ ]
|
|
272
|
+
|
|
273
|
+
[ 'u_tau' , 'p' ], ## [uτ,p] --> FFT[ uτ′ , p′ ]
|
|
274
|
+
[ 'tau_uy' , 'p' ], ## [τuy,p] --> FFT[ τuy′ , p′ ]
|
|
275
|
+
|
|
276
|
+
]
|
|
277
|
+
|
|
278
|
+
## generate FFT cospectrum scalar names
|
|
279
|
+
scalars = []
|
|
280
|
+
for fft_combi in fft_combis:
|
|
281
|
+
#s1,s2,do_density_weighting = fft_combi
|
|
282
|
+
s1,s2 = fft_combi
|
|
283
|
+
if do_density_weighting:
|
|
284
|
+
raise NotImplementedError
|
|
285
|
+
else:
|
|
286
|
+
scalars.append(f"{s1.replace('_','')}I_{s2.replace('_','')}I")
|
|
287
|
+
|
|
288
|
+
## generate AVG scalar names
|
|
289
|
+
scalars_Re_avg = []
|
|
290
|
+
#scalars_Fv_avg = []
|
|
291
|
+
for fft_combi in fft_combis:
|
|
292
|
+
#s1,s2,do_density_weighting = fft_combi
|
|
293
|
+
s1,s2 = fft_combi
|
|
294
|
+
if do_density_weighting and ('rho' not in scalars_Re_avg):
|
|
295
|
+
scalars_Re_avg.append('rho')
|
|
296
|
+
if do_density_weighting:
|
|
297
|
+
#if (s1 not in scalars_Fv_avg):
|
|
298
|
+
# scalars_Fv_avg.append(s1)
|
|
299
|
+
#if (s2 not in scalars_Fv_avg):
|
|
300
|
+
# scalars_Fv_avg.append(s2)
|
|
301
|
+
raise NotImplementedError
|
|
302
|
+
else:
|
|
303
|
+
if (s1 not in scalars_Re_avg):
|
|
304
|
+
scalars_Re_avg.append(s1)
|
|
305
|
+
if (s2 not in scalars_Re_avg):
|
|
306
|
+
scalars_Re_avg.append(s2)
|
|
307
|
+
|
|
308
|
+
## numpy formatted arrays: buffers for PSD & other data (rank-local)
|
|
309
|
+
Ekz = np.zeros(shape=(nir,nkz ) , dtype={'names':scalars , 'formats':[ np.dtype(np.complex128) for s in scalars ]})
|
|
310
|
+
Ef = np.zeros(shape=(nir,nf ) , dtype={'names':scalars , 'formats':[ np.dtype(np.complex128) for s in scalars ]})
|
|
311
|
+
covariance = np.zeros(shape=(nir, ) , dtype={'names':scalars , 'formats':[ np.dtype(np.float64) for s in scalars ]})
|
|
312
|
+
avg_Re = np.zeros(shape=(nir, ) , dtype={'names':scalars_Re_avg , 'formats':[ np.dtype(np.float64) for s in scalars_Re_avg ]})
|
|
313
|
+
#avg_Fv = np.zeros(shape=(nir, ) , dtype={'names':scalars_Fv_avg , 'formats':[ np.dtype(np.float64) for s in scalars_Fv_avg ]})
|
|
314
|
+
|
|
315
|
+
if verbose:
|
|
316
|
+
even_print('n turb spectrum scalar combinations' , '%i'%(len(fft_combis),))
|
|
317
|
+
print(72*'-')
|
|
318
|
+
|
|
319
|
+
## window for [z] -- rectangular because [z] is assumed periodic already
|
|
320
|
+
window_z = np.ones(nz,dtype=np.float64)
|
|
321
|
+
mean_sq_win_z = np.mean(window_z**2)
|
|
322
|
+
if verbose:
|
|
323
|
+
even_print('mean(window_z**2)', '%0.5f'%(mean_sq_win_z,))
|
|
324
|
+
|
|
325
|
+
# ==============================================================
|
|
326
|
+
# main loop
|
|
327
|
+
# ==============================================================
|
|
328
|
+
|
|
329
|
+
if verbose:
|
|
330
|
+
progress_bar = tqdm(
|
|
331
|
+
total=len(fft_combis)*nir,
|
|
332
|
+
ncols=100,
|
|
333
|
+
desc='fft',
|
|
334
|
+
leave=True,
|
|
335
|
+
file=sys.stdout,
|
|
336
|
+
mininterval=0.1,
|
|
337
|
+
smoothing=0.,
|
|
338
|
+
#bar_format="\033[B{l_bar}{bar}| {n}/{total} [{percentage:.1f}%] {elapsed}/{remaining}\033[A\n\b",
|
|
339
|
+
bar_format="{l_bar}{bar}| {n}/{total} [{percentage:.1f}%] {elapsed}/{remaining}",
|
|
340
|
+
ascii="░█",
|
|
341
|
+
colour='#FF6600',
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
for cci,cc in enumerate(fft_combis): ## fft pairs
|
|
345
|
+
|
|
346
|
+
if verbose: tqdm.write(72*'-')
|
|
347
|
+
|
|
348
|
+
scalar_L, scalar_R = cc
|
|
349
|
+
|
|
350
|
+
msg = f'FFT[{scalar_L}′,{scalar_R}′]'
|
|
351
|
+
if verbose:
|
|
352
|
+
tqdm.write(even_print('computing',msg,s=True,))
|
|
353
|
+
|
|
354
|
+
dset_L = self[f'data/{scalar_L}']
|
|
355
|
+
dset_R = self[f'data/{scalar_R}']
|
|
356
|
+
data_gb_1x = self.n_ranks * 1 * self.nj * self.nt * dset_L.dtype.itemsize / 1024**3
|
|
357
|
+
|
|
358
|
+
scalar = scalars[cci]
|
|
359
|
+
|
|
360
|
+
## assert scalar name
|
|
361
|
+
scalar_ = f"{scalar_L.replace('_','')}I_{scalar_R.replace('_','')}I"
|
|
362
|
+
if (scalar != scalar_):
|
|
363
|
+
raise ValueError
|
|
364
|
+
|
|
365
|
+
## assert scalar name
|
|
366
|
+
if do_density_weighting:
|
|
367
|
+
#if (f'r{scalar_L}II_r{scalar_R}II' != scalar ):
|
|
368
|
+
# raise ValueError
|
|
369
|
+
raise NotImplementedError
|
|
370
|
+
else:
|
|
371
|
+
if (f"{scalar_L.replace('_','')}I_{scalar_R.replace('_','')}I" != scalar ):
|
|
372
|
+
raise ValueError
|
|
373
|
+
|
|
374
|
+
## [x] loop (rank-local)
|
|
375
|
+
for ii in range(ri1,ri2):
|
|
376
|
+
|
|
377
|
+
iii = ii - ri1
|
|
378
|
+
|
|
379
|
+
data_L = np.zeros( (nz,nt) , dtype=np.float64 )
|
|
380
|
+
data_R = np.zeros( (nz,nt) , dtype=np.float64 )
|
|
381
|
+
|
|
382
|
+
self.comm.Barrier()
|
|
383
|
+
t_start = timeit.default_timer()
|
|
384
|
+
|
|
385
|
+
## read data L
|
|
386
|
+
n_scalars_read = 1 ## initialize
|
|
387
|
+
scalar_str = scalar_L ## initialize
|
|
388
|
+
with dset_L.collective:
|
|
389
|
+
data_L[:,:] = np.copy( dset_L[ii,:,:] ).astype(np.float64)
|
|
390
|
+
self.comm.Barrier()
|
|
391
|
+
|
|
392
|
+
## read data R (if != data L)
|
|
393
|
+
if (scalar_L==scalar_R):
|
|
394
|
+
data_R[:,:] = np.copy( data_L )
|
|
395
|
+
else:
|
|
396
|
+
n_scalars_read += 1
|
|
397
|
+
scalar_str += f',{scalar_R}'
|
|
398
|
+
with dset_R.collective:
|
|
399
|
+
data_R[:,:] = np.copy( dset_R[ii,:,:] ).astype(np.float64)
|
|
400
|
+
self.comm.Barrier()
|
|
401
|
+
|
|
402
|
+
self.comm.Barrier()
|
|
403
|
+
t_delta = timeit.default_timer() - t_start
|
|
404
|
+
data_gb = data_gb_1x * n_scalars_read
|
|
405
|
+
|
|
406
|
+
if verbose:
|
|
407
|
+
tqdm.write(even_print(f'read: {scalar_str}', f'{data_gb:0.3f} [GB] {t_delta:0.3f} [s] {data_gb/t_delta:0.3f} [GB/s]', s=True))
|
|
408
|
+
|
|
409
|
+
## data_L and data_R shape should be (nz,nt)
|
|
410
|
+
if ( data_L.shape != (nz,nt) ) or ( data_R.shape != (nz,nt) ):
|
|
411
|
+
print(f'rank {self.rank:d}: shape violation')
|
|
412
|
+
self.comm.Abort(1)
|
|
413
|
+
|
|
414
|
+
# === redimensionalize
|
|
415
|
+
|
|
416
|
+
if scalar_L in ['tau_uy','tau_vy','tau_wy',]:
|
|
417
|
+
data_L *= rho_inf * U_inf**2
|
|
418
|
+
elif scalar_L in ['u_tau','v_tau','w_tau',]:
|
|
419
|
+
data_L *= U_inf
|
|
420
|
+
elif scalar_L in ['p',]:
|
|
421
|
+
data_L *= rho_inf * U_inf**2
|
|
422
|
+
elif scalar_L in ['T',]:
|
|
423
|
+
data_L *= T_inf
|
|
424
|
+
elif scalar_L in ['rho',]:
|
|
425
|
+
data_L *= rho_inf
|
|
426
|
+
else:
|
|
427
|
+
raise ValueError
|
|
428
|
+
|
|
429
|
+
if scalar_R in ['tau_uy','tau_vy','tau_wy',]:
|
|
430
|
+
data_R *= rho_inf * U_inf**2
|
|
431
|
+
elif scalar_R in ['u_tau','v_tau','w_tau',]:
|
|
432
|
+
data_R *= U_inf
|
|
433
|
+
elif scalar_R in ['p',]:
|
|
434
|
+
data_R *= rho_inf * U_inf**2
|
|
435
|
+
elif scalar_R in ['T',]:
|
|
436
|
+
data_R *= T_inf
|
|
437
|
+
elif scalar_R in ['rho',]:
|
|
438
|
+
data_R *= rho_inf
|
|
439
|
+
else:
|
|
440
|
+
raise ValueError
|
|
441
|
+
|
|
442
|
+
## data_L and data_R shape should be (nz,nt)
|
|
443
|
+
if ( data_L.shape != (nz,nt) ) or ( data_R.shape != (nz,nt) ):
|
|
444
|
+
print(f'rank {self.rank:d}: shape violation')
|
|
445
|
+
self.comm.Abort(1)
|
|
446
|
+
|
|
447
|
+
# === compute mean-removed data
|
|
448
|
+
|
|
449
|
+
## avg(□) or avg(ρ·□)/avg(ρ) in [t]
|
|
450
|
+
if do_density_weighting:
|
|
451
|
+
#rho_avg = np.mean( rho , axis=-1, dtype=np.float64, keepdims=True)
|
|
452
|
+
#data_L_avg = np.mean( rho*data_L , axis=-1, dtype=np.float64, keepdims=True)
|
|
453
|
+
#data_L_avg /= rho_avg
|
|
454
|
+
#data_R_avg = np.mean( rho*data_R , axis=-1, dtype=np.float64, keepdims=True)
|
|
455
|
+
#data_R_avg /= rho_avg
|
|
456
|
+
raise NotImplementedError
|
|
457
|
+
else:
|
|
458
|
+
data_L_avg = np.mean( data_L , axis=-1, dtype=np.float64, keepdims=True) ## (nz,1)
|
|
459
|
+
data_R_avg = np.mean( data_R , axis=-1, dtype=np.float64, keepdims=True) ## (nz,1)
|
|
460
|
+
|
|
461
|
+
## data_L_avg and data_R_avg shape should be (nz,1)
|
|
462
|
+
if ( data_L_avg.shape != (nz,1) ) or ( data_R_avg.shape != (nz,1) ):
|
|
463
|
+
print(f'rank {self.rank:d}: shape violation')
|
|
464
|
+
self.comm.Abort(1)
|
|
465
|
+
|
|
466
|
+
## Reynolds prime □′ or Favre prime □″ --> shape (nz,nt)
|
|
467
|
+
data_L -= data_L_avg
|
|
468
|
+
data_R -= data_R_avg
|
|
469
|
+
|
|
470
|
+
## data_L and data_R shape should be (nz,nt)
|
|
471
|
+
if ( data_L.shape != (nz,nt) ) or ( data_R.shape != (nz,nt) ):
|
|
472
|
+
print(f'rank {self.rank:d}: shape violation')
|
|
473
|
+
self.comm.Abort(1)
|
|
474
|
+
|
|
475
|
+
## assert stationarity / definition averaging
|
|
476
|
+
## avg(□′)==0 or avg(ρ·□″)==0
|
|
477
|
+
if do_density_weighting:
|
|
478
|
+
#a_ = np.mean(rho*data_L, axis=-1, dtype=np.float64, keepdims=True)
|
|
479
|
+
#b_ = np.mean(rho*data_R, axis=-1, dtype=np.float64, keepdims=True)
|
|
480
|
+
raise NotImplementedError
|
|
481
|
+
else:
|
|
482
|
+
a_ = np.mean(data_L, axis=-1, dtype=np.float64, keepdims=True) ## average in [t] --> (nz,1)
|
|
483
|
+
b_ = np.mean(data_R, axis=-1, dtype=np.float64, keepdims=True)
|
|
484
|
+
if not np.allclose( a_, np.zeros_like(a_), atol=1e-6 ) or not np.allclose( b_, np.zeros_like(b_), atol=1e-6 ):
|
|
485
|
+
print(f'rank {self.rank:d}: avg(□′)!=0 or avg(ρ·□″)!=0')
|
|
486
|
+
self.comm.Abort(1)
|
|
487
|
+
|
|
488
|
+
## covariance: <□′·□′> OR <ρ□″·ρ□″> --> note that this is NOT the typical Favre <ρ·□″□″>
|
|
489
|
+
if do_density_weighting:
|
|
490
|
+
#covariance_ = np.mean( rho*data_L * rho*data_R , axis=-1 , dtype=np.float64, keepdims=True)
|
|
491
|
+
raise NotImplementedError
|
|
492
|
+
else:
|
|
493
|
+
covariance_ = np.mean( data_L*data_R , axis=-1 , dtype=np.float64, keepdims=True) ## average in [t] --> (nz,1)
|
|
494
|
+
|
|
495
|
+
if ( covariance_.shape != (nz,1) ):
|
|
496
|
+
print(f'rank {self.rank:d}: shape violation')
|
|
497
|
+
self.comm.Abort(1)
|
|
498
|
+
|
|
499
|
+
## write this chunk/scalar's covariance to covariance buffer
|
|
500
|
+
## avg over [z,t] --> np.float64()
|
|
501
|
+
covariance[scalar][iii] = np.mean( covariance_ , axis=(0,1) , dtype=np.float64)
|
|
502
|
+
|
|
503
|
+
## write (rank-local) 1D [x] average
|
|
504
|
+
if do_density_weighting:
|
|
505
|
+
#avg_Fv[scalar_L][iii] = np.mean( data_L_avg , axis=(0,1) , dtype=np.float64) )
|
|
506
|
+
#avg_Fv[scalar_R][iii] = np.mean( data_R_avg , axis=(0,1) , dtype=np.float64) )
|
|
507
|
+
#avg_Re['rho'][iii] = np.mean( rho_avg , axis=(0,1) , dtype=np.float64) )
|
|
508
|
+
raise ValueError
|
|
509
|
+
else:
|
|
510
|
+
avg_Re[scalar_L][iii] = np.mean( data_L_avg , axis=(0,1) , dtype=np.float64)
|
|
511
|
+
avg_Re[scalar_R][iii] = np.mean( data_R_avg , axis=(0,1) , dtype=np.float64)
|
|
512
|
+
|
|
513
|
+
# ===============================================================================
|
|
514
|
+
# At this point you have 4D [x,y,z,t] □′ data
|
|
515
|
+
# ===============================================================================
|
|
516
|
+
|
|
517
|
+
## do [z] FFT for every [t]
|
|
518
|
+
Ekz_buf = np.zeros((nt,nkz), dtype=np.complex128)
|
|
519
|
+
for ti in range(nt):
|
|
520
|
+
uL = np.copy( data_L[:,ti] )
|
|
521
|
+
uR = np.copy( data_R[:,ti] )
|
|
522
|
+
|
|
523
|
+
## One-sided amplitude spectra
|
|
524
|
+
A1 = sp.fft.fft( uL * window_z )[kzp] / nz
|
|
525
|
+
A2 = sp.fft.fft( uR * window_z )[kzp] / nz
|
|
526
|
+
|
|
527
|
+
Ekz_buf[ti,:] = 2. * A1 * np.conj(A2) / ( dkz * mean_sq_win_z )
|
|
528
|
+
|
|
529
|
+
Ekz[scalar][iii,:] = np.mean(Ekz_buf, axis=0) ## mean across [t] --> (nkz,)
|
|
530
|
+
|
|
531
|
+
## do [t] FFT for every [z]
|
|
532
|
+
Ef_buf = np.zeros((nz,nf), dtype=np.complex128)
|
|
533
|
+
#for zi in range(self.nj):
|
|
534
|
+
for zi in range(nz):
|
|
535
|
+
uL = np.copy( data_L[zi,:] )
|
|
536
|
+
uR = np.copy( data_R[zi,:] )
|
|
537
|
+
|
|
538
|
+
## One-sided complex cross-spectral density in [f] (using Welch's method)
|
|
539
|
+
_,P = csd(
|
|
540
|
+
uL,uR,
|
|
541
|
+
fs=fs,
|
|
542
|
+
nperseg=nperseg,
|
|
543
|
+
noverlap=noverlap,
|
|
544
|
+
window='hann',
|
|
545
|
+
detrend='constant',
|
|
546
|
+
scaling='density',
|
|
547
|
+
return_onesided=True,
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
Ef_buf[zi,:] = P
|
|
551
|
+
|
|
552
|
+
Ef[scalar][iii,:] = np.mean(Ef_buf, axis=0) ## mean across [z] --> (nf,)
|
|
553
|
+
|
|
554
|
+
self.comm.Barrier() ## [x] loop ('ii' within this rank's range)
|
|
555
|
+
if verbose: progress_bar.update()
|
|
556
|
+
|
|
557
|
+
#break ## DEBUG
|
|
558
|
+
|
|
559
|
+
self.comm.Barrier()
|
|
560
|
+
if verbose:
|
|
561
|
+
progress_bar.close()
|
|
562
|
+
print(72*'-')
|
|
563
|
+
|
|
564
|
+
# ==============================================================
|
|
565
|
+
# write HDF5 (.h5) file
|
|
566
|
+
# ==============================================================
|
|
567
|
+
|
|
568
|
+
## overwrite outfile!
|
|
569
|
+
## open on rank 0 and write attributes, dimensions, etc.
|
|
570
|
+
if (self.rank==0):
|
|
571
|
+
with h5py.File(fn_h5_out, 'w') as hfw:
|
|
572
|
+
|
|
573
|
+
## write floats,ints as top-level attributes
|
|
574
|
+
for key,val in data.items():
|
|
575
|
+
if isinstance(data[key], (int,np.int32,np.int64)):
|
|
576
|
+
hfw.attrs[key] = val
|
|
577
|
+
elif isinstance(data[key], (float,np.float32,np.float64)):
|
|
578
|
+
hfw.attrs[key] = val
|
|
579
|
+
elif isinstance(data[key], np.ndarray):
|
|
580
|
+
pass
|
|
581
|
+
else:
|
|
582
|
+
print(f'key {key} is type {str(type(data[key]))}')
|
|
583
|
+
self.comm.Abort(1)
|
|
584
|
+
|
|
585
|
+
## write numpy arrays
|
|
586
|
+
hfw.create_dataset( 'dims/x' , data=x ) ## [m]
|
|
587
|
+
hfw.create_dataset( 'dims/z' , data=z ) ## [m]
|
|
588
|
+
hfw.create_dataset( 'dims/t' , data=t ) ## [s]
|
|
589
|
+
hfw.create_dataset( 'dims/freq' , data=freq ) ## [1/s] | [Hz]
|
|
590
|
+
hfw.create_dataset( 'dims/kz' , data=kz ) ## [1/m]
|
|
591
|
+
hfw.create_dataset( 'dims/lz' , data=lz ) ## [m]
|
|
592
|
+
|
|
593
|
+
## initialize datasets : covariance,Ekz,Ef
|
|
594
|
+
for scalar in scalars:
|
|
595
|
+
hfw.create_dataset( f'covariance/{scalar}' , shape=(nx,) , dtype=np.float64 , chunks=None , data=np.full((nx,),0.,np.float64) )
|
|
596
|
+
hfw.create_dataset( f'Ekz/{scalar}' , shape=(nx,nkz) , dtype=np.complex128 , chunks=(1,nkz) , data=np.full((nx,nkz),0.,np.complex128) )
|
|
597
|
+
hfw.create_dataset( f'Ef/{scalar}' , shape=(nx,nf) , dtype=np.complex128 , chunks=(1,nf) , data=np.full((nx,nf),0.,np.complex128) )
|
|
598
|
+
|
|
599
|
+
## initialize datasets : 1D [x] mean
|
|
600
|
+
for scalar in avg_Re.dtype.names:
|
|
601
|
+
hfw.create_dataset( f'avg/Re/{scalar}', shape=(nx,), dtype=np.float64, chunks=None, data=np.full((nx,),0.,np.float64) )
|
|
602
|
+
|
|
603
|
+
self.comm.Barrier()
|
|
604
|
+
|
|
605
|
+
## re-open in parallel for data writes
|
|
606
|
+
with h5py.File(fn_h5_out, 'a', driver='mpio', comm=self.comm) as hfw:
|
|
607
|
+
|
|
608
|
+
## collectively write covariance,Ekz,Ef
|
|
609
|
+
for scalar in scalars:
|
|
610
|
+
dset = hfw[f'covariance/{scalar}']
|
|
611
|
+
with dset.collective:
|
|
612
|
+
dset[ri1:ri2] = covariance[scalar][:]
|
|
613
|
+
dset = hfw[f'Ekz/{scalar}']
|
|
614
|
+
with dset.collective:
|
|
615
|
+
dset[ri1:ri2,:] = Ekz[scalar][:,:]
|
|
616
|
+
dset = hfw[f'Ef/{scalar}']
|
|
617
|
+
with dset.collective:
|
|
618
|
+
dset[ri1:ri2,:] = Ef[scalar][:,:]
|
|
619
|
+
|
|
620
|
+
## collectively write 1D [y] avgs
|
|
621
|
+
for scalar in avg_Re.dtype.names:
|
|
622
|
+
dset = hfw[f'avg/Re/{scalar}']
|
|
623
|
+
with dset.collective:
|
|
624
|
+
dset[ri1:ri2] = avg_Re[scalar][:]
|
|
625
|
+
|
|
626
|
+
## report file contents
|
|
627
|
+
self.comm.Barrier()
|
|
628
|
+
if (self.rank==0):
|
|
629
|
+
even_print( os.path.basename(fn_h5_out) , f'{(os.path.getsize(fn_h5_out)/1024**2):0.1f} [MB]' )
|
|
630
|
+
print(72*'-')
|
|
631
|
+
with h5py.File(fn_h5_out,'r') as hfr:
|
|
632
|
+
h5_print_contents(hfr)
|
|
633
|
+
self.comm.Barrier()
|
|
634
|
+
|
|
635
|
+
if verbose: print(72*'-')
|
|
636
|
+
if verbose: print('total time : spd.calc_turb_cospectrum_wall() : %s'%format_time_string((timeit.default_timer() - t_start_func)))
|
|
637
|
+
if verbose: print(72*'-')
|
|
638
|
+
return
|