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,738 @@
1
+ import os
2
+ import re
3
+ import sys
4
+ import timeit
5
+ from pathlib import Path, PurePosixPath
6
+
7
+ import h5py
8
+ import numpy as np
9
+ import psutil
10
+ from mpi4py import MPI
11
+ from tqdm import tqdm
12
+
13
+ from .h5 import h5_print_contents
14
+ from .utils import even_print, format_time_string
15
+
16
+ # ======================================================================
17
+
18
+ def _calc_statistics_xpln(self,**kwargs):
19
+ '''
20
+ calculate statistics for an unsteady volumetric measurement
21
+ which has a small number of points in the [x] direction
22
+ - mean
23
+ - covariance
24
+ - skewness, kurtosis
25
+ - probability distribution function (PDF)
26
+ '''
27
+
28
+ if (self.rank==0):
29
+ verbose = True
30
+ else:
31
+ verbose = False
32
+
33
+ if verbose: print('\n'+'rgd.calc_statistics_xpln()'+'\n'+72*'-')
34
+ t_start_func = timeit.default_timer()
35
+
36
+ ## assert that the opened RGD has fsubtype 'unsteady' (i.e. is NOT a prime file)
37
+ if (self.fsubtype!='unsteady'):
38
+ raise ValueError
39
+
40
+ rx = kwargs.get('rx',1)
41
+ ry = kwargs.get('ry',1)
42
+ rz = kwargs.get('rz',1)
43
+ rt = kwargs.get('rt',1)
44
+
45
+ # cy = kwargs.get('cy',1) ## number of subdivisions per rank [y] range
46
+ # if not isinstance(cy,int):
47
+ # raise TypeError('cy should be an int')
48
+ # if (cy<1):
49
+ # raise TypeError('cy should be an int')
50
+
51
+ sy = kwargs.get('sy',1) ## number of [y] layers to read at a time
52
+ if not isinstance(sy,int) or (sy<1):
53
+ raise TypeError('sy should be a positive non-zero int')
54
+
55
+ #n_threads = kwargs.get('n_threads',1)
56
+ try:
57
+ n_threads = int(os.environ.get('OMP_NUM_THREADS'))
58
+ except TypeError: ## not set
59
+ n_threads = os.cpu_count()
60
+
61
+ #fn_dat_stats = kwargs.get('fn_dat_stats',None) ## filename for output pickle (.dat) file
62
+ fn_h5_out = kwargs.get('fn_h5_out',None) ## filename for output HDF5 (.h5) file
63
+
64
+ n_bins = kwargs.get('n_bins',512) ## n bins for histogram (PDF) calculation
65
+
66
+ ## for now only distribute data in [y] --> allows [x,z] mean before Send/Recv
67
+ if (rx!=1):
68
+ raise AssertionError('rx!=1')
69
+ if (rz!=1):
70
+ raise AssertionError('rz!=1')
71
+ if (rt!=1):
72
+ raise AssertionError('rt!=1')
73
+
74
+ if not isinstance(ry,int) or (ry<1):
75
+ raise ValueError('ry should be a positive non-zero int')
76
+
77
+ ## check the choice of ranks per dimension
78
+ if (rx*ry*rz*rt != self.n_ranks):
79
+ raise AssertionError('rx*ry*rz*rt != self.n_ranks')
80
+ if (rx>self.nx):
81
+ raise AssertionError('rx>self.nx')
82
+ if (ry>self.ny):
83
+ raise AssertionError('ry>self.ny')
84
+ if (rz>self.nz):
85
+ raise AssertionError('rz>self.nz')
86
+ if (rt>self.nt):
87
+ raise AssertionError('rt>self.nt')
88
+
89
+ if (self.ny%ry!=0):
90
+ raise ValueError('ny not divisible by ry')
91
+
92
+ ## distribute 4D data over ranks --> here only in [y]
93
+ ryl_ = np.array_split(np.arange(self.ny,dtype=np.int64),ry)
94
+ ryl = [[b[0],b[-1]+1] for b in ryl_ ]
95
+ ry1,ry2 = ryl[self.rank]
96
+ nyr = ry2 - ry1
97
+
98
+ ## check all [y] ranges have same size
99
+ for ryl_ in ryl:
100
+ if not (ryl_[1]-ryl_[0]==nyr):
101
+ raise ValueError('[y] chunks are not even in size')
102
+
103
+ # ## [y] sub chunk range --> cyl = list of ranges in ry1:ry2
104
+ # ## cy is the NUMBER of chunks for the rank sub-range
105
+ # cyl_ = np.array_split( np.arange(ry1,ry2) , min(cy,nyr) )
106
+ # cyl = [[b[0],b[-1]+1] for b in cyl_ ]
107
+ #
108
+ # for nyc_ in [ cyl_[1]-cyl_[0] for cyl_ in cyl ]:
109
+ # if (nyc_ < 1):
110
+ # #raise ValueError
111
+ # print(f'rank {self.rank:d}: sub-range is <1')
112
+ # self.comm.Abort(1)
113
+ #
114
+ # if 1: ## assert that [y] sub-chunk ranges are correct
115
+ #
116
+ # yi = np.arange(self.ny, dtype=np.int32)
117
+ #
118
+ # local_indices = []
119
+ # for cyl_ in cyl:
120
+ # cy1, cy2 = cyl_
121
+ # local_indices += [ yi_ for yi_ in yi[cy1:cy2] ]
122
+ #
123
+ # G = self.comm.gather([ self.rank , local_indices ], root=0)
124
+ # G = self.comm.bcast(G, root=0)
125
+ #
126
+ # all_indices = []
127
+ # for G_ in G:
128
+ # all_indices += G_[1]
129
+ # all_indices = np.array( sorted(all_indices), dtype=np.int32 )
130
+ #
131
+ # if not np.array_equal( all_indices , yi ):
132
+ # raise AssertionError
133
+
134
+ if (nyr%sy!=0):
135
+ raise ValueError('nyr not divisible by sy')
136
+
137
+ ## output filename : HDF5 (.h5)
138
+ if (fn_h5_out is None): ## automatically determine name
139
+ fname_path = os.path.dirname(self.fname)
140
+ fname_base = os.path.basename(self.fname)
141
+ fname_root, fname_ext = os.path.splitext(fname_base)
142
+ fname_root = re.findall(r'io\S+_mpi_[0-9]+', fname_root)[0]
143
+ fname_stats_h5_base = fname_root+'_stats.h5'
144
+ fn_h5_out = str(PurePosixPath(fname_path, fname_stats_h5_base))
145
+ if (Path(fn_h5_out).suffix != '.h5'):
146
+ raise ValueError(f"fn_h5_out='{str(fn_h5_out)}' must end in .h5")
147
+ if os.path.isfile(fn_h5_out):
148
+ #if (os.path.getsize(fn_h5_out) > 8*1024**3):
149
+ # raise ValueError(f"fn_h5_out='{str(fn_h5_out)}' exists and is >8 [GB]. exiting for your own safety.")
150
+ if (fn_h5_out == self.fname):
151
+ raise ValueError(f"fn_h5_out='{str(fn_h5_out)}' cannot be same as input filename.")
152
+
153
+ # ===
154
+
155
+ if verbose: even_print( 'fn_h5' , self.fname )
156
+ if verbose: even_print( 'fn_h5_out' , fn_h5_out )
157
+ if verbose: print(72*'-')
158
+ self.comm.Barrier()
159
+
160
+ ## the data dictionary to be pickled later
161
+ data = {}
162
+
163
+ ## infile
164
+ fsize = os.path.getsize(self.fname)/1024**3
165
+ if verbose: even_print(os.path.basename(self.fname),'%0.1f [GB]'%fsize)
166
+ if verbose: even_print('nx',f'{self.nx:d}')
167
+ if verbose: even_print('ny',f'{self.ny:d}')
168
+ if verbose: even_print('nz',f'{self.nz:d}')
169
+ if verbose: even_print('nt',f'{self.nt:d}')
170
+ if verbose: even_print('ngp',f'{self.ngp/1e6:0.1f} [M]')
171
+ #if verbose: even_print('cy',f'{cy:d}')
172
+ if verbose: even_print('sy',f'{sy:d}')
173
+ if verbose: even_print('n_ranks',f'{self.n_ranks:d}')
174
+ if verbose: even_print('n_threads',f'{n_threads:d}')
175
+ if verbose: print(72*'-')
176
+
177
+ ## 0D freestream scalars
178
+ lchar = self.lchar ; data['lchar'] = lchar
179
+ U_inf = self.U_inf ; data['U_inf'] = U_inf
180
+ rho_inf = self.rho_inf ; data['rho_inf'] = rho_inf
181
+ T_inf = self.T_inf ; data['T_inf'] = T_inf
182
+
183
+ #data['M_inf'] = self.M_inf
184
+ data['Ma'] = self.Ma
185
+ data['Pr'] = self.Pr
186
+
187
+ ## read in 1D coordinate arrays & re-dimensionalize
188
+ x = np.copy( self['dims/x'][()] * self.lchar )
189
+ y = np.copy( self['dims/y'][()] * self.lchar )
190
+ z = np.copy( self['dims/z'][()] * self.lchar )
191
+ t = np.copy( self['dims/t'][()] * self.tchar )
192
+
193
+ nx = self.nx ; data['nx'] = nx
194
+ ny = self.ny ; data['ny'] = ny
195
+ nz = self.nz ; data['nz'] = nz
196
+ nt = self.nt ; data['nt'] = nt
197
+
198
+ ## assert constant Δz
199
+ dz0 = np.diff(z)[0]
200
+ if not np.all(np.isclose(np.diff(z), dz0, rtol=1e-6)):
201
+ raise NotImplementedError('Δz not constant')
202
+ dz = np.diff(z)[0]
203
+
204
+ ## dimensional [s]
205
+ dt = self.dt * self.tchar
206
+ np.testing.assert_allclose(dt, t[1]-t[0], rtol=1e-12, atol=1e-12)
207
+
208
+ t_meas = self.duration * self.tchar
209
+ np.testing.assert_allclose(t_meas, t.max()-t.min(), rtol=1e-12, atol=1e-12)
210
+
211
+ zrange = z.max() - z.min()
212
+
213
+ data['x'] = x
214
+ data['y'] = y
215
+ data['z'] = z
216
+
217
+ data['t'] = t
218
+ data['t_meas'] = t_meas
219
+ data['dt'] = dt
220
+ data['dz'] = dz
221
+ data['zrange'] = zrange
222
+
223
+ if verbose: even_print( 'Δt/tchar' , f'{dt/self.tchar:0.8f}' )
224
+ if verbose: even_print( 'Δt' , f'{dt:0.3e} [s]' )
225
+ if verbose: even_print( 'duration/tchar' , f'{self.duration:0.1f}' )
226
+ if verbose: even_print( 'duration' , f'{self.duration*self.tchar:0.3e} [s]' )
227
+ if verbose: print(72*'-')
228
+
229
+ ## report
230
+ if verbose:
231
+ even_print('Δt' , f'{dt :0.5e} [s]' )
232
+ even_print('t_meas' , f'{t_meas:0.5e} [s]' )
233
+ even_print('Δz' , f'{dz0 :0.5e} [m]' )
234
+ even_print('zrange' , f'{zrange:0.5e} [m]' )
235
+ #print(72*'-')
236
+
237
+ # ===
238
+
239
+ ## key = str:scalar name
240
+ ## value = tuple:recipe,
241
+ ## bool:do_mean,
242
+ ## bool:do_pdf,
243
+ ## bool:do_skew_kurt
244
+ ##
245
+ ## recipe elements:
246
+ ## - if tuple : ( str:scalar , bool:ρ weighting ) --> always mean-removed
247
+ ## - if str : str:scalar
248
+
249
+ scalars_dict = {
250
+
251
+ 'r_uIIuII' : [ ( 'rho', ('u',True ), ('u',True ) ), True,True,True ], ## ρ·u″u″
252
+ 'r_vIIvII' : [ ( 'rho', ('v',True ), ('v',True ) ), True,True,True ], ## ρ·v″v″
253
+ 'r_wIIwII' : [ ( 'rho', ('w',True ), ('w',True ) ), True,True,True ], ## ρ·w″w″
254
+ 'r_uIIvII' : [ ( 'rho', ('u',True ), ('v',True ) ), True,True,True ], ## ρ·u″v″
255
+ 'r_uIIwII' : [ ( 'rho', ('u',True ), ('w',True ) ), True,True,True ], ## ρ·u″w″
256
+ 'r_vIIwII' : [ ( 'rho', ('v',True ), ('w',True ) ), True,True,True ], ## ρ·v″w″
257
+
258
+ 'uIuI' : [ ( ('u',False), ('u',False) ), True,True,True ], ## u′u′
259
+ 'vIvI' : [ ( ('v',False), ('v',False) ), True,True,True ], ## v′v′
260
+ 'wIwI' : [ ( ('w',False), ('w',False) ), True,True,True ], ## w′w′
261
+ 'uIvI' : [ ( ('u',False), ('v',False) ), True,True,True ], ## u′v′
262
+ 'uIwI' : [ ( ('u',False), ('w',False) ), True,True,True ], ## u′w′
263
+ 'vIwI' : [ ( ('v',False), ('w',False) ), True,True,True ], ## v′w′
264
+
265
+ 'uITI' : [ ( ('u',False), ('T',False) ), True,True,True ], ## u′T′
266
+ 'vITI' : [ ( ('v',False), ('T',False) ), True,True,True ], ## v′T′
267
+ 'wITI' : [ ( ('w',False), ('T',False) ), True,True,True ], ## w′T′
268
+
269
+ 'TITI' : [ ( ('T',False), ('T',False) ), True,True,False ], ## T′T′
270
+ 'TIITII' : [ ( ('T',True ), ('T',True ) ), True,True,False ], ## T″T″
271
+ 'r_TIITII' : [ ( 'rho', ('T',True ), ('T',True ) ), True,True,False ], ## ρ·T″T″
272
+
273
+ 'rho' : [ ( 'rho', ) , True, True, False, ], ## ρ
274
+ 'rhoI' : [ ( ('rho',False), ) , False, True, True, ], ## ρ′
275
+
276
+ 'T' : [ ( 'T', ) , True, True, False, ], ## T
277
+ 'TI' : [ ( ('T',False), ) , False, True, True, ], ## T′
278
+ 'TII' : [ ( ('T',True ), ) , False, True, True, ], ## T″
279
+ 'r_TII' : [ ( 'rho', ('T',True ), ) , False, True, True, ], ## ρ·T″
280
+
281
+ 'p' : [ ( 'p', ) , True, True, False, ], ## p
282
+ 'pI' : [ ( ('p',False), ) , False, True, True, ], ## p′
283
+
284
+ 'u' : [ ( 'u', ) , True, True, False, ], ## u
285
+ 'uI' : [ ( ('u',False), ) , False, True, True, ], ## u′
286
+ #'uII' : [ ( ('u',True ), ) , False, True, True, ], ## u″
287
+ 'r_uII' : [ ( 'rho', ('u',True ), ) , False, True, True, ], ## ρ·u″
288
+
289
+ 'v' : [ ( 'v', ) , True, True, False, ], ## v
290
+ 'vI' : [ ( ('v',False), ) , False, True, True, ], ## v′
291
+ 'r_vII' : [ ( 'rho', ('v',True ), ) , False, True, True, ], ## ρ·v″
292
+
293
+ 'w' : [ ( 'w', ) , True, True, False, ], ## w
294
+ 'wI' : [ ( ('w',False), ) , False, True, True, ], ## w′
295
+ 'r_wII' : [ ( 'rho', ('w',True ), ) , False, True, True, ], ## ρ·w″
296
+
297
+ }
298
+
299
+ dtype_unsteady = np.float64
300
+
301
+ scalars_avg = []
302
+ scalars_pdf = []
303
+ scalars_hos_ = []
304
+ for s,ss in scalars_dict.items():
305
+ recipe, do_mean, do_pdf, do_skew_kurt = ss
306
+ if do_mean:
307
+ scalars_avg.append(s)
308
+ if do_pdf:
309
+ scalars_pdf.append(s)
310
+ if do_skew_kurt:
311
+ scalars_hos_.append(s)
312
+
313
+ scalars_hos=[]
314
+ for s_ in ['skew','kurt']:
315
+ for ss_ in scalars_hos_:
316
+ scalars_hos.append(f'{ss_}_{s_}')
317
+
318
+ data_avg = np.zeros(shape=(nyr,) , dtype={'names':scalars_avg, 'formats':[ np.float64 for sss in scalars_avg ]})
319
+ data_bins = np.zeros(shape=(nyr,n_bins+1) , dtype={'names':scalars_pdf, 'formats':[ np.float64 for sss in scalars_pdf ]})
320
+ data_pdf = np.zeros(shape=(nyr,n_bins) , dtype={'names':scalars_pdf, 'formats':[ np.float64 for sss in scalars_pdf ]})
321
+ data_hos = np.zeros(shape=(nyr,) , dtype={'names':scalars_hos, 'formats':[ np.float64 for sss in scalars_hos ]})
322
+
323
+ # ==============================================================
324
+ # check memory
325
+ # ==============================================================
326
+
327
+ hostname = MPI.Get_processor_name()
328
+ mem_free_gb = psutil.virtual_memory().free / 1024**3
329
+ G = self.comm.gather([ self.rank , hostname , mem_free_gb ], root=0)
330
+ G = self.comm.bcast(G, root=0)
331
+
332
+ host_mem = {}
333
+ for rank, host, mem in G:
334
+ if host not in host_mem or mem < host_mem[host]:
335
+ host_mem[host] = mem
336
+ total_free = sum(host_mem.values())
337
+
338
+ if verbose:
339
+ print(72*'-')
340
+ for key,value in host_mem.items():
341
+ even_print(f'RAM free {key}', f'{int(np.floor(value)):d} [GB]')
342
+ even_print('RAM free (local,min)', f'{int(np.floor(min(host_mem.values()))):d} [GB]')
343
+ even_print('RAM free (global)', f'{int(np.floor(total_free)):d} [GB]')
344
+
345
+ shape_read = (nx,sy,nz,nt) ## local
346
+ if verbose: even_print('read shape (local)', f'[{nx:d},{sy:d},{nz:d},{nt:d}]')
347
+ data_gb = np.dtype(np.float64).itemsize * np.prod(shape_read) / 1024**3
348
+ if verbose: even_print('read size (global)', f'{int(np.ceil(data_gb*ry)):d} [GB]')
349
+
350
+ if verbose: even_print('read size (global) ×6', f'{int(np.ceil(data_gb*ry*6)):d} [GB]')
351
+ ram_usage_est = data_gb*ry*6/total_free
352
+ if verbose: even_print('RAM usage estimate', f'{100*ram_usage_est:0.1f} [%]')
353
+
354
+ self.comm.Barrier()
355
+ if (ram_usage_est>0.80):
356
+ print('RAM consumption might be too high. exiting.')
357
+ self.comm.Abort(1)
358
+
359
+ # ==============================================================
360
+ # main loop
361
+ # ==============================================================
362
+
363
+ self.comm.Barrier()
364
+ if verbose:
365
+ progress_bar = tqdm(
366
+ #total=cy*len(scalars_dict),
367
+ total=len(scalars_dict)*(nyr//sy),
368
+ ncols=100,
369
+ desc='statistics',
370
+ leave=True,
371
+ file=sys.stdout,
372
+ mininterval=0.1,
373
+ smoothing=0.,
374
+ #bar_format="\033[B{l_bar}{bar}| {n}/{total} [{percentage:.1f}%] {elapsed}/{remaining}\033[A\n\b",
375
+ bar_format="{l_bar}{bar}| {n}/{total} [{percentage:.1f}%] {elapsed}/{remaining}",
376
+ ascii="░█",
377
+ colour='#FF6600',
378
+ )
379
+
380
+ ## scalar dict loop
381
+ for s,ss in scalars_dict.items(): ## e.g. where s='r_uIIvII' & ss=[ ( 'rho', ('u',True ), ('v',True ) ), True,True,False ]
382
+
383
+ if verbose: tqdm.write(72*'-')
384
+
385
+ recipe, do_mean, do_pdf, do_skew_kurt = ss
386
+
387
+ if verbose:
388
+ tqdm.write(even_print('computing',s,s=True,))
389
+
390
+ # if verbose: ## report per-rank read shape
391
+ # nyc_max = max([ cyl_[1]-cyl_[0] for cyl_ in cyl ])
392
+ # data_gb = 8 * nx * nyc_max * nz * nt / 1024**3
393
+ # tqdm.write(even_print('read shape per rank', f'[{nx:d},{nyc_max:d},{nz:d},{nt:d}] · 8 [Bytes] --> {data_gb:0.1f} [GB]', s=True))
394
+ # tqdm.write(even_print('mem per read', f'{self.n_ranks*data_gb:0.1f} [GB]', s=True))
395
+ # tqdm.write(even_print('mem per read ×6', f'{self.n_ranks*data_gb*6.:0.3f} [GB]', s=True)) ## genoa3tb64c, ?R ...
396
+
397
+ ## should ρ be read?
398
+ read_rho = False
399
+ for s_ in recipe:
400
+ if isinstance(s_, str) and (s_=='rho'):
401
+ read_rho = True
402
+ elif isinstance(s_, str) and (s_!='rho'):
403
+ pass
404
+ elif isinstance(s_, tuple):
405
+ if not isinstance(s_[1], bool):
406
+ raise ValueError
407
+ if s_[1]: ## i.e. density-weighted
408
+ read_rho = True
409
+ else:
410
+ raise ValueError
411
+
412
+ ## [y] loop outer (grid subchunks within rank)
413
+ # for cyl_ in cyl:
414
+ # cy1, cy2 = cyl_
415
+ # nyc = cy2 - cy1
416
+
417
+ for ci in range(nyr//sy):
418
+ cy1 = ry1 + ci*sy
419
+ cy2 = cy1 + sy
420
+ nyc = cy2 - cy1
421
+
422
+ ## read ρ
423
+ if read_rho:
424
+
425
+ #rho = np.zeros(shape=(nx,nyc,nz,nt), dtype=dtype_unsteady) ## buffer... chunk range context
426
+
427
+ dset = self['data/rho']
428
+ self.comm.Barrier()
429
+ t_start = timeit.default_timer()
430
+ if self.usingmpi:
431
+ with dset.collective:
432
+ #rho[:,:,:,:] = dset[:,:,cy1:cy2,:].T.astype(np.float64)
433
+ rho = dset[:,:,cy1:cy2,:].T
434
+ else:
435
+ #rho[:,:,:,:] = dset[()].T.astype(np.float64)
436
+ rho = dset[()].T
437
+ self.comm.Barrier()
438
+ t_delta = timeit.default_timer() - t_start
439
+ data_gb = dset.dtype.itemsize * self.nx * ry * (cy2-cy1) * self.nz * self.nt / 1024**3
440
+ if verbose:
441
+ 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))
442
+
443
+ ## cast to double
444
+ rho = rho.astype(np.float64)
445
+
446
+ ## re-dimensionalize
447
+ rho *= self.rho_inf
448
+
449
+ ## ρ mean in [t] --> leave [x,y,z,1]
450
+ rho_avg = np.mean(rho, axis=3, dtype=np.float64, keepdims=True)
451
+
452
+ else:
453
+ rho = None ; del rho
454
+ rho_avg = None ; del rho_avg
455
+
456
+ ## product buffer for multiplication --> !!! notices ones() here and not zeros() !!!
457
+ data_accum = np.ones(shape=(nx,nyc,nz,nt), dtype=dtype_unsteady) ## chunk range context
458
+
459
+ ## read unsteady scalar data, remove mean, <density weight>, multiply
460
+ for sss in recipe:
461
+
462
+ if isinstance(sss, str) and (sss=='rho'): ## ρ
463
+
464
+ ## multiply product accumulator, ρ was already read and is already dimensional
465
+ data_accum *= rho
466
+
467
+ elif isinstance(sss, str) and (sss!='rho'): ## scalar which will NOT be mean-removed
468
+
469
+ #data_X = np.zeros(shape=(nx,nyc,nz,nt), dtype=dtype_unsteady) ## buffer... chunk range context
470
+ dset = self[f'data/{sss}']
471
+
472
+ ## read
473
+ self.comm.Barrier()
474
+ t_start = timeit.default_timer()
475
+ if self.usingmpi:
476
+ with dset.collective:
477
+ #data_X[:,:,:,:] = dset[:,:,cy1:cy2,:].T.astype(np.float64)
478
+ #data_X = np.copy( dset[:,:,cy1:cy2,:].T )
479
+ data_X = dset[:,:,cy1:cy2,:].T
480
+ else:
481
+ #data_X[:,:,:,:] = dset[()].T.astype(np.float64)
482
+ #data_X = np.copy( dset[()].T )
483
+ data_X = dset[()].T
484
+ self.comm.Barrier()
485
+ t_delta = timeit.default_timer() - t_start
486
+ data_gb = dset.dtype.itemsize * self.nx * ry * (cy2-cy1) * self.nz * self.nt / 1024**3
487
+ if verbose:
488
+ 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))
489
+
490
+ ## cast to double
491
+ data_X = data_X.astype(np.float64)
492
+
493
+ ## re-dimensionalize
494
+ if sss in ['u','v','w',]:
495
+ data_X *= self.U_inf
496
+ elif sss in ['T',]:
497
+ data_X *= self.T_inf
498
+ elif sss in ['rho',]:
499
+ data_X *= self.rho_inf
500
+ elif sss in ['p',]:
501
+ data_X *= self.rho_inf * self.U_inf**2
502
+ else:
503
+ raise ValueError(f"condition needed for redimensionalizing '{str(sss)}'")
504
+
505
+ ## MULTIPLY product accumulator
506
+ data_accum *= data_X
507
+
508
+ elif isinstance(sss, tuple): ## scalar which WILL be mean-removed (with- or without ρ-weighting)
509
+
510
+ if (len(sss)!=2):
511
+ raise ValueError
512
+
513
+ sn, do_density_weighting = sss ## e.g. ('u',True)
514
+
515
+ #data_X = np.zeros(shape=(nx,nyc,nz,nt), dtype=dtype_unsteady) ## buffer... chunk range context
516
+ dset = self[f'data/{sn}']
517
+
518
+ ## read
519
+ self.comm.Barrier()
520
+ t_start = timeit.default_timer()
521
+ if self.usingmpi:
522
+ with dset.collective:
523
+ #data_X[:,:,:,:] = dset[:,:,cy1:cy2,:].T.astype(np.float64)
524
+ #data_X = np.copy( dset[:,:,cy1:cy2,:].T )
525
+ data_X = dset[:,:,cy1:cy2,:].T
526
+ else:
527
+ #data_X[:,:,:,:] = dset[()].T.astype(np.float64)
528
+ #data_X = np.copy( dset[()].T )
529
+ data_X = dset[()].T
530
+ self.comm.Barrier()
531
+ t_delta = timeit.default_timer() - t_start
532
+ data_gb = dset.dtype.itemsize * self.nx * ry * (cy2-cy1) * self.nz * self.nt / 1024**3
533
+ if verbose:
534
+ 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))
535
+
536
+ ## cast to double
537
+ data_X = data_X.astype(np.float64)
538
+
539
+ ## redimensionalize
540
+ if sn in ['u','v','w',]:
541
+ data_X *= self.U_inf
542
+ elif sn in ['T',]:
543
+ data_X *= self.T_inf
544
+ elif sn in ['rho',]:
545
+ data_X *= self.rho_inf
546
+ elif sn in ['p',]:
547
+ data_X *= self.rho_inf * self.U_inf**2
548
+ else:
549
+ raise ValueError(f"condition needed for redimensionalizing '{str(sn)}'")
550
+
551
+ ## avg(□) or avg(ρ·□)/avg(ρ)
552
+ if do_density_weighting:
553
+ data_X_mean = np.mean( rho*data_X , axis=3, dtype=np.float64, keepdims=True) ## [x,y,z,1]
554
+ data_X_mean /= rho_avg
555
+ else:
556
+ data_X_mean = np.mean( data_X , axis=3, dtype=np.float64, keepdims=True) ## [x,y,z,1]
557
+
558
+ ## Reynolds prime □′ or Favre prime □″
559
+ data_X -= data_X_mean
560
+
561
+ ## assert avg(□′)==0 or avg(ρ·□″)==0
562
+ if do_density_weighting:
563
+ a_ = np.mean(rho*data_X, axis=3, dtype=np.float64, keepdims=True)
564
+ else:
565
+ a_ = np.mean(data_X, axis=3, dtype=np.float64, keepdims=True)
566
+ #np.testing.assert_allclose(a_, np.zeros_like(a_), atol=1e-3)
567
+ if not np.allclose( a_, np.zeros_like(a_), atol=1e-3 ):
568
+ print(f'rank {self.rank:d}: avg(□′)!=0 or avg(ρ·□″)!=0')
569
+ self.comm.Abort(1)
570
+
571
+ ## MULTIPLY product accumulator by □′ | □″
572
+ data_accum *= data_X
573
+
574
+ else:
575
+ raise ValueError
576
+
577
+ # ===============================================================================
578
+ # At this point you have the UNSTEADY 4D [x,y,z,t] data according to 'recipe'
579
+ # ===============================================================================
580
+
581
+ yiA = cy1 - ry1
582
+ yiB = cy2 - ry1
583
+
584
+ ## mean in [t] --> leave [x,y,z,1]
585
+ d_mean = np.mean( data_accum, axis=(3,), keepdims=True, dtype=np.float64)
586
+ if ( d_mean.shape != (nx,nyc,nz,1,) ):
587
+ print(f'rank {self.rank:d}: shape violation')
588
+ self.comm.Abort(1)
589
+
590
+ if do_mean: ## mean in [x,z] --> leave [y]
591
+ data_avg[s][yiA:yiB] = np.squeeze( np.mean( d_mean, axis=(0,2), dtype=np.float64) )
592
+
593
+ ## [y] loop inner ([y] indices within subdivision within rank)
594
+ for yi in range(cy1,cy2):
595
+
596
+ yii = yi - cy1 ## chunk local
597
+ yiii = yi - ry1 ## rank local
598
+
599
+ if do_pdf:
600
+
601
+ d_ = np.copy( data_accum[:,yii,:,:].ravel() )
602
+ if ( d_.shape != (nx*1*nz*nt,) ):
603
+ print(f'rank {self.rank:d}: shape violation')
604
+ self.comm.Abort(1)
605
+ pdf_ , bin_edges_ = np.histogram( d_ , bins=n_bins , density=True )
606
+ data_bins[s][yiii,:] = bin_edges_
607
+ data_pdf[s][yiii,:] = pdf_
608
+
609
+ if do_skew_kurt:
610
+
611
+ #d_ = np.copy( data_accum[:,yii,:,:] ) ## [x,1,z,t]
612
+ d_ = np.zeros(shape=(nx,1,nz,nt), dtype=dtype_unsteady)
613
+ d_[:,:,:,:] = data_accum[:,yii,:,:][:,np.newaxis,:,:] ## [x,1,z,t]
614
+ if ( d_.shape != (nx,1,nz,nt) ):
615
+ print(f'rank {self.rank:d}: shape violation')
616
+ self.comm.Abort(1)
617
+
618
+ ## ## is it interpretable as a Reynolds mean-removed quantity? (□′)
619
+ ## interpretable_as_Re_mean = False
620
+ ## a_ = np.mean(d_, axis=3, dtype=np.float64, keepdims=True) ## mean in [t]
621
+ ## np.testing.assert_equal( a_.shape, (nx,1,nz,1,) )
622
+ ## if np.allclose(a_, np.zeros_like(a_), atol=1e-10):
623
+ ## interpretable_as_Re_mean = True
624
+ ##
625
+ ## ## is it interpretable as a Favre mean-removed quantity? (□″)
626
+ ## interpretable_as_Fv_mean = False
627
+ ## if read_rho and not interpretable_as_Re_mean:
628
+ ## #rho_ = np.copy( rho[:,yii,:,:] )
629
+ ## rho_ = np.zeros(shape=(nx,1,nz,nt), dtype=dtype_unsteady)
630
+ ## rho_[:,:,:,:] = rho[:,yii,:,:][:,np.newaxis,:,:] ## [x,1,z,t]
631
+ ## np.testing.assert_equal( rho_.shape, (nx,1,nz,nt) )
632
+ ##
633
+ ## a_ = np.mean(d_*rho_, axis=3, dtype=np.float64, keepdims=True) ## mean in [t]
634
+ ## np.testing.assert_equal( a_.shape, (nx,1,nz,1,) )
635
+ ## if np.allclose(a_, np.zeros_like(a_), atol=1e-10):
636
+ ## interpretable_as_Fv_mean = True
637
+ ##
638
+ ## if (not interpretable_as_Re_mean) and (not interpretable_as_Fv_mean):
639
+ ## print(f'{s} has non-zero Favre and Reynolds mean, i.e. is not <□′>!=0 and <ρ□″>!=0')
640
+ ## self.comm.Abort(1)
641
+
642
+ dI = np.copy( d_.ravel() ) ## □′ or □″
643
+ if ( dI.shape != (nx*1*nz*nt,) ):
644
+ print(f'rank {self.rank:d}: shape violation')
645
+ self.comm.Abort(1)
646
+
647
+ d_std = np.sqrt( np.mean( dI**2 , dtype=np.float64 ) )
648
+
649
+ if np.isclose(d_std, 0., atol=1e-08):
650
+ d_skew = 0.
651
+ d_kurt = 0.
652
+ else:
653
+ d_skew = np.mean( dI**3 , dtype=np.float64 ) / d_std**3
654
+ d_kurt = np.mean( dI**4 , dtype=np.float64 ) / d_std**4
655
+
656
+ data_hos[f'{s}_skew'][yiii] = d_skew
657
+ data_hos[f'{s}_kurt'][yiii] = d_kurt
658
+
659
+ self.comm.Barrier() ## [y] loop outer (chunks within rank)
660
+ if verbose: progress_bar.update()
661
+
662
+ # break ## debug
663
+
664
+ if verbose:
665
+ progress_bar.close()
666
+ print(72*'-')
667
+
668
+ # ==============================================================
669
+ # write HDF5 (.h5) file
670
+ # ==============================================================
671
+
672
+ ## open on rank 0 and write attributes, dimensions, etc.
673
+ if (self.rank==0):
674
+ with h5py.File(fn_h5_out, 'w') as hfw:
675
+
676
+ ## write floats,ints as top-level attributes
677
+ for key,val in data.items():
678
+ if isinstance(data[key], (int,np.int32,np.int64)):
679
+ hfw.attrs[key] = val
680
+ elif isinstance(data[key], (float,np.float32,np.float64)):
681
+ hfw.attrs[key] = val
682
+ elif isinstance(data[key], np.ndarray):
683
+ pass
684
+ else:
685
+ print(f'key {key} is type {str(type(data[key]))}')
686
+ self.comm.Abort(1)
687
+
688
+ ## write numpy arrays
689
+ hfw.create_dataset( 'dims/x' , data=x ) ## [m]
690
+ hfw.create_dataset( 'dims/y' , data=y ) ## [m]
691
+ hfw.create_dataset( 'dims/z' , data=z ) ## [m]
692
+ hfw.create_dataset( 'dims/t' , data=t ) ## [s]
693
+
694
+ ## initialize datasets
695
+ for scalar in scalars_avg:
696
+ hfw.create_dataset( f'avg/{scalar}', shape=(ny,), dtype=np.float64, chunks=None, data=np.full((ny,),0.,np.float64) )
697
+ for scalar in scalars_pdf:
698
+ hfw.create_dataset( f'bins/{scalar}', shape=(ny,n_bins+1), dtype=np.float64, chunks=(1,n_bins+1), data=np.full((ny,n_bins+1),0.,np.float64) )
699
+ for scalar in scalars_pdf:
700
+ hfw.create_dataset( f'pdf/{scalar}', shape=(ny,n_bins), dtype=np.float64, chunks=(1,n_bins), data=np.full((ny,n_bins),0.,np.float64) )
701
+ for scalar in scalars_hos:
702
+ hfw.create_dataset( f'hos/{scalar}', shape=(ny,), dtype=np.float64, chunks=None, data=np.full((ny,),0.,np.float64) )
703
+
704
+ self.comm.Barrier()
705
+
706
+ with h5py.File(fn_h5_out, 'a', driver='mpio', comm=self.comm) as hfw:
707
+
708
+ ## collectively write avg,bins,pdf,hos
709
+ for scalar in scalars_avg:
710
+ dset = hfw[f'avg/{scalar}']
711
+ with dset.collective:
712
+ dset[ry1:ry2] = data_avg[scalar][:]
713
+ for scalar in scalars_pdf:
714
+ dset = hfw[f'bins/{scalar}']
715
+ with dset.collective:
716
+ dset[ry1:ry2,:] = data_bins[scalar][:,:]
717
+ for scalar in scalars_pdf:
718
+ dset = hfw[f'pdf/{scalar}']
719
+ with dset.collective:
720
+ dset[ry1:ry2,:] = data_pdf[scalar][:,:]
721
+ for scalar in scalars_hos:
722
+ dset = hfw[f'hos/{scalar}']
723
+ with dset.collective:
724
+ dset[ry1:ry2] = data_hos[scalar][:]
725
+
726
+ ## report file contents
727
+ self.comm.Barrier()
728
+ if (self.rank==0):
729
+ even_print( os.path.basename(fn_h5_out) , f'{(os.path.getsize(fn_h5_out)/1024**2):0.1f} [MB]' )
730
+ print(72*'-')
731
+ with h5py.File(fn_h5_out,'r') as hfr:
732
+ h5_print_contents(hfr)
733
+ self.comm.Barrier()
734
+
735
+ if verbose: print(72*'-')
736
+ if verbose: print('total time : rgd.calc_statistics_xpln() : %s'%format_time_string((timeit.default_timer() - t_start_func)))
737
+ if verbose: print(72*'-')
738
+ return