h2lib 0.0.3__cp310-cp310-win_amd64.whl → 13.0.705__cp310-cp310-win_amd64.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.
- h2lib/HAWC2Lib.dll +0 -0
- h2lib/__init__.py +15 -0
- h2lib/_h2lib.py +346 -0
- h2lib/_version.py +4 -0
- {h2lib-0.0.3.data/purelib/h2lib → h2lib}/dll_wrapper.py +326 -236
- h2lib/h2lib_signatures.py +318 -0
- h2lib-13.0.705.dist-info/METADATA +18 -0
- h2lib-13.0.705.dist-info/RECORD +14 -0
- {h2lib-0.0.3.dist-info → h2lib-13.0.705.dist-info}/WHEEL +1 -1
- h2lib-13.0.705.dist-info/top_level.txt +2 -0
- multiclass_interface/mpi_interface.py +184 -0
- multiclass_interface/multi_object_list.py +57 -0
- multiclass_interface/multiprocess_interface.py +184 -0
- multiclass_interface/my_test_cls.py +33 -0
- h2lib-0.0.3.data/purelib/h2lib/TestLib.dll +0 -0
- h2lib-0.0.3.data/purelib/h2lib/__init__.py +0 -1
- h2lib-0.0.3.data/purelib/h2lib/_h2lib.py +0 -13
- h2lib-0.0.3.data/purelib/h2lib/calc.py +0 -21
- h2lib-0.0.3.dist-info/METADATA +0 -14
- h2lib-0.0.3.dist-info/RECORD +0 -9
- h2lib-0.0.3.dist-info/top_level.txt +0 -1
h2lib/HAWC2Lib.dll
ADDED
Binary file
|
h2lib/__init__.py
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
import sys
|
2
|
+
import os
|
3
|
+
from ._h2lib import H2Lib, MultiH2Lib
|
4
|
+
from ._version import __version__, h2lib_version, hawc2_version
|
5
|
+
# try:
|
6
|
+
# from ._version import __version__
|
7
|
+
# if __version__ == 'unknown':
|
8
|
+
# f = os.path.abspath(os.path.dirname(__file__) + '/../../update_version.py')
|
9
|
+
# if os.path.isfile(f):
|
10
|
+
# os.system(f'{sys.executable} {f}')
|
11
|
+
# import importlib
|
12
|
+
# importlib.reload(_version)
|
13
|
+
# from ._version import __version__, h2lib_version, hawc2_version
|
14
|
+
# except BaseException:
|
15
|
+
# pass
|
h2lib/_h2lib.py
ADDED
@@ -0,0 +1,346 @@
|
|
1
|
+
from contextlib import contextmanager
|
2
|
+
from h2lib.dll_wrapper import DLLWrapper
|
3
|
+
from h2lib.h2lib_signatures import H2LibSignatures
|
4
|
+
import os
|
5
|
+
import sys
|
6
|
+
|
7
|
+
from multiclass_interface.multiprocess_interface import MultiProcessClassInterface, ProcessClass
|
8
|
+
import numpy as np
|
9
|
+
|
10
|
+
|
11
|
+
def H2Lib(suppress_output=False, subprocess=True):
|
12
|
+
H2 = [H2LibThread, H2LibProcess][subprocess]
|
13
|
+
return H2(suppress_output=suppress_output)
|
14
|
+
|
15
|
+
|
16
|
+
class H2LibThread(H2LibSignatures, DLLWrapper):
|
17
|
+
_model_path = '.'
|
18
|
+
_aero_sections_data_shape = {}
|
19
|
+
|
20
|
+
def __init__(self, suppress_output=True, filename=None, cwd='.'):
|
21
|
+
if filename is None:
|
22
|
+
if os.name == 'nt':
|
23
|
+
filename = os.path.dirname(__file__) + '/HAWC2Lib.dll'
|
24
|
+
else:
|
25
|
+
filename = os.path.dirname(__file__) + '/HAWC2Lib.so' # pragma: no cover
|
26
|
+
# doubles the speed of single instances and 2N of N instances on linux
|
27
|
+
os.environ['MKL_THREADING_LAYER'] = 'sequential'
|
28
|
+
filename = os.path.abspath(filename)
|
29
|
+
library_bin = os.path.abspath(os.path.join(os.path.dirname(sys.executable), '../Library/bin'))
|
30
|
+
if os.path.isdir(library_bin): # pragma: no cover
|
31
|
+
os.add_dll_directory(library_bin)
|
32
|
+
DLLWrapper.__init__(self, filename, cwd=cwd, cdecl=True)
|
33
|
+
self.suppress_output = suppress_output
|
34
|
+
self._initialized = False
|
35
|
+
self.time = 0
|
36
|
+
|
37
|
+
@property
|
38
|
+
def model_path(self):
|
39
|
+
return self._model_path
|
40
|
+
|
41
|
+
def __enter__(self):
|
42
|
+
return self
|
43
|
+
|
44
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
45
|
+
self.close()
|
46
|
+
|
47
|
+
def close(self):
|
48
|
+
if self._initialized:
|
49
|
+
self.finalize()
|
50
|
+
DLLWrapper.close(self)
|
51
|
+
return "closed h2lib"
|
52
|
+
|
53
|
+
def getState(self):
|
54
|
+
return H2LibSignatures.getState(self, restype=np.int32)[1]
|
55
|
+
|
56
|
+
def work(self, time):
|
57
|
+
"""Return number of loops"""
|
58
|
+
return H2LibSignatures.work(self, np.float64(time), restype=np.int64)[1]
|
59
|
+
|
60
|
+
def loop(self, N):
|
61
|
+
"""Return time to compute N loops"""
|
62
|
+
return H2LibSignatures.loop(self, int(N), restype=np.float64)[1]
|
63
|
+
|
64
|
+
def get_version(self):
|
65
|
+
s = " " * 255
|
66
|
+
return H2LibSignatures.get_version(self, s)[0][0].strip()
|
67
|
+
|
68
|
+
def get_wind_speed(self, pos_g):
|
69
|
+
return self.get_lib_function('get_wind_speed')(np.asarray(pos_g, dtype=np.float64),
|
70
|
+
np.asarray([0, 0, 0], dtype=np.float64))[0][1]
|
71
|
+
|
72
|
+
def get_uvw(self, pos_g):
|
73
|
+
vx, vy, vz = self.get_wind_speed(pos_g)
|
74
|
+
return [vy, vx, -vz]
|
75
|
+
|
76
|
+
def get_time(self):
|
77
|
+
return np.round(H2LibSignatures.get_time(self, time=0.)[0][0], 6)
|
78
|
+
|
79
|
+
def read_input(self, htc_path='htc/input_hawc.htc', model_path='.'):
|
80
|
+
self._model_path = model_path
|
81
|
+
self.cwd = self.model_path
|
82
|
+
return H2LibSignatures.read_input(self, htc_path)
|
83
|
+
|
84
|
+
def init(self, htc_path=None, model_path='.'):
|
85
|
+
assert not hasattr(self, '_init_result'), "init called twice"
|
86
|
+
if htc_path is not None:
|
87
|
+
self.read_input(htc_path, model_path)
|
88
|
+
r = H2LibSignatures.init(self)
|
89
|
+
self._initialized = True
|
90
|
+
return r
|
91
|
+
|
92
|
+
def step(self):
|
93
|
+
self.time = np.round(H2LibSignatures.step(self, restype=np.float64)[1], 6)
|
94
|
+
return self.time
|
95
|
+
|
96
|
+
def run(self, time):
|
97
|
+
self.time = np.round(H2LibSignatures.run(self, np.float64(time), restype=np.float64)[1], 6)
|
98
|
+
return self.time
|
99
|
+
|
100
|
+
def add_sensor(self, sensor_line):
|
101
|
+
"""Add sensor to hawc2. The sensor will be accessible from h2lib but will not show up in the output file of HAWC2
|
102
|
+
Note, that some sensors consist of multiple HAWC2 sensors, e.g. "wind free_wind" which has a Vx, Vy and Vz sensors
|
103
|
+
|
104
|
+
Parameters
|
105
|
+
----------
|
106
|
+
Sensor_line : str
|
107
|
+
Sensor line as used in the output sections in HAWC2. See How2Hawc2
|
108
|
+
|
109
|
+
Returns
|
110
|
+
-------
|
111
|
+
index_lst : list
|
112
|
+
List of sensor index(es). These index(es) can be used to call get_sensor_info or get_sensor_values
|
113
|
+
"""
|
114
|
+
if ";" not in sensor_line:
|
115
|
+
sensor_line += ";"
|
116
|
+
index_start, index_stop = 0, 0
|
117
|
+
index_start, index_stop = H2LibSignatures.add_sensor(self, sensor_line.lower(), index_start, index_stop)[0][1:]
|
118
|
+
return tuple(range(index_start, index_stop + 1))
|
119
|
+
|
120
|
+
def get_sensor_info(self, id):
|
121
|
+
"return name, unit, description"
|
122
|
+
if isinstance(id, tuple):
|
123
|
+
return [self.get_sensor_info(i) for i in id]
|
124
|
+
return [s[:-1].strip() # remove null termination
|
125
|
+
for s in H2LibSignatures.get_sensor_info(self, id, name=" " * 30, unit=" " * 10, desc=" " * 512)[0][1:]]
|
126
|
+
|
127
|
+
def get_sensor_values(self, id_lst):
|
128
|
+
"""Get sensor values from HAWC2
|
129
|
+
|
130
|
+
Parameters
|
131
|
+
----------
|
132
|
+
id_lst : array_like or int
|
133
|
+
list of sensor ids
|
134
|
+
|
135
|
+
Returns
|
136
|
+
-------
|
137
|
+
values : array_like or float
|
138
|
+
"""
|
139
|
+
if isinstance(id_lst, int):
|
140
|
+
return self.get_sensor_values([id_lst])[0]
|
141
|
+
values = np.zeros(len(id_lst), dtype=np.float64)
|
142
|
+
id_lst = np.array(id_lst, dtype=np.int64)
|
143
|
+
return H2LibSignatures.get_sensor_values(self, id_lst, values, len(id_lst))[0][1]
|
144
|
+
|
145
|
+
def set_variable_sensor_value(self, id, value):
|
146
|
+
return H2LibSignatures.set_variable_sensor_value(self, id, np.float64(value))
|
147
|
+
|
148
|
+
def init_windfield(self, Nxyz, dxyz, box_offset_yz, transport_speed):
|
149
|
+
"""Initialize wind field which afterwards can be set using set_windfield
|
150
|
+
|
151
|
+
|
152
|
+
x: direction of wind
|
153
|
+
y: horizontal to the left when looking along x
|
154
|
+
z: vertical up
|
155
|
+
|
156
|
+
Parameters
|
157
|
+
----------
|
158
|
+
Nxyz : (int, int, int)
|
159
|
+
Number of points in wind field
|
160
|
+
dxyz : (float, float, float)
|
161
|
+
Distance between wind field points
|
162
|
+
box_offset_yz : (float, float)
|
163
|
+
Box offset in y and z, relative to hawc2 origo. Note this is in met coordinates as described above
|
164
|
+
To set a wind field of size 200x80x80, such that the center is located at hawc2 coordinate (0,0,-70),
|
165
|
+
box_offset_yz must be (-40,30)
|
166
|
+
Note that the wind field size is (Nxyz)-1*dxyz
|
167
|
+
transport_speed : float
|
168
|
+
Box transport speed
|
169
|
+
|
170
|
+
Notes
|
171
|
+
-----
|
172
|
+
The wind field will be transported in the hawc2 global y-direction with the transport speed,
|
173
|
+
In HAWC2:
|
174
|
+
- shear format is set to 0 (which also means that the mean wind (transport speed) is not added)
|
175
|
+
- turbformat is set to 1 (mann), but the buffer should be filled manually via set_windfield
|
176
|
+
- center_pos0 is set such that the lower right corner (when looking along global y) is located at box_offset_yz
|
177
|
+
- windfield_rotations is set to (0,0,0), i.e. the wind is aligned with y, and w points up (opposite global z)
|
178
|
+
- scaling is disabled
|
179
|
+
- the buffer is interpolated in the standard way, i.e. it is mirrored in the lateral and vertical direction and
|
180
|
+
repeated in the longitudinal direction
|
181
|
+
|
182
|
+
"""
|
183
|
+
return H2LibSignatures.init_windfield(self, np.array(Nxyz, dtype=np.int64), np.array(dxyz, dtype=np.float64),
|
184
|
+
np.array(box_offset_yz, dtype=np.float64), np.float64(transport_speed))
|
185
|
+
|
186
|
+
def set_windfield(self, uvw, box_offset_x, time=None):
|
187
|
+
"""Set wind field, must be called after init_windfield and init
|
188
|
+
|
189
|
+
Parameters
|
190
|
+
----------
|
191
|
+
uvw : array_like, dims=(3,Nx,Ny,Nz)
|
192
|
+
wind field components including mean wind speed, shear etc.
|
193
|
+
box_offset_x : float
|
194
|
+
Offset in x direction at the <time>
|
195
|
+
To set a wind field of size 200x80x80, such that the front plane (largest x) is located
|
196
|
+
at hawc2 coordinate (0,20,-70), i.e. 20m downstream of origo, set box_offset_x=-180
|
197
|
+
Note that the wind field size is (Nxyz)-1*dxyz
|
198
|
+
Note also that the end plane (x=0) will be located in -180 and repeated in 20+dx
|
199
|
+
time : float, optional
|
200
|
+
Time at which the the last plane (x=0) is at x=box_offset_x
|
201
|
+
If None, default, time is set to the current time in HAWC2
|
202
|
+
|
203
|
+
Notes
|
204
|
+
-----
|
205
|
+
uvw must be scaled in advance to the right turbulence level
|
206
|
+
and should contain mean wind, shear, gusts, direction change etc.
|
207
|
+
and uvw(:,1) is the back plane of the turbulence box, while uvw(:,Nx) is the front plane
|
208
|
+
"""
|
209
|
+
if time is None:
|
210
|
+
time = self.get_time()
|
211
|
+
return H2LibSignatures.set_windfield(self, np.asarray(uvw, dtype=np.float32),
|
212
|
+
np.float64(box_offset_x), np.float64(time))
|
213
|
+
|
214
|
+
# ===================================================================================================================
|
215
|
+
# H2rotor
|
216
|
+
# ===================================================================================================================
|
217
|
+
|
218
|
+
def get_rotor_dims(self):
|
219
|
+
return [[self.get_nSections(r, b) for b in range(self.get_nblades(r))]
|
220
|
+
for r in range(self.get_nrotors())]
|
221
|
+
|
222
|
+
def get_nrotors(self):
|
223
|
+
return H2LibSignatures.get_nrotors(self, restype=np.int64)[1]
|
224
|
+
|
225
|
+
def get_nblades(self, rotor=0):
|
226
|
+
return H2LibSignatures.get_nblades(self, rotor + 1, restype=np.int64)[1]
|
227
|
+
|
228
|
+
def get_nSections(self, rotor=0, blade=0):
|
229
|
+
return H2LibSignatures.get_nSections(self, rotor + 1, blade + 1, restype=np.int64)[1]
|
230
|
+
|
231
|
+
def get_diameter(self, rotor=0):
|
232
|
+
return H2LibSignatures.get_diameter(self, rotor + 1, restype=np.float64)[1]
|
233
|
+
|
234
|
+
def aero_sections_data_shape(self, rotor):
|
235
|
+
if rotor not in self._aero_sections_data_shape:
|
236
|
+
self._aero_sections_data_shape[rotor] = (self.get_nblades(rotor), self.get_nSections(rotor), 3)
|
237
|
+
return self._aero_sections_data_shape[rotor]
|
238
|
+
|
239
|
+
def get_aerosections_position(self, rotor=0):
|
240
|
+
position = np.zeros(self.aero_sections_data_shape(rotor), dtype=np.float64, order='F')
|
241
|
+
return H2LibSignatures.get_aerosections_position(self, rotor + 1, position)[0][1]
|
242
|
+
|
243
|
+
def set_aerosections_windspeed(self, uvw, rotor=0):
|
244
|
+
return H2LibSignatures.set_aerosections_windspeed(self, rotor + 1, uvw)
|
245
|
+
|
246
|
+
def get_aerosections_forces(self, rotor=0):
|
247
|
+
shape = self.aero_sections_data_shape(rotor)
|
248
|
+
Fxyz = np.zeros(shape, dtype=np.float64, order='F')
|
249
|
+
return H2LibSignatures.get_aerosections_forces(self, rotor + 1, Fxyz)[0][1]
|
250
|
+
|
251
|
+
def get_aerosections_moments(self, rotor=0):
|
252
|
+
shape = self.aero_sections_data_shape(rotor)
|
253
|
+
Mxyz = np.zeros(shape, dtype=np.float64, order='F')
|
254
|
+
return H2LibSignatures.get_aerosections_moments(self, rotor + 1, Mxyz)[0][1]
|
255
|
+
|
256
|
+
def get_bem_grid_dim(self, rotor=0):
|
257
|
+
"""returns (nazi, nrad)"""
|
258
|
+
return H2LibSignatures.get_bem_grid_dim(self, rotor + 1, 0, 0)[0][1:]
|
259
|
+
|
260
|
+
def get_bem_grid(self, rotor=0):
|
261
|
+
"""returns azi, rad"""
|
262
|
+
nazi, nrad = self.get_bem_grid_dim(rotor)
|
263
|
+
return H2LibSignatures.get_bem_grid(self, rotor + 1,
|
264
|
+
np.zeros(nazi, dtype=np.float64, order='F'),
|
265
|
+
np.zeros(nrad, dtype=np.float64, order='F'))[0][1:]
|
266
|
+
|
267
|
+
def get_induction_polargrid(self, rotor=0):
|
268
|
+
nazi, nrad = self.get_bem_grid_dim(rotor)
|
269
|
+
induction = np.zeros((nazi, nrad), dtype=np.float64, order='F')
|
270
|
+
return H2LibSignatures.get_induction_polargrid(self, rotor + 1, induction)[0][1]
|
271
|
+
|
272
|
+
def get_induction_axisymmetric(self, rotor=0):
|
273
|
+
nrad = self.get_bem_grid_dim(rotor)[1]
|
274
|
+
induction = np.zeros(nrad, dtype=np.float64)
|
275
|
+
return H2LibSignatures.get_induction_axisymmetric(self, rotor + 1, induction)[0][1]
|
276
|
+
|
277
|
+
def get_induction_rotoravg(self, rotor=0):
|
278
|
+
induction = np.float64(0)
|
279
|
+
return H2LibSignatures.get_induction_rotoravg(self, rotor + 1, induction)[0][1]
|
280
|
+
|
281
|
+
def get_rotor_orientation(self, rotor=0, deg=False):
|
282
|
+
"""return yaw, tilt, azi(of first blade) in rad(default) or deg"""
|
283
|
+
r = H2LibSignatures.get_rotor_orientation(self, rotor=rotor + 1, yaw=0., tilt=0., azi=0.)[0][1:]
|
284
|
+
if deg:
|
285
|
+
return np.rad2deg(r)
|
286
|
+
else:
|
287
|
+
return r
|
288
|
+
|
289
|
+
def get_rotor_position(self, rotor=0):
|
290
|
+
return H2LibSignatures.get_rotor_position(self, rotor=rotor + 1, position=np.zeros(3, dtype=np.float64))[0][1]
|
291
|
+
|
292
|
+
def get_rotor_avg_wsp(self, coo=1, rotor=0):
|
293
|
+
"""Returns the rotor averaged wind speed in global(coo=1, default) or rotor(coo=2) coordinates."""
|
294
|
+
assert self.time > 0
|
295
|
+
wsp = np.zeros(3, dtype=np.float64)
|
296
|
+
return H2LibSignatures.get_rotor_avg_wsp(self, coo=coo, rotor=rotor + 1, wsp=wsp)[0][2]
|
297
|
+
|
298
|
+
def get_rotor_avg_uvw(self, rotor=0):
|
299
|
+
vx, vy, vz = self.get_rotor_avg_wsp(1, rotor)
|
300
|
+
return [vy, vx, -vz]
|
301
|
+
|
302
|
+
|
303
|
+
@contextmanager
|
304
|
+
def set_LD_LIBRARY_PATH():
|
305
|
+
_file__ = np.__file__
|
306
|
+
old = os.environ.get('LD_LIBRARY_PATH', "")
|
307
|
+
|
308
|
+
if '/lib/' in _file__: # pragma: no cover (only on linux)
|
309
|
+
lib_path = _file__[:_file__.index("/lib/") + 5]
|
310
|
+
os.environ['LD_LIBRARY_PATH'] = f'{lib_path}:{old}'
|
311
|
+
|
312
|
+
try:
|
313
|
+
yield
|
314
|
+
finally:
|
315
|
+
os.environ['LD_LIBRARY_PATH'] = old
|
316
|
+
|
317
|
+
|
318
|
+
class H2LibProcess(ProcessClass, H2LibThread):
|
319
|
+
def __init__(self, suppress_output, filename=None, cwd='.'):
|
320
|
+
with set_LD_LIBRARY_PATH():
|
321
|
+
ProcessClass.__init__(self, cls=H2LibThread, cls_attrs=set(dir(H2LibThread)) - set(dir(ProcessClass)))
|
322
|
+
self(suppress_output=suppress_output, filename=filename, cwd=cwd)
|
323
|
+
|
324
|
+
|
325
|
+
def MultiH2Lib(N, filename=None, cwd='.', suppress_output=False):
|
326
|
+
|
327
|
+
if not hasattr(suppress_output, '__len__'):
|
328
|
+
suppress_output = [suppress_output] * N
|
329
|
+
args = [(suppress_output[i], filename, cwd) for i in range(N)]
|
330
|
+
|
331
|
+
with set_LD_LIBRARY_PATH():
|
332
|
+
from multiclass_interface import mpi_interface
|
333
|
+
if mpi_interface.size > 1: # pragma: no cover
|
334
|
+
# try:
|
335
|
+
# with H2LibThread(filename):
|
336
|
+
# pass
|
337
|
+
# # LD_LIBRARY_PATH is set. Run H2LibThread directly in mpi processes
|
338
|
+
# cls = H2LibThread
|
339
|
+
# except OSError:
|
340
|
+
# # Set LD_LIBRARY_PATH in mpi workers and run H2LibThread from the workers via ProcessClass
|
341
|
+
# cls = H2LibProcess
|
342
|
+
from multiclass_interface.mpi_interface import MPIClassInterface
|
343
|
+
cls = H2LibProcess
|
344
|
+
return MPIClassInterface(cls, args)
|
345
|
+
else:
|
346
|
+
return MultiProcessClassInterface(H2LibThread, args)
|
h2lib/_version.py
ADDED