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
turbx/spd_wall_stats.py
ADDED
|
@@ -0,0 +1,618 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import time
|
|
4
|
+
import timeit
|
|
5
|
+
from pathlib import Path, PurePosixPath
|
|
6
|
+
|
|
7
|
+
import h5py
|
|
8
|
+
import numpy as np
|
|
9
|
+
from tqdm import tqdm
|
|
10
|
+
|
|
11
|
+
from .h5 import h5_print_contents
|
|
12
|
+
from .utils import even_print, format_time_string
|
|
13
|
+
|
|
14
|
+
# ======================================================================
|
|
15
|
+
|
|
16
|
+
def _calc_statistics_wall(self, **kwargs):
|
|
17
|
+
'''
|
|
18
|
+
Calculate statistics for an unsteady wall measurement
|
|
19
|
+
which has dimensions (nx,1,nz)
|
|
20
|
+
- mean
|
|
21
|
+
- covariance
|
|
22
|
+
- skewness, kurtosis
|
|
23
|
+
- probability distribution function (PDF)
|
|
24
|
+
'''
|
|
25
|
+
|
|
26
|
+
if (self.rank==0):
|
|
27
|
+
verbose = True
|
|
28
|
+
else:
|
|
29
|
+
verbose = False
|
|
30
|
+
|
|
31
|
+
if verbose: print('\n'+'spd.calc_statistics_wall()'+'\n'+72*'-')
|
|
32
|
+
t_start_func = timeit.default_timer()
|
|
33
|
+
|
|
34
|
+
if not self.usingmpi:
|
|
35
|
+
raise NotImplementedError('function is not implemented for non-MPI usage')
|
|
36
|
+
|
|
37
|
+
h5py_is_mpi_build = h5py.h5.get_config().mpi
|
|
38
|
+
if not h5py_is_mpi_build:
|
|
39
|
+
if verbose: print('h5py was not compiled for parallel usage! exiting.')
|
|
40
|
+
sys.exit(1)
|
|
41
|
+
|
|
42
|
+
ri = kwargs.get('ri',1)
|
|
43
|
+
rj = kwargs.get('rj',1)
|
|
44
|
+
rt = kwargs.get('rt',1)
|
|
45
|
+
|
|
46
|
+
fn_h5_stats = kwargs.get('fn_h5_stats',None) ## filename for output HDF5 (.h5) file
|
|
47
|
+
n_bins = kwargs.get('n_bins',512) ## n bins for histogram (PDF) calculation
|
|
48
|
+
|
|
49
|
+
## check data distribution
|
|
50
|
+
if (rj!=1):
|
|
51
|
+
raise AssertionError('rj!=1')
|
|
52
|
+
if (rt!=1):
|
|
53
|
+
raise AssertionError('rt!=1')
|
|
54
|
+
if (ri*rj*rt != self.n_ranks):
|
|
55
|
+
raise AssertionError('ri*rj*rt != self.n_ranks')
|
|
56
|
+
if (ri>self.ni):
|
|
57
|
+
raise AssertionError('ri>self.ni')
|
|
58
|
+
if (self.ni%ri!=0):
|
|
59
|
+
raise AssertionError('ni currently needs to be divisible by the n ranks')
|
|
60
|
+
|
|
61
|
+
## distribute data over i/[x]
|
|
62
|
+
ril_ = np.array_split(np.arange(self.ni,dtype=np.int64),min(ri,self.ni))
|
|
63
|
+
ril = [[b[0],b[-1]+1] for b in ril_ ]
|
|
64
|
+
ri1,ri2 = ril[self.rank]
|
|
65
|
+
nir = ri2 - ri1
|
|
66
|
+
|
|
67
|
+
## output filename : HDF5 (.h5)
|
|
68
|
+
if (fn_h5_stats is None): ## automatically determine name
|
|
69
|
+
fname_path = os.path.dirname(self.fname)
|
|
70
|
+
fname_base = os.path.basename(self.fname)
|
|
71
|
+
fname_root, fname_ext = os.path.splitext(fname_base)
|
|
72
|
+
#fname_root = re.findall(r'io\S+_mpi_[0-9]+', fname_root)[0]
|
|
73
|
+
fname_stats_h5_base = fname_root+'_stats.h5'
|
|
74
|
+
fn_h5_stats = str(PurePosixPath(fname_path, fname_stats_h5_base))
|
|
75
|
+
if (Path(fn_h5_stats).suffix != '.h5'):
|
|
76
|
+
raise ValueError(f"fn_h5_stats='{str(fn_h5_stats)}' must end in .h5")
|
|
77
|
+
if os.path.isfile(fn_h5_stats):
|
|
78
|
+
if (fn_h5_stats == self.fname):
|
|
79
|
+
raise ValueError(f"fn_h5_stats='{str(fn_h5_stats)}' cannot be same as input filename.")
|
|
80
|
+
|
|
81
|
+
if verbose: even_print( 'fn_h5' , self.fname )
|
|
82
|
+
if verbose: even_print( 'fn_h5_stats' , fn_h5_stats )
|
|
83
|
+
if verbose: print(72*'-')
|
|
84
|
+
if verbose: even_print( 'ni' , f'{self.ni:d}' )
|
|
85
|
+
if verbose: even_print( 'nj' , f'{self.nj:d}' )
|
|
86
|
+
if verbose: even_print( 'nt' , f'{self.nt:d}' )
|
|
87
|
+
if verbose: print(72*'-')
|
|
88
|
+
self.comm.Barrier()
|
|
89
|
+
|
|
90
|
+
# ===
|
|
91
|
+
|
|
92
|
+
## the data dictionary to be pickled or written to .h5 later
|
|
93
|
+
data = {}
|
|
94
|
+
|
|
95
|
+
## freestream data
|
|
96
|
+
data['lchar'] = self.lchar
|
|
97
|
+
data['U_inf'] = self.U_inf
|
|
98
|
+
data['rho_inf'] = self.rho_inf
|
|
99
|
+
data['T_inf'] = self.T_inf
|
|
100
|
+
data['mu_inf'] = self.mu_inf
|
|
101
|
+
data['p_inf'] = self.p_inf
|
|
102
|
+
data['Ma'] = self.Ma
|
|
103
|
+
data['Pr'] = self.Pr
|
|
104
|
+
|
|
105
|
+
## read in 1D coordinate arrays & re-dimensionalize
|
|
106
|
+
x = np.copy( self['dims/x'][()] * self.lchar )
|
|
107
|
+
z = np.copy( self['dims/z'][()] * self.lchar )
|
|
108
|
+
t = np.copy( self['dims/t'][()] * self.tchar )
|
|
109
|
+
data['x'] = x
|
|
110
|
+
data['z'] = z
|
|
111
|
+
data['t'] = t
|
|
112
|
+
|
|
113
|
+
nx = self.ni
|
|
114
|
+
ni = self.ni
|
|
115
|
+
nz = self.nj
|
|
116
|
+
nj = self.nj
|
|
117
|
+
data['ni'] = ni
|
|
118
|
+
data['nx'] = nx
|
|
119
|
+
data['nj'] = nj
|
|
120
|
+
data['nz'] = nz
|
|
121
|
+
|
|
122
|
+
nt = self.nt
|
|
123
|
+
data['nt'] = nt
|
|
124
|
+
|
|
125
|
+
## assert constant Δz
|
|
126
|
+
dz0 = np.diff(z)[0]
|
|
127
|
+
if not np.all(np.isclose(np.diff(z), dz0, rtol=1e-6)):
|
|
128
|
+
raise NotImplementedError('Δz not constant')
|
|
129
|
+
|
|
130
|
+
## get Δt, dimensional [s]
|
|
131
|
+
if hasattr(self,'dt'):
|
|
132
|
+
dt = self.dt * self.tchar
|
|
133
|
+
np.testing.assert_allclose(dt, t[1]-t[0], rtol=1e-12, atol=1e-12)
|
|
134
|
+
else:
|
|
135
|
+
dt = t[1] - t[0] ## already dimensional
|
|
136
|
+
|
|
137
|
+
if hasattr(self,'duration'):
|
|
138
|
+
t_meas = self.duration * self.tchar
|
|
139
|
+
np.testing.assert_allclose(t_meas, t.max()-t.min(), rtol=1e-12, atol=1e-12)
|
|
140
|
+
else:
|
|
141
|
+
t_meas = t[-1] - t[0] ## already dimensional
|
|
142
|
+
self.duration = t_meas / self.tchar ## non-dimensionalize for attribute
|
|
143
|
+
|
|
144
|
+
zrange = z.max() - z.min()
|
|
145
|
+
|
|
146
|
+
data['t'] = t
|
|
147
|
+
data['dt'] = dt
|
|
148
|
+
data['dz'] = dz0
|
|
149
|
+
data['zrange'] = zrange
|
|
150
|
+
|
|
151
|
+
if verbose: even_print( 'Δt/tchar' , f'{dt/self.tchar:0.8f}' )
|
|
152
|
+
if verbose: even_print( 'Δt' , f'{dt:0.3e} [s]' )
|
|
153
|
+
if verbose: even_print( 'duration/tchar' , f'{self.duration:0.1f}' )
|
|
154
|
+
if verbose: even_print( 'duration' , f'{self.duration*self.tchar:0.3e} [s]' )
|
|
155
|
+
if verbose: print(72*'-')
|
|
156
|
+
|
|
157
|
+
## report
|
|
158
|
+
if verbose:
|
|
159
|
+
even_print('Δt' , f'{dt :0.5e} [s]' )
|
|
160
|
+
even_print('t_meas' , f'{t_meas:0.5e} [s]' )
|
|
161
|
+
even_print('Δz' , f'{dz0 :0.5e} [m]' )
|
|
162
|
+
even_print('zrange' , f'{zrange:0.5e} [m]' )
|
|
163
|
+
#print(72*'-')
|
|
164
|
+
|
|
165
|
+
# ==============================================================
|
|
166
|
+
# prepare buffers, maps, etc.
|
|
167
|
+
# ==============================================================
|
|
168
|
+
|
|
169
|
+
## key = str:scalar name
|
|
170
|
+
## value = tuple:recipe,
|
|
171
|
+
## bool:do_mean,
|
|
172
|
+
## bool:do_pdf,
|
|
173
|
+
## bool:do_skew_kurt
|
|
174
|
+
##
|
|
175
|
+
## recipe elements:
|
|
176
|
+
## - if tuple : ( str:scalar , bool:ρ weighting ) --> always mean-removed
|
|
177
|
+
## - if str : str:scalar
|
|
178
|
+
|
|
179
|
+
scalars_dict = {
|
|
180
|
+
|
|
181
|
+
'u_tau' : [ ( 'u_tau', ) , True, True, False ], ## uτ
|
|
182
|
+
'utauI' : [ ( ('u_tau',False), ) , False, True, True ], ## uτ′
|
|
183
|
+
'r_utauII' : [ ( 'rho', ('u_tau',True ), ) , False, True, True ], ## ρ·uτ″
|
|
184
|
+
|
|
185
|
+
'v_tau' : [ ( 'v_tau', ) , True, True, False ], ## vτ
|
|
186
|
+
'vtauI' : [ ( ('v_tau',False), ) , False, True, True ], ## vτ′
|
|
187
|
+
'r_vtauII' : [ ( 'rho', ('v_tau',True ), ) , False, True, True ], ## ρ·vτ″
|
|
188
|
+
|
|
189
|
+
'w_tau' : [ ( 'w_tau', ) , True, True, False ], ## wτ
|
|
190
|
+
'wtauI' : [ ( ('w_tau',False), ) , False, True, True ], ## wτ′
|
|
191
|
+
'r_wtauII' : [ ( 'rho', ('w_tau',True ), ) , False, True, True ], ## ρ·wτ″
|
|
192
|
+
|
|
193
|
+
'utauIutauI' : [ ( ('u_tau',False), ('u_tau',False) ), True, True, False ], ## uτ′uτ′
|
|
194
|
+
'vtauIvtauI' : [ ( ('v_tau',False), ('v_tau',False) ), True, True, False ], ## vτ′vτ′
|
|
195
|
+
'wtauIwtauI' : [ ( ('w_tau',False), ('w_tau',False) ), True, True, False ], ## wτ′wτ′
|
|
196
|
+
#'utauIvtauI' : [ ( ('u_tau',False), ('v_tau',False) ), True, True, False ], ## uτ′vτ′
|
|
197
|
+
#'utauIwtauI' : [ ( ('u_tau',False), ('w_tau',False) ), True, True, False ], ## uτ′wτ′
|
|
198
|
+
|
|
199
|
+
'tau_uy' : [ ( 'tau_uy', ) , True, True, False ], ## τuy
|
|
200
|
+
'tauuyI' : [ ( ('tau_uy',False) , ) , False, True, True ], ## τ′uy
|
|
201
|
+
'tauuyItauuyI' : [ ( ('tau_uy',False) , ('tau_uy',False) ) , True, True, False ], ## τ′uy·τ′uy
|
|
202
|
+
|
|
203
|
+
'tau_vy' : [ ( 'tau_vy', ) , True, True, False ], ## τvy
|
|
204
|
+
'tauvyI' : [ ( ('tau_vy',False) , ) , False, True, True ], ## τ′vy
|
|
205
|
+
'tauvyItauvyI' : [ ( ('tau_vy',False) , ('tau_vy',False) ) , True, True, False ], ## τ′vy·τ′vy
|
|
206
|
+
|
|
207
|
+
'tau_wy' : [ ( 'tau_wy', ) , True, True, False ], ## τwy
|
|
208
|
+
'tauwyI' : [ ( ('tau_wy',False) , ) , False, True, True ], ## τ′wy
|
|
209
|
+
'tauwyItauwyI' : [ ( ('tau_wy',False) , ('tau_wy',False) ) , True, True, False ], ## τ′wy·τ′wy
|
|
210
|
+
|
|
211
|
+
'TITI' : [ ( ('T',False), ('T',False) ) , True, True, False ], ## T′T′
|
|
212
|
+
'TIITII' : [ ( ('T',True ), ('T',True ) ) , True, True, False ], ## T″T″
|
|
213
|
+
'r_TIITII' : [ ( 'rho', ('T',True ), ('T',True ) ) , True, True, False ], ## ρ·T″T″
|
|
214
|
+
|
|
215
|
+
'rho' : [ ( 'rho', ) , True, True, False, ], ## ρ
|
|
216
|
+
'rhoI' : [ ( ('rho',False), ) , False, True, True, ], ## ρ′
|
|
217
|
+
'rhoIrhoI' : [ ( ('rho',False), ('rho',False), ) , True, True, False, ], ## ρ′ρ′
|
|
218
|
+
|
|
219
|
+
'p' : [ ( 'p', ) , True, True, False, ], ## p
|
|
220
|
+
'pI' : [ ( ('p',False), ) , False, True, True, ], ## p′
|
|
221
|
+
'pIpI' : [ ( ('p',False), ('p',False), ) , True, True, False, ], ## p′p′
|
|
222
|
+
|
|
223
|
+
'T' : [ ( 'T', ) , True, True, False, ], ## T
|
|
224
|
+
'TI' : [ ( ('T',False), ) , False, True, True, ], ## T′
|
|
225
|
+
'TII' : [ ( ('T',True ), ) , False, True, False, ], ## T″
|
|
226
|
+
'r_TII' : [ ( 'rho', ('T',True ), ) , False, True, True, ], ## ρ·T″
|
|
227
|
+
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
scalars_avg = []
|
|
231
|
+
scalars_pdf = []
|
|
232
|
+
scalars_hos_ = []
|
|
233
|
+
for s,ss in scalars_dict.items():
|
|
234
|
+
recipe, do_mean, do_pdf, do_skew_kurt = ss
|
|
235
|
+
if do_mean:
|
|
236
|
+
scalars_avg.append(s)
|
|
237
|
+
if do_pdf:
|
|
238
|
+
scalars_pdf.append(s)
|
|
239
|
+
if do_skew_kurt:
|
|
240
|
+
scalars_hos_.append(s)
|
|
241
|
+
|
|
242
|
+
scalars_hos=[]
|
|
243
|
+
for s_ in ['skew','kurt']:
|
|
244
|
+
for ss_ in scalars_hos_:
|
|
245
|
+
scalars_hos.append(f'{ss_}_{s_}')
|
|
246
|
+
|
|
247
|
+
## rank-local buffsres
|
|
248
|
+
data_avg = np.zeros(shape=(nir,), dtype={'names':scalars_avg, 'formats':[ np.float64 for sss in scalars_avg ]})
|
|
249
|
+
data_bins = np.zeros(shape=(nir,n_bins+1), dtype={'names':scalars_pdf, 'formats':[ np.float64 for sss in scalars_pdf ]})
|
|
250
|
+
data_pdf = np.zeros(shape=(nir,n_bins), dtype={'names':scalars_pdf, 'formats':[ np.float64 for sss in scalars_pdf ]})
|
|
251
|
+
data_hos = np.zeros(shape=(nir,), dtype={'names':scalars_hos, 'formats':[ np.float64 for sss in scalars_hos ]})
|
|
252
|
+
|
|
253
|
+
# ==============================================================
|
|
254
|
+
# main loop
|
|
255
|
+
# ==============================================================
|
|
256
|
+
|
|
257
|
+
if verbose:
|
|
258
|
+
progress_bar = tqdm(
|
|
259
|
+
total=len(scalars_dict)*nir,
|
|
260
|
+
ncols=100,
|
|
261
|
+
desc='statistics',
|
|
262
|
+
leave=True,
|
|
263
|
+
file=sys.stdout,
|
|
264
|
+
mininterval=0.1,
|
|
265
|
+
smoothing=0.,
|
|
266
|
+
#bar_format="\033[B{l_bar}{bar}| {n}/{total} [{percentage:.1f}%] {elapsed}/{remaining}\033[A\n\b",
|
|
267
|
+
bar_format="{l_bar}{bar}| {n}/{total} [{percentage:.1f}%] {elapsed}/{remaining}",
|
|
268
|
+
ascii="░█",
|
|
269
|
+
colour='#FF6600',
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
for s,ss in scalars_dict.items(): ## e.g. where s='r_uIIvII' & ss=[ ( 'rho', ('u',True ), ('v',True ) ), True,True,False ]
|
|
273
|
+
|
|
274
|
+
if verbose: tqdm.write(72*'-')
|
|
275
|
+
|
|
276
|
+
recipe, do_mean, do_pdf, do_skew_kurt = ss
|
|
277
|
+
|
|
278
|
+
if verbose:
|
|
279
|
+
tqdm.write(even_print('computing',s,s=True,))
|
|
280
|
+
|
|
281
|
+
## should ρ be read?
|
|
282
|
+
read_rho = False
|
|
283
|
+
for s_ in recipe:
|
|
284
|
+
if isinstance(s_, str) and (s_=='rho'):
|
|
285
|
+
read_rho = True
|
|
286
|
+
elif isinstance(s_, str) and (s_!='rho'):
|
|
287
|
+
pass
|
|
288
|
+
elif isinstance(s_, tuple):
|
|
289
|
+
if not isinstance(s_[1], bool):
|
|
290
|
+
raise ValueError
|
|
291
|
+
if s_[1]: ## i.e. density-weighted
|
|
292
|
+
read_rho = True
|
|
293
|
+
else:
|
|
294
|
+
raise ValueError
|
|
295
|
+
|
|
296
|
+
## [x] loop (rank-local)
|
|
297
|
+
for ii in range(ri1,ri2):
|
|
298
|
+
|
|
299
|
+
iii = ii - ri1
|
|
300
|
+
|
|
301
|
+
## read ρ
|
|
302
|
+
if read_rho:
|
|
303
|
+
|
|
304
|
+
dset = self['data/rho']
|
|
305
|
+
self.comm.Barrier()
|
|
306
|
+
t_start = timeit.default_timer()
|
|
307
|
+
if self.usingmpi:
|
|
308
|
+
with dset.collective:
|
|
309
|
+
rho = np.copy( dset[ii,:,:] )
|
|
310
|
+
else:
|
|
311
|
+
rho = np.copy( dset[ii,:,:] )
|
|
312
|
+
self.comm.Barrier()
|
|
313
|
+
t_delta = timeit.default_timer() - t_start
|
|
314
|
+
data_gb = self.n_ranks * 1 * self.nj * self.nt * dset.dtype.itemsize / 1024**3
|
|
315
|
+
if verbose:
|
|
316
|
+
tqdm.write(even_print('read: ρ', '%0.3f [GB] %0.3f [s] %0.3f [GB/s]'%(data_gb,t_delta,(data_gb/t_delta)), s=True))
|
|
317
|
+
|
|
318
|
+
rho = rho.astype(np.float64) ## cast to double
|
|
319
|
+
|
|
320
|
+
## re-dimensionalize
|
|
321
|
+
rho *= self.rho_inf
|
|
322
|
+
|
|
323
|
+
if ( rho.shape != (nj,nt) ):
|
|
324
|
+
raise ValueError
|
|
325
|
+
print(f'rank {self.rank:d}: shape violation')
|
|
326
|
+
self.comm.Abort(1)
|
|
327
|
+
|
|
328
|
+
## ρ mean in [t] --> leave (j,1)
|
|
329
|
+
rho_avg = np.mean(rho, axis=-1, dtype=np.float64, keepdims=True)
|
|
330
|
+
|
|
331
|
+
else:
|
|
332
|
+
rho = None ; del rho
|
|
333
|
+
rho_avg = None ; del rho_avg
|
|
334
|
+
|
|
335
|
+
## product buffer for multiplication --> !!! notices ones() here and not zeros() !!!
|
|
336
|
+
#data_accum = np.ones(shape=(ni,nj,nt), dtype=np.float64) ## chunk range context
|
|
337
|
+
data_accum = np.ones(shape=(nj,nt), dtype=np.float64) ## chunk range context
|
|
338
|
+
|
|
339
|
+
## read unsteady scalar data, remove mean, <density weight>, multiply
|
|
340
|
+
for sss in recipe:
|
|
341
|
+
|
|
342
|
+
if isinstance(sss, str) and (sss=='rho'): ## ρ
|
|
343
|
+
|
|
344
|
+
## multiply product accumulator, ρ was already read and is already dimensional
|
|
345
|
+
data_accum *= rho
|
|
346
|
+
|
|
347
|
+
elif isinstance(sss, str) and (sss!='rho'): ## scalar which will NOT be mean-removed
|
|
348
|
+
|
|
349
|
+
## read
|
|
350
|
+
dset = self[f'data/{sss}']
|
|
351
|
+
self.comm.Barrier()
|
|
352
|
+
t_start = timeit.default_timer()
|
|
353
|
+
if self.usingmpi:
|
|
354
|
+
with dset.collective:
|
|
355
|
+
data_X = np.copy( dset[ii,:,:] )
|
|
356
|
+
else:
|
|
357
|
+
data_X = np.copy( dset[ii,:,:] )
|
|
358
|
+
self.comm.Barrier()
|
|
359
|
+
t_delta = timeit.default_timer() - t_start
|
|
360
|
+
data_gb = self.n_ranks * 1 * self.nj * self.nt * dset.dtype.itemsize / 1024**3
|
|
361
|
+
if verbose:
|
|
362
|
+
tqdm.write(even_print(f'read: {sss}', '%0.3f [GB] %0.3f [s] %0.3f [GB/s]'%(data_gb,t_delta,(data_gb/t_delta)), s=True))
|
|
363
|
+
|
|
364
|
+
data_X = data_X.astype(np.float64) ## cast to double
|
|
365
|
+
|
|
366
|
+
if ( data_X.shape != (nj,nt) ):
|
|
367
|
+
raise ValueError
|
|
368
|
+
print(f'rank {self.rank:d}: shape violation')
|
|
369
|
+
self.comm.Abort(1)
|
|
370
|
+
|
|
371
|
+
## redimensionalize
|
|
372
|
+
if sss in ['tau_uy','tau_vy','tau_wy']:
|
|
373
|
+
data_X *= self.rho_inf * self.U_inf**2
|
|
374
|
+
elif sss in ['u_tau','v_tau','w_tau']:
|
|
375
|
+
data_X *= self.U_inf
|
|
376
|
+
elif sss in ['T',]:
|
|
377
|
+
data_X *= self.T_inf
|
|
378
|
+
elif sss in ['rho',]:
|
|
379
|
+
data_X *= self.rho_inf
|
|
380
|
+
elif sss in ['p',]:
|
|
381
|
+
data_X *= self.rho_inf * self.U_inf**2
|
|
382
|
+
else:
|
|
383
|
+
raise ValueError(f"condition needed for redimensionalizing '{str(sss)}'")
|
|
384
|
+
|
|
385
|
+
## MULTIPLY product accumulator
|
|
386
|
+
data_accum *= data_X
|
|
387
|
+
|
|
388
|
+
elif isinstance(sss, tuple): ## scalar which WILL be mean-removed (with- or without ρ-weighting)
|
|
389
|
+
|
|
390
|
+
if (len(sss)!=2):
|
|
391
|
+
raise ValueError
|
|
392
|
+
|
|
393
|
+
sn, do_density_weighting = sss ## e.g. ('u',True)
|
|
394
|
+
|
|
395
|
+
## read
|
|
396
|
+
dset = self[f'data/{sn}']
|
|
397
|
+
self.comm.Barrier()
|
|
398
|
+
t_start = timeit.default_timer()
|
|
399
|
+
if self.usingmpi:
|
|
400
|
+
with dset.collective:
|
|
401
|
+
data_X = np.copy( dset[ii,:,:] )
|
|
402
|
+
else:
|
|
403
|
+
data_X = np.copy( dset[ii,:,:] )
|
|
404
|
+
self.comm.Barrier()
|
|
405
|
+
t_delta = timeit.default_timer() - t_start
|
|
406
|
+
data_gb = self.n_ranks * 1 * self.nj * self.nt * dset.dtype.itemsize / 1024**3
|
|
407
|
+
if verbose:
|
|
408
|
+
tqdm.write(even_print(f'read: {sn}', '%0.3f [GB] %0.3f [s] %0.3f [GB/s]'%(data_gb,t_delta,(data_gb/t_delta)), s=True))
|
|
409
|
+
|
|
410
|
+
data_X = data_X.astype(np.float64) ## cast to double
|
|
411
|
+
|
|
412
|
+
## redimensionalize
|
|
413
|
+
if sn in ['tau_uy','tau_vy','tau_wy']:
|
|
414
|
+
data_X *= self.rho_inf * self.U_inf**2
|
|
415
|
+
elif sn in ['u_tau','v_tau','w_tau']:
|
|
416
|
+
data_X *= self.U_inf
|
|
417
|
+
elif sn in ['T',]:
|
|
418
|
+
data_X *= self.T_inf
|
|
419
|
+
elif sn in ['rho',]:
|
|
420
|
+
data_X *= self.rho_inf
|
|
421
|
+
elif sn in ['p',]:
|
|
422
|
+
data_X *= self.rho_inf * self.U_inf**2
|
|
423
|
+
else:
|
|
424
|
+
raise ValueError(f"condition needed for redimensionalizing '{str(sn)}'")
|
|
425
|
+
|
|
426
|
+
## avg(□) or avg(ρ·□)/avg(ρ)
|
|
427
|
+
if do_density_weighting:
|
|
428
|
+
data_X_mean = np.mean( rho*data_X , axis=-1, dtype=np.float64, keepdims=True) ## (nz,1)
|
|
429
|
+
data_X_mean /= rho_avg
|
|
430
|
+
else:
|
|
431
|
+
data_X_mean = np.mean( data_X , axis=-1, dtype=np.float64, keepdims=True) ## (nz,1)
|
|
432
|
+
|
|
433
|
+
## Reynolds prime □′ or Favre prime □″
|
|
434
|
+
data_X -= data_X_mean
|
|
435
|
+
|
|
436
|
+
## assert avg(□′)==0 or avg(ρ·□″)==0
|
|
437
|
+
if do_density_weighting:
|
|
438
|
+
a_ = np.mean(rho*data_X, axis=-1, dtype=np.float64, keepdims=True)
|
|
439
|
+
else:
|
|
440
|
+
a_ = np.mean(data_X, axis=-1, dtype=np.float64, keepdims=True)
|
|
441
|
+
if not np.allclose( a_, np.zeros_like(a_), atol=1e-3 ):
|
|
442
|
+
print(f'rank {self.rank:d}: avg(□′)!=0 or avg(ρ·□″)!=0')
|
|
443
|
+
self.comm.Abort(1)
|
|
444
|
+
|
|
445
|
+
## MULTIPLY product accumulator by □′ | □″
|
|
446
|
+
data_accum *= data_X
|
|
447
|
+
|
|
448
|
+
else:
|
|
449
|
+
raise ValueError
|
|
450
|
+
|
|
451
|
+
# ===============================================================================
|
|
452
|
+
# At this point you have the UNSTEADY 2D [j,t] data according to 'recipe'
|
|
453
|
+
# ===============================================================================
|
|
454
|
+
|
|
455
|
+
#xiA = cx1 - rx1
|
|
456
|
+
#xiB = cx2 - rx1
|
|
457
|
+
|
|
458
|
+
self.comm.Barrier()
|
|
459
|
+
t_start = timeit.default_timer()
|
|
460
|
+
|
|
461
|
+
## mean in [t] --> leave [j,1]
|
|
462
|
+
d_mean = np.mean( data_accum, axis=-1, keepdims=True, dtype=np.float64)
|
|
463
|
+
#if ( d_mean.shape != (ni,nj,1,) ):
|
|
464
|
+
if ( d_mean.shape != (nj,1) ):
|
|
465
|
+
raise ValueError
|
|
466
|
+
print(f'rank {self.rank:d}: shape violation')
|
|
467
|
+
self.comm.Abort(1)
|
|
468
|
+
|
|
469
|
+
if do_mean: ## mean in [j] --> leave float
|
|
470
|
+
data_avg[s][iii] = np.mean( d_mean, axis=(0,1), dtype=np.float64)
|
|
471
|
+
|
|
472
|
+
if do_pdf:
|
|
473
|
+
|
|
474
|
+
d_ = np.copy( data_accum.ravel() )
|
|
475
|
+
if ( d_.shape != (nj*nt,) ):
|
|
476
|
+
raise ValueError
|
|
477
|
+
print(f'rank {self.rank:d}: shape violation')
|
|
478
|
+
self.comm.Abort(1)
|
|
479
|
+
pdf_ , bin_edges_ = np.histogram( d_ , bins=n_bins , density=True )
|
|
480
|
+
data_bins[s][iii,:] = bin_edges_
|
|
481
|
+
data_pdf[s][iii,:] = pdf_
|
|
482
|
+
|
|
483
|
+
if do_skew_kurt:
|
|
484
|
+
|
|
485
|
+
d_ = np.copy( data_accum.ravel() ) ## □′ or □″, although mean ==0 is not checked
|
|
486
|
+
if ( d_.shape != (nj*nt,) ):
|
|
487
|
+
raise ValueError
|
|
488
|
+
print(f'rank {self.rank:d}: shape violation')
|
|
489
|
+
self.comm.Abort(1)
|
|
490
|
+
|
|
491
|
+
## ## is it interpretable as a Reynolds mean-removed quantity? (□′)
|
|
492
|
+
## interpretable_as_Re_mean = False
|
|
493
|
+
## a_ = np.mean(d_, axis=3, dtype=np.float64, keepdims=True) ## mean in [t]
|
|
494
|
+
## np.testing.assert_equal( a_.shape, (nx,1,nz,1,) )
|
|
495
|
+
## if np.allclose(a_, np.zeros_like(a_), atol=1e-10):
|
|
496
|
+
## interpretable_as_Re_mean = True
|
|
497
|
+
##
|
|
498
|
+
## ## is it interpretable as a Favre mean-removed quantity? (□″)
|
|
499
|
+
## interpretable_as_Fv_mean = False
|
|
500
|
+
## if read_rho and not interpretable_as_Re_mean:
|
|
501
|
+
## #rho_ = np.copy( rho[:,yii,:,:] )
|
|
502
|
+
## rho_ = np.zeros(shape=(nx,1,nz,nt), dtype=dtype_unsteady)
|
|
503
|
+
## rho_[:,:,:,:] = rho[:,yii,:,:][:,np.newaxis,:,:] ## [x,1,z,t]
|
|
504
|
+
## np.testing.assert_equal( rho_.shape, (nx,1,nz,nt) )
|
|
505
|
+
##
|
|
506
|
+
## a_ = np.mean(d_*rho_, axis=3, dtype=np.float64, keepdims=True) ## mean in [t]
|
|
507
|
+
## np.testing.assert_equal( a_.shape, (nx,1,nz,1,) )
|
|
508
|
+
## if np.allclose(a_, np.zeros_like(a_), atol=1e-10):
|
|
509
|
+
## interpretable_as_Fv_mean = True
|
|
510
|
+
##
|
|
511
|
+
## if (not interpretable_as_Re_mean) and (not interpretable_as_Fv_mean):
|
|
512
|
+
## print(f'{s} has non-zero Favre and Reynolds mean, i.e. is not <□′>!=0 and <ρ□″>!=0')
|
|
513
|
+
## self.comm.Abort(1)
|
|
514
|
+
|
|
515
|
+
d_std = np.sqrt( np.mean( d_**2 , dtype=np.float64 ) )
|
|
516
|
+
|
|
517
|
+
if np.isclose(d_std, 0., atol=1e-08):
|
|
518
|
+
d_skew = 0.
|
|
519
|
+
d_kurt = 0.
|
|
520
|
+
else:
|
|
521
|
+
d_skew = np.mean( d_**3 , dtype=np.float64 ) / d_std**3
|
|
522
|
+
d_kurt = np.mean( d_**4 , dtype=np.float64 ) / d_std**4
|
|
523
|
+
|
|
524
|
+
data_hos[f'{s}_skew'][iii] = d_skew
|
|
525
|
+
data_hos[f'{s}_kurt'][iii] = d_kurt
|
|
526
|
+
|
|
527
|
+
self.comm.Barrier() ## [x] loop ('ii' within this rank's range)
|
|
528
|
+
if verbose: progress_bar.update()
|
|
529
|
+
|
|
530
|
+
self.comm.Barrier()
|
|
531
|
+
if verbose:
|
|
532
|
+
progress_bar.close()
|
|
533
|
+
print(72*'-')
|
|
534
|
+
|
|
535
|
+
# ==============================================================
|
|
536
|
+
# write HDF5 (.h5) file
|
|
537
|
+
# ==============================================================
|
|
538
|
+
|
|
539
|
+
## open on rank 0 and write attributes, dimensions, etc.
|
|
540
|
+
if (self.rank==0):
|
|
541
|
+
with h5py.File(fn_h5_stats, 'w') as hfw:
|
|
542
|
+
|
|
543
|
+
## write floats,ints as top-level attributes
|
|
544
|
+
for key,val in data.items():
|
|
545
|
+
if isinstance(data[key], (int,np.int32,np.int64)):
|
|
546
|
+
hfw.attrs[key] = val
|
|
547
|
+
elif isinstance(data[key], (float,np.float32,np.float64)):
|
|
548
|
+
hfw.attrs[key] = val
|
|
549
|
+
elif isinstance(data[key], np.ndarray):
|
|
550
|
+
pass
|
|
551
|
+
else:
|
|
552
|
+
print(f'key {key} is type {str(type(data[key]))}')
|
|
553
|
+
self.comm.Abort(1)
|
|
554
|
+
|
|
555
|
+
## write numpy arrays
|
|
556
|
+
hfw.create_dataset( 'dims/x' , data=x ) ## [m]
|
|
557
|
+
hfw.create_dataset( 'dims/z' , data=z ) ## [m]
|
|
558
|
+
hfw.create_dataset( 'dims/t' , data=t ) ## [s]
|
|
559
|
+
|
|
560
|
+
## initialize datasets
|
|
561
|
+
for scalar in scalars_avg:
|
|
562
|
+
hfw.create_dataset( f'avg/{scalar}', shape=(nx,), dtype=np.float64, chunks=(1,) )
|
|
563
|
+
for scalar in scalars_pdf:
|
|
564
|
+
hfw.create_dataset( f'bins/{scalar}', shape=(nx,n_bins+1), dtype=np.float64, chunks=(1,n_bins+1) )
|
|
565
|
+
for scalar in scalars_pdf:
|
|
566
|
+
hfw.create_dataset( f'pdf/{scalar}', shape=(nx,n_bins), dtype=np.float64, chunks=(1,n_bins) )
|
|
567
|
+
for scalar in scalars_hos:
|
|
568
|
+
hfw.create_dataset( f'hos/{scalar}', shape=(nx,), dtype=np.float64, chunks=(1,) )
|
|
569
|
+
|
|
570
|
+
self.comm.Barrier()
|
|
571
|
+
time.sleep(2.)
|
|
572
|
+
self.comm.Barrier()
|
|
573
|
+
|
|
574
|
+
with h5py.File(fn_h5_stats, 'a', driver='mpio', comm=self.comm) as hfw:
|
|
575
|
+
|
|
576
|
+
# === collectively write data
|
|
577
|
+
|
|
578
|
+
for scalar in scalars_avg:
|
|
579
|
+
dset = hfw[f'avg/{scalar}']
|
|
580
|
+
with dset.collective:
|
|
581
|
+
dset[ri1:ri2] = data_avg[scalar][:]
|
|
582
|
+
self.comm.Barrier()
|
|
583
|
+
|
|
584
|
+
for scalar in scalars_pdf:
|
|
585
|
+
dset = hfw[f'bins/{scalar}']
|
|
586
|
+
with dset.collective:
|
|
587
|
+
dset[ri1:ri2,:] = data_bins[scalar][:,:]
|
|
588
|
+
self.comm.Barrier()
|
|
589
|
+
|
|
590
|
+
for scalar in scalars_pdf:
|
|
591
|
+
dset = hfw[f'pdf/{scalar}']
|
|
592
|
+
with dset.collective:
|
|
593
|
+
dset[ri1:ri2,:] = data_pdf[scalar][:,:]
|
|
594
|
+
self.comm.Barrier()
|
|
595
|
+
|
|
596
|
+
for scalar in scalars_hos:
|
|
597
|
+
dset = hfw[f'hos/{scalar}']
|
|
598
|
+
with dset.collective:
|
|
599
|
+
dset[ri1:ri2] = data_hos[scalar][:]
|
|
600
|
+
self.comm.Barrier()
|
|
601
|
+
|
|
602
|
+
## report file size
|
|
603
|
+
if verbose:
|
|
604
|
+
even_print( os.path.basename(fn_h5_stats), f'{(os.path.getsize(fn_h5_stats)/1024**2):0.2f} [MB]' )
|
|
605
|
+
print(72*'-')
|
|
606
|
+
|
|
607
|
+
## report file contents
|
|
608
|
+
self.comm.Barrier()
|
|
609
|
+
if (self.rank==0):
|
|
610
|
+
with h5py.File(fn_h5_stats,'r') as hfr:
|
|
611
|
+
h5_print_contents(hfr)
|
|
612
|
+
self.comm.Barrier()
|
|
613
|
+
|
|
614
|
+
if verbose: print(72*'-')
|
|
615
|
+
if verbose: print('total time : spd.calc_statistics_wall() : %s'%format_time_string((timeit.default_timer() - t_start_func)))
|
|
616
|
+
if verbose: print(72*'-')
|
|
617
|
+
return
|
|
618
|
+
|