User guide¶
Generate and access turbulence field¶
[1]:
import os
import time
import numpy as np
import matplotlib.pyplot as plt
from hipersim import MannTurbulenceField
import multiprocessing
import importlib
Turbulence fields are generated using the MannTurbulenceField.generate method:
[2]:
help(MannTurbulenceField.generate)
Help on function generate in module hipersim.mann_turbulence:
generate(alphaepsilon=1, L=33.6, Gamma=3.9, Nxyz=(8192, 64, 64), dxyz=(1, 1, 1), seed=1, HighFreqComp=0, double_xyz=(False, True, True), n_cpu=1, verbose=0, random_generator=None, cache_spectral_tensor=False)
Generate a MannTurbulenceField
Parameters
----------
alphaepsilon : float, optional
Mann model turbulence parameter $(\alpha \varepsilon)^{2/3}$ (Mann, 1994), default is 1.
L : float, optional
Mann model turbulence length scale parameter $L$ (Mann, 1994), default is 33.6
Gamma : float, optional
Mann model turbulence anisotropy parameter $\Gamma$ (Mann, 1994), default is 3.9
Nxyz: (int,int,int)
Dimension of the turbulence box in x (longitudinal), y (transveral) and z (vertical) direction.
Default is (8192,64,64)
dxyz : (float, float, float), optional
Spacing in meters between data points along the x,y,z coordinates. Default is (1,1,1)
seed : int, optional
Seed number for random generator. Default is 1
HighFreqComp : bool, optional
Defines whether high-frequency compensation is applied. There are three options
0 or False (default): No high-frequency compensation applied
1 or True: A fast high-Frequency compensation method is applied. This method differs from the method in Mann (1998)
2: The high-Frequency compensation method from the C++ version is applied.
The method corresponds to Eq. A.6 in Mann (1998) except that the convolution is only applied in the (k2,k3),
i.e. -2<=n_l<=2, l=(2,3)
double_xyz : (bool,bool,bool)
Defines whether doubling is enabled along the x, y and z direction.
When doubling is applied, a box with the double size is generated and the first half is returned. In this
way periodicity is avoided.
Default is False in the x direction and True in the y and z direction
n_cpu : int or None, optional
Number of CPUs to use for the turbulence generation. Default is 1 (no parallelization).
If None, all available CPUs are used.
verbose : bool
If true, status messages and progress bars are printed
random_generator : function or None, optional
If None (default), the random generator depends on n_cpu:
n_cpu=1: hipersim.turbgen.spectral_tensor.random_generator_seq
n_cpu!=1: hipersim.turbgen.spectral_tensor.random_generator_par
Alternatively a function, f(MannSpectralTensor) -> RandomNumbers, dim=(3, N1r, N2, N3), can be specified
cache_spectral_tensor : boolean, optional
If True, the spectral tensor is loaded from file if exists otherwise it is calculated and saved to file
If False, the spectral tensor is always recalculated
Returns
-------
MannTurbulenceField-object
[3]:
mtf = MannTurbulenceField.generate(alphaepsilon=.1,
L=33.6,
Gamma=3.9,
Nxyz=(1024,64,64),
dxyz=(4,2,2),
seed=1,
HighFreqComp=0,
double_xyz=(False, True, True))
The raw turbulence data is stored in the uvw variable
[4]:
u,v,w = mtf.uvw
u.shape
[4]:
(1024, 64, 64)
The to_xarray method exports an xarray dataarray with the turbulence data and all attributes
[5]:
da = mtf.to_xarray() # xarray dataarray
da
[5]:
<xarray.DataArray (uvw: 3, x: 1024, y: 64, z: 64)> Size: 50MB
array([[[[-1.06722391e+00, -9.11766350e-01, -1.09172642e+00, ...,
1.45228708e+00, 1.39533019e+00, 1.53455162e+00],
[-9.47559476e-01, -6.49923682e-01, -9.84678030e-01, ...,
1.44495678e+00, 1.25722265e+00, 1.48809803e+00],
[-1.18221796e+00, -7.66179323e-01, -1.18622351e+00, ...,
1.15684581e+00, 1.43644488e+00, 1.12957585e+00],
...,
[ 1.37539446e+00, 1.44499826e+00, 1.36412323e+00, ...,
1.71722853e+00, 1.24690521e+00, 6.60602987e-01],
[ 1.36570394e+00, 1.47212410e+00, 1.27690542e+00, ...,
1.60486281e+00, 1.37281942e+00, 1.16389358e+00],
[ 1.19318187e+00, 1.18873072e+00, 1.42475224e+00, ...,
2.07942677e+00, 1.92836571e+00, 1.34069228e+00]],
[[-8.27491939e-01, -7.72828639e-01, -1.01054978e+00, ...,
2.01455545e+00, 1.88230836e+00, 2.06121898e+00],
[-1.40368748e+00, -1.15813982e+00, -1.04139829e+00, ...,
2.05697250e+00, 2.31357455e+00, 2.17605233e+00],
[-1.13080359e+00, -6.60503864e-01, -8.17114472e-01, ...,
1.52948534e+00, 1.34062982e+00, 1.04008341e+00],
...
-1.17631316e+00, -1.34029853e+00, -1.63597703e+00],
[ 8.88433233e-02, 1.40094057e-01, -6.92046806e-03, ...,
-9.75362539e-01, -1.41609395e+00, -1.98467863e+00],
[-3.63194138e-01, -1.65986419e-01, 8.71252567e-02, ...,
-9.36011136e-01, -9.41912413e-01, -1.21727693e+00]],
[[ 1.03636050e+00, 1.30921483e+00, 1.74372816e+00, ...,
-9.00405526e-01, -9.26196635e-01, -8.01780283e-01],
[ 1.12547183e+00, 1.30546427e+00, 1.49324310e+00, ...,
-1.12577999e+00, -1.17425358e+00, -8.98413181e-01],
[ 1.19445455e+00, 1.50068903e+00, 1.64676011e+00, ...,
-1.34154344e+00, -1.22823966e+00, -1.16993845e+00],
...,
[ 7.20019490e-02, 8.58015120e-02, -1.63560644e-01, ...,
-1.47009027e+00, -1.67855024e+00, -1.31417513e+00],
[-6.60947442e-01, -5.48535287e-01, -3.43858898e-01, ...,
-1.26657009e+00, -9.75701094e-01, -1.09911346e+00],
[-9.10558581e-01, -8.29948843e-01, -5.32981575e-01, ...,
-1.25635195e+00, -1.13243425e+00, -7.64118254e-01]]]],
dtype=float32)
Coordinates:
* x (x) int32 4kB 0 4 8 12 16 20 24 ... 4072 4076 4080 4084 4088 4092
* y (y) int32 256B 0 2 4 6 8 10 12 14 ... 114 116 118 120 122 124 126
* z (z) int32 256B 0 2 4 6 8 10 12 14 ... 114 116 118 120 122 124 126
* uvw (uvw) <U1 12B 'u' 'v' 'w'
Attributes:
double_xyz: [0 1 1]
name: Hipersim_mann_l33.6_ae0.1000_g3.9_h0_1024xd64xd64_4.000x2....
alphaepsilon: 0.1
L: 33.6
Gamma: 3.9
HighFreqComp: 0
Generator: Hipersim
seed: 1From the dataarray you can easily plot the turbulence witht the correct scaled axes
[6]:
plt.figure(figsize=(18,2))
da.sel(uvw='u',y=0).plot(x='x')
plt.axis('scaled')
[6]:
(-2.0, 4094.0, -1.0, 127.0)
Save turbulence box¶
[7]:
# make tmp folder
os.makedirs('tmp', exist_ok=True)
Netcdf¶
The turbulence box can be saved as netcdf (one file including all attributes)
[8]:
mtf.to_netcdf(folder='tmp', filename=None)
If filename=None (default), the name is autogenerated from the properties:
[9]:
mtf.name
[9]:
'Hipersim_mann_l33.6_ae0.1000_g3.9_h0_1024xd64xd64_4.000x2.00x2.00_s0001'
HAWC2¶
The turbulence box can be saved as hawc2 (three binary files) by
[10]:
mtf.to_hawc2(folder='tmp', basename=None,htc_dict={'wind.wsp':9})
[10]:
<wetb.hawc2.htc_contents.HTCSection at 0x1ae00b0bcd0>
[11]:
os.listdir('tmp')
[11]:
['Hipersim_mann_l33.6_ae0.1000_g3.9_h0_1024xd64xd64_4.000x2.00x2.00_s0001.nc',
'Hipersim_mann_l33.6_ae0.1000_g3.9_h0_1024xd64xd64_4.000x2.00x2.00_s0001u.turb',
'Hipersim_mann_l33.6_ae0.1000_g3.9_h0_1024xd64xd64_4.000x2.00x2.00_s0001v.turb',
'Hipersim_mann_l33.6_ae0.1000_g3.9_h0_1024xd64xd64_4.000x2.00x2.00_s0001w.turb']
Run HAWC2 simulation and compare with turbulence field¶
The to_hawc2 method returns the a wind section for the HAWC2 htc input file. Its contents can be overriden via the htc_dict argument
[59]:
htc_wind_section = mtf.to_hawc2(folder='tmp', basename=None,htc_dict={'wind.wsp':9, 'wind.center_pos0':[0,0,-100]})
print (htc_wind_section)
begin wind;
density 1.225;
wsp 9;
tint 1;
horizontal_input 1; 0=false, 1=true
windfield_rotations 0 0 0; yaw, tilt, rotation
center_pos0 0 0 -100; hub heigth
shear_format 1 0; 0=none,1=constant,2=log,3=power,4=linear
turb_format 1; 0=none, 1=mann,2=flex
tower_shadow_method 0; 0=none, 1=potential flow, 2=jet
begin mann;
filename_u tmp/Hipersim_mann_l33.6_ae0.1000_g3.9_h0_1024xd64xd64_4.000x2.00x2.00_s0001u.turb;
filename_v tmp/Hipersim_mann_l33.6_ae0.1000_g3.9_h0_1024xd64xd64_4.000x2.00x2.00_s0001v.turb;
filename_w tmp/Hipersim_mann_l33.6_ae0.1000_g3.9_h0_1024xd64xd64_4.000x2.00x2.00_s0001w.turb;
box_dim_u 1024 4;
box_dim_v 64 2;
box_dim_w 64 2;
dont_scale 1;
end mann;
end wind;
;
;----------------------------------------------------------------------------------------------------------------------------------------------------------------
;
;
Run HAWC2 with a sensor in \((x,y,z)=(0,5,10)\) and load result
[61]:
from wetb.hawc2.htc_file import HTCFile
from h2lib import H2Lib
from wetb.gtsdf import gtsdf
htc = HTCFile(modelpath='.')
htc.wind = htc_wind_section
# HAWC2 global coordinate system: [y,x,-z]
# box center in h2_gl: [0,0,-100]
# box origo in h2_gl [-63,0,-37]
# point (0,5,10) in [-58,0,-47]
center_pos = htc.wind.center_pos0
htc.output.data_format = 'gtsdf64'
htc.output.add_sensor('wind', 'free_wind', [1,-58,0,-47])
htc.set_name('tmp')
htc.save()
with H2Lib(suppress_output=0) as h2:
h2.init(htc.filename)
h2.run(100)
time, data, info = gtsdf.load(htc.output_files()[0])
Plot wind speed from HAWC2 sensor and turbulence box interpolation
[58]:
h2_uvw = [data[:,1], data[:,0],-data[:,2]]
ws = htc.wind.wsp[0]
x = -time * ws # convert time to box x coordinate
turb_uvw = mtf(x, x*0+5, x*0+10).T + np.array([ws,0,0])[:,np.newaxis]
for uvw, h2, turb in zip('uvw',h2_uvw, turb_uvw):
plt.plot(time, turb, label=f'Turb {uvw}')
plt.plot(time, h2, '--', label=f'Hawc2 {uvw}')
np.testing.assert_array_almost_equal(h2,turb,7)
plt.legend()
[58]:
<matplotlib.legend.Legend at 0x1ae02b98310>
Interpolation¶
The MannTurbulenceField has a buildin linear interpolation function that handles out-of-box interpolation depending on whether the axes have been doubled. For axes which have been doubled (default for y and z), the box is mirrored, while axes that have not been doubled (default for x), the box is repeated.
[12]:
ip_x, ip_z = np.meshgrid(np.linspace(-1000,5000,2000), np.linspace(-100,400,200))
ip_y = ip_x*0
[13]:
u = mtf(ip_x, ip_y, ip_z)[...,0]
[14]:
plt.figure(figsize=(16,2))
plt.contourf(ip_x,ip_z,u.reshape(ip_x.shape), cmap='RdBu_r')
x1,y1 = mtf.Nx*mtf.dx, mtf.Nz*mtf.dz
plt.plot([0,x1, x1, 0,0],[0,0, y1,y1,0],'k', label='box')
plt.legend()
plt.axis('scaled')
[14]:
(-1000.0, 5000.0, -100.0, 400.0)
The raw turbulence box is marked with the black rectangle. The remaining turbulence is mirrored (vertical direction) or repeated (longitudinal direction)
Multiple turbulence boxes (reuse spectral tensor)¶
In case, you need to generate multiple turbulence boxes where only the seed and alphaepsilon varies, the computational time can be reduced by reusing the spectral tensor. The eaiest way to do this is set the argument cache_spectral_tensor=True
[15]:
for seed, alphaepsilon in [(1,1), (1, 2), (2, 2)]:
mtf = MannTurbulenceField.generate(alphaepsilon=alphaepsilon,
L=33.6,
Gamma=3.9,
Nxyz=(1024,64,64),
dxyz=(4,2,2),
seed=seed,
HighFreqComp=0,
double_xyz=(False, True, True),
cache_spectral_tensor=True) # reuse spectal tensor
plt.figure(figsize=(18,2))
mtf.to_xarray().sel(uvw='u',y=0).plot(x='x')
plt.title(f'Seed: {seed}, alphaepsilon: {alphaepsilon}')
In this case the cached spectral tensor is stored in the file mannsqrtphi_l33.6_g3.9_h0_1024xd64xd64_4.000x2.00x2.00.npy. Note, remember to delete the cached spectral tensor files after use as they can be quite big, in this case around 300MB
[16]:
!ls mannsqrtphi_l33.6_g3.9_h0_1024xd64xd64_4.000x2.00x2.00.npy
(.py311_dynamiks_jupyter7) ]9;8;"USERNAME"\@]9;8;"COMPUTERNAME"\ c:\mmpe\programming\python\Topfarm\hipersim\doc
$ ]9;12\dir mannsqrtphi_l33.6_g3.9_h0_1024xd64xd64_4.000x2.00x2.00.npy
Volume in drive C is Windows
Volume Serial Number is 4637-B881
Directory of c:\mmpe\programming\python\Topfarm\hipersim\doc
28-10-2024 14:51 302.579.840 mannsqrtphi_l33.6_g3.9_h0_1024xd64xd64_4.000x2.00x2.00.npy
1 File(s) 302.579.840 bytes
0 Dir(s) 677.719.523.328 bytes free
Spectra¶
The spectra of the turbulence realization can be obtained by the spectra method
[17]:
k_rea, spectra_rea = mtf.spectra()
Furthermore, the theoretical spectra of the spectral tensor can be found by integration
[18]:
k_int, spectra_int = mtf.spectra_integrated()
or from a build-in look-up table
[19]:
k_lut, spectra_lut = mtf.spectra_lookup()
[20]:
c_lst = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728']
s_lst = ["uu","vv","ww","uw"]
[21]:
for phi_rea, phi_int, phi_lut, c, l in zip(spectra_rea, spectra_int, spectra_lut, c_lst, s_lst):
plt.semilogx(k_rea, phi_rea*k_rea, color=c, label=l)
plt.semilogx(k_int, phi_int*k_int, '--', color=c)
plt.semilogx(k_lut, phi_lut*k_lut, ':', color=c)
plt.plot([], '-', color='gray', label='Realization')
plt.plot([], '--', color='gray', label='LookupTable')
plt.plot([], ':', color='gray', label='Integrated')
plt.xlabel('Wave number, $k_1$ $ [m^{-1}$]')
plt.ylabel('$k_1 S(k_1)[m^2s^{-2}]$')
plt.legend()
[21]:
<matplotlib.legend.Legend at 0x25484c52010>
Coherence¶
The coherence of the turbulence in two points separated by (dy, dz), can be obtained by the coherence method
Furthermore, the theoretical coherence of the spectral tensor can be found by integration
[22]:
dy = 2*mtf.dy # 4m
dz = 3*mtf.dz # 6m
[23]:
for comp in ['u','v','w']:
k_int, coherence_int = mtf.coherence_integrated(dy,dz, component=comp)
k_rea, coherence_rea = mtf.coherence(dy,dz, component=comp)
plt.figure()
s = r'$\Delta_y$ = %.2fm, $\Delta_z$ = %.2fm' % (dy, dz)
plt.title(f'{comp}, {s}')
plt.plot(k_int, coherence_int, label='Theoretical')
plt.plot(k_rea, coherence_rea, label='Realization')
plt.xlabel('Wave number, $k_1$ [$m^{-1}$]')
plt.ylabel('co-coherence [-]')
plt.legend()
Variance¶
Theoretical spectrum¶
The variance of the theoretical Mann model spectrum can be obtained by the spectrum_variance method
[24]:
mtf.spectrum_variance()
[24]:
38.559824397503185
The variance is obtained by discrete integration of the theoretical spectrum
[25]:
k = mtf.get_k()
k_lut, spectra_lut = mtf.spectra_lookup(k)
def plot_variance_integration(k,S):
plt.semilogx(k, k*S[0],'.-')
dk = np.diff(k[:2])
variance = 2 * np.sum(S[0]*dk)
plt.bar(k, S[0]*k, width=dk, alpha=.5, label=f'var={variance:.3f}')
plt.title('uu spectrum')
plt.xlabel('Wave number, $k_1$ $ [m^{-1}$]')
plt.ylabel('$k_1 S(k_1)[m^2s^{-2}]$')
plt.legend()
plot_variance_integration(k_lut,spectra_lut)
As default get_variance obtains the wave number limits from the length of the box, Nx*dx and the distance between grid points, dx, but other values can be specified. This is usefull if you want to compare the variance of a 1 hour box with the variance of e.g. 10min measurements.
[26]:
mtf.spectrum_variance(Lx=1024, dx=16)
[26]:
26.040102636402843
[27]:
k = mtf.get_k(Lx=1024, dx=16)
k_lut, spectra_lut = mtf.spectra_lookup(k)
plot_variance_integration(k_lut, spectra_lut)
Realization¶
The variance can be obtained from the realization as the mean of the variance of each grid point in the (y,z) plane:
[28]:
mtf.uvw[0].var(0).mean()
[28]:
38.490097
or by discrete integrating the spectrum:
[29]:
k_rea, spectra_rea = mtf.spectra(log10_bin_size=None) # skip binning
plot_variance_integration(k_rea, spectra_rea)
Turbulence intensity¶
[30]:
mtf_lst = [MannTurbulenceField.generate(alphaepsilon=.1,L=33.6,Gamma=3.9,
Nxyz=(1024,64,64), dxyz=(4,2,2), seed=seed,
HighFreqComp=0, double_xyz=(False, True, True),
cache_spectral_tensor=True)
for seed in [0,4,8]]
mtf = mtf_lst[0]
U = 10
Theoretical spectrum¶
The turbulence intensity of the theoretical Mann model spectrum can be obtained with the spectra_TI method
[31]:
mtf.spectrum_TI(U=U)
[31]:
0.1388521234938508
Wave number limits can be specified via signal length, T, and cut-off frequency, cutoff_frq, associated with the TI measure. The cut-off frequency is e.g. caused by inertia in the cups of a cup anemometer and probe volume of a lidar.
[32]:
mtf.spectrum_TI(U=U, T=600, cutoff_frq=10)
[32]:
0.14324855863543767
Realization¶
The turbulence intensity of a box realization can be obtained by
[33]:
mtf_lst[0].uvw[0].std(0).mean() / U
[33]:
0.1373198390007019
Realizations may, however have very different turbulence intensities due to uncertainty on the low frequencies
[34]:
T = mtf.dx * mtf.Nx / U # Box length [s]
cutoff_frq = U / (2 * mtf.dx) # Nyquist frequency [Hz]
# Calculate and plot theoretical spectrum and ti
k_lut, spectra_lut = mtf.spectra_lookup(k1 = mtf.get_k())
spectra_ti = mtf.spectrum_TI(U=10)
plt.semilogx(k_lut, k_lut*spectra_lut[0], '--k', label=f'Theoretical, ti: {np.round(spectra_ti,3):0.3f}')
# Calculate and plot spectrum and ti of the four realizations
for mtf in mtf_lst:
k_rea, spectra_rea = mtf.spectra(min_bin_count=1, log10_bin_size=None)
plt.semilogx(k_rea, k_rea*spectra_rea[0], label=f'Seed: {mtf.seed}, ti: {np.round(np.mean(mtf.uvw[0].std(0)) / U,3):0.3f}')
plt.title('uu spectrum')
plt.xlabel('Wave number, $k_1$ $ [m^{-1}$]')
plt.ylabel('$k_1 S(k_1)[m^2s^{-2}]$')
plt.legend()
[34]:
<matplotlib.legend.Legend at 0x25483e6b150>
Turbulence scaling¶
In case, a specific turbulence intensity is needed, the turbulence field can be scaled accordingly.
[35]:
for i, mtf in enumerate(mtf_lst):
print(f"Box {i}")
print (f'Before: Box TI={mtf.uvw[0].std(0).mean()/U:.3f}, alphaepsilon:{mtf.alphaepsilon:.3f}, theoretical spectrum TI {mtf.spectrum_TI(U):.2f}')
mtf.scale_TI(TI=0.1, U=10)
print (f'After: Box TI={mtf.uvw[0].std(0).mean()/U:.3f}, alphaepsilon:{mtf.alphaepsilon:.3f}, theoretical spectrum TI {mtf.spectrum_TI(U):.2f}')
print()
Box 0
Before: Box TI=0.137, alphaepsilon:0.100, theoretical spectrum TI 0.14
After: Box TI=0.099, alphaepsilon:0.052, theoretical spectrum TI 0.10
Box 1
Before: Box TI=0.167, alphaepsilon:0.100, theoretical spectrum TI 0.14
After: Box TI=0.120, alphaepsilon:0.052, theoretical spectrum TI 0.10
Box 2
Before: Box TI=0.113, alphaepsilon:0.100, theoretical spectrum TI 0.14
After: Box TI=0.081, alphaepsilon:0.052, theoretical spectrum TI 0.10
Get alpha epsilon¶
The \(\alpha\epsilon^{2/3}\) value that corresponds to a theoretical spectrum with a specific TI can be obtained by
[36]:
mtf.get_alpha_epsilon(TI=.1, U=U)
[36]:
0.051867456121753086
It can even be calculated without generating the turbulence box:
[37]:
from hipersim.turbgen.spectral_tensor import MannTurbulenceInput
mti = MannTurbulenceInput(alphaepsilon=1, # dummy value
L=33.6,Gamma=3.9,
Nxyz=(1024,64,64), dxyz=(4,2,2))
mti.get_alpha_epsilon(TI=.1, U=U)
[37]:
0.051867456121753086
High frequency compensation¶
The HighFreqComp argument defines whether high-frequency compensation is applied. There are three options:
0orFalse(default): No high-frequency compensation applied1orTrue: A fast high-Frequency compensation method is applied. This method differs from the method in Mann (1998)2: The high-Frequency compensation method from the C++ version is applied. The method corresponds to Eq. A.6 in Mann (1998) except that the convolution is only applied in the (k2,k3), i.e. -2<=n_l<=2, l=(2,3). Note that this method is very slow
[38]:
axes = plt.subplots(2,2, figsize=(10,8))[1].flatten()
for hfc in [0,1,2]:
t = time.time()
mtf = MannTurbulenceField.generate(Nxyz=(256,64,64), HighFreqComp=hfc, double_xyz=(0,0,0), verbose=0)
k,S = mtf.spectra()
print (f"Spectra with HighFreqComp={hfc} computed in {time.time()-t:.0f}s")
for ax, Phi, in zip(axes, S):
ls = ['-', '--'][hfc==2]
ax.semilogx(k, Phi*k, ls, label=f'HighFreqComp={hfc}')
k,S = mtf.spectra_lookup()
for ax, Phi, s in zip(axes, S, s_lst):
ax.set_title(s)
ax.semilogx(k, Phi*k, label=f'Theoretical', zorder=-32)
ax.set_xlabel('Wave number, $k_1$ $ [m^{-1}$]')
ax.set_ylabel('$k_1 S(k_1)[m^2s^{-2}]$')
ax.grid()
ax.legend()
ax.set_xlim([0.1,5])
ax.set_ylim([0,.5])
axes[3].set_ylim([-0.1,.02])
plt.tight_layout()
Spectra with HighFreqComp=0 computed in 0s
Spectra with HighFreqComp=1 computed in 1s
Spectra with HighFreqComp=2 computed in 22s
Contraints¶
It is possible to modify a turbulence field
[39]:
mtf = MannTurbulenceField.generate(Nxyz=(128, 16, 8), dxyz=(2, 3, 4))
to satisfy a number of constraints
[40]:
constraints = np.array([[0, 0, 4, 5, 1, 2], # constr 1, x,y,z, u,v,w
[50, 0, 4, 6, 2, 1],
[100, 0, 4, 5, 1, 2]])
via the constrain method
[41]:
axes = plt.subplots(3, 1, figsize=(10,10))[1]
for ax, c in zip(axes, 'uvw'):
mtf.to_xarray().sel(uvw=c, y=0, z=4).plot(ax=ax, label='Raw turbulence')
mtf.constrain(constraints)
for i, (ax, c) in enumerate(zip(axes, 'uvw'), 3):
mtf.to_xarray().sel(uvw=c, y=0, z=4).plot(ax=ax, label='Constrained turbulence')
ax.plot([], '.k', label='Contraints')
for con in constraints:
ax.plot(con[0], con[i], '.k')
ax.legend()
Computing Mann tensor / correlation arrays for constrained simulation:
Correlation computations complete
Time elapsed is 0.02411961555480957
Populating covariance matrix for the constraints:
Constraint-constraint covariance matrix has been assembled
Time elapsed is 0.0010647773742675781
Applying constraints...
Constrained simulation complete
Total time elapsed is 0.027193307876586914