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,676 @@
1
+ import os
2
+ import sys
3
+ import timeit
4
+
5
+ import h5py
6
+ import numpy as np
7
+ from tqdm import tqdm
8
+
9
+ from .eas4 import eas4
10
+ from .gradient import gradient
11
+ from .h5 import h5_ds_force_allocate_chunks, h5_print_contents
12
+ from .utils import even_print, format_time_string
13
+
14
+ # ======================================================================
15
+
16
+ def _init_from_eas4_wall(self, fn_eas4, **kwargs):
17
+ '''
18
+ Initialize 'wall' SPD from an EAS4
19
+ '''
20
+ verbose = kwargs.get('verbose',True)
21
+ if (self.rank!=0):
22
+ verbose=False
23
+
24
+ if verbose: print('\n'+'spd.init_from_eas4_wall()'+'\n'+72*'-')
25
+ t_start_func = timeit.default_timer()
26
+
27
+ #if (self.rank==0):
28
+ with eas4(fn_eas4,'r',comm=self.comm,driver=self.driver) as hfr:
29
+
30
+ if (hfr.x.ndim!=1):
31
+ raise RuntimeError('hfr.x.ndim!=1')
32
+ if (hfr.z.ndim!=1):
33
+ raise RuntimeError('hfr.z.ndim!=1')
34
+
35
+ ## Primary attributes
36
+ ats = ['Ma','Re','Pr','kappa','R','p_inf','T_inf','S_Suth','mu_Suth_ref','T_Suth_ref',]
37
+ for at in ats:
38
+ self.attrs[at] = hfr.udef[at]
39
+
40
+ ## Derived attributes
41
+ ats = ['C_Suth','mu_inf','rho_inf','nu_inf','a_inf','U_inf','cp','cv','lchar','tchar','uchar','M_inf',]
42
+ for at in ats:
43
+ if at in hfr.attrs:
44
+ self.attrs[at] = hfr.attrs[at]
45
+
46
+ ## 3D polydata grid coordinates : shape (nx,nz,3)
47
+ xyz = np.zeros((hfr.nx,hfr.nz,3), dtype=np.float64)
48
+ xyz[:,:,0] = hfr.x[:,np.newaxis]
49
+ xyz[:,:,1] = 0.
50
+ xyz[:,:,2] = hfr.z[np.newaxis,:]
51
+
52
+ self.create_dataset(
53
+ name='dims/xyz',
54
+ chunks=(1,hfr.nz,1), ## (x,z,3)
55
+ #shape=(hfr.nx, hfr.nz, 3),
56
+ #dtype=np.float64,
57
+ data=xyz,
58
+ )
59
+
60
+ self.flush()
61
+ xyz = None; del xyz
62
+
63
+ ## 1D [x],[y],[z] vector
64
+ self.create_dataset('dims/x', data=hfr.x, chunks=None)
65
+ self.create_dataset('dims/z', data=hfr.z, chunks=None)
66
+ self.create_dataset('dims/y', data=np.array([0.,],dtype=np.float64), chunks=None)
67
+
68
+ ## Add attributes
69
+ self.attrs['ni'] = hfr.nx
70
+ self.attrs['nj'] = hfr.nz
71
+ self.attrs['n_quads'] = ( hfr.nx - 1 ) * ( hfr.nz - 1 )
72
+ self.attrs['n_pts'] = hfr.nx * hfr.nz
73
+ #self.attrs['nt'] = hfr.nt
74
+ self.attrs['nt'] = 0 ## overwritten later
75
+
76
+ if self.usingmpi:
77
+ self.comm.Barrier()
78
+
79
+ self.get_header(verbose=True)
80
+ if verbose: print(72*'-')
81
+
82
+ if (self.rank==0):
83
+ with h5py.File(self.fname,'r') as hf:
84
+ h5_print_contents(hf)
85
+ if self.usingmpi:
86
+ self.comm.Barrier()
87
+
88
+ ## Report
89
+ if verbose:
90
+ print(72*'-')
91
+ even_print( os.path.basename(self.fname), f'{(os.path.getsize(self.fname)/1024**3):0.1f} [GB]')
92
+ if verbose: print(72*'-')
93
+ if verbose: print('total time : spd.init_from_eas4_wall() : %s'%format_time_string((timeit.default_timer() - t_start_func)))
94
+ if verbose: print(72*'-')
95
+ return
96
+
97
+ def _import_eas4_wall(self, fn_eas4_list, **kwargs):
98
+ '''
99
+ Directly import to 'wall' SPD file from EAS4s
100
+ - only parallelize in [x]
101
+ '''
102
+
103
+ if (self.rank!=0):
104
+ verbose=False
105
+ else:
106
+ verbose=True
107
+
108
+ if verbose: print('\n'+'spd.import_eas4_wall()'+'\n'+72*'-')
109
+ t_start_func = timeit.default_timer()
110
+
111
+ ## dont actually copy over data, just initialize datasets with 0's
112
+ init_dsets_only = kwargs.get('init_dsets_only',False)
113
+
114
+ ## import from EAS4 as 3D unchunked datasets
115
+ ## - have to convert to 4D later
116
+ ## - necessary workaround for disk space with 'huge' datasets
117
+ threeD = kwargs.get('threeD',False)
118
+ fn_h5_3D = kwargs.get('fn_h5_3D',None)
119
+ fi_min = kwargs.get('fi_min',0) ## minimum 'file' ID (for restarting MOVE)
120
+
121
+ if fn_h5_3D is not None:
122
+ if not os.path.isfile(fn_h5_3D):
123
+ raise FileNotFoundError(fn_h5_3D)
124
+
125
+ # if not self.usingmpi:
126
+ # if verbose: print('this function has not been implemented in non-MPI mode')
127
+ # sys.exit(1)
128
+
129
+ # if not h5py.h5.get_config().mpi:
130
+ # if verbose: print('h5py was not compiled for parallel usage! exiting.')
131
+ # sys.exit(1)
132
+
133
+ acc = kwargs.get('acc',4)
134
+ edge_stencil = kwargs.get('edge_stencil','full')
135
+ chunks = kwargs.get('chunks',None)
136
+
137
+ if chunks is None:
138
+ #chunks = (4, self.nj, 50) ## (x,z,t)
139
+ chunks = (1,self.nj,1) ## (x,z,t) --> probably a bad default!
140
+ print("WARNING! Not providing 'chunk' could result in very bad performance")
141
+ if not isinstance(chunks,tuple):
142
+ raise ValueError("'chunks' must be tuple")
143
+ if len(chunks)!=3:
144
+ raise ValueError("len(chunks)!=3")
145
+
146
+ ## delete EAS4s after import --> DANGER!
147
+ ## ... only actually deletes files if 'do_delete.txt' is present
148
+ delete_after_import = kwargs.get('delete_after_import',False)
149
+
150
+ ## check that the passed list of EAS4 files is OK
151
+ if not isinstance(fn_eas4_list, list):
152
+ raise ValueError("'fn_eas4_list' must be list")
153
+ #if not hasattr(fn_eas4_list, '__iter__'):
154
+ # raise ValueError("'fn_eas4_list' must be iterable")
155
+ for fn_eas4 in fn_eas4_list:
156
+ if not os.path.isfile(fn_eas4):
157
+ raise FileNotFoundError(fn_eas4)
158
+
159
+ ## n ranks per direction
160
+ rx = kwargs.get('rx',1)
161
+ if (rx != self.n_ranks):
162
+ raise AssertionError('rx != self.n_ranks')
163
+
164
+ ## nx = ni
165
+ if not hasattr(self,'ni'):
166
+ raise ValueError('attribute ni not found.')
167
+ else:
168
+ self.nx = self.ni
169
+
170
+ ## nz = nj
171
+ if not hasattr(self,'nj'):
172
+ raise ValueError('attribute nj not found.')
173
+ else:
174
+ self.nz = self.nj
175
+
176
+ ## distribute in [x]
177
+ if self.usingmpi:
178
+ rxl_ = np.array_split(np.arange(self.nx,dtype=np.int64),min(rx,self.nx))
179
+ rxl = [[b[0],b[-1]+1] for b in rxl_ ]
180
+ rx1, rx2 = rxl[self.rank]
181
+ nxr = rx2 - rx1
182
+ else:
183
+ rx1,rx2 = 0,self.nx
184
+ nxr = self.nx
185
+
186
+ ## Get all time info & check
187
+ # ==============================================================
188
+
189
+ if len(fn_eas4_list) == 0:
190
+ if not hasattr(self,'t') or not hasattr(self,'nt'):
191
+ raise RuntimeError("if fn_eas4_list=[], then t should exist")
192
+ nt = self.nt
193
+ t = np.copy(self.t)
194
+
195
+ else:
196
+ if (self.rank==0):
197
+ t = np.array([], dtype=np.float64)
198
+ for fn_eas4 in fn_eas4_list:
199
+ with eas4(fn_eas4, 'r', verbose=False) as hf_eas4:
200
+ t_ = np.copy(hf_eas4.t)
201
+ t = np.concatenate((t,t_))
202
+ else:
203
+ t = np.array([], dtype=np.float64) ## 't' must exist on all ranks before bcast
204
+
205
+ if self.usingmpi:
206
+ self.comm.Barrier()
207
+ t = self.comm.bcast(t, root=0)
208
+ nt = t.shape[0]
209
+ self.nt = nt
210
+ self.t = t
211
+ assert self.t.dtype == np.float64, f'Array dtype is {str(t.dtype)}, expected np.float64'
212
+
213
+ if len(fn_eas4_list) > 0:
214
+ if verbose: even_print('n EAS4 files','%i'%len(fn_eas4_list))
215
+ if verbose: even_print('nt all files','%i'%nt)
216
+ if verbose: even_print('delete after import',str(delete_after_import))
217
+ else:
218
+ if verbose: even_print('nt',f'{nt:d}')
219
+ if verbose: print(72*'-')
220
+
221
+ # ==============================================================
222
+
223
+ ## check [t] & Δt
224
+ if (nt>1):
225
+
226
+ ## check no zero distance elements
227
+ if (np.diff(t).size - np.count_nonzero(np.diff(t))) != 0.:
228
+ raise AssertionError('t arr has zero-distance elements')
229
+ else:
230
+ if verbose: even_print('check: Δt!=0','passed')
231
+
232
+ ## check monotonically increasing
233
+ if not np.all(np.diff(t) > 0.):
234
+ raise AssertionError('t arr not monotonically increasing')
235
+ else:
236
+ if verbose: even_print('check: t mono increasing','passed')
237
+
238
+ ## check constant Δt
239
+ dt0 = np.diff(t)[0]
240
+ if not np.all(np.isclose(np.diff(t), dt0, rtol=1e-3)):
241
+ if (self.rank==0):
242
+ print(np.diff(t))
243
+ #raise AssertionError('t arr not uniformly spaced')
244
+ if verbose:
245
+ even_print('check: constant Δt','failed')
246
+ print('WARNING: [t] not uniformly spaced!!')
247
+ else:
248
+ if verbose: even_print('check: constant Δt','passed')
249
+
250
+ ## (over)write [t]
251
+ if len(fn_eas4_list) > 0:
252
+ if self.usingmpi: self.comm.Barrier()
253
+ if 'dims/t' in self:
254
+ del self['dims/t']
255
+ self.create_dataset('dims/t', data=t, chunks=None, dtype=np.float64)
256
+ self.attrs['nt'] = nt
257
+ self.attrs['dt'] = dt0
258
+ self.attrs['duration'] = dt0 * (nt - 1)
259
+ self.flush()
260
+ if self.usingmpi: self.comm.Barrier()
261
+ if verbose: print(72*'-')
262
+
263
+ else:
264
+ return ## nothing to do
265
+
266
+ # ==============================================================
267
+ # Initialize datasets (harmless if they exist)
268
+ # ==============================================================
269
+
270
+ if not threeD: ## ...because '3D' mode doesnt require pre-initialization
271
+
272
+ scalars = [
273
+ 'tau_uy','tau_vy','tau_wy',
274
+ 'u_tau','v_tau','w_tau',
275
+ 'T','mu','nu','rho','p',
276
+ ]
277
+
278
+ dtype = np.dtype(np.float32)
279
+ shape = (self.nx, self.nz, self.nt)
280
+ data_gb = np.prod(shape) * dtype.itemsize / 1024**3
281
+
282
+ if verbose:
283
+ progress_bar = tqdm(
284
+ total=len(scalars),
285
+ ncols=100,
286
+ desc='initialize dsets',
287
+ leave=True,
288
+ file=sys.stdout,
289
+ mininterval=0.1,
290
+ smoothing=0.,
291
+ #bar_format="\033[B{l_bar}{bar}| {n}/{total} [{percentage:.1f}%] {elapsed}/{remaining}\033[A\n\b",
292
+ bar_format="{l_bar}{bar}| {n}/{total} [{percentage:.1f}%] {elapsed}/{remaining}",
293
+ ascii="░█",
294
+ colour='#FF6600',
295
+ )
296
+
297
+ ## Initialize output datasets
298
+ for scalar in scalars:
299
+
300
+ dsn = f'data/{scalar}'
301
+ if dsn not in self:
302
+ if self.usingmpi: self.comm.Barrier()
303
+ t_start = timeit.default_timer()
304
+
305
+ if verbose:
306
+ tqdm.write( even_print(f'initializing data/{scalar}', f'{str(shape)} / {data_gb:0.1f} [GB]', s=True) )
307
+
308
+ dset = self.create_dataset(
309
+ dsn,
310
+ shape=shape,
311
+ dtype=dtype,
312
+ chunks=chunks,
313
+ )
314
+
315
+ ## write dummy data to dataset to ensure that it is truly initialized
316
+ if not self.usingmpi:
317
+ h5_ds_force_allocate_chunks(dset,verbose=verbose) #,quick=True)
318
+
319
+ if self.usingmpi: self.comm.Barrier()
320
+ t_delta = timeit.default_timer() - t_start
321
+ if verbose:
322
+ tqdm.write( even_print(f'initialize data/{scalar}', f'{data_gb:0.2f} [GB] {t_delta:0.2f} [s] {(data_gb/t_delta):0.3f} [GB/s]', s=True) )
323
+
324
+ chunk_kb_ = np.prod(dset.chunks) * dset.dtype.itemsize / 1024. ## actual
325
+ if verbose:
326
+ tqdm.write( even_print('chunk shape (x,z,t)', str(dset.chunks), s=True) )
327
+ tqdm.write( even_print('chunk size', f'{int(round(chunk_kb_)):d} [KB]', s=True) )
328
+
329
+ if verbose: progress_bar.update()
330
+
331
+ if self.usingmpi:
332
+ self.comm.Barrier()
333
+ if verbose:
334
+ progress_bar.close()
335
+ print(72*'-')
336
+
337
+ # ==============================================================
338
+ # Read,process,write (from EAS4)
339
+ # ==============================================================
340
+
341
+ if not init_dsets_only and fn_h5_3D is None:
342
+
343
+ if verbose:
344
+ progress_bar = tqdm(
345
+ total=len(fn_eas4_list),
346
+ ncols=100,
347
+ desc='import',
348
+ leave=True,
349
+ file=sys.stdout,
350
+ mininterval=0.1,
351
+ smoothing=0.,
352
+ #bar_format="\033[B{l_bar}{bar}| {n}/{total} [{percentage:.1f}%] {elapsed}/{remaining}\033[A\n\b",
353
+ bar_format="{l_bar}{bar}| {n}/{total} [{percentage:.1f}%] {elapsed}/{remaining}",
354
+ ascii="░█",
355
+ colour='#FF6600',
356
+ )
357
+
358
+ tii = 0 ## timestep index counter full series
359
+
360
+ for i_eas4,fn_eas4 in enumerate(fn_eas4_list):
361
+
362
+ with eas4(fn_eas4, 'r', verbose=False, driver=self.driver, comm=self.comm) as hf_eas4:
363
+
364
+ ## dimensional coordinates
365
+ #x = np.copy( hf_eas4.x * hf_eas4.lchar )
366
+ y = np.copy( hf_eas4.y * hf_eas4.lchar )
367
+ #z = np.copy( hf_eas4.z * hf_eas4.lchar )
368
+
369
+ nx = hf_eas4.nx
370
+ ny = hf_eas4.ny
371
+ nz = hf_eas4.nz
372
+ nt = hf_eas4.nt ## OVERWRITING ABOVE!!!
373
+
374
+ if verbose:
375
+ tqdm.write(even_print(os.path.basename(fn_eas4), f'{(os.path.getsize(fn_eas4)/1024**3):0.1f} [GB]', s=True))
376
+
377
+ ## rank-local data read buffer for this EAS4
378
+ scalars = ['rho','u','v','w','T','p']
379
+ #formats = [ np.dtype(np.float32) for s in scalars ]
380
+ formats = [ np.dtype(np.float64) for s in scalars ] ## do arithmetic in double
381
+ data = np.zeros(shape=(nxr,ny,nz,nt), dtype={'names':scalars, 'formats':formats})
382
+
383
+ ## read (FULL file)
384
+ self.comm.Barrier()
385
+ t_start = timeit.default_timer()
386
+ for ti in range(hf_eas4.nt): ## timesteps in EAS4
387
+ for scalar in scalars:
388
+ dset_path = f'Data/DOMAIN_000000/ts_{ti:06d}/par_{hf_eas4.scalar_n_map[scalar]:06d}'
389
+ dset = hf_eas4[dset_path]
390
+ with dset.collective:
391
+ if hf_eas4.dform==1:
392
+ data[scalar][:,:,:,ti] = dset[rx1:rx2,:,:]
393
+ elif hf_eas4.dform==2:
394
+ data[scalar][:,:,:,ti] = dset[:,:,rx1:rx2].T
395
+ else:
396
+ raise RuntimeError
397
+
398
+ self.comm.Barrier()
399
+ t_delta = timeit.default_timer() - t_start
400
+
401
+ data_gb = os.path.getsize(fn_eas4)/1024**3
402
+ if verbose:
403
+ #msg = even_print('read {os.path.basename(fn_eas4)}', f'{data_gb:0.2f} [GB] {t_delta:0.2f} [s] {(data_gb/t_delta):0.3f} [GB/s]', s=True)
404
+ msg = even_print('read', f'{data_gb:0.2f} [GB] {t_delta:0.2f} [s] {(data_gb/t_delta):0.3f} [GB/s]', s=True)
405
+ tqdm.write(msg)
406
+
407
+ ## re-dimensionalize EAS4 data
408
+ data['rho'][:,:,:,:] *= hf_eas4.rho_inf
409
+ data['u'][:,:,:,:] *= hf_eas4.U_inf
410
+ data['v'][:,:,:,:] *= hf_eas4.U_inf
411
+ data['w'][:,:,:,:] *= hf_eas4.U_inf
412
+ data['T'][:,:,:,:] *= hf_eas4.T_inf
413
+ data['p'][:,:,:,:] *= hf_eas4.rho_inf * hf_eas4.U_inf**2
414
+
415
+ ## calculate μ and ν (dimensional)
416
+ mu = np.zeros(shape=(nxr,ny,nz,nt), dtype=np.float64)
417
+ nu = np.zeros(shape=(nxr,ny,nz,nt), dtype=np.float64)
418
+ mu[:,:,:,:] = hf_eas4.mu_Suth_ref * ( data['T'][:,:,:,:] / hf_eas4.T_Suth_ref )**(3/2) * ( ( hf_eas4.T_Suth_ref + hf_eas4.S_Suth ) / ( data['T'][:,:,:,:] + hf_eas4.S_Suth ) )
419
+ nu[:,:,:,:] = mu / data['rho'][:,:,:,:]
420
+
421
+ # ==========================================================
422
+
423
+ ## Dimensional wall strains
424
+ ddy_u = gradient( data['u'][:,:,:,:], y, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
425
+ ddy_v = gradient( data['v'][:,:,:,:], y, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
426
+ ddy_w = gradient( data['w'][:,:,:,:], y, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
427
+ ddy_u_wall = np.copy( ddy_u[:,0,:,:] )
428
+ ddy_v_wall = np.copy( ddy_v[:,0,:,:] )
429
+ ddy_w_wall = np.copy( ddy_w[:,0,:,:] )
430
+
431
+ if (ddy_u_wall.ndim!=3): ## (x,z,t)
432
+ raise ValueError
433
+ if (ddy_u_wall.shape!=(nxr,nz,nt)): ## (x,z,t)
434
+ raise ValueError
435
+
436
+ ## Dimensional wall quantities
437
+ rho_wall = np.copy( data['rho'][:,0,:,:] )
438
+ mu_wall = np.copy( mu[:,0,:,:] )
439
+ nu_wall = np.copy( nu[:,0,:,:] )
440
+ T_wall = np.copy( data['T'][:,0,:,:] )
441
+ p_wall = np.copy( data['p'][:,0,:,:] )
442
+
443
+ if (mu_wall.ndim!=3): ## (x,z,t)
444
+ raise ValueError
445
+ if (mu_wall.shape!=(nxr,nz,nt)): ## (x,z,t)
446
+ raise ValueError
447
+
448
+ if (rho_wall.ndim!=3): ## (x,z,t)
449
+ raise ValueError
450
+ if (rho_wall.shape!=(nxr,nz,nt)): ## (x,z,t)
451
+ raise ValueError
452
+
453
+ tau_uy = np.copy( mu_wall * ddy_u_wall ) ## INSTANTANEOUS τw
454
+ tau_vy = np.copy( mu_wall * ddy_v_wall )
455
+ tau_wy = np.copy( mu_wall * ddy_w_wall )
456
+
457
+ u_tau = np.copy( np.sign(tau_uy) * np.sqrt( np.abs(tau_uy) / rho_wall ) ) ## INSTANTANEOUS uτ
458
+ v_tau = np.copy( np.sign(tau_vy) * np.sqrt( np.abs(tau_vy) / rho_wall ) ) ## INSTANTANEOUS vτ
459
+ w_tau = np.copy( np.sign(tau_wy) * np.sqrt( np.abs(tau_wy) / rho_wall ) ) ## INSTANTANEOUS wτ
460
+
461
+ #grp = self['data']
462
+ #scalars = list(grp.keys())
463
+ scalars = [
464
+ 'tau_uy','tau_vy','tau_wy',
465
+ 'u_tau','v_tau','w_tau',
466
+ 'T','mu','nu','rho','p',
467
+ ]
468
+
469
+ ## 3D [scalar][x,z,t] numpy structured array
470
+ ## rank-local data buffer for write
471
+ formats = [ np.dtype(np.float32) for s in scalars ] ## casting to single
472
+ data4spd = np.zeros(shape=(nxr,hf_eas4.nz,hf_eas4.nt), dtype={'names':scalars, 'formats':formats})
473
+ data4spd['tau_uy'][:,:,:] = tau_uy / ( self.rho_inf * self.U_inf**2 )
474
+ data4spd['tau_vy'][:,:,:] = tau_vy / ( self.rho_inf * self.U_inf**2 )
475
+ data4spd['tau_wy'][:,:,:] = tau_wy / ( self.rho_inf * self.U_inf**2 )
476
+ data4spd['T'][:,:,:] = T_wall / self.T_inf
477
+ data4spd['rho'][:,:,:] = rho_wall / self.rho_inf
478
+ data4spd['p'][:,:,:] = p_wall / ( self.rho_inf * self.U_inf**2 )
479
+ data4spd['mu'][:,:,:] = mu_wall / self.mu_inf
480
+ data4spd['nu'][:,:,:] = nu_wall / self.nu_inf
481
+ data4spd['u_tau'][:,:,:] = u_tau / self.U_inf
482
+ data4spd['v_tau'][:,:,:] = v_tau / self.U_inf
483
+ data4spd['w_tau'][:,:,:] = w_tau / self.U_inf
484
+
485
+ tiA = tii
486
+ tiB = tiA + nt
487
+ tii += nt ## increment tii by this EAS4's nt
488
+
489
+ ## write
490
+ self.comm.Barrier()
491
+ t_start = timeit.default_timer()
492
+
493
+ if not threeD:
494
+
495
+ #for scalar in data4spd.dtype.names:
496
+ for scalar in scalars:
497
+ dset = self[f'data/{scalar}']
498
+ with dset.collective:
499
+ dset[rx1:rx2,:,tiA:tiB] = data4spd[scalar][:,:,:]
500
+
501
+ else: ## Write as chunkless dset per-file
502
+
503
+ for scalar in scalars:
504
+ dsn = f'data/{i_eas4:d}/{scalar}'
505
+ shape = ( self.nx, self.nz, nt ) ## 'nt' here is from EAS4
506
+ dtype = np.dtype(np.float32)
507
+
508
+ dset = self.create_dataset(
509
+ dsn,
510
+ shape=shape,
511
+ dtype=dtype,
512
+ chunks=None,
513
+ )
514
+
515
+ with dset.collective: ## do actual collective write
516
+ dset[rx1:rx2,:,:] = data4spd[scalar][:,:,:]
517
+
518
+ self.comm.Barrier()
519
+ t_delta = timeit.default_timer() - t_start
520
+
521
+ ## Report write speed
522
+ data_gb = self.n_ranks * data4spd.nbytes / 1024**3
523
+ if verbose:
524
+ msg = even_print('write', f'{data_gb:0.2f} [GB] {t_delta:0.2f} [s] {(data_gb/t_delta):0.3f} [GB/s]', s=True)
525
+ tqdm.write(msg)
526
+
527
+ ## Delete source file (under restrictive conditions)
528
+ if delete_after_import:
529
+ if os.path.isfile('do_delete.txt'):
530
+ if (self.rank==0):
531
+ tqdm.write(even_print('deleting', fn_eas4, s=True))
532
+ os.remove(fn_eas4)
533
+ self.comm.Barrier()
534
+
535
+ if verbose: progress_bar.update()
536
+ if verbose: progress_bar.close()
537
+
538
+ # ==============================================================
539
+ # MOVE from 3D, chunkless HDF5 file to CHUNKED SPD file
540
+ # ==============================================================
541
+
542
+ if not init_dsets_only and fn_h5_3D is not None:
543
+
544
+ # ## report contents of 3D file
545
+ # if (self.rank==0):
546
+ # with h5py.File(fn_h5_3D, 'r') as hfr:
547
+ # h5_print_contents(hfr)
548
+ # if self.usingmpi:
549
+ # self.comm.Barrier()
550
+
551
+ ## Get 'file indices' -- 'indices' are digits in 'data/%d/...' dset names
552
+ if (self.rank==0):
553
+ fi = []
554
+ with h5py.File(fn_h5_3D, 'r') as hfr:
555
+ gpd = hfr['data']
556
+ fi_list = sorted([int(name) for name in gpd.keys() if name.isdigit()])
557
+ nfi_actual = len([ fi for fi in fi_list if fi >= fi_min ]) ## n files to actually process
558
+ fi = np.array(fi_list, dtype=np.int32)
559
+ else:
560
+ fi = np.array([], dtype=np.int32) ## 'fi' must exist on all ranks before bcast
561
+ if self.usingmpi:
562
+ self.comm.Barrier()
563
+ fi = self.comm.bcast(fi, root=0)
564
+
565
+ if fi.shape[0]==0:
566
+ raise RuntimeError
567
+
568
+ nx = self.nx
569
+ #ny = self.ny ## doesnt exist
570
+ nz = self.nz
571
+ #nt = self.nt ## no!
572
+
573
+ scalars = [
574
+ 'tau_uy','tau_vy','tau_wy',
575
+ 'u_tau','v_tau','w_tau',
576
+ 'T','mu','nu','rho','p',
577
+ ]
578
+
579
+ if verbose:
580
+ progress_bar = tqdm(
581
+ #total=fi.shape[0]*len(scalars),
582
+ total=nfi_actual*len(scalars),
583
+ ncols=100,
584
+ desc='import',
585
+ leave=True,
586
+ file=sys.stdout,
587
+ mininterval=1/24,
588
+ smoothing=0.3,
589
+ #bar_format="\033[B{l_bar}{bar}| {n}/{total} [{percentage:.1f}%] {elapsed}/{remaining}\033[A\n\b",
590
+ bar_format="{l_bar}{bar}| {n}/{total} [{percentage:.1f}%] {elapsed}/{remaining}",
591
+ ascii="░█",
592
+ colour='#FF6600',
593
+ )
594
+
595
+ tii = 0 ## timestep index counter full series
596
+
597
+ with h5py.File(fn_h5_3D, 'r', driver=self.driver, comm=self.comm) as hfr:
598
+ for fii in fi:
599
+ for scalar in scalars:
600
+
601
+ ## dataset name & handle in HDF5 file composed of chunkless dsets
602
+ dsn = f'data/{fii:d}/{scalar}'
603
+ dset = hfr[dsn]
604
+ nt = dset.shape[2] ## nt of corresponding chunkless dset (EAS4)
605
+
606
+ ## time range for this EAS4 data
607
+ tiA = tii
608
+ tiB = tiA + nt
609
+ #if verbose:
610
+ # tqdm.write(f'tiA={tiA:d},tiB={tiB:d}')
611
+
612
+ if fii >= fi_min: ## do read / write
613
+
614
+ data_gb = nx * nz * nt * dset.dtype.itemsize / 1024**3
615
+
616
+ ## COLLECTIVE read
617
+ if self.usingmpi: self.comm.Barrier()
618
+ t_start = timeit.default_timer()
619
+ if self.usingmpi:
620
+ with dset.collective:
621
+ dd = np.copy( dset[rx1:rx2,:,:] )
622
+ else:
623
+ dd = np.copy( dset[()] )
624
+ if self.usingmpi: self.comm.Barrier()
625
+ t_delta = timeit.default_timer() - t_start
626
+
627
+ if verbose:
628
+ tqdm.write(even_print(f'read: {fii:d}/{scalar}', '%0.3f [GB] %0.3f [s] %0.3f [GB/s]'%(data_gb,t_delta,(data_gb/t_delta)), s=True))
629
+
630
+ ## assert shape
631
+ if ( dd.shape != (nxr,nz,nt) ):
632
+ print(f'rank {self.rank:d}: shape violation')
633
+ if self.usingmpi: self.comm.Abort(1)
634
+ raise ValueError
635
+
636
+ ## dataset name & handle in SPD file
637
+ dsn = f'data/{scalar}'
638
+ dset = self[dsn]
639
+
640
+ ## COLLECTIVE write
641
+ if self.usingmpi: self.comm.Barrier()
642
+ t_start = timeit.default_timer()
643
+ if self.usingmpi:
644
+ with dset.collective:
645
+ dset[rx1:rx2,:,tiA:tiB] = dd[:,:,:]
646
+ else:
647
+ dset[:,:,tiA:tiB] = dd[:,:,:]
648
+ if self.usingmpi: self.comm.Barrier()
649
+ t_delta = timeit.default_timer() - t_start
650
+
651
+ if verbose:
652
+ tqdm.write(even_print(f'write: data/{scalar}', '%0.3f [GB] %0.3f [s] %0.3f [GB/s]'%(data_gb,t_delta,(data_gb/t_delta)), s=True))
653
+ if verbose:
654
+ progress_bar.update()
655
+
656
+ if os.path.isfile('stop.txt'):
657
+ break
658
+
659
+ tii += nt ## increment tii by this EAS4's nt
660
+
661
+ if os.path.isfile('stop.txt'):
662
+ break
663
+
664
+ if verbose:
665
+ progress_bar.close()
666
+
667
+ ## Report file
668
+ if self.usingmpi:
669
+ self.comm.Barrier()
670
+ if verbose:
671
+ print(72*'-')
672
+ even_print( os.path.basename(self.fname), f'{(os.path.getsize(self.fname)/1024**3):0.1f} [GB]')
673
+ if verbose: print(72*'-')
674
+ if verbose: print('total time : spd.import_eas4_wall() : %s'%format_time_string((timeit.default_timer() - t_start_func)))
675
+ if verbose: print(72*'-')
676
+ return