HAWC2Lib Quickstart¶
Install¶
HAWC2Lib is currently available for linux (python 3.7 - 3.11) and for windows (python 3.8). You can install it by:
pip install h2lib
To also install tests, tests files and modules needed to run tests you need to run
pip install h2lib[test]
[1]:
try:
import h2lib
except ModuleNotFoundError:
!pip install h2lib[test]
Import modules needed for this tutorial¶
[2]:
from h2lib import H2Lib, MultiH2Lib
import numpy as np
import matplotlib.pyplot as plt
from h2lib_tests import tfp
model_path = tfp + 'minimal'
print (model_path)
c:\mmpe\gitlab\DYNAMIKS\.py311_dynamiks_jupyter7\Lib\site-packages\h2lib_tests/test_files/minimal
Open and close library¶
[3]:
with H2Lib() as h2:
print (h2.get_version())
13.1.201
Alternatively you can close it manually
[4]:
h2 = H2Lib()
print (h2.get_version())
h2.close() # remember to close when you are finish
13.1.201
[4]:
'closed h2lib'
Run HAWC2 simulation¶
[5]:
with H2Lib() as h2:
h2.init(htc_path='htc/minimal.htc', model_path=model_path)
h2.step() # step one time step
h2.run(1) # run until 1s
h2.run(2) # run until 2s
Output from HAWC2¶
Time and free wind speed¶
[6]:
with H2Lib(suppress_output=False, subprocess=False) as h2:
h2.init(htc_path='htc/minimal_mann_turb.htc', model_path=model_path)
h2.run(2)
print (h2.get_time())
print (h2.get_wind_speed([0,0,-100])) # Vx,Vy,Vz at hawc2 global position (0,0,-100)
print (h2.get_uvw([0,0,-100])) # uvw at hawc2 global position (0,0,-100)
2.0
[ 1.82427096 0.12895566 -0.43977132]
[0.1289556622505188, 1.8242709636688232, 0.4397713243961334]
HAWC2 sensors¶
You can add normal HAWC2 sensor at any point during the simulation using the add_sensor function. These sensors will not affect the output defined in the htc file
add_sensor returns the index of the sensor. This index can be used to access the name, unit and description of the sensor using get_sensor_info(<index>) and the sensor value via get_sensor_value(<index>).
The sensor info and value are not updated before HAWC2 has run at least one time step after the sensor was added.
Some sensor commands add multiple sensors, wind free_wind ... for instance adds three sensors (Vx, Vy and Vz). The index returned from add_sensor is the index of the last one, so the value of Vx can be accessed by the index-2
[7]:
with H2Lib() as h2:
h2.init(htc_path='htc/minimal_mann_turb.htc', model_path=model_path)
time_sensor = h2.add_sensor('general time') # add a time sensor
h2.run(2)
print (h2.get_sensor_info(time_sensor))
print (h2.get_sensor_values(time_sensor))
wind_sensors = h2.add_sensor('wind free_wind 1 0 0 -100') # add wind speed sensor in global coo at position (0,0,-100)
h2.step() # need to run one step to update the sensor value
# print Vx, Vy and Vz
print (h2.get_sensor_values(wind_sensors))
[['Time', 's', 'Time']]
[2.]
[ 1.86098054 0.00672464 -0.47506651]
You can capture sensor values during simulation like this
[8]:
with H2Lib() as h2:
h2.init(htc_path='htc/minimal_mann_turb.htc', model_path=model_path)
wind_sensors = h2.add_sensor('wind free_wind 1 0 0 -100') # add wind speed sensor in global coo at position (0,0,-100)
res = []
for _ in range(100):
h2.step()
res.append(np.r_[h2.get_time(), h2.get_sensor_values(wind_sensors)])
t, Vx,Vy,Vz = np.array(res).T
plt.plot(t, Vz)
plt.xlabel('Time [s]')
plt.ylabel('Vz [m/s]')
General variable¶
HAWC2 has 10 sensors which can be set from outside.
general variable <index: 1-10> <initial value>
Name, unit and description can be specified via the # $name(myname) $unit(myunit) $desc(mydesc) options
[9]:
with H2Lib() as h2:
print (h2.filename)
h2.init(htc_path='htc/minimal_mann_turb.htc', model_path=model_path)
# add variable sensor 1 with 5 as initial value that can be set from python
index = h2.add_sensor('general variable 1 5 # $name(myname) $unit(myunit) $desc(mydesc)')
h2.step()
print (h2.get_sensor_info(index))
print ('Initial value:', h2.get_sensor_values(index))
h2.set_variable_sensor_value(index, 10) # update the sensor value to 10
h2.step() # need a step to update the value
print ('Updated value:', h2.get_sensor_values(index))
c:\mmpe\gitlab\DYNAMIKS\.py311_dynamiks_jupyter7\Lib\site-packages\h2lib\HAWC2Lib.dll
[['myname', 'myunit', 'mydesc']]
Initial value: [5.]
Updated value: [10.]
Set wind field¶
You can set the wind field, i.e. gridded three-component wind speed values including mean wind, shear, gusts and turbulence.
Before setting the wind field you need to run init_windfield and after that you can set the wind field as many time as you like.
[10]:
with H2Lib() as h2:
print (help(h2.init_windfield))
Help on function init_windfield in module h2lib._h2lib:
init_windfield(self, Nxyz, dxyz, box_offset_yz, transport_speed)
Initialize wind field which afterwards can be set using set_windfield
x: direction of wind
y: horizontal to the left when looking along x
z: vertical up
Parameters
----------
Nxyz : (int, int, int)
Number of points in wind field
dxyz : (float, float, float)
Distance between wind field points
box_offset_yz : (float, float)
Box offset in y and z, relative to hawc2 origo. Note this is in met coordinates as described above
To set a wind field of size 200x80x80, such that the center is located at hawc2 coordinate (0,0,-70),
box_offset_yz must be (-40,30)
Note that the wind field size is (Nxyz)-1*dxyz
transport_speed : float
Box transport speed
Notes
-----
The wind field will be transported in the hawc2 global y-direction with the transport speed,
In HAWC2:
- shear format is set to 0 (which also means that the mean wind (transport speed) is not added)
- turbformat is set to 1 (mann), but the buffer should be filled manually via set_windfield
- center_pos0 is set such that the lower right corner (when looking along global y) is located at box_offset_yz
- windfield_rotations is set to (0,0,0), i.e. the wind is aligned with y, and w points up (opposite global z)
- scaling is disabled
- the buffer is interpolated in the standard way, i.e. it is mirrored in the lateral and vertical direction and
repeated in the longitudinal direction
None
[11]:
with H2Lib() as h2:
print (help(h2.set_windfield))
Help on function set_windfield in module h2lib._h2lib:
set_windfield(self, uvw, box_offset_x, time=None)
Set wind field, must be called after init_windfield and init
Parameters
----------
uvw : array_like, dims=(3,Nx,Ny,Nz)
wind field components including mean wind speed, shear etc.
box_offset_x : float
Offset in x direction at the <time>
To set a wind field of size 200x80x80, such that the front plane (largest x) is located
at hawc2 coordinate (0,20,-70), i.e. 20m downstream of origo, set box_offset_x=-180
Note that the wind field size is (Nxyz)-1*dxyz
Note also that the end plane (x=0) will be located in -180 and repeated in 20+dx
time : float, optional
Time at which the the last plane (x=0) is at x=box_offset_x
If None, default, time is set to the current time in HAWC2
Notes
-----
uvw must be scaled in advance to the right turbulence level
and should contain mean wind, shear, gusts, direction change etc.
and uvw(:,1) is the back plane of the turbulence box, while uvw(:,Nx) is the front plane
None
[12]:
with H2Lib() as h2:
h2.init(htc_path='htc/minimal.htc', model_path=model_path)
h2.init_windfield(Nxyz=(100,2,2), dxyz=(1,1,1), box_offset_yz=(0,0), transport_speed=10)
u = np.sin(np.linspace(0,np.pi*2, 100))
uvw = np.array(np.meshgrid(u, [0,0], [0,0], indexing='ij'))
h2.set_windfield(uvw=uvw, box_offset_x=0)
plt.xlabel('Time [s]')
plt.ylabel('U [m/s]')
for _ in range(100):
h2.step()
plt.plot(h2.get_time(), h2.get_uvw([0,0,0])[0],'.k')
Multiple HAWC2 instances¶
Multiple instances of H2Lib can be created using MultiH2Lib(N). These instances are executed in separate processes and will run in parallel (if the system has enough cores available otherwise they will run sequentially).
MultiH2Lib has the same methods as H2Lib, but they works slightly different:
Output The methods of MultiH2Libwill return a list with the result from each of the instances
input MultiH2Lib distributes method arguments to the instances depending on their type:
List with exactly N elements: The first element in the list is passed to the first instance, the second to the second and so on
int, float, str, tuple, List (if len!=N), numpy arrays etc: The argument is passed to all instances
[13]:
with MultiH2Lib(N=2) as h2: # create two H2Lib instances
print (h2.get_version()) # print list of version of both instances
['13.1.201', '13.1.201']
[14]:
with MultiH2Lib(N=2) as h2: # create two H2Lib instances
h2.init(htc_path='htc/minimal.htc', model_path=model_path)
id1 = h2.add_sensor('general variable 1 5') # same input for both instances
id2 = h2.add_sensor(['general variable 2 5', # input for first instance
'general variable 2 10' # input for second instance
])
h2.step()
print (h2.get_sensor_values(id1))
print (h2.get_sensor_values(id2))
[array([5.]), array([5.])]
[array([5.]), array([10.])]