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.
@@ -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
+