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/ztmd_analysis.py ADDED
@@ -0,0 +1,2337 @@
1
+ import sys
2
+ import timeit
3
+
4
+ import numpy as np
5
+ import scipy as sp
6
+ from tqdm import tqdm
7
+
8
+ from .bl import (
9
+ calc_d1,
10
+ calc_d2,
11
+ calc_d3,
12
+ calc_d99_1d,
13
+ calc_dRC,
14
+ calc_profile_edge_1d,
15
+ )
16
+ from .gradient import gradient
17
+ from .grid_metric import get_metric_tensor_2d
18
+ from .utils import even_print, format_time_string
19
+
20
+ # ======================================================================
21
+
22
+ def _calc_gradients(self, acc=6, edge_stencil='full', **kwargs):
23
+ '''
24
+ Calculate spatial gradients of averaged quantities
25
+ '''
26
+
27
+ verbose = kwargs.get('verbose',True)
28
+ do_favre = kwargs.get('favre',True)
29
+
30
+ if verbose: print('\n'+'ztmd.calc_gradients()'+'\n'+72*'-')
31
+ t_start_func = timeit.default_timer()
32
+
33
+ if verbose: even_print('acc','%i'%(acc,))
34
+ if verbose: even_print('edge_stencil','%s'%(edge_stencil,))
35
+ if verbose: even_print('do_favre',str(do_favre))
36
+
37
+ ## check
38
+ if not hasattr(self,'rectilinear') and not hasattr(self,'curvilinear'):
39
+ raise AssertionError('neither rectilinear nor curvilinear attr set')
40
+
41
+ if hasattr(self,'rectilinear'):
42
+ if self.rectilinear:
43
+ if verbose: even_print('grid type','rectilinear')
44
+ if hasattr(self,'curvilinear'):
45
+ if self.curvilinear:
46
+ if verbose: even_print('grid type','curvilinear')
47
+
48
+ if (self.x.ndim==1) and (self.y.ndim==1):
49
+ if hasattr(self,'rectilinear'):
50
+ if not self.rectilinear:
51
+ raise AssertionError
52
+ if hasattr(self,'curvilinear'):
53
+ if self.curvilinear:
54
+ raise AssertionError
55
+ elif (self.x.ndim==2) and (self.y.ndim==2):
56
+ if hasattr(self,'rectilinear'):
57
+ if self.rectilinear:
58
+ raise AssertionError
59
+ if hasattr(self,'curvilinear'):
60
+ if not self.curvilinear:
61
+ raise AssertionError
62
+ else:
63
+ raise ValueError
64
+
65
+ # ===
66
+
67
+ if self.curvilinear: ## get metric tensor 2D
68
+
69
+ M = get_metric_tensor_2d(self.x, self.y, acc=acc, edge_stencil=edge_stencil, verbose=False)
70
+
71
+ ddx_q1 = np.copy( M[:,:,0,0] ) ## ξ_x
72
+ ddx_q2 = np.copy( M[:,:,1,0] ) ## η_x
73
+ ddy_q1 = np.copy( M[:,:,0,1] ) ## ξ_y
74
+ ddy_q2 = np.copy( M[:,:,1,1] ) ## η_y
75
+
76
+ if verbose: even_print('ξ_x','%s'%str(ddx_q1.shape))
77
+ if verbose: even_print('η_x','%s'%str(ddx_q2.shape))
78
+ if verbose: even_print('ξ_y','%s'%str(ddy_q1.shape))
79
+ if verbose: even_print('η_y','%s'%str(ddy_q2.shape))
80
+
81
+ M = None; del M
82
+
83
+ ## the 'computational' grid (unit Cartesian)
84
+ #x_comp = np.arange(nx, dtype=np.float64)
85
+ #y_comp = np.arange(ny, dtype=np.float64)
86
+ x_comp = 1.
87
+ y_comp = 1.
88
+
89
+ print(72*'-')
90
+
91
+ # === get gradients of [u,v,p,T,ρ]
92
+
93
+ if ('data/u' in self):
94
+
95
+ u = np.copy( self['data/u'][()].T )
96
+
97
+ if self.rectilinear:
98
+ ddx_u = gradient(u, self.x, axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
99
+ ddy_u = gradient(u, self.y, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
100
+ elif self.curvilinear:
101
+ ddx_u_comp = gradient(u, x_comp, axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
102
+ ddy_u_comp = gradient(u, y_comp, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
103
+ ddx_u = ddx_u_comp*ddx_q1 + ddy_u_comp*ddx_q2
104
+ ddy_u = ddx_u_comp*ddy_q1 + ddy_u_comp*ddy_q2
105
+ else:
106
+ raise ValueError
107
+
108
+ if ('data/ddx_u' in self): del self['data/ddx_u']
109
+ self.create_dataset('data/ddx_u', data=ddx_u.T, chunks=None)
110
+
111
+ if ('data/ddy_u' in self): del self['data/ddy_u']
112
+ self.create_dataset('data/ddy_u', data=ddy_u.T, chunks=None)
113
+
114
+ if verbose: even_print('ddx[u]','%s'%str(ddx_u.shape))
115
+ if verbose: even_print('ddy[u]','%s'%str(ddy_u.shape))
116
+
117
+ if ('data/v' in self):
118
+
119
+ v = np.copy( self['data/v'][()].T )
120
+
121
+ if self.rectilinear:
122
+ ddx_v = gradient(v, self.x, axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
123
+ ddy_v = gradient(v, self.y, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
124
+ elif self.curvilinear:
125
+ ddx_v_comp = gradient(v, x_comp, axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
126
+ ddy_v_comp = gradient(v, y_comp, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
127
+ ddx_v = ddx_v_comp*ddx_q1 + ddy_v_comp*ddx_q2
128
+ ddy_v = ddx_v_comp*ddy_q1 + ddy_v_comp*ddy_q2
129
+ else:
130
+ raise ValueError
131
+
132
+ if ('data/ddx_v' in self): del self['data/ddx_v']
133
+ self.create_dataset('data/ddx_v', data=ddx_v.T, chunks=None)
134
+
135
+ if ('data/ddy_v' in self): del self['data/ddy_v']
136
+ self.create_dataset('data/ddy_v', data=ddy_v.T, chunks=None)
137
+
138
+ if verbose: even_print('ddx[v]','%s'%str(ddx_v.shape))
139
+ if verbose: even_print('ddy[v]','%s'%str(ddy_v.shape))
140
+
141
+ if ('data/p' in self):
142
+
143
+ p = np.copy( self['data/p'][()].T )
144
+
145
+ if self.rectilinear:
146
+ ddx_p = gradient(p, self.x, axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
147
+ ddy_p = gradient(p, self.y, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
148
+ elif self.curvilinear:
149
+ ddx_p_comp = gradient(p, x_comp, axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
150
+ ddy_p_comp = gradient(p, y_comp, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
151
+ ddx_p = ddx_p_comp*ddx_q1 + ddy_p_comp*ddx_q2
152
+ ddy_p = ddx_p_comp*ddy_q1 + ddy_p_comp*ddy_q2
153
+ else:
154
+ raise ValueError
155
+
156
+ if ('data/ddx_p' in self): del self['data/ddx_p']
157
+ self.create_dataset('data/ddx_p', data=ddx_p.T, chunks=None)
158
+
159
+ if ('data/ddy_p' in self): del self['data/ddy_p']
160
+ self.create_dataset('data/ddy_p', data=ddy_p.T, chunks=None)
161
+
162
+ if verbose: even_print('ddx[p]','%s'%str(ddx_p.shape))
163
+ if verbose: even_print('ddy[p]','%s'%str(ddy_p.shape))
164
+
165
+ if ('data/T' in self):
166
+
167
+ T = np.copy( self['data/T'][()].T )
168
+
169
+ if self.rectilinear:
170
+ ddx_T = gradient(T, self.x, axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
171
+ ddy_T = gradient(T, self.y, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
172
+ elif self.curvilinear:
173
+ ddx_T_comp = gradient(T, x_comp, axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
174
+ ddy_T_comp = gradient(T, y_comp, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
175
+ ddx_T = ddx_T_comp*ddx_q1 + ddy_T_comp*ddx_q2
176
+ ddy_T = ddx_T_comp*ddy_q1 + ddy_T_comp*ddy_q2
177
+ else:
178
+ raise ValueError
179
+
180
+ if ('data/ddx_T' in self): del self['data/ddx_T']
181
+ self.create_dataset('data/ddx_T', data=ddx_T.T, chunks=None)
182
+
183
+ if ('data/ddy_T' in self): del self['data/ddy_T']
184
+ self.create_dataset('data/ddy_T', data=ddy_T.T, chunks=None)
185
+
186
+ if verbose: even_print('ddx[T]','%s'%str(ddx_T.shape))
187
+ if verbose: even_print('ddy[T]','%s'%str(ddy_T.shape))
188
+
189
+ if ('data/rho' in self):
190
+
191
+ r = np.copy( self['data/rho'][()].T )
192
+
193
+ if self.rectilinear:
194
+ ddx_r = gradient(r, self.x, axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
195
+ ddy_r = gradient(r, self.y, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
196
+ elif self.curvilinear:
197
+ ddx_r_comp = gradient(r, x_comp, axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
198
+ ddy_r_comp = gradient(r, y_comp, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
199
+ ddx_r = ddx_r_comp*ddx_q1 + ddy_r_comp*ddx_q2
200
+ ddy_r = ddx_r_comp*ddy_q1 + ddy_r_comp*ddy_q2
201
+ else:
202
+ raise ValueError
203
+
204
+ if ('data/ddx_r' in self): del self['data/ddx_r']
205
+ self.create_dataset('data/ddx_r', data=ddx_r.T, chunks=None)
206
+
207
+ if ('data/ddy_r' in self): del self['data/ddy_r']
208
+ self.create_dataset('data/ddy_r', data=ddy_r.T, chunks=None)
209
+
210
+ if verbose: even_print('ddx[ρ]','%s'%str(ddx_r.shape))
211
+ if verbose: even_print('ddy[ρ]','%s'%str(ddy_r.shape))
212
+
213
+ # === vorticity
214
+
215
+ ## z-vorticity :: ω_z
216
+ vort_z = ddx_v - ddy_u
217
+
218
+ if ('data/vort_z' in self): del self['data/vort_z']
219
+ self.create_dataset('data/vort_z', data=vort_z.T, chunks=None)
220
+ if verbose: even_print('ω_z','%s'%str(vort_z.shape))
221
+
222
+ ## divergence (in xy-plane)
223
+ div_xy = ddx_u + ddy_v
224
+
225
+ if ('data/div_xy' in self): del self['data/div_xy']
226
+ self.create_dataset('data/div_xy', data=div_xy.T, chunks=None)
227
+ if verbose: even_print('div_xy','%s'%str(div_xy.shape))
228
+
229
+ # ===
230
+
231
+ if ('data/utang' in self):
232
+
233
+ utang = np.copy( self['data/utang'][()].T )
234
+
235
+ if self.rectilinear:
236
+ ddx_utang = gradient(utang, self.x, axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
237
+ ddy_utang = gradient(utang, self.y, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
238
+ elif self.curvilinear:
239
+ ddx_utang_comp = gradient(utang, x_comp, axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
240
+ ddy_utang_comp = gradient(utang, y_comp, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
241
+ ddx_utang = ddx_utang_comp*ddx_q1 + ddy_utang_comp*ddx_q2
242
+ ddy_utang = ddx_utang_comp*ddy_q1 + ddy_utang_comp*ddy_q2
243
+ else:
244
+ raise ValueError
245
+
246
+ if ('data/ddx_utang' in self): del self['data/ddx_utang']
247
+ self.create_dataset('data/ddx_utang', data=ddx_utang.T, chunks=None)
248
+ if verbose: even_print('ddx[utang]','%s'%str(ddx_utang.shape))
249
+
250
+ if ('data/ddy_utang' in self): del self['data/ddy_utang']
251
+ self.create_dataset('data/ddy_utang', data=ddy_utang.T, chunks=None)
252
+ if verbose: even_print('ddy[utang]','%s'%str(ddy_utang.shape))
253
+
254
+ if ('data/unorm' in self):
255
+
256
+ unorm = np.copy( self['data/unorm'][()].T )
257
+
258
+ if self.rectilinear:
259
+ ddx_unorm = gradient(unorm, self.x, axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
260
+ ddy_unorm = gradient(unorm, self.y, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
261
+ elif self.curvilinear:
262
+ ddx_unorm_comp = gradient(unorm, x_comp, axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
263
+ ddy_unorm_comp = gradient(unorm, y_comp, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
264
+ ddx_unorm = ddx_unorm_comp*ddx_q1 + ddy_unorm_comp*ddx_q2
265
+ ddy_unorm = ddx_unorm_comp*ddy_q1 + ddy_unorm_comp*ddy_q2
266
+ else:
267
+ raise ValueError
268
+
269
+ if ('data/ddx_unorm' in self): del self['data/ddx_unorm']
270
+ self.create_dataset('data/ddx_unorm', data=ddx_unorm.T, chunks=None)
271
+ if verbose: even_print('ddx[unorm]','%s'%str(ddx_unorm.shape))
272
+
273
+ if ('data/ddy_unorm' in self): del self['data/ddy_unorm']
274
+ self.create_dataset('data/ddy_unorm', data=ddy_unorm.T, chunks=None)
275
+ if verbose: even_print('ddy[unorm]','%s'%str(ddy_unorm.shape))
276
+
277
+ # === Favre
278
+
279
+ if do_favre:
280
+
281
+ print(72*'-')
282
+
283
+ if ('data/u_Fv' in self):
284
+
285
+ u_Fv = np.copy( self['data/u_Fv'][()].T )
286
+
287
+ if self.rectilinear:
288
+ ddx_u_Fv = gradient(u_Fv, self.x, axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
289
+ ddy_u_Fv = gradient(u_Fv, self.y, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
290
+ elif self.curvilinear:
291
+ ddx_u_Fv_comp = gradient(u_Fv, x_comp, axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
292
+ ddy_u_Fv_comp = gradient(u_Fv, y_comp, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
293
+ ddx_u_Fv = ddx_u_Fv_comp*ddx_q1 + ddy_u_Fv_comp*ddx_q2
294
+ ddy_u_Fv = ddx_u_Fv_comp*ddy_q1 + ddy_u_Fv_comp*ddy_q2
295
+ else:
296
+ raise ValueError
297
+
298
+ if ('data/ddx_u_Fv' in self): del self['data/ddx_u_Fv']
299
+ self.create_dataset('data/ddx_u_Fv', data=ddx_u_Fv.T, chunks=None)
300
+
301
+ if ('data/ddy_u_Fv' in self): del self['data/ddy_u_Fv']
302
+ self.create_dataset('data/ddy_u_Fv', data=ddy_u_Fv.T, chunks=None)
303
+
304
+ if verbose: even_print('ddx[u_Fv]','%s'%str(ddx_u_Fv.shape))
305
+ if verbose: even_print('ddy[u_Fv]','%s'%str(ddy_u_Fv.shape))
306
+
307
+ if ('data/v_Fv' in self):
308
+
309
+ v_Fv = np.copy( self['data/v_Fv'][()].T )
310
+
311
+ if self.rectilinear:
312
+ ddx_v_Fv = gradient(v_Fv, self.x, axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
313
+ ddy_v_Fv = gradient(v_Fv, self.y, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
314
+ elif self.curvilinear:
315
+ ddx_v_Fv_comp = gradient(v_Fv, x_comp, axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
316
+ ddy_v_Fv_comp = gradient(v_Fv, y_comp, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
317
+ ddx_v_Fv = ddx_v_Fv_comp*ddx_q1 + ddy_v_Fv_comp*ddx_q2
318
+ ddy_v_Fv = ddx_v_Fv_comp*ddy_q1 + ddy_v_Fv_comp*ddy_q2
319
+ else:
320
+ raise ValueError
321
+
322
+ if ('data/ddx_v_Fv' in self): del self['data/ddx_v_Fv']
323
+ self.create_dataset('data/ddx_v_Fv', data=ddx_v_Fv.T, chunks=None)
324
+
325
+ if ('data/ddy_v_Fv' in self): del self['data/ddy_v_Fv']
326
+ self.create_dataset('data/ddy_v_Fv', data=ddy_v_Fv.T, chunks=None)
327
+
328
+ if verbose: even_print('ddx[v_Fv]','%s'%str(ddx_v_Fv.shape))
329
+ if verbose: even_print('ddy[v_Fv]','%s'%str(ddy_v_Fv.shape))
330
+
331
+ self.get_header(verbose=False)
332
+ if verbose: print(72*'-')
333
+ if verbose: print('total time : ztmd.calc_gradients() : %s'%format_time_string((timeit.default_timer() - t_start_func)))
334
+ if verbose: print(72*'-')
335
+
336
+ return
337
+
338
+ def _calc_psvel(self, **kwargs):
339
+ '''
340
+ Calculate pseudovelocity, wall-normal cumulative integration of (-) z-vorticity
341
+ '''
342
+
343
+ verbose = kwargs.get('verbose',True)
344
+
345
+ if verbose: print('\n'+'ztmd.calc_psvel()'+'\n'+72*'-')
346
+ t_start_func = timeit.default_timer()
347
+
348
+ if 'data/vort_z' not in self:
349
+ raise ValueError("'data/vort_z' not in ztmd")
350
+
351
+ vort_z = np.copy( self['data/vort_z'][()].T )
352
+
353
+ nx = self.nx
354
+ ny = self.ny
355
+
356
+ if self.rectilinear:
357
+
358
+ x = np.copy( self['dims/x'][()] )
359
+ y = np.copy( self['dims/y'][()] )
360
+
361
+ elif self.curvilinear:
362
+
363
+ ## copy dims into memory
364
+ x = np.copy( self['dims/x'][()].T ) ## 2D
365
+ y = np.copy( self['dims/y'][()].T ) ## 2D
366
+
367
+ if ('dims/snorm' not in self):
368
+ raise AssertionError('dims/snorm not present')
369
+ if ('dims/stang' not in self):
370
+ raise AssertionError('dims/stang not present')
371
+
372
+ snorm = np.copy( self['dims/snorm'][()] ) ## 1D
373
+ #stang = np.copy( self['dims/stang'][()] ) ## 1D
374
+
375
+ if ('data/utang' not in self):
376
+ raise AssertionError('data/utang not present')
377
+
378
+ #utang = np.copy( self['data/utang'][()].T )
379
+ #unorm = np.copy( self['data/unorm'][()].T )
380
+
381
+ ## copy csys datasets into memory
382
+ #vtang = np.copy( self['csys/vtang'][()] )
383
+ #vnorm = np.copy( self['csys/vnorm'][()] )
384
+
385
+ if (x.shape != (self.nx,self.ny)):
386
+ raise ValueError('x.shape != (self.nx,self.ny)')
387
+ if (y.shape != (self.nx,self.ny)):
388
+ raise ValueError('y.shape != (self.nx,self.ny)')
389
+
390
+ else:
391
+ raise ValueError
392
+
393
+ ## the local 1D wall-normal coordinate
394
+ if self.rectilinear:
395
+ y_ = np.copy(y)
396
+ elif self.curvilinear:
397
+ y_ = np.copy(snorm)
398
+ else:
399
+ raise ValueError
400
+
401
+ ## pseudo-velocity is a cumulative integration of (-) z-vorticity
402
+ psvel = np.zeros(shape=(nx,ny), dtype=np.float64)
403
+ for i in range(nx):
404
+ psvel_ = sp.integrate.cumulative_trapezoid(-1*vort_z[i,:], y_, initial=0.)
405
+ psvel[i,:] = psvel_
406
+
407
+ if ('data/psvel' in self):
408
+ del self['data/psvel']
409
+ self.create_dataset('data/psvel', data=psvel.T, chunks=None)
410
+ if verbose: even_print('data/psvel','%s'%str(psvel.shape))
411
+
412
+ self.get_header(verbose=False)
413
+ if verbose: print(72*'-')
414
+ if verbose: print('total time : ztmd.calc_psvel() : %s'%format_time_string((timeit.default_timer() - t_start_func)))
415
+ if verbose: print(72*'-')
416
+
417
+ return
418
+
419
+ def _calc_wall_quantities(self, acc=6, edge_stencil='full', **kwargs):
420
+ '''
421
+ Get 1D wall quantities
422
+ -----
423
+ - [ ρ_wall, ν_wall, μ_wall, T_wall ]
424
+ - τ_wall = μ_wall·ddn[utang] :: [kg/(m·s)]·[m/s]/[m] = [kg/(m·s²)] = [N/m²] = [Pa]
425
+ - u_τ = (τ_wall/ρ_wall)^(1/2)
426
+ '''
427
+
428
+ verbose = kwargs.get('verbose',True)
429
+
430
+ if verbose: print('\n'+'ztmd.calc_wall_quantities()'+'\n'+72*'-')
431
+ t_start_func = timeit.default_timer()
432
+
433
+ if verbose: even_print('acc','%i'%(acc,))
434
+ if verbose: even_print('edge_stencil','%s'%(edge_stencil,))
435
+
436
+ ## check
437
+ if (self.x.ndim==1) and (self.y.ndim==1):
438
+ if hasattr(self,'rectilinear'):
439
+ if not self.rectilinear:
440
+ raise AssertionError
441
+ if hasattr(self,'curvilinear'):
442
+ if self.curvilinear:
443
+ raise AssertionError
444
+ elif (self.x.ndim==2) and (self.y.ndim==2):
445
+ if hasattr(self,'rectilinear'):
446
+ if self.rectilinear:
447
+ raise AssertionError
448
+ if hasattr(self,'curvilinear'):
449
+ if not self.curvilinear:
450
+ raise AssertionError
451
+ else:
452
+ raise ValueError
453
+
454
+ # ===
455
+
456
+ if self.curvilinear:
457
+
458
+ if self.requires_wall_norm_interp:
459
+
460
+ gndata = 'data_2Dw' ## group name for 2D data (interpolated)
461
+ #gndims = 'dims_2Dw' ## group name for 2D dims (interpolated)
462
+
463
+ ## wall-normal interpolation coordinates (2D)
464
+ #x_wn = np.copy( self[f'{gndata}/x'][()].T )
465
+ #y_wn = np.copy( self[f'{gndata}/y'][()].T )
466
+ s_wn = np.copy( self[f'{gndata}/wall_distance'][()].T )
467
+
468
+ else:
469
+
470
+ gndata = 'data' ## group name for 2D data
471
+ #gndims = 'dims' ## group name for 2D dims
472
+
473
+ #x_wn = np.copy( self['dims/x'][()].T )
474
+ #y_wn = np.copy( self['dims/y'][()].T )
475
+ s_wn = np.copy( self['dims/snorm'][()] )
476
+ #s_wn = np.broadcast_to(s_wn, (self.nx,self.ny))
477
+
478
+ if (f'{gndata}/utang' not in self):
479
+ raise AssertionError(f'{gndata}/utang not present')
480
+
481
+ ## wall-normal interpolated scalars (2D)
482
+ utang_wn = np.copy( self[f'{gndata}/utang'][()].T )
483
+ #T_wn = np.copy( self[f'{gndata}/T'][()].T )
484
+ vort_z_wn = np.copy( self[f'{gndata}/vort_z'][()].T )
485
+
486
+ # === get ρ_wall, ν_wall, μ_wall, T_wall
487
+
488
+ rho = np.copy( self['data/rho'][()].T )
489
+ rho_wall = np.copy( rho[:,0] )
490
+ if ('data_1Dx/rho_wall' in self): del self['data_1Dx/rho_wall']
491
+ self.create_dataset('data_1Dx/rho_wall', data=rho_wall, chunks=None)
492
+ if verbose: even_print('data_1Dx/rho_wall','%s'%str(rho_wall.shape))
493
+
494
+ nu = np.copy( self['data/nu'][()].T )
495
+ nu_wall = np.copy( nu[:,0] )
496
+ if ('data_1Dx/nu_wall' in self): del self['data_1Dx/nu_wall']
497
+ self.create_dataset('data_1Dx/nu_wall', data=nu_wall, chunks=None)
498
+ if verbose: even_print('data_1Dx/nu_wall','%s'%str(nu_wall.shape))
499
+
500
+ mu = np.copy( self['data/mu'][()].T )
501
+ mu_wall = np.copy( mu[:,0] )
502
+ if ('data_1Dx/mu_wall' in self): del self['data_1Dx/mu_wall']
503
+ self.create_dataset('data_1Dx/mu_wall', data=mu_wall, chunks=None)
504
+ if verbose: even_print('data_1Dx/mu_wall','%s'%str(mu_wall.shape))
505
+
506
+ T = np.copy( self['data/T'][()].T )
507
+ T_wall = np.copy( T[:,0] )
508
+ if ('data_1Dx/T_wall' in self): del self['data_1Dx/T_wall']
509
+ self.create_dataset('data_1Dx/T_wall', data=T_wall, chunks=None)
510
+ if verbose: even_print('data_1Dx/T_wall','%s'%str(T_wall.shape))
511
+
512
+ # === get wall ddn[]
513
+
514
+ if self.rectilinear:
515
+
516
+ ddy_u = np.copy( self['data/ddy_u'][()].T )
517
+
518
+ elif self.curvilinear:
519
+
520
+ if True:
521
+
522
+ if (s_wn.ndim==2): ## wall-normal distance (s_norm) is a 2D field
523
+
524
+ ddn_utang = np.zeros((self.nx,self.ny), dtype=np.float64) ## dimensional [m/s]/[m] = [1/s]
525
+ ddn_vort_z = np.zeros((self.nx,self.ny), dtype=np.float64)
526
+
527
+ progress_bar = tqdm(total=self.nx, ncols=100, desc='get ddn[]', leave=False, file=sys.stdout)
528
+ for i in range(self.nx):
529
+ ddn_utang[i,:] = gradient(utang_wn[i,:] , s_wn[i,:], axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
530
+ ddn_vort_z[i,:] = gradient(vort_z_wn[i,:] , s_wn[i,:], axis=0, acc=acc, edge_stencil=edge_stencil, d=1)
531
+ progress_bar.update()
532
+ progress_bar.close()
533
+
534
+ elif (s_wn.ndim==1): ## wall-normal distance (s_norm) is a 1D vector
535
+
536
+ ddn_utang = gradient(utang_wn , s_wn, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
537
+ ddn_vort_z = gradient(vort_z_wn , s_wn, axis=1, acc=acc, edge_stencil=edge_stencil, d=1)
538
+
539
+ if (f'{gndata}/ddn_utang' in self): del self[f'{gndata}/ddn_utang']
540
+ self.create_dataset(f'{gndata}/ddn_utang', data=ddn_utang.T, chunks=None)
541
+
542
+ if (f'{gndata}/ddn_vort_z' in self): del self[f'{gndata}/ddn_vort_z']
543
+ self.create_dataset(f'{gndata}/ddn_vort_z', data=ddn_vort_z.T, chunks=None)
544
+
545
+ if ('data_1Dx/ddn_utang_wall' in self): del self['data_1Dx/ddn_utang_wall']
546
+ self.create_dataset('data_1Dx/ddn_utang_wall', data=ddn_utang[:,0], chunks=None)
547
+
548
+ else:
549
+
550
+ ddn_utang = np.copy( self[f'{gndata}/ddn_utang'][()].T )
551
+ ddn_vort_z = np.copy( self[f'{gndata}/ddn_vort_z'][()].T )
552
+
553
+ else:
554
+ raise ValueError
555
+
556
+ # === calculate τ_wall & u_τ
557
+
558
+ ## wall shear stress τ_wall
559
+ if self.rectilinear:
560
+ tau_wall = np.copy( mu_wall * ddy_u[:,0] )
561
+ elif self.curvilinear:
562
+ tau_wall = np.copy( mu_wall * ddn_utang[:,0] )
563
+ else:
564
+ raise ValueError
565
+
566
+ ## τw
567
+ ## [N/m²] = [kg/(m·s²)] = [Pa]
568
+ if ('data_1Dx/tau_wall' in self): del self['data_1Dx/tau_wall']
569
+ self.create_dataset('data_1Dx/tau_wall', data=tau_wall, chunks=None)
570
+ if verbose: even_print('data_1Dx/tau_wall','%s'%str(tau_wall.shape))
571
+
572
+ ## friction velocity u_τ [m/s]
573
+ u_tau = np.copy( np.sqrt( tau_wall / rho_wall ) )
574
+
575
+ if ('data_1Dx/u_tau' in self): del self['data_1Dx/u_tau']
576
+ self.create_dataset('data_1Dx/u_tau', data=u_tau, chunks=None)
577
+ if verbose: even_print('data_1Dx/u_tau','%s'%str(u_tau.shape))
578
+
579
+ # === inner scales: length, velocity & time
580
+
581
+ sc_u_in = np.copy( u_tau )
582
+ sc_l_in = np.copy( nu_wall / u_tau )
583
+ sc_t_in = np.copy( nu_wall / u_tau**2 )
584
+ np.testing.assert_allclose(sc_t_in, sc_l_in/sc_u_in, rtol=1e-6, atol=1e-12)
585
+
586
+ if ('data_1Dx/sc_u_in' in self): del self['data_1Dx/sc_u_in']
587
+ self.create_dataset('data_1Dx/sc_u_in', data=sc_u_in, chunks=None)
588
+ if verbose: even_print('data_1Dx/sc_u_in','%s'%str(sc_u_in.shape))
589
+
590
+ if ('data_1Dx/sc_l_in' in self): del self['data_1Dx/sc_l_in']
591
+ self.create_dataset('data_1Dx/sc_l_in', data=sc_l_in, chunks=None)
592
+ if verbose: even_print('data_1Dx/sc_l_in','%s'%str(sc_l_in.shape))
593
+
594
+ if ('data_1Dx/sc_t_in' in self): del self['data_1Dx/sc_t_in']
595
+ self.create_dataset('data_1Dx/sc_t_in', data=sc_t_in, chunks=None)
596
+ if verbose: even_print('data_1Dx/sc_t_in','%s'%str(sc_t_in.shape))
597
+
598
+ self.get_header(verbose=False)
599
+ if verbose: print(72*'-')
600
+ if verbose: print('total time : ztmd.calc_wall_quantities() : %s'%format_time_string((timeit.default_timer() - t_start_func)))
601
+ if verbose: print(72*'-')
602
+
603
+ return
604
+
605
+ def _calc_bl_edge(self, **kwargs):
606
+ '''
607
+ Determine the boundary layer edge location
608
+ -----
609
+ if 'method'=='u' : 'edge' is where |du+/dy+|<ϵ
610
+ if 'method'=='vorticity' : 'edge' is where |-ω+|<ϵ
611
+ -----
612
+ y_edge : the wall-normal edge location
613
+ j_edge : the nearest index to y_edge
614
+ -----
615
+ ongrid : snap to [y] grid point
616
+ '''
617
+
618
+ verbose = kwargs.get('verbose',True)
619
+ method = kwargs.get('method','vorticity') ## 'u','vorticity'
620
+ epsilon = kwargs.get('epsilon',5e-5)
621
+ acc = kwargs.get('acc',6)
622
+ edge_stencil = kwargs.get('edge_stencil','full')
623
+ interp_kind = kwargs.get('interp_kind','cubic') ## 'linear','cubic'
624
+ ongrid = kwargs.get('ongrid',True) ## snap to grid point
625
+
626
+ if verbose: print('\n'+'ztmd.calc_bl_edge()'+'\n'+72*'-')
627
+ t_start_func = timeit.default_timer()
628
+
629
+ ## check rectilinear/curvilinear
630
+ if (self.x.ndim==1) and (self.y.ndim==1):
631
+ if hasattr(self,'rectilinear'):
632
+ if not self.rectilinear:
633
+ raise AssertionError
634
+ if hasattr(self,'curvilinear'):
635
+ if self.curvilinear:
636
+ raise AssertionError
637
+ elif (self.x.ndim==2) and (self.y.ndim==2):
638
+ if hasattr(self,'rectilinear'):
639
+ if self.rectilinear:
640
+ raise AssertionError
641
+ if hasattr(self,'curvilinear'):
642
+ if not self.curvilinear:
643
+ raise AssertionError
644
+ else:
645
+ raise ValueError
646
+
647
+ ## grids that don't have even s2 vectors
648
+ if self.requires_wall_norm_interp:
649
+ raise NotImplementedError
650
+
651
+ if not any([(method=='u'),(method=='vorticity')]):
652
+ raise ValueError("'method' should be one of: 'u','vorticity'")
653
+ if not any([(interp_kind=='linear'),(interp_kind=='cubic')]):
654
+ raise ValueError("'interp_kind' should be one of: 'linear','cubic'")
655
+
656
+ if verbose: even_print('method',method)
657
+ if verbose: even_print('epsilon','%0.1e'%(epsilon,))
658
+ if verbose: even_print('acc',f'{acc:d}')
659
+ if verbose: even_print('edge_stencil',edge_stencil)
660
+ if verbose: even_print('1D interp kind',interp_kind)
661
+ if verbose: even_print('ongrid',str(ongrid))
662
+
663
+ # ===
664
+
665
+ nx = self.nx
666
+ #ny = self.ny
667
+
668
+ ## copy 2D datasets into memory
669
+ u = np.copy( self['data/u'][()].T ) ## dimensional
670
+
671
+ sc_u_in = np.copy( self['data_1Dx/sc_u_in'][()] ) ## uτ
672
+ sc_l_in = np.copy( self['data_1Dx/sc_l_in'][()] ) ## δν = νw/uτ
673
+
674
+ if self.rectilinear:
675
+
676
+ x = np.copy( self['dims/x'][()] ) ## dimensional
677
+ y = np.copy( self['dims/y'][()] )
678
+
679
+ elif self.curvilinear:
680
+
681
+ ## copy dims into memory
682
+ x = np.copy( self['dims/x'][()].T ) ## 2D
683
+ y = np.copy( self['dims/y'][()].T ) ## 2D
684
+
685
+ if ('dims/snorm' not in self):
686
+ raise AssertionError('dims/snorm not present')
687
+ if ('dims/stang' not in self):
688
+ raise AssertionError('dims/stang not present')
689
+
690
+ snorm = np.copy( self['dims/snorm'][()] ) ## 1D
691
+ #stang = np.copy( self['dims/stang'][()] ) ## 1D
692
+
693
+ if ('data/utang' not in self):
694
+ raise AssertionError('data/utang not present')
695
+
696
+ utang = np.copy( self['data/utang'][()].T )
697
+ #unorm = np.copy( self['data/unorm'][()].T )
698
+
699
+ ## copy csys datasets into memory
700
+ #vtang = np.copy( self['csys/vtang'][()] )
701
+ vnorm = np.copy( self['csys/vnorm'][()] )
702
+
703
+ if (x.shape != (self.nx,self.ny)):
704
+ raise ValueError('x.shape != (self.nx,self.ny)')
705
+ if (y.shape != (self.nx,self.ny)):
706
+ raise ValueError('y.shape != (self.nx,self.ny)')
707
+
708
+ else:
709
+ raise ValueError
710
+
711
+ # ===
712
+
713
+ ## the local 1D wall-normal coordinate
714
+ if self.rectilinear:
715
+ y_ = np.copy(y)
716
+ elif self.curvilinear:
717
+ y_ = np.copy(snorm)
718
+ else:
719
+ raise ValueError
720
+
721
+ # ===
722
+
723
+ if (method=='vorticity'): ## use -ωz i.e. where |-ωz|<ϵ
724
+ if 'data/vort_z' not in self:
725
+ raise ValueError('data/vort_z not in ztmd')
726
+ vort_z = np.copy( self['data/vort_z'][()].T )
727
+
728
+ # ===
729
+
730
+ y_edge = np.zeros(shape=(nx,) , dtype=np.float64 )
731
+ j_edge = np.zeros(shape=(nx,) , dtype=np.int32 )
732
+ y_edge_2d = np.zeros(shape=(nx,2) , dtype=np.float64 )
733
+ y_edge_g = np.zeros(shape=(nx,) , dtype=np.float64 )
734
+
735
+ if (method=='vorticity'): ## ωz is already a derivative, dont need to pre-compute
736
+ pass
737
+ elif (method=='u'): ## pre-compute du/dy for efficiency
738
+ if self.rectilinear:
739
+ ddy_var = gradient(
740
+ u,
741
+ y_,
742
+ axis=1,
743
+ d=1,
744
+ acc=acc,
745
+ edge_stencil=edge_stencil,
746
+ )
747
+ elif self.curvilinear:
748
+ ddy_var = gradient(
749
+ utang,
750
+ y_,
751
+ axis=1,
752
+ d=1,
753
+ acc=acc,
754
+ edge_stencil=edge_stencil,
755
+ )
756
+ else:
757
+ raise ValueError
758
+ else:
759
+ raise ValueError
760
+
761
+ if verbose: progress_bar = tqdm(total=nx, ncols=100, desc='y_edge', leave=False, file=sys.stdout)
762
+ for i in range(nx):
763
+
764
+ do_debug_plot = False
765
+ #if (i==5000):
766
+ # do_debug_plot = True
767
+
768
+ if (method=='u'): ## |du+/dy+|<ϵ
769
+
770
+ ddy_u_ = np.copy( ddy_var[i,:] ) ## du/dy
771
+ ddy_u_plus_ = np.copy( ddy_u_ / ( sc_u_in[i] / sc_l_in[i] ) ) ## du+/dy+ = (du/dy)/(uτ/δν) = (du/dy)/(uτ^2/νw)
772
+
773
+ y_edge_ = calc_profile_edge_1d(
774
+ y=y_,
775
+ ddy_u=ddy_u_plus_,
776
+ ongrid=ongrid,
777
+ epsilon=epsilon,
778
+ acc=acc,
779
+ edge_stencil=edge_stencil,
780
+ interp_kind=interp_kind,
781
+ do_debug_plot=do_debug_plot,
782
+ )
783
+
784
+ elif (method=='vorticity'): ## |-ωz+|<ϵ
785
+
786
+ vort_z_ = np.copy( vort_z[i,:] ) ## ωz = (dv/dx)-(du/dy)
787
+ vort_z_plus_ = np.copy( vort_z_ / ( sc_u_in[i] / sc_l_in[i] ) ) ## ωz+ = ωz/(uτ/δν) = ωz/(uτ^2/νw)
788
+
789
+ y_edge_ = calc_profile_edge_1d(
790
+ y=y_,
791
+ ddy_u=-1*vort_z_plus_,
792
+ ongrid=ongrid,
793
+ epsilon=epsilon,
794
+ acc=acc,
795
+ edge_stencil=edge_stencil,
796
+ interp_kind=interp_kind,
797
+ do_debug_plot=do_debug_plot,
798
+ )
799
+
800
+ else:
801
+ raise ValueError
802
+
803
+ # ===
804
+
805
+ y_edge[i] = y_edge_
806
+ j_edge_ = np.abs( y_ - y_edge_ ).argmin()
807
+ j_edge[i] = j_edge_
808
+ y_edge_g[i] = y_[j_edge_]
809
+
810
+ if ongrid:
811
+ y_edge[i] = y_[j_edge_]
812
+
813
+ ## get the [x,y] coordinates of the 'edge line' --> shape=(nx,2)
814
+ if self.rectilinear:
815
+ pt_edge_ = np.array([self.x[i],y_edge_], dtype=np.float64)
816
+ elif self.curvilinear:
817
+ p0_ = np.array([self.x[i,0],self.y[i,0]], dtype=np.float64)
818
+ vnorm_ = np.copy( vnorm[i,0,:] ) ## unit normal vec @ wall at this x
819
+ pt_edge_ = p0_ + np.dot( y_edge_ , vnorm_ )
820
+ else:
821
+ raise ValueError
822
+
823
+ y_edge_2d[i,:] = pt_edge_
824
+
825
+ progress_bar.update()
826
+ progress_bar.close()
827
+
828
+ if ongrid:
829
+ np.testing.assert_allclose(y_edge,y_edge_g,rtol=1e-5)
830
+
831
+ if ('data_1Dx/y_edge' in self): del self['data_1Dx/y_edge']
832
+ self.create_dataset('data_1Dx/y_edge', data=y_edge, chunks=None)
833
+ if verbose: even_print('data_1Dx/y_edge','%s'%str(y_edge.shape))
834
+
835
+ if ('data_1Dx/y_edge_g' in self): del self['data_1Dx/y_edge_g']
836
+ self.create_dataset('data_1Dx/y_edge_g', data=y_edge_g, chunks=None)
837
+ if verbose: even_print('data_1Dx/y_edge_g','%s'%str(y_edge_g.shape))
838
+
839
+ if ('data_1Dx/y_edge_2d' in self): del self['data_1Dx/y_edge_2d']
840
+ self.create_dataset('data_1Dx/y_edge_2d', data=y_edge_2d, chunks=None)
841
+ if verbose: even_print('data_1Dx/y_edge_2d','%s'%str(y_edge_2d.shape))
842
+
843
+ if ('data_1Dx/j_edge' in self): del self['data_1Dx/j_edge']
844
+ self.create_dataset('data_1Dx/j_edge', data=j_edge, chunks=None)
845
+ if verbose: even_print('data_1Dx/j_edge','%s'%str(j_edge.shape))
846
+
847
+ # ===
848
+
849
+ self.get_header(verbose=False)
850
+ if verbose: print(72*'-')
851
+ if verbose: print('total time : ztmd.calc_bl_edge() : %s'%format_time_string((timeit.default_timer() - t_start_func)))
852
+ if verbose: print(72*'-')
853
+
854
+ return
855
+
856
+ def _calc_bl_edge_quantities(self, **kwargs):
857
+ '''
858
+ calculate field quantity values at [y_edge]
859
+ - calculate friction coefficient: cf = 2·τw/(ρe·ue^2) = 2/(ρe+·(ue+)^2)
860
+ '''
861
+
862
+ verbose = kwargs.get('verbose',True)
863
+ interp_kind = kwargs.get('interp_kind','cubic') ## 'linear','cubic'
864
+
865
+ if verbose: print('\n'+'ztmd.calc_bl_edge_quantities()'+'\n'+72*'-')
866
+ t_start_func = timeit.default_timer()
867
+
868
+ # ===
869
+
870
+ nx = self.nx
871
+ ny = self.ny
872
+
873
+ if self.rectilinear:
874
+
875
+ ## copy dims into memory
876
+ x = np.copy( self['dims/x'][()] )
877
+ y = np.copy( self['dims/y'][()] )
878
+
879
+ elif self.curvilinear:
880
+
881
+ if ('dims/snorm' not in self):
882
+ raise AssertionError('dims/snorm not present')
883
+ if ('dims/stang' not in self):
884
+ raise AssertionError('dims/stang not present')
885
+
886
+ snorm = np.copy( self['dims/snorm'][()] ) ## 1D
887
+ #stang = np.copy( self['dims/stang'][()] ) ## 1D
888
+
889
+ if ('data/utang' not in self):
890
+ raise AssertionError('data/utang not present')
891
+
892
+ ## copy dims into memory
893
+ x = np.copy( self['dims/x'][()].T )
894
+ y = np.copy( self['dims/y'][()].T )
895
+
896
+ ## copy csys datasets into memory
897
+ #vtang = np.copy( self['csys/vtang'][()] )
898
+ #vnorm = np.copy( self['csys/vnorm'][()] )
899
+
900
+ if (x.shape != (self.nx,self.ny)):
901
+ raise ValueError('x.shape != (self.nx,self.ny)')
902
+ if (y.shape != (self.nx,self.ny)):
903
+ raise ValueError('y.shape != (self.nx,self.ny)')
904
+
905
+ else:
906
+ raise ValueError
907
+
908
+ y_edge = np.copy( self['data_1Dx/y_edge'][()] )
909
+ y_edge_g = np.copy( self['data_1Dx/y_edge_g'][()] )
910
+ j_edge = np.copy( self['data_1Dx/j_edge'][()] )
911
+
912
+ ## was calc_bl_edge() run with ongrid=True?
913
+ if np.allclose(y_edge,y_edge_g,rtol=1e-6):
914
+ ongrid = True
915
+ else:
916
+ ongrid = False
917
+
918
+ if ongrid:
919
+ np.testing.assert_allclose(y_edge,y_edge_g,rtol=1e-6)
920
+
921
+ if self.rectilinear:
922
+ np.testing.assert_allclose(
923
+ y_edge_g,
924
+ np.array([ self.y[j] for j in j_edge ],dtype=y_edge.dtype),
925
+ rtol=1e-6,
926
+ )
927
+ elif self.curvilinear:
928
+ np.testing.assert_allclose(
929
+ y_edge_g,
930
+ np.array([ snorm[j] for j in j_edge ],dtype=y_edge.dtype),
931
+ rtol=1e-6,
932
+ )
933
+ else:
934
+ raise RuntimeError
935
+
936
+ ## the local 1D wall-normal coordinate
937
+ if self.rectilinear:
938
+ y_ = np.copy(y)
939
+ elif self.curvilinear:
940
+ y_ = np.copy(snorm)
941
+ else:
942
+ raise ValueError
943
+
944
+ # === make a numpy structured array
945
+
946
+ names = [ 'rho', 'u', 'v', 'w', 'T', 'p', 'vort_z', 'mu', 'nu', 'M' ]
947
+ if ('data/u_inc' in self):
948
+ names += [ 'u_inc' ]
949
+ if ('data/psvel' in self):
950
+ names += [ 'psvel' ]
951
+ if ('data/utang' in self):
952
+ names += [ 'utang' ]
953
+ if ('data/unorm' in self):
954
+ names += [ 'unorm' ]
955
+ if ('data/umag' in self):
956
+ names += [ 'umag' ]
957
+
958
+ dtypes=[]
959
+ for n in names:
960
+ ds = self[f'data/{n}']
961
+ dtypes.append( ds.dtype )
962
+
963
+ names_edge = [ n+'_edge' for n in names ]
964
+
965
+ data = np.zeros(shape=(nx,ny), dtype={'names':names, 'formats':dtypes})
966
+ data_edge = np.zeros(shape=(nx,), dtype={'names':names_edge, 'formats':dtypes})
967
+
968
+ ## populate 2D structured array with data to find edge for
969
+ for scalar in data.dtype.names:
970
+ data[scalar][:,:] = np.copy( self[f'data/{scalar}'][()].T )
971
+
972
+ # === interpolate edge quantity for all vars
973
+
974
+ if verbose: progress_bar = tqdm(total=nx*len(names), ncols=100, desc='edge quantities', leave=False, file=sys.stdout)
975
+ for scalar in data.dtype.names:
976
+ for i in range(nx):
977
+ if ongrid:
978
+ je = j_edge[i]
979
+ data_edge_ = data[scalar][i,je]
980
+ else:
981
+ data_y_ = np.copy( data[scalar][i,:] )
982
+ intrp_func = sp.interpolate.interp1d(y_, data_y_, kind=interp_kind, bounds_error=True)
983
+ data_edge_ = intrp_func(y_edge[i])
984
+ data_edge[scalar+'_edge'][i] = data_edge_
985
+ if verbose: progress_bar.update()
986
+ if verbose: progress_bar.close()
987
+
988
+ # === write
989
+
990
+ for scalar in data_edge.dtype.names:
991
+ if (f'data_1Dx/{scalar}' in self):
992
+ del self[f'data_1Dx/{scalar}']
993
+ data_ = np.copy( data_edge[scalar][:] )
994
+ dset = self.create_dataset(f'data_1Dx/{scalar}', data=data_, chunks=None)
995
+ if verbose: even_print(f'data_1Dx/{scalar}',str(dset.shape))
996
+
997
+ # ===
998
+
999
+ # if False:
1000
+ # plt.close('all')
1001
+ # fig1 = plt.figure(figsize=(3*2,3), dpi=300)
1002
+ # ax1 = plt.gca()
1003
+ # ax1.plot( stang/self.lchar, data_edge['utang_edge']/self.U_inf, lw=0.5 )
1004
+ # ax1.set_xlabel('stang')
1005
+ # fig1.tight_layout(pad=0.25)
1006
+ # fig1.tight_layout(pad=0.25)
1007
+ # plt.show()
1008
+
1009
+ # === cf (friction coefficient) = 2·τw/(ρe·ue^2) = 2/(ρe+·(ue+)^2)
1010
+
1011
+ u_tau = np.copy( self['data_1Dx/u_tau'][()] )
1012
+ rho_wall = np.copy( self['data_1Dx/rho_wall'][()] )
1013
+ tau_wall = np.copy( self['data_1Dx/tau_wall'][()] )
1014
+
1015
+ u_edge = np.copy( data_edge['u_edge'] )
1016
+ rho_edge = np.copy( data_edge['rho_edge'] )
1017
+
1018
+ #if self.curvilinear:
1019
+ # utang_edge = np.copy( data_edge['utang_edge'] )
1020
+
1021
+ if self.rectilinear:
1022
+
1023
+ ## assert cf formulas
1024
+ cf_1 = np.copy( 2. * (u_tau/u_edge)**2 * (rho_wall/rho_edge) )
1025
+ cf_2 = np.copy( 2. * tau_wall / (rho_edge*u_edge**2) )
1026
+ np.testing.assert_allclose(cf_1, cf_2, rtol=1e-6, atol=1e-8)
1027
+ cf_1 = None ; del cf_1
1028
+ cf_2 = None ; del cf_2
1029
+
1030
+ cf_inf = np.copy( 2. * tau_wall / ( self.rho_inf * self.U_inf**2 ) )
1031
+ cf_edge = np.copy( 2. * tau_wall / ( rho_edge * u_edge**2 ) )
1032
+ #np.testing.assert_allclose(cf_inf, cf_edge, rtol=0.01)
1033
+
1034
+ ## take 'edge' cf rather than 'inf' cf
1035
+ cf = np.copy(cf_edge)
1036
+
1037
+ elif self.curvilinear:
1038
+
1039
+ # cf_1 = 2. * (u_tau/utang_edge)**2 * (rho_wall/rho_edge)
1040
+ # cf_2 = 2. * tau_wall / (rho_edge*utang_edge**2)
1041
+ # np.testing.assert_allclose(cf_1, cf_2, rtol=1e-6, atol=1e-8)
1042
+ # cf = np.copy(cf_2)
1043
+
1044
+ cf_inf = np.copy( 2. * tau_wall / ( self.rho_inf * self.U_inf**2 ) )
1045
+ cf = np.copy(cf_inf)
1046
+
1047
+ else:
1048
+ raise ValueError
1049
+
1050
+ if ('data_1Dx/cf' in self): del self['data_1Dx/cf']
1051
+ self.create_dataset('data_1Dx/cf', data=cf, chunks=None)
1052
+ if verbose: even_print('data_1Dx/cf', '%s'%str(cf.shape))
1053
+
1054
+ # ===
1055
+
1056
+ self.get_header(verbose=False)
1057
+ if verbose: print(72*'-')
1058
+ if verbose: print('total time : ztmd.calc_bl_edge_quantities() : %s'%format_time_string((timeit.default_timer() - t_start_func)))
1059
+ if verbose: print(72*'-')
1060
+
1061
+ return
1062
+
1063
+ def _calc_d99(self, **kwargs):
1064
+ '''
1065
+ determine δ
1066
+ δ = δ99 = y[ u(y) == 0.99*u_edge ]
1067
+ 'u' can be pseudovelocity or streamwise velocity (set with 'method')
1068
+ '''
1069
+
1070
+ verbose = kwargs.get('verbose',True)
1071
+ method = kwargs.get('method','psvel') ## 'u','psvel'
1072
+ interp_kind = kwargs.get('interp_kind','cubic') ## 'linear','cubic'
1073
+ #rtol = kwargs.get('rtol',1e-3) ## used by calc_d99_1d() for asserting u[y_edge]==u_edge
1074
+ #rtol = 1e-3 ## now hardcoded rather than kwarg (inconsequential)
1075
+
1076
+ if verbose: print('\n'+'ztmd.calc_d99()'+'\n'+72*'-')
1077
+ t_start_func = timeit.default_timer()
1078
+
1079
+ ## check
1080
+ # ...
1081
+
1082
+ if not any([(method=='u'),(method=='psvel')]):
1083
+ raise ValueError("'method' should be one of: 'u','psvel'")
1084
+ if not any([(interp_kind=='linear'),(interp_kind=='cubic')]):
1085
+ raise ValueError("'interp_kind' should be one of: 'linear','cubic'")
1086
+
1087
+ if verbose: even_print('method',method)
1088
+ #if verbose: even_print('rtol','%0.1e'%(rtol,))
1089
+ if verbose: even_print('1D interp kind',interp_kind)
1090
+
1091
+ # ===
1092
+
1093
+ nx = self.nx
1094
+ #ny = self.ny
1095
+
1096
+ if self.rectilinear:
1097
+
1098
+ ## copy dims into memory (1D)
1099
+ x = np.copy( self['dims/x'][()] )
1100
+ y = np.copy( self['dims/y'][()] )
1101
+
1102
+ elif self.curvilinear:
1103
+
1104
+ if ('dims/snorm' not in self):
1105
+ raise AssertionError('dims/snorm not present')
1106
+ if ('dims/stang' not in self):
1107
+ raise AssertionError('dims/stang not present')
1108
+
1109
+ snorm = np.copy( self['dims/snorm'][()] ) ## 1D
1110
+ #stang = np.copy( self['dims/stang'][()] ) ## 1D
1111
+
1112
+ if ('data/utang' not in self):
1113
+ raise AssertionError('data/utang not present')
1114
+
1115
+ ## copy dims into memory (2D)
1116
+ x = np.copy( self['dims/x'][()].T )
1117
+ y = np.copy( self['dims/y'][()].T )
1118
+
1119
+ ## copy csys datasets into memory
1120
+ #vtang = np.copy( self['csys/vtang'][()] )
1121
+ vnorm = np.copy( self['csys/vnorm'][()] )
1122
+
1123
+ if (x.shape != (self.nx,self.ny)):
1124
+ raise ValueError('x.shape != (self.nx,self.ny)')
1125
+ if (y.shape != (self.nx,self.ny)):
1126
+ raise ValueError('y.shape != (self.nx,self.ny)')
1127
+
1128
+ else:
1129
+ raise ValueError
1130
+
1131
+ ## the local 1D wall-normal coordinate
1132
+ if self.rectilinear:
1133
+ y_ = np.copy(y)
1134
+ elif self.curvilinear:
1135
+ y_ = np.copy(snorm)
1136
+ else:
1137
+ raise ValueError
1138
+
1139
+ ## the wall normal location of BL edge, as determined in e.g. ztmd.calc_bl_edge()
1140
+ y_edge = np.copy( self['data_1Dx/y_edge'][()] )
1141
+ #y_edge_g = np.copy( self['data_1Dx/y_edge_g'][()] )
1142
+
1143
+ ## the index closest y_edge
1144
+ #j_edge = np.copy( self['data_1Dx/j_edge'][()] )
1145
+
1146
+ ## get pseudovelocity / u / utang
1147
+ if (method=='psvel'):
1148
+ var = np.copy( self['data/psvel'][()].T )
1149
+ var_edge = np.copy( self['data_1Dx/psvel_edge'][()].T )
1150
+ elif (method=='u'):
1151
+ if self.rectilinear:
1152
+ var = np.copy( self['data/u'][()].T )
1153
+ var_edge = np.copy( self['data_1Dx/u_edge'][()] )
1154
+ elif self.curvilinear:
1155
+ var = np.copy( self['data/utang'][()].T )
1156
+ var_edge = np.copy( self['data_1Dx/utang_edge'][()] )
1157
+ else:
1158
+ raise ValueError
1159
+ else:
1160
+ raise ValueError
1161
+
1162
+ # ===
1163
+
1164
+ d99 = np.zeros(shape=(nx,), dtype=np.float64 )
1165
+ d95 = np.zeros(shape=(nx,), dtype=np.float64 )
1166
+ d99_2d = np.zeros(shape=(nx,2), dtype=np.float64 )
1167
+ d95_2d = np.zeros(shape=(nx,2), dtype=np.float64 )
1168
+
1169
+ j99 = np.zeros(shape=(nx,), dtype=np.int32 )
1170
+ d99g = np.zeros(shape=(nx,), dtype=np.float64 )
1171
+
1172
+ if verbose: progress_bar = tqdm(total=nx, ncols=100, desc='δ', leave=False, file=sys.stdout)
1173
+ for i in range(nx):
1174
+
1175
+ y_edge_ = y_edge[i]
1176
+ var_ = np.copy( var[i,:] )
1177
+ var_edge_ = var_edge[i]
1178
+
1179
+ d99_ = calc_d99_1d(y=y_, u=var_, y_edge=y_edge_, u_edge=var_edge_, interp_kind=interp_kind, d95=False)
1180
+ d99[i] = d99_
1181
+
1182
+ d95_ = calc_d99_1d(y=y_, u=var_, y_edge=y_edge_, u_edge=var_edge_, interp_kind=interp_kind, d95=True)
1183
+ d95[i] = d95_
1184
+
1185
+ j99_ = np.abs( y_ - d99_ ).argmin()
1186
+ j99[i] = j99_
1187
+ d99g[i] = y_[j99_]
1188
+
1189
+ # ===
1190
+
1191
+ ## get the [x,y] coordinates of the 'd99 line' --> shape=(nx,2)
1192
+ if self.rectilinear:
1193
+ pt_99_ = np.array([self.x[i],d99_], dtype=np.float64)
1194
+ pt_95_ = np.array([self.x[i],d95_], dtype=np.float64)
1195
+ elif self.curvilinear:
1196
+ p0_ = np.array([self.x[i,0],self.y[i,0]], dtype=np.float64)
1197
+ vnorm_ = np.copy( vnorm[i,0,:] ) ## unit normal vec @ wall at this x
1198
+ pt_99_ = p0_ + np.dot( d99_ , vnorm_ )
1199
+ pt_95_ = p0_ + np.dot( d95_ , vnorm_ )
1200
+ else:
1201
+ raise ValueError
1202
+
1203
+ d99_2d[i,:] = pt_99_
1204
+ d95_2d[i,:] = pt_95_
1205
+
1206
+ progress_bar.update()
1207
+ progress_bar.close()
1208
+
1209
+ if ('data_1Dx/d99' in self): del self['data_1Dx/d99']
1210
+ self.create_dataset('data_1Dx/d99', data=d99, chunks=None)
1211
+ if verbose: even_print('data_1Dx/d99','%s'%str(d99.shape))
1212
+
1213
+ if ('data_1Dx/d95' in self): del self['data_1Dx/d95']
1214
+ self.create_dataset('data_1Dx/d95', data=d95, chunks=None)
1215
+ if verbose: even_print('data_1Dx/d95','%s'%str(d95.shape))
1216
+
1217
+ if ('data_1Dx/d99_2d' in self): del self['data_1Dx/d99_2d']
1218
+ self.create_dataset('data_1Dx/d99_2d', data=d99_2d, chunks=None)
1219
+ if verbose: even_print('data_1Dx/d99_2d','%s'%str(d99_2d.shape))
1220
+
1221
+ if ('data_1Dx/d95_2d' in self): del self['data_1Dx/d95_2d']
1222
+ self.create_dataset('data_1Dx/d95_2d', data=d95_2d, chunks=None)
1223
+ if verbose: even_print('data_1Dx/d95_2d','%s'%str(d95_2d.shape))
1224
+
1225
+ if ('data_1Dx/d99g' in self): del self['data_1Dx/d99g']
1226
+ self.create_dataset('data_1Dx/d99g', data=d99g, chunks=None)
1227
+ if verbose: even_print('data_1Dx/d99g','%s'%str(d99g.shape))
1228
+
1229
+ if ('data_1Dx/j99' in self): del self['data_1Dx/j99']
1230
+ self.create_dataset('data_1Dx/j99', data=j99, chunks=None)
1231
+ if verbose: even_print('data_1Dx/j99','%s'%str(j99.shape))
1232
+
1233
+ # ===
1234
+
1235
+ self.get_header(verbose=False)
1236
+ if verbose: print(72*'-')
1237
+ if verbose: print('total time : ztmd.calc_d99() : %s'%format_time_string((timeit.default_timer() - t_start_func)))
1238
+ if verbose: print(72*'-')
1239
+
1240
+ return
1241
+
1242
+ def _calc_d99_quantities(self, **kwargs):
1243
+ '''
1244
+ calculate interpolated field quantity values at y=δ
1245
+ - sc_l_out = δ99
1246
+ - sc_u_out = u99
1247
+ - sc_t_out = u99/d99
1248
+ '''
1249
+
1250
+ verbose = kwargs.get('verbose',True)
1251
+ interp_kind = kwargs.get('interp_kind','cubic') ## 'linear','cubic'
1252
+
1253
+ if verbose: print('\n'+'ztmd.calc_d99_quantities()'+'\n'+72*'-')
1254
+ t_start_func = timeit.default_timer()
1255
+
1256
+ ## check
1257
+ # ...
1258
+
1259
+ if not any([(interp_kind=='linear'),(interp_kind=='cubic')]):
1260
+ raise ValueError("'interp_kind' should be one of: 'linear','cubic'")
1261
+
1262
+ if verbose: even_print('1D interp kind',interp_kind)
1263
+
1264
+ nx = self.nx
1265
+ ny = self.ny
1266
+
1267
+ if self.rectilinear:
1268
+
1269
+ ## copy dims into memory
1270
+ x = np.copy( self['dims/x'][()] )
1271
+ y = np.copy( self['dims/y'][()] )
1272
+
1273
+ elif self.curvilinear:
1274
+
1275
+ if ('dims/snorm' not in self):
1276
+ raise AssertionError('dims/snorm not present')
1277
+ if ('dims/stang' not in self):
1278
+ raise AssertionError('dims/stang not present')
1279
+
1280
+ snorm = np.copy( self['dims/snorm'][()] ) ## 1D
1281
+ #stang = np.copy( self['dims/stang'][()] ) ## 1D
1282
+
1283
+ if ('data/utang' not in self):
1284
+ raise AssertionError('data/utang not present')
1285
+
1286
+ ## copy dims into memory
1287
+ x = np.copy( self['dims/x'][()].T )
1288
+ y = np.copy( self['dims/y'][()].T )
1289
+
1290
+ ## copy csys datasets into memory
1291
+ #vtang = np.copy( self['csys/vtang'][()] )
1292
+ #vnorm = np.copy( self['csys/vnorm'][()] )
1293
+
1294
+ if (x.shape != (self.nx,self.ny)):
1295
+ raise ValueError('x.shape != (self.nx,self.ny)')
1296
+ if (y.shape != (self.nx,self.ny)):
1297
+ raise ValueError('y.shape != (self.nx,self.ny)')
1298
+
1299
+ else:
1300
+ raise ValueError
1301
+
1302
+ d99 = np.copy( self['data_1Dx/d99'][()] )
1303
+
1304
+ ## the local 1D wall-normal coordinate
1305
+ if self.rectilinear:
1306
+ y_ = np.copy(y)
1307
+ elif self.curvilinear:
1308
+ y_ = np.copy(snorm)
1309
+ else:
1310
+ raise ValueError
1311
+
1312
+ # === make a structured array
1313
+
1314
+ names = [ 'rho', 'u', 'v', 'w', 'T', 'p', 'vort_z', 'mu', 'nu', 'M' ]
1315
+ if ('data/psvel' in self):
1316
+ names += [ 'psvel' ]
1317
+ if ('data/utang' in self):
1318
+ names += [ 'utang' ]
1319
+ if ('data/unorm' in self):
1320
+ names += [ 'unorm' ]
1321
+ if ('data/umag' in self):
1322
+ names += [ 'umag' ]
1323
+
1324
+ dtypes=[]
1325
+ for n in names:
1326
+ ds = self[f'data/{n}']
1327
+ dtypes.append( ds.dtype )
1328
+
1329
+ #names_99 = [ n+'99' for n in names ]
1330
+ names_99 = [ n+'_99' if ('_' in n) else n+'99' for n in names ]
1331
+
1332
+ data = np.zeros(shape=(nx,ny), dtype={'names':names, 'formats':dtypes})
1333
+ data_99 = np.zeros(shape=(nx,), dtype={'names':names_99, 'formats':dtypes})
1334
+
1335
+ # === populate structured array
1336
+
1337
+ for scalar in data.dtype.names:
1338
+ data[scalar][:,:] = np.copy( self[f'data/{scalar}'][()].T )
1339
+
1340
+ # === interpolate @ δ99 for all vars
1341
+
1342
+ if verbose: progress_bar = tqdm(total=nx*len(names), ncols=100, desc='δ99 quantities', leave=False, file=sys.stdout)
1343
+ for ni,scalar in enumerate(data.dtype.names):
1344
+ for i in range(nx):
1345
+
1346
+ data_y_ = np.copy( data[scalar][i,:] )
1347
+ intrp_func = sp.interpolate.interp1d(y_, data_y_, kind=interp_kind, bounds_error=True)
1348
+
1349
+ d99_ = d99[i]
1350
+ data_99_ = intrp_func(d99_)
1351
+
1352
+ data_99[names_99[ni]][i] = data_99_
1353
+
1354
+ if verbose: progress_bar.update()
1355
+ if verbose: progress_bar.close()
1356
+
1357
+ # === write
1358
+
1359
+ for scalar in data_99.dtype.names:
1360
+ if (f'data_1Dx/{scalar}' in self):
1361
+ del self[f'data_1Dx/{scalar}']
1362
+ data_ = np.copy( data_99[scalar][:] )
1363
+ dset = self.create_dataset(f'data_1Dx/{scalar}', data=data_, chunks=None)
1364
+ if verbose: even_print(f'data_1Dx/{scalar}',str(dset.shape))
1365
+
1366
+ # === outer scales: length, velocity & time
1367
+
1368
+ sc_l_out = np.copy( d99 )
1369
+
1370
+ if self.rectilinear:
1371
+ sc_u_out = np.copy( data_99['u99'] )
1372
+ sc_t_out = np.copy( d99/data_99['u99'] )
1373
+ elif self.curvilinear:
1374
+ sc_u_out = np.copy( data_99['utang99'] )
1375
+ sc_t_out = np.copy( d99/data_99['utang99'] )
1376
+ else:
1377
+ raise ValueError
1378
+
1379
+ np.testing.assert_allclose(sc_t_out, sc_l_out/sc_u_out, rtol=1e-14, atol=1e-14)
1380
+
1381
+ u_tau = np.copy( self['data_1Dx/u_tau'][()] )
1382
+ sc_t_eddy = np.copy( d99/u_tau )
1383
+
1384
+ if ('data_1Dx/sc_u_out' in self): del self['data_1Dx/sc_u_out']
1385
+ self.create_dataset('data_1Dx/sc_u_out', data=sc_u_out, chunks=None)
1386
+ if verbose: even_print('data_1Dx/sc_u_out', '%s'%str(sc_u_out.shape))
1387
+
1388
+ if ('data_1Dx/sc_l_out' in self): del self['data_1Dx/sc_l_out']
1389
+ self.create_dataset('data_1Dx/sc_l_out', data=sc_l_out, chunks=None)
1390
+ if verbose: even_print('data_1Dx/sc_l_out', '%s'%str(sc_l_out.shape))
1391
+
1392
+ if ('data_1Dx/sc_t_out' in self): del self['data_1Dx/sc_t_out']
1393
+ self.create_dataset('data_1Dx/sc_t_out', data=sc_t_out, chunks=None)
1394
+ if verbose: even_print('data_1Dx/sc_t_out', '%s'%str(sc_t_out.shape))
1395
+
1396
+ if ('data_1Dx/sc_t_eddy' in self): del self['data_1Dx/sc_t_eddy']
1397
+ self.create_dataset('data_1Dx/sc_t_eddy', data=sc_t_eddy, chunks=None)
1398
+ if verbose: even_print('data_1Dx/sc_t_eddy', '%s'%str(sc_t_eddy.shape))
1399
+
1400
+ self.get_header(verbose=False)
1401
+ if verbose: print(72*'-')
1402
+ if verbose: print('total time : ztmd.calc_d99_quantities() : %s'%format_time_string((timeit.default_timer() - t_start_func)))
1403
+ if verbose: print(72*'-')
1404
+
1405
+ return
1406
+
1407
+ def _calc_bl_integral_quantities(self, **kwargs):
1408
+ '''
1409
+ Calculate boundary layer integral quantities
1410
+ δ*=δ1, θ=δ2, Reθ, Reδ2, H12, H32, etc.
1411
+ -----
1412
+ - Also: Reδ2, Reδ99 out of convenience
1413
+ '''
1414
+ verbose = kwargs.get('verbose', True)
1415
+ interp_kind = kwargs.get('interp_kind', 'cubic')
1416
+
1417
+ if interp_kind not in ('linear', 'cubic'):
1418
+ raise ValueError("'interp_kind' should be one of: 'linear','cubic'")
1419
+
1420
+ if verbose:
1421
+ print('\n' + 'ztmd.calc_bl_integral_quantities()' + '\n' + 72*'-')
1422
+ t_start_func = timeit.default_timer()
1423
+
1424
+ nx = self.nx
1425
+ #ny = self.ny
1426
+
1427
+ ## Geometry: Flat-plate vs Curved
1428
+ if self.rectilinear:
1429
+ y = np.copy(self['dims/y'][()])
1430
+ y_ = y
1431
+ elif self.curvilinear:
1432
+ y_ = np.copy(self['dims/snorm'][()])
1433
+ else:
1434
+ raise ValueError
1435
+
1436
+ ## 1D [x] profiles
1437
+ u_tau = np.copy(self['data_1Dx/u_tau'][()])
1438
+ rho_wall = np.copy(self['data_1Dx/rho_wall'][()])
1439
+ nu_wall = np.copy(self['data_1Dx/nu_wall'][()])
1440
+ mu_wall = np.copy(self['data_1Dx/mu_wall'][()])
1441
+
1442
+ y_edge = np.copy(self['data_1Dx/y_edge'][()])
1443
+ d99 = np.copy(self['data_1Dx/d99'][()])
1444
+ rho_edge = np.copy(self['data_1Dx/rho_edge'][()])
1445
+ mu_edge = np.copy(self['data_1Dx/mu_edge'][()])
1446
+ nu_edge = np.copy(self['data_1Dx/nu_edge'][()])
1447
+
1448
+ if self.rectilinear:
1449
+ u_edge = np.copy(self['data_1Dx/u_edge'][()])
1450
+ else:
1451
+ u_edge = np.copy(self['data_1Dx/utang_edge'][()]) ## !! reading 'utang' as local 'u' !!
1452
+
1453
+ ## 2D data
1454
+ u = np.copy(self['data/u'][()].T)
1455
+ rho = np.copy(self['data/rho'][()].T)
1456
+
1457
+ if self.curvilinear:
1458
+ u = np.copy(self['data/utang'][()].T)
1459
+
1460
+ ## Output arrays
1461
+ d1 = np.full((nx,), np.nan, dtype=np.float64)
1462
+ d1_k = np.full((nx,), np.nan, dtype=np.float64)
1463
+ d2 = np.full((nx,), np.nan, dtype=np.float64)
1464
+ d2_k = np.full((nx,), np.nan, dtype=np.float64)
1465
+ d3 = np.full((nx,), np.nan, dtype=np.float64)
1466
+ d3_k = np.full((nx,), np.nan, dtype=np.float64)
1467
+ dRC = np.full((nx,), np.nan, dtype=np.float64)
1468
+ dRC_k = np.full((nx,), np.nan, dtype=np.float64)
1469
+
1470
+ if verbose:
1471
+ progress_bar = tqdm(total=nx, ncols=100, desc='BL integrals', leave=False)
1472
+
1473
+ # Main loop
1474
+ # ==================================================================
1475
+
1476
+ for i in range(nx):
1477
+
1478
+ u_ = u[i,:]
1479
+ rho_ = rho[i,:]
1480
+ y_edge_ = y_edge[i]
1481
+
1482
+ ## Compressible integrals
1483
+
1484
+ d1[i] = calc_d1(
1485
+ y_, u_,
1486
+ rho=rho_,
1487
+ y_edge=y_edge_,
1488
+ interp_kind=interp_kind,
1489
+ )
1490
+
1491
+ d2[i] = calc_d2(
1492
+ y_, u_,
1493
+ rho=rho_,
1494
+ y_edge=y_edge_,
1495
+ interp_kind=interp_kind,
1496
+ )
1497
+
1498
+ d3[i] = calc_d3(
1499
+ y_, u_,
1500
+ rho=rho_,
1501
+ y_edge=y_edge_,
1502
+ interp_kind=interp_kind,
1503
+ )
1504
+
1505
+ dRC[i] = calc_dRC(
1506
+ y_, u_,
1507
+ u_tau=u_tau[i],
1508
+ rho=rho_,
1509
+ rho_wall=rho_wall[i],
1510
+ y_edge=y_edge_,
1511
+ interp_kind=interp_kind,
1512
+ )
1513
+
1514
+ ## Kinetic (u-only) integrals
1515
+
1516
+ d1_k[i] = calc_d1(
1517
+ y_, u_,
1518
+ rho=None,
1519
+ y_edge=y_edge_,
1520
+ interp_kind=interp_kind,
1521
+ )
1522
+
1523
+ d2_k[i] = calc_d2(
1524
+ y_, u_,
1525
+ rho=None,
1526
+ y_edge=y_edge_,
1527
+ interp_kind=interp_kind,
1528
+ )
1529
+
1530
+ d3_k[i] = calc_d3(
1531
+ y_, u_,
1532
+ rho=None,
1533
+ y_edge=y_edge_,
1534
+ interp_kind=interp_kind,
1535
+ )
1536
+
1537
+ dRC_k[i] = calc_dRC(
1538
+ y_, u_,
1539
+ u_tau=u_tau[i],
1540
+ rho=None,
1541
+ rho_wall=None,
1542
+ y_edge=y_edge_,
1543
+ interp_kind=interp_kind,
1544
+ )
1545
+
1546
+ if verbose:
1547
+ progress_bar.update()
1548
+
1549
+ if verbose:
1550
+ progress_bar.close()
1551
+
1552
+ # ===
1553
+
1554
+ dstar = np.copy( d1 ) ## δ* = δ1
1555
+ dstar_k = np.copy( d1_k )
1556
+
1557
+ theta = np.copy( d2 ) ## θ = δ2
1558
+ theta_k = np.copy( d2_k )
1559
+
1560
+ H12 = np.copy( d1 / d2 ) ## H12 = δ*/θ
1561
+ H12_k = np.copy( d1_k / d2_k )
1562
+ H32 = np.copy( d3 / d2 ) ## H32 = δ3/δ2
1563
+ H32_k = np.copy( d3_k / d2_k )
1564
+
1565
+ ## νw = μw / ρw
1566
+ np.testing.assert_allclose(
1567
+ nu_wall,
1568
+ mu_wall / rho_wall,
1569
+ rtol=1e-6,
1570
+ )
1571
+
1572
+ ## νe = μe / ρe
1573
+ np.testing.assert_allclose(
1574
+ nu_edge,
1575
+ mu_edge / rho_edge,
1576
+ rtol=1e-6,
1577
+ )
1578
+
1579
+ ## Reynolds numbers
1580
+ Re_tau = np.copy( d99 * u_tau * rho_wall / mu_wall ) ## Reτ = δ99·uτ·ρw / μw
1581
+ Re_theta = np.copy( theta * u_edge * rho_edge / mu_edge ) ## Reθ = θ·ue·ρe / μe
1582
+ Re_dstar = np.copy( dstar * u_edge * rho_edge / mu_edge ) ## Reδ* = δ*·ue·ρe / μe
1583
+ Re_d2 = np.copy( theta * u_edge * rho_edge / mu_wall ) ## Reδ2 = θ·ue·ρe / μw
1584
+ Re_d99 = np.copy( d99 * u_edge * rho_edge / mu_edge ) ## Reδ99 = δ99·ue·ρe / μe
1585
+ Re_theta_k = np.copy( theta_k * u_edge * rho_edge / mu_edge ) ## Reθk = θk·ue·ρe / μe
1586
+ Re_dstar_k = np.copy( dstar_k * u_edge * rho_edge / mu_edge ) ## Reδ*k = δ*k·ue·ρe / μe
1587
+
1588
+ ## Reδ2 = Reθk = (μe/μw)·Reθ ≈ (μ∞/μw)·Reθ
1589
+ np.testing.assert_allclose(
1590
+ Re_d2,
1591
+ (mu_edge / mu_wall) * Re_theta,
1592
+ rtol=1e-6,
1593
+ )
1594
+
1595
+ ## H12 = δ*/θ = Reδ*/Reθ
1596
+ np.testing.assert_allclose(
1597
+ Re_dstar / Re_theta,
1598
+ H12,
1599
+ rtol=1e-6,
1600
+ )
1601
+
1602
+ ## H12k = δ*k/θk = Reδ*k/Reθk
1603
+ np.testing.assert_allclose(
1604
+ Re_dstar_k / Re_theta_k,
1605
+ H12_k,
1606
+ rtol=1e-6,
1607
+ )
1608
+
1609
+ uplus_edge = np.copy( u_edge / u_tau )
1610
+ rhoplus_edge = np.copy( rho_edge / rho_wall )
1611
+ muplus_edge = np.copy( mu_edge / mu_wall )
1612
+
1613
+ ## Reδ*/Reτ = (δ*/δ99)·(ue/uτ)·(ρe/ρw)·(μw/μe)
1614
+ ## = (δ*/δ99)·(ue+·ρe+/μe+)
1615
+ np.testing.assert_allclose(
1616
+ Re_dstar / Re_tau,
1617
+ ( dstar / d99 ) * uplus_edge * rhoplus_edge / muplus_edge,
1618
+ rtol=1e-6,
1619
+ )
1620
+
1621
+ ## Reθ/Reτ = (θ/δ99)·(ue/uτ)·(ρe/ρw)·(μw/μe)
1622
+ ## = (θ/δ99)·(ue+·ρe+/μe+)
1623
+ np.testing.assert_allclose(
1624
+ Re_theta / Re_tau,
1625
+ ( theta / d99 ) * uplus_edge * rhoplus_edge / muplus_edge,
1626
+ rtol=1e-6,
1627
+ )
1628
+
1629
+ ## Helper for writing datasets
1630
+ def _write(name, arr):
1631
+ if name in self: ## Delete if exists
1632
+ del self[name]
1633
+ self.create_dataset(name, data=arr, chunks=None) ## Write
1634
+ if verbose:
1635
+ even_print(name, str(arr.shape))
1636
+
1637
+ ## Write datasets to ZTMD HDF5
1638
+ _write('data_1Dx/d1' , d1 )
1639
+ _write('data_1Dx/d1_k' , d1_k )
1640
+ _write('data_1Dx/dstar' , dstar )
1641
+ _write('data_1Dx/dstar_k' , dstar_k )
1642
+
1643
+ _write('data_1Dx/d2' , d2 )
1644
+ _write('data_1Dx/d2_k' , d2_k )
1645
+ _write('data_1Dx/theta' , theta )
1646
+ _write('data_1Dx/theta_k' , theta_k )
1647
+
1648
+ _write('data_1Dx/d3' , d3 )
1649
+ _write('data_1Dx/d3_k' , d3_k )
1650
+
1651
+ _write('data_1Dx/dRC' , dRC )
1652
+ _write('data_1Dx/dRC_k' , dRC_k )
1653
+
1654
+ _write('data_1Dx/H12' , H12 )
1655
+ _write('data_1Dx/H12_k' , H12_k )
1656
+ _write('data_1Dx/H32' , H32 )
1657
+ _write('data_1Dx/H32_k' , H32_k )
1658
+
1659
+ _write('data_1Dx/Re_tau' , Re_tau )
1660
+ _write('data_1Dx/Re_theta' , Re_theta )
1661
+ _write('data_1Dx/Re_theta_k' , Re_theta_k )
1662
+ _write('data_1Dx/Re_d99' , Re_d99 )
1663
+ _write('data_1Dx/Re_d2' , Re_d2 )
1664
+ _write('data_1Dx/Re_dstar' , Re_dstar )
1665
+ _write('data_1Dx/Re_dstar_k' , Re_dstar_k )
1666
+
1667
+ ## Update header
1668
+ self.get_header(verbose=False)
1669
+
1670
+ if verbose:
1671
+ print(72*'-')
1672
+ print(
1673
+ 'total time : ztmd.calc_bl_integral_quantities() : %s'
1674
+ % format_time_string(timeit.default_timer() - t_start_func)
1675
+ )
1676
+ print(72*'-')
1677
+
1678
+ return
1679
+
1680
+ # ======================================================================
1681
+
1682
+ def _calc_u_inc(self, method='rho', **kwargs):
1683
+ '''
1684
+ calculate the 'incompressible' streamwise velocity profile
1685
+ Van Driest (1951) : https://doi.org/10.2514/8.1895
1686
+ '''
1687
+
1688
+ verbose = kwargs.get('verbose',True)
1689
+
1690
+ if verbose: print('\n'+'ztmd.calc_u_inc()'+'\n'+72*'-')
1691
+ t_start_func = timeit.default_timer()
1692
+
1693
+ if not any([(method=='rho'),(method=='T')]):
1694
+ raise ValueError(f"method {str(method)} not valid. options are: 'rho','T'")
1695
+
1696
+ if verbose: even_print('method',method)
1697
+
1698
+ rho_wall = np.copy( self['data_1Dx/rho_wall'][()] )
1699
+ T_wall = np.copy( self['data_1Dx/T_wall'][()] )
1700
+
1701
+ T = np.copy( self['data/T'][()].T )
1702
+ rho = np.copy( self['data/rho'][()].T )
1703
+
1704
+ if self.rectilinear:
1705
+ u = np.copy( self['data/u'][()].T )
1706
+ elif self.curvilinear:
1707
+ u = np.copy( self['data/utang'][()].T )
1708
+ else:
1709
+ raise ValueError
1710
+
1711
+ u_inc = np.zeros(shape=(self.nx,self.ny), dtype=np.float64)
1712
+ if verbose: progress_bar = tqdm(total=self.nx, ncols=100, desc='calc u_inc', leave=False, file=sys.stdout)
1713
+ for i in range(self.nx):
1714
+
1715
+ if (method=='T'):
1716
+ integrand_u_inc = np.copy( np.sqrt(T_wall[i]/T[i,:]) )
1717
+ elif (method=='rho'):
1718
+ integrand_u_inc = np.copy( np.sqrt(rho[i,:]/rho_wall[i]) )
1719
+ else:
1720
+ raise ValueError
1721
+
1722
+ u_inc[i,:] = sp.integrate.cumulative_trapezoid(integrand_u_inc, u[i,:], initial=0.)
1723
+
1724
+ if verbose: progress_bar.update()
1725
+ if verbose: progress_bar.close()
1726
+
1727
+ if self.rectilinear:
1728
+ if ('data/u_inc' in self): del self['data/u_inc']
1729
+ self.create_dataset('data/u_inc', data=u_inc.T, chunks=None)
1730
+ if verbose: even_print('data/u_inc', '%s'%str(u_inc.shape))
1731
+ elif self.curvilinear:
1732
+ if ('data/utang_inc' in self): del self['data/utang_inc']
1733
+ self.create_dataset('data/utang_inc', data=u_inc.T, chunks=None)
1734
+ if verbose: even_print('data/utang_inc', '%s'%str(u_inc.shape))
1735
+ else:
1736
+ raise ValueError
1737
+
1738
+ self.get_header(verbose=False)
1739
+ if verbose: print(72*'-')
1740
+ if verbose: print('total time : ztmd.calc_u_inc() : %s'%format_time_string((timeit.default_timer() - t_start_func)))
1741
+ if verbose: print(72*'-')
1742
+
1743
+ return
1744
+
1745
+ def _calc_d99_inc(self, **kwargs):
1746
+ '''
1747
+ determine δ99 & δ95 for van Driest transformed u
1748
+ '''
1749
+
1750
+ verbose = kwargs.get('verbose',True)
1751
+ interp_kind = kwargs.get('interp_kind','cubic') ## 'linear','cubic'
1752
+ #rtol = kwargs.get('rtol',1e-3)
1753
+
1754
+ if verbose: print('\n'+'ztmd.calc_d99_inc()'+'\n'+72*'-')
1755
+ t_start_func = timeit.default_timer()
1756
+
1757
+ ## check
1758
+ # ...
1759
+
1760
+ if not any([(interp_kind=='linear'),(interp_kind=='cubic')]):
1761
+ raise ValueError("'interp_kind' should be one of: 'linear','cubic'")
1762
+
1763
+ #if verbose: even_print('rtol','%0.1e'%(rtol,))
1764
+ if verbose: even_print('1D interp kind',interp_kind)
1765
+
1766
+ #y_edge = np.copy( self['data_1Dx/y_edge_inc'][()] ) ## !! importing INCOMPRESSIBLE y_edge_inc as y_edge
1767
+ y_edge = np.copy( self['data_1Dx/y_edge'][()] ) ## !! importing REGULAR y_edge
1768
+
1769
+ #print( np.mean( y_edge[2406:19124] - y_edge_inc[2406:19124] ) )
1770
+
1771
+ if self.rectilinear:
1772
+ y = np.copy( self['dims/y'][()] )
1773
+ u = np.copy( self['data/u_inc'][()].T ) ## !! importing van Driest incompressible u_inc as 'u'
1774
+ elif self.curvilinear:
1775
+ y = np.copy( self['dims/snorm'][()] )
1776
+ u = np.copy( self['data/utang_inc'][()].T )
1777
+ else:
1778
+ raise ValueError
1779
+
1780
+ d99_inc = np.zeros(shape=(self.nx,), dtype=np.float64)
1781
+ d95_inc = np.zeros(shape=(self.nx,), dtype=np.float64)
1782
+ u_inc_99 = np.zeros(shape=(self.nx,), dtype=np.float64)
1783
+ u_inc_95 = np.zeros(shape=(self.nx,), dtype=np.float64)
1784
+
1785
+ if verbose: progress_bar = tqdm(total=self.nx, ncols=100, desc='δ', leave=False, file=sys.stdout)
1786
+ for i in range(self.nx):
1787
+
1788
+ y_edge_ = y_edge[i]
1789
+ u_ = np.copy( u[i,:] )
1790
+
1791
+ d99_inc_ = calc_d99_1d(y=y, u=u_, y_edge=y_edge_, interp_kind=interp_kind, d95=False)
1792
+ d99_inc[i] = d99_inc_
1793
+
1794
+ d95_inc_ = calc_d99_1d(y=y, u=u_, y_edge=y_edge_, interp_kind=interp_kind, d95=True)
1795
+ d95_inc[i] = d95_inc_
1796
+
1797
+ intrp_func = sp.interpolate.interp1d(y, u_, kind=interp_kind, bounds_error=True)
1798
+ u_inc_99[i] = intrp_func(d99_inc_)
1799
+ u_inc_95[i] = intrp_func(d95_inc_)
1800
+
1801
+ progress_bar.update()
1802
+ progress_bar.close()
1803
+
1804
+ if ('data_1Dx/d99_inc' in self): del self['data_1Dx/d99_inc']
1805
+ self.create_dataset('data_1Dx/d99_inc', data=d99_inc, chunks=None)
1806
+ if verbose: even_print('data_1Dx/d99_inc','%s'%str(d99_inc.shape))
1807
+
1808
+ if ('data_1Dx/d95_inc' in self): del self['data_1Dx/d95_inc']
1809
+ self.create_dataset('data_1Dx/d95_inc', data=d95_inc, chunks=None)
1810
+ if verbose: even_print('data_1Dx/d95_inc','%s'%str(d95_inc.shape))
1811
+
1812
+ if ('data_1Dx/u_inc_99' in self): del self['data_1Dx/u_inc_99']
1813
+ self.create_dataset('data_1Dx/u_inc_99', data=u_inc_99, chunks=None)
1814
+ if verbose: even_print('data_1Dx/u_inc_99','%s'%str(u_inc_99.shape))
1815
+
1816
+ if ('data_1Dx/u_inc_95' in self): del self['data_1Dx/u_inc_95']
1817
+ self.create_dataset('data_1Dx/u_inc_95', data=u_inc_95, chunks=None)
1818
+ if verbose: even_print('data_1Dx/u_inc_95','%s'%str(u_inc_95.shape))
1819
+
1820
+ self.get_header(verbose=False)
1821
+ if verbose: print(72*'-')
1822
+ if verbose: print('total time : ztmd.calc_d99_inc() : %s'%format_time_string((timeit.default_timer() - t_start_func)))
1823
+ if verbose: print(72*'-')
1824
+
1825
+ return
1826
+
1827
+ def _calc_wake_parameter(self, **kwargs):
1828
+ '''
1829
+ calculate the Coles wake parameter "Π"
1830
+ u+ = (1/κ)·ln(y+) + B + (2Π/κ)·w(y/δ)
1831
+ - at y=δ, w(y/δ)==1
1832
+ --> Π = ( u(δ) - (1/κ)·ln(δ+) - B ) · k / 2
1833
+ -----
1834
+ Coles (1956) : https://doi.org/10.1017/S0022112056000135
1835
+ Pirozzoli (2004) : https://doi.org/10.1063/1.1637604
1836
+ Smits & Dussauge (2006) : https://doi.org/10.1007/b137383
1837
+ Chauhan et al. (2009) : https://doi.org/10.1088/0169-5983/41/2/021404
1838
+ Nagib et al. (2007) : https://doi.org/10.1098/rsta.2006.1948
1839
+ '''
1840
+
1841
+ verbose = kwargs.get('verbose',True)
1842
+ k = kwargs.get('k',0.41) ## Von Kármán constant (κ)
1843
+ B = kwargs.get('B',5.2) ## constant in log law eqn. : u+ = (1/κ)·ln(y+) + B
1844
+
1845
+ ## see Nagib et al. (2007)
1846
+ #k = kwargs.get('k',0.384)
1847
+ #B = kwargs.get('B',4.173) ## called 'B' in Nagib et al. (2007)
1848
+
1849
+ if verbose: print('\n'+'ztmd.calc_wake_parameter()'+'\n'+72*'-')
1850
+ t_start_func = timeit.default_timer()
1851
+
1852
+ ## check
1853
+ # ...
1854
+
1855
+ if verbose: even_print('κ',f'{k:0.5f}')
1856
+ if verbose: even_print('B',f'{B:0.5f}')
1857
+
1858
+ if self.curvilinear:
1859
+ raise NotImplementedError('ztmd.calc_wake_parameter() has not been implemented for curved cases')
1860
+
1861
+ #y = np.copy( self['dims/y'][()] )
1862
+ u_tau = np.copy( self['data_1Dx/u_tau'][()] )
1863
+ sc_l_in = np.copy( self['data_1Dx/sc_l_in'][()] ) ## δν = νw/uτ
1864
+
1865
+ d99_inc = np.copy( self['data_1Dx/d99_inc'][()] ) ## 'incompressible' BL δ99 i.e. δ99_inc
1866
+ u_inc_99 = np.copy( self['data_1Dx/u_inc_99'][()] )
1867
+
1868
+ #y_edge_inc = np.copy( self['data_1Dx/y_edge_inc'][()] ) ## 'incompressible' BL edge
1869
+ #u_inc_edge = np.copy( self['data_1Dx/u_inc_edge'][()] )
1870
+
1871
+ # u_inc = np.copy( self['data/u_inc'][()].T ) ## 'incompressible' transformed u profile
1872
+
1873
+ wake_parameter = np.zeros(shape=(self.nx,), dtype=np.float64) ## Π = (κ/2)·Δ(u/uτ)
1874
+ wake_strength = np.zeros(shape=(self.nx,), dtype=np.float64) ## Δ(u/uτ) @ δ
1875
+
1876
+ if verbose: progress_bar = tqdm(total=self.nx, ncols=100, desc='wake parameter', leave=False, file=sys.stdout)
1877
+ for i in range(self.nx):
1878
+
1879
+ #up_ = u_inc_edge[i] / u_tau[i] ## ue_inc+
1880
+ #yp_ = y_edge_inc[i] / sc_l_in[i] ## ye_inc+
1881
+
1882
+ up_ = u_inc_99[i] / u_tau[i] ## u99_inc+
1883
+ yp_ = d99_inc[i] / sc_l_in[i] ## δ99_inc+
1884
+
1885
+ up_loglaw_99_ = (1/k)*np.log(yp_) + B
1886
+ wake_strength_ = up_ - up_loglaw_99_
1887
+ wake_parameter_ = wake_strength_ * (k/2)
1888
+
1889
+ wake_strength[i] = wake_strength_
1890
+ wake_parameter[i] = wake_parameter_
1891
+
1892
+ # ===
1893
+
1894
+ #u_edge_plus_ = u_inc_99[i] / u_tau[i]
1895
+ #delta_plus_ = d99_inc[i] / sc_l_in[i]
1896
+ #wake_parameter2_ = (k/2)*( u_edge_plus_ - (1/k)*np.log(delta_plus_) - B )
1897
+ #wake_strength2_ = wake_parameter2_ * (2/k)
1898
+ #np.testing.assert_allclose(wake_parameter2_ , wake_parameter_ , rtol=1e-12, atol=1e-12)
1899
+ #np.testing.assert_allclose(wake_strength2_ , wake_strength_ , rtol=1e-12, atol=1e-12)
1900
+
1901
+ progress_bar.update()
1902
+ progress_bar.close()
1903
+
1904
+ if ('data_1Dx/wake_strength' in self): del self['data_1Dx/wake_strength']
1905
+ self.create_dataset('data_1Dx/wake_strength', data=wake_strength, chunks=None)
1906
+ if verbose: even_print('data_1Dx/wake_strength','%s'%str(wake_strength.shape))
1907
+
1908
+ if ('data_1Dx/wake_parameter' in self): del self['data_1Dx/wake_parameter']
1909
+ self.create_dataset('data_1Dx/wake_parameter', data=wake_parameter, chunks=None)
1910
+ if verbose: even_print('data_1Dx/wake_parameter','%s'%str(wake_parameter.shape))
1911
+
1912
+ self.get_header(verbose=False)
1913
+ if verbose: print(72*'-')
1914
+ if verbose: print('total time : ztmd.calc_wake_parameter() : %s'%format_time_string((timeit.default_timer() - t_start_func)))
1915
+ if verbose: print(72*'-')
1916
+
1917
+ def _calc_VDII(self, **kwargs):
1918
+ '''
1919
+ perform 'incompressible' cf,Reθ transform according to Van Driest (1956), yields
1920
+ Fc (compressibility factor)
1921
+ Reδ2 = (μe/μw)·Reθ
1922
+ cfi = Fc·cf
1923
+ often referred to as the 'Van Driest II' compressibility transform
1924
+ -----
1925
+ Van Driest 1956 'The Problem of Aerodynamic Heating'
1926
+ https://web.stanford.edu/~jurzay/ME356_files/vandriest_aeroheating.pdf
1927
+ White 2006 'Viscous Fluid Flow' 7-7 and 7-8 (p.547-556)
1928
+ '''
1929
+
1930
+ verbose = kwargs.get('verbose',True)
1931
+ adiabatic = kwargs.get('adiabatic',False) ## compute Fc as special case of adiabatic
1932
+
1933
+ if verbose: print('\n'+'ztmd.calc_VDII()'+'\n'+72*'-')
1934
+ t_start_func = timeit.default_timer()
1935
+
1936
+ if verbose: even_print('adiabatic',str(adiabatic))
1937
+
1938
+ #y = np.copy( self['dims/y'][()] )
1939
+ T_wall = np.copy( self['data_1Dx/T_wall'][()] )
1940
+ T_edge = np.copy( self['data_1Dx/T_edge'][()] )
1941
+ #M_edge = np.copy( self['data_1Dx/M_edge'][()] )
1942
+ rho_edge = np.copy( self['data_1Dx/rho_edge'][()] )
1943
+ u_edge = np.copy( self['data_1Dx/u_edge'][()] )
1944
+
1945
+ #mu_wall = np.copy( self['data_1Dx/mu_wall'][()] )
1946
+ #mu_edge = np.copy( self['data_1Dx/mu_edge'][()] )
1947
+ #Re_theta = np.copy( self['data_1Dx/Re_theta'][()] )
1948
+ cf = np.copy( self['data_1Dx/cf'][()] )
1949
+ tau_wall = np.copy( self['data_1Dx/tau_wall'][()] )
1950
+
1951
+ if adiabatic:
1952
+ Fc = np.copy( ((T_wall / T_edge)-1.) / (np.arcsin( (1.-(T_edge/T_wall))**0.5 ))**2 )
1953
+ else:
1954
+ Taw = self.Taw
1955
+ A = np.copy( (Taw/T_edge + T_wall/T_edge - 2) / np.sqrt( (Taw/T_edge + T_wall/T_edge)**2 - 4*T_wall/T_edge ) )
1956
+ B = np.copy( (Taw/T_edge - T_wall/T_edge ) / np.sqrt( (Taw/T_edge + T_wall/T_edge)**2 - 4*T_wall/T_edge ) )
1957
+ Fc = np.copy( (Taw/T_edge - 1. ) / ( np.arcsin(A) + np.arcsin(B) )**2 )
1958
+
1959
+ # ===
1960
+
1961
+ ## assert that cf is calculated with EDGE values
1962
+ if self.rectilinear:
1963
+ cf_edge = np.copy( tau_wall / (0.5 * rho_edge * u_edge**2 ) )
1964
+ cf_inf = np.copy( tau_wall / (0.5 * self.rho_inf * self.U_inf**2 ) )
1965
+ np.testing.assert_allclose(cf, cf_edge, rtol=1e-6)
1966
+ cf_edge = None ; del cf_edge
1967
+ cf_inf = None ; del cf_inf
1968
+
1969
+ cf_inc = np.copy( Fc * cf )
1970
+
1971
+ # ===
1972
+
1973
+ if ('data_1Dx/cf_inc' in self): del self['data_1Dx/cf_inc']
1974
+ self.create_dataset('data_1Dx/cf_inc', data=cf_inc, chunks=None)
1975
+ if verbose: even_print('data_1Dx/cf_inc','%s'%str(cf_inc.shape))
1976
+
1977
+ if ('data_1Dx/Fc' in self): del self['data_1Dx/Fc']
1978
+ self.create_dataset('data_1Dx/Fc', data=Fc, chunks=None)
1979
+ if verbose: even_print('data_1Dx/Fc','%s'%str(Fc.shape))
1980
+
1981
+ self.get_header(verbose=False)
1982
+ if verbose: print(72*'-')
1983
+ if verbose: print('total time : ztmd.calc_VDII() : %s'%format_time_string((timeit.default_timer() - t_start_func)))
1984
+ if verbose: print(72*'-')
1985
+
1986
+ return
1987
+
1988
+ def _calc_peak_tauI(self, **kwargs):
1989
+ '''
1990
+ calculate peak τ′xx, τ′xy, τ′yy
1991
+ '''
1992
+
1993
+ verbose = kwargs.get('verbose',True)
1994
+
1995
+ if verbose: print('\n'+'ztmd.calc_peak_tauI()'+'\n'+72*'-')
1996
+ t_start_func = timeit.default_timer()
1997
+
1998
+ ## check
1999
+ if self.rectilinear:
2000
+ pass
2001
+ elif self.curvilinear:
2002
+ #raise NotImplementedError('ztmd.calc_peak_tauI() has not been implemented for curved cases')
2003
+ print('>>> ztmd.calc_peak_tauI() has not been implemented for curved cases')
2004
+ return
2005
+ else:
2006
+ raise ValueError
2007
+
2008
+ ## check
2009
+ if 'data_1Dx/sc_l_in' not in self:
2010
+ raise ValueError('data_1Dx/sc_l_in not found')
2011
+ if 'data/r_uII_uII' not in self:
2012
+ raise ValueError('data/r_uII_uII not found')
2013
+ if 'data/r_uII_vII' not in self:
2014
+ raise ValueError('data/r_uII_vII not found')
2015
+ if 'data/r_vII_vII' not in self:
2016
+ raise ValueError('data/r_vII_vII not found')
2017
+
2018
+ r_uII_uII = np.copy( self['data/r_uII_uII'][()].T )
2019
+ r_uII_vII = np.copy( self['data/r_uII_vII'][()].T )
2020
+ r_vII_vII = np.copy( self['data/r_vII_vII'][()].T )
2021
+
2022
+ y = np.copy( self['dims/y'][()] )
2023
+ tau_wall = np.copy( self['data_1Dx/tau_wall'][()] )
2024
+ sc_l_in = np.copy( self['data_1Dx/sc_l_in'][()] )
2025
+ sc_l_out = np.copy( self['data_1Dx/sc_l_out'][()] )
2026
+ nu_wall = np.copy( self['data_1Dx/nu_wall'][()] )
2027
+ u_tau = np.copy( self['data_1Dx/u_tau'][()] )
2028
+ d99 = np.copy( self['data_1Dx/d99'][()] )
2029
+
2030
+ np.testing.assert_allclose(sc_l_in , nu_wall/u_tau , rtol=1e-14, atol=1e-14)
2031
+ np.testing.assert_allclose(sc_l_out , d99 , rtol=1e-14, atol=1e-14)
2032
+
2033
+ r_uII_uII_plus = np.copy( r_uII_uII / tau_wall[:,np.newaxis] )
2034
+ r_uII_vII_plus = np.copy( r_uII_vII / tau_wall[:,np.newaxis] )
2035
+ r_vII_vII_plus = np.copy( r_vII_vII / tau_wall[:,np.newaxis] )
2036
+
2037
+ tau_xx_I_peak = np.zeros((self.nx,), dtype=np.float64)
2038
+ tau_xx_I_peak_y = np.zeros((self.nx,), dtype=np.float64)
2039
+
2040
+ tau_xy_I_peak = np.zeros((self.nx,), dtype=np.float64)
2041
+ tau_xy_I_peak_y = np.zeros((self.nx,), dtype=np.float64)
2042
+
2043
+ tau_yy_I_peak = np.zeros((self.nx,), dtype=np.float64)
2044
+ tau_yy_I_peak_y = np.zeros((self.nx,), dtype=np.float64)
2045
+
2046
+ # ===
2047
+
2048
+ def __opt_find_peak(y_plus_pk,func):
2049
+ root = func(y_plus_pk,1)
2050
+ return root
2051
+
2052
+ if verbose: progress_bar = tqdm(total=self.nx, ncols=100, desc='peak τ′', leave=False, file=sys.stdout)
2053
+ #for i in [5000,10000,15000]:
2054
+ for i in range(self.nx):
2055
+
2056
+ y_plus_ = np.copy( y / sc_l_in[i] )
2057
+ #yovd_ = np.copy( y / sc_l_out[i] )
2058
+
2059
+ r_uII_uII_plus_ = np.copy( r_uII_uII_plus[i,:] )
2060
+ r_uII_vII_plus_ = np.copy( r_uII_vII_plus[i,:] )
2061
+ r_vII_vII_plus_ = np.copy( r_vII_vII_plus[i,:] )
2062
+
2063
+ # === τ′xx
2064
+
2065
+ i_naive = np.argmax( r_uII_uII_plus_ )
2066
+ #tau_xx_I_peak_naive_ = r_uII_uII_plus_[i_naive]
2067
+
2068
+ func_tauIxx = sp.interpolate.CubicSpline( y_plus_ , r_uII_uII_plus_ , bc_type='natural', extrapolate=False )
2069
+
2070
+ bounds_ = ( max(y_plus_[i_naive]*0.9,y_plus_.min()) , min(y_plus_[i_naive]*1.1,y_plus_.max()) )
2071
+
2072
+ sol = sp.optimize.least_squares(fun=__opt_find_peak,
2073
+ args=(func_tauIxx,),
2074
+ x0=y_plus_[i_naive],
2075
+ xtol=1e-15,
2076
+ ftol=1e-15,
2077
+ gtol=1e-15,
2078
+ method='dogbox',
2079
+ bounds=bounds_,
2080
+ )
2081
+ if not sol.success:
2082
+ raise ValueError
2083
+
2084
+ y_plus_pk_ = float(sol.x[0])
2085
+ tau_xx_I_peak[i] = func_tauIxx(y_plus_pk_) * tau_wall[i] ## re-dimensionalizing
2086
+ tau_xx_I_peak_y[i] = y_plus_pk_ * sc_l_in[i] ## re-dimensionalizing
2087
+
2088
+ # ===
2089
+
2090
+ # ## debug plot for τ′xx
2091
+ # #if (i==5000) or (i==10000) or (i==15000):
2092
+ # if 0:
2093
+ #
2094
+ # plt.close('all')
2095
+ # fig1 = plt.figure(figsize=(3,2), dpi=400)
2096
+ # ax1 = plt.gca()
2097
+ #
2098
+ # ax1.tick_params(axis='x', which='both', direction='in')
2099
+ # ax1.tick_params(axis='y', which='both', direction='in')
2100
+ # #ax1.xaxis.set_ticks_position('both')
2101
+ # #ax1.yaxis.set_ticks_position('both')
2102
+ # ax1.set_xscale('log',base=10)
2103
+ # #ax1.set_yscale('log',base=10)
2104
+ #
2105
+ # #ax1.set_xlim(100,3000)
2106
+ # #ax1.xaxis.set_major_locator(mpl.ticker.LogLocator(subs=(1,)))
2107
+ # #ax1.xaxis.set_minor_locator(mpl.ticker.LogLocator(subs=np.linspace(1,9,9)))
2108
+ # #ax1.xaxis.set_minor_formatter(mpl.ticker.NullFormatter())
2109
+ #
2110
+ # ax1.plot(
2111
+ # y_plus_,
2112
+ # r_uII_uII_plus_,
2113
+ # c='k',
2114
+ # zorder=19,
2115
+ # lw=0.8,
2116
+ # marker='o',
2117
+ # ms=1.5,
2118
+ # ls='none',
2119
+ # )
2120
+ #
2121
+ # y_plus_dummy_ = np.logspace(np.log10(1),np.log10(1000),1000)
2122
+ # r_uII_uII_plus_spline_ = func_tauIxx(y_plus_dummy_)
2123
+ #
2124
+ # ax1.plot(
2125
+ # y_plus_dummy_,
2126
+ # r_uII_uII_plus_spline_,
2127
+ # c='blue',
2128
+ # zorder=19,
2129
+ # lw=0.8,
2130
+ # #marker='o',
2131
+ # #ms=1.5,
2132
+ # #ls='none',
2133
+ # )
2134
+ #
2135
+ # ax1.axvline(x=y_plus_pk_ , linestyle='solid', c='gray', zorder=1, lw=0.5)
2136
+ # ax1.axhline(y=func_tauIxx(y_plus_pk_) , linestyle='solid', c='gray', zorder=1, lw=0.5)
2137
+ #
2138
+ # plt.show()
2139
+
2140
+ # === τ′xy
2141
+
2142
+ i_naive = np.argmin( r_uII_vII_plus_ ) ## ACHTUNG argmin(), NOT argmax() !!
2143
+ #tau_xy_I_peak_naive_ = r_uII_vII_plus_[i_naive]
2144
+
2145
+ func_tauIxy = sp.interpolate.CubicSpline( y_plus_ , r_uII_vII_plus_ , bc_type='natural', extrapolate=False )
2146
+
2147
+ bounds_ = ( max(y_plus_[i_naive]*0.9,y_plus_.min()) , min(y_plus_[i_naive]*1.1,y_plus_.max()) )
2148
+
2149
+ sol = sp.optimize.least_squares(fun=__opt_find_peak,
2150
+ args=(func_tauIxy,),
2151
+ x0=y_plus_[i_naive],
2152
+ xtol=1e-15,
2153
+ ftol=1e-15,
2154
+ gtol=1e-15,
2155
+ method='dogbox',
2156
+ bounds=bounds_,
2157
+ )
2158
+ if not sol.success:
2159
+ raise ValueError
2160
+
2161
+ y_plus_pk_ = float(sol.x[0])
2162
+ tau_xy_I_peak[i] = func_tauIxy(y_plus_pk_) * tau_wall[i] ## re-dimensionalizing
2163
+ tau_xy_I_peak_y[i] = y_plus_pk_ * sc_l_in[i] ## re-dimensionalizing
2164
+
2165
+ # ===
2166
+
2167
+ # ## debug plot for τ′xy
2168
+ # #if (i==5000) or (i==10000) or (i==15000):
2169
+ # if 0:
2170
+ #
2171
+ # plt.close('all')
2172
+ # fig1 = plt.figure(figsize=(3,2), dpi=400)
2173
+ # ax1 = plt.gca()
2174
+ #
2175
+ # ax1.tick_params(axis='x', which='both', direction='in')
2176
+ # ax1.tick_params(axis='y', which='both', direction='in')
2177
+ # #ax1.xaxis.set_ticks_position('both')
2178
+ # #ax1.yaxis.set_ticks_position('both')
2179
+ # ax1.set_xscale('log',base=10)
2180
+ # #ax1.set_yscale('log',base=10)
2181
+ #
2182
+ # #ax1.set_xlim(100,3000)
2183
+ # #ax1.xaxis.set_major_locator(mpl.ticker.LogLocator(subs=(1,)))
2184
+ # #ax1.xaxis.set_minor_locator(mpl.ticker.LogLocator(subs=np.linspace(1,9,9)))
2185
+ # #ax1.xaxis.set_minor_formatter(mpl.ticker.NullFormatter())
2186
+ #
2187
+ # ax1.plot(
2188
+ # y_plus_,
2189
+ # r_uII_vII_plus_,
2190
+ # c='k',
2191
+ # zorder=19,
2192
+ # lw=0.8,
2193
+ # marker='o',
2194
+ # ms=1.5,
2195
+ # ls='none',
2196
+ # )
2197
+ #
2198
+ # y_plus_dummy_ = np.logspace(np.log10(1),np.log10(1000),1000)
2199
+ # r_uII_vII_plus_spline_ = func_tauIxy(y_plus_dummy_)
2200
+ #
2201
+ # ax1.plot(
2202
+ # y_plus_dummy_,
2203
+ # r_uII_vII_plus_spline_,
2204
+ # c='blue',
2205
+ # zorder=19,
2206
+ # lw=0.8,
2207
+ # #marker='o',
2208
+ # #ms=1.5,
2209
+ # #ls='none',
2210
+ # )
2211
+ #
2212
+ # ax1.axvline(x=y_plus_pk_ , linestyle='solid', c='gray', zorder=1, lw=0.5)
2213
+ # ax1.axhline(y=func_tauIxy(y_plus_pk_) , linestyle='solid', c='gray', zorder=1, lw=0.5)
2214
+ #
2215
+ # plt.show()
2216
+
2217
+ # === τ′yy
2218
+
2219
+ i_naive = np.argmax( r_vII_vII_plus_ )
2220
+ #tau_yy_I_peak_naive_ = r_vII_vII_plus_[i_naive]
2221
+
2222
+ func_tauIyy = sp.interpolate.CubicSpline( y_plus_ , r_vII_vII_plus_ , bc_type='natural', extrapolate=False )
2223
+
2224
+ bounds_ = ( max(y_plus_[i_naive]*0.9,y_plus_.min()) , min(y_plus_[i_naive]*1.1,y_plus_.max()) )
2225
+
2226
+ sol = sp.optimize.least_squares(fun=__opt_find_peak,
2227
+ args=(func_tauIyy,),
2228
+ x0=y_plus_[i_naive],
2229
+ xtol=1e-15,
2230
+ ftol=1e-15,
2231
+ gtol=1e-15,
2232
+ method='dogbox',
2233
+ bounds=bounds_,
2234
+ )
2235
+ if not sol.success:
2236
+ raise ValueError
2237
+
2238
+ y_plus_pk_ = float(sol.x[0])
2239
+ tau_yy_I_peak[i] = func_tauIyy(y_plus_pk_) * tau_wall[i] ## re-dimensionalizing
2240
+ tau_yy_I_peak_y[i] = y_plus_pk_ * sc_l_in[i] ## re-dimensionalizing
2241
+
2242
+ # ===
2243
+
2244
+ # ## debug plot for τ′yy
2245
+ # #if (i==5000) or (i==10000) or (i==15000):
2246
+ # if 0:
2247
+ #
2248
+ # plt.close('all')
2249
+ # fig1 = plt.figure(figsize=(3,2), dpi=400)
2250
+ # ax1 = plt.gca()
2251
+ #
2252
+ # ax1.tick_params(axis='x', which='both', direction='in')
2253
+ # ax1.tick_params(axis='y', which='both', direction='in')
2254
+ # #ax1.xaxis.set_ticks_position('both')
2255
+ # #ax1.yaxis.set_ticks_position('both')
2256
+ # ax1.set_xscale('log',base=10)
2257
+ # #ax1.set_yscale('log',base=10)
2258
+ #
2259
+ # #ax1.set_xlim(100,3000)
2260
+ # #ax1.xaxis.set_major_locator(mpl.ticker.LogLocator(subs=(1,)))
2261
+ # #ax1.xaxis.set_minor_locator(mpl.ticker.LogLocator(subs=np.linspace(1,9,9)))
2262
+ # #ax1.xaxis.set_minor_formatter(mpl.ticker.NullFormatter())
2263
+ #
2264
+ # ax1.plot(
2265
+ # y_plus_,
2266
+ # r_vII_vII_plus_,
2267
+ # c='k',
2268
+ # zorder=19,
2269
+ # lw=0.8,
2270
+ # marker='o',
2271
+ # ms=1.5,
2272
+ # ls='none',
2273
+ # )
2274
+ #
2275
+ # y_plus_dummy_ = np.logspace(np.log10(1),np.log10(1000),1000)
2276
+ # r_vII_vII_plus_spline_ = func_tauIyy(y_plus_dummy_)
2277
+ #
2278
+ # ax1.plot(
2279
+ # y_plus_dummy_,
2280
+ # r_vII_vII_plus_spline_,
2281
+ # c='blue',
2282
+ # zorder=19,
2283
+ # lw=0.8,
2284
+ # #marker='o',
2285
+ # #ms=1.5,
2286
+ # #ls='none',
2287
+ # )
2288
+ #
2289
+ # ax1.axvline(x=y_plus_pk_ , linestyle='solid', c='gray', zorder=1, lw=0.5)
2290
+ # ax1.axhline(y=func_tauIyy(y_plus_pk_) , linestyle='solid', c='gray', zorder=1, lw=0.5)
2291
+ #
2292
+ # plt.show()
2293
+
2294
+ # ===
2295
+
2296
+ progress_bar.update()
2297
+ progress_bar.close()
2298
+
2299
+
2300
+ if ('data_1Dx/tau_xx_I_peak' in self): del self['data_1Dx/tau_xx_I_peak']
2301
+ self.create_dataset('data_1Dx/tau_xx_I_peak', data=tau_xx_I_peak, chunks=None)
2302
+ if verbose: even_print('data_1Dx/tau_xx_I_peak','%s'%str(tau_xx_I_peak.shape))
2303
+
2304
+ if ('data_1Dx/tau_xy_I_peak' in self): del self['data_1Dx/tau_xy_I_peak']
2305
+ self.create_dataset('data_1Dx/tau_xy_I_peak', data=tau_xy_I_peak, chunks=None)
2306
+ if verbose: even_print('data_1Dx/tau_xy_I_peak','%s'%str(tau_xy_I_peak.shape))
2307
+
2308
+ if ('data_1Dx/tau_yy_I_peak' in self): del self['data_1Dx/tau_yy_I_peak']
2309
+ self.create_dataset('data_1Dx/tau_yy_I_peak', data=tau_yy_I_peak, chunks=None)
2310
+ if verbose: even_print('data_1Dx/tau_yy_I_peak','%s'%str(tau_yy_I_peak.shape))
2311
+
2312
+ ## old
2313
+ if ('data_1Dx/tau_xx_I_peak_y_plus' in self):
2314
+ del self['data_1Dx/tau_xx_I_peak_y_plus']
2315
+ if ('data_1Dx/tau_xy_I_peak_y_plus' in self):
2316
+ del self['data_1Dx/tau_xy_I_peak_y_plus']
2317
+ if ('data_1Dx/tau_yy_I_peak_y_plus' in self):
2318
+ del self['data_1Dx/tau_yy_I_peak_y_plus']
2319
+
2320
+ if ('data_1Dx/tau_xx_I_peak_y' in self): del self['data_1Dx/tau_xx_I_peak_y']
2321
+ self.create_dataset('data_1Dx/tau_xx_I_peak_y', data=tau_xx_I_peak_y, chunks=None)
2322
+ if verbose: even_print('data_1Dx/tau_xx_I_peak_y','%s'%str(tau_xx_I_peak_y.shape))
2323
+
2324
+ if ('data_1Dx/tau_xy_I_peak_y' in self): del self['data_1Dx/tau_xy_I_peak_y']
2325
+ self.create_dataset('data_1Dx/tau_xy_I_peak_y', data=tau_xy_I_peak_y, chunks=None)
2326
+ if verbose: even_print('data_1Dx/tau_xy_I_peak_y','%s'%str(tau_xy_I_peak_y.shape))
2327
+
2328
+ if ('data_1Dx/tau_yy_I_peak_y' in self): del self['data_1Dx/tau_yy_I_peak_y']
2329
+ self.create_dataset('data_1Dx/tau_yy_I_peak_y', data=tau_yy_I_peak_y, chunks=None)
2330
+ if verbose: even_print('data_1Dx/tau_yy_I_peak_y','%s'%str(tau_yy_I_peak_y.shape))
2331
+
2332
+
2333
+ self.get_header(verbose=False)
2334
+ if verbose: print(72*'-')
2335
+ if verbose: print('total time : ztmd.calc_peak_tauI() : %s'%format_time_string((timeit.default_timer() - t_start_func)))
2336
+ if verbose: print(72*'-')
2337
+ return