h2lib 13.1.301__cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.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.so +0 -0
- h2lib/__init__.py +15 -0
- h2lib/_h2lib.py +347 -0
- h2lib/_version.py +4 -0
- h2lib/dll_wrapper.py +329 -0
- h2lib/h2lib_signatures.py +324 -0
- h2lib-13.1.301.dist-info/METADATA +21 -0
- h2lib-13.1.301.dist-info/RECORD +10 -0
- h2lib-13.1.301.dist-info/WHEEL +6 -0
- h2lib-13.1.301.dist-info/top_level.txt +1 -0
h2lib/HAWC2Lib.so
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,347 @@
|
|
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.write_output()
|
50
|
+
self.finalize()
|
51
|
+
DLLWrapper.close(self)
|
52
|
+
return "closed h2lib"
|
53
|
+
|
54
|
+
def getState(self):
|
55
|
+
return H2LibSignatures.getState(self, restype=np.int32)[1]
|
56
|
+
|
57
|
+
def work(self, time):
|
58
|
+
"""Return number of loops"""
|
59
|
+
return H2LibSignatures.work(self, np.float64(time), restype=np.int64)[1]
|
60
|
+
|
61
|
+
def loop(self, N):
|
62
|
+
"""Return time to compute N loops"""
|
63
|
+
return H2LibSignatures.loop(self, int(N), restype=np.float64)[1]
|
64
|
+
|
65
|
+
def get_version(self):
|
66
|
+
s = " " * 255
|
67
|
+
return H2LibSignatures.get_version(self, s)[0][0].strip()
|
68
|
+
|
69
|
+
def get_wind_speed(self, pos_g):
|
70
|
+
return self.get_lib_function('get_wind_speed')(np.asarray(pos_g, dtype=np.float64),
|
71
|
+
np.asarray([0, 0, 0], dtype=np.float64))[0][1]
|
72
|
+
|
73
|
+
def get_uvw(self, pos_g):
|
74
|
+
vx, vy, vz = self.get_wind_speed(pos_g)
|
75
|
+
return [vy, vx, -vz]
|
76
|
+
|
77
|
+
def get_time(self):
|
78
|
+
return np.round(H2LibSignatures.get_time(self, time=0.)[0][0], 6)
|
79
|
+
|
80
|
+
def read_input(self, htc_path='htc/input_hawc.htc', model_path='.'):
|
81
|
+
self._model_path = model_path
|
82
|
+
self.cwd = self.model_path
|
83
|
+
return H2LibSignatures.read_input(self, htc_path)
|
84
|
+
|
85
|
+
def init(self, htc_path=None, model_path='.'):
|
86
|
+
assert not hasattr(self, '_init_result'), "init called twice"
|
87
|
+
if htc_path is not None:
|
88
|
+
self.read_input(htc_path, model_path)
|
89
|
+
r = H2LibSignatures.init(self)
|
90
|
+
self._initialized = True
|
91
|
+
return r
|
92
|
+
|
93
|
+
def step(self):
|
94
|
+
self.time = np.round(H2LibSignatures.step(self, restype=np.float64)[1], 6)
|
95
|
+
return self.time
|
96
|
+
|
97
|
+
def run(self, time):
|
98
|
+
self.time = np.round(H2LibSignatures.run(self, np.float64(time), restype=np.float64)[1], 6)
|
99
|
+
return self.time
|
100
|
+
|
101
|
+
def add_sensor(self, sensor_line):
|
102
|
+
"""Add sensor to hawc2. The sensor will be accessible from h2lib but will not show up in the output file of HAWC2
|
103
|
+
Note, that some sensors consist of multiple HAWC2 sensors, e.g. "wind free_wind" which has a Vx, Vy and Vz sensors
|
104
|
+
|
105
|
+
Parameters
|
106
|
+
----------
|
107
|
+
Sensor_line : str
|
108
|
+
Sensor line as used in the output sections in HAWC2. See How2Hawc2
|
109
|
+
|
110
|
+
Returns
|
111
|
+
-------
|
112
|
+
index_lst : list
|
113
|
+
List of sensor index(es). These index(es) can be used to call get_sensor_info or get_sensor_values
|
114
|
+
"""
|
115
|
+
if ";" not in sensor_line:
|
116
|
+
sensor_line += ";"
|
117
|
+
index_start, index_stop = 0, 0
|
118
|
+
index_start, index_stop = H2LibSignatures.add_sensor(self, sensor_line.lower(), index_start, index_stop)[0][1:]
|
119
|
+
return tuple(range(index_start, index_stop + 1))
|
120
|
+
|
121
|
+
def get_sensor_info(self, id):
|
122
|
+
"return name, unit, description"
|
123
|
+
if isinstance(id, tuple):
|
124
|
+
return [self.get_sensor_info(i) for i in id]
|
125
|
+
return [s[:-1].strip() # remove null termination
|
126
|
+
for s in H2LibSignatures.get_sensor_info(self, id, name=" " * 30, unit=" " * 10, desc=" " * 512)[0][1:]]
|
127
|
+
|
128
|
+
def get_sensor_values(self, id_lst):
|
129
|
+
"""Get sensor values from HAWC2
|
130
|
+
|
131
|
+
Parameters
|
132
|
+
----------
|
133
|
+
id_lst : array_like or int
|
134
|
+
list of sensor ids
|
135
|
+
|
136
|
+
Returns
|
137
|
+
-------
|
138
|
+
values : array_like or float
|
139
|
+
"""
|
140
|
+
if isinstance(id_lst, int):
|
141
|
+
return self.get_sensor_values([id_lst])[0]
|
142
|
+
values = np.zeros(len(id_lst), dtype=np.float64)
|
143
|
+
id_lst = np.array(id_lst, dtype=np.int64)
|
144
|
+
return H2LibSignatures.get_sensor_values(self, id_lst, values, len(id_lst))[0][1]
|
145
|
+
|
146
|
+
def set_variable_sensor_value(self, id, value):
|
147
|
+
return H2LibSignatures.set_variable_sensor_value(self, id, np.float64(value))
|
148
|
+
|
149
|
+
def init_windfield(self, Nxyz, dxyz, box_offset_yz, transport_speed):
|
150
|
+
"""Initialize wind field which afterwards can be set using set_windfield
|
151
|
+
|
152
|
+
|
153
|
+
x: direction of wind
|
154
|
+
y: horizontal to the left when looking along x
|
155
|
+
z: vertical up
|
156
|
+
|
157
|
+
Parameters
|
158
|
+
----------
|
159
|
+
Nxyz : (int, int, int)
|
160
|
+
Number of points in wind field
|
161
|
+
dxyz : (float, float, float)
|
162
|
+
Distance between wind field points
|
163
|
+
box_offset_yz : (float, float)
|
164
|
+
Box offset in y and z, relative to hawc2 origo. Note this is in met coordinates as described above
|
165
|
+
To set a wind field of size 200x80x80, such that the center is located at hawc2 coordinate (0,0,-70),
|
166
|
+
box_offset_yz must be (-40,30)
|
167
|
+
Note that the wind field size is (Nxyz)-1*dxyz
|
168
|
+
transport_speed : float
|
169
|
+
Box transport speed
|
170
|
+
|
171
|
+
Notes
|
172
|
+
-----
|
173
|
+
The wind field will be transported in the hawc2 global y-direction with the transport speed,
|
174
|
+
In HAWC2:
|
175
|
+
- shear format is set to 0 (which also means that the mean wind (transport speed) is not added)
|
176
|
+
- turbformat is set to 1 (mann), but the buffer should be filled manually via set_windfield
|
177
|
+
- center_pos0 is set such that the lower right corner (when looking along global y) is located at box_offset_yz
|
178
|
+
- windfield_rotations is set to (0,0,0), i.e. the wind is aligned with y, and w points up (opposite global z)
|
179
|
+
- scaling is disabled
|
180
|
+
- the buffer is interpolated in the standard way, i.e. it is mirrored in the lateral and vertical direction and
|
181
|
+
repeated in the longitudinal direction
|
182
|
+
|
183
|
+
"""
|
184
|
+
return H2LibSignatures.init_windfield(self, np.array(Nxyz, dtype=np.int64), np.array(dxyz, dtype=np.float64),
|
185
|
+
np.array(box_offset_yz, dtype=np.float64), np.float64(transport_speed))
|
186
|
+
|
187
|
+
def set_windfield(self, uvw, box_offset_x, time=None):
|
188
|
+
"""Set wind field, must be called after init_windfield and init
|
189
|
+
|
190
|
+
Parameters
|
191
|
+
----------
|
192
|
+
uvw : array_like, dims=(3,Nx,Ny,Nz)
|
193
|
+
wind field components including mean wind speed, shear etc.
|
194
|
+
box_offset_x : float
|
195
|
+
Offset in x direction at the <time>
|
196
|
+
To set a wind field of size 200x80x80, such that the front plane (largest x) is located
|
197
|
+
at hawc2 coordinate (0,20,-70), i.e. 20m downstream of origo, set box_offset_x=-180
|
198
|
+
Note that the wind field size is (Nxyz)-1*dxyz
|
199
|
+
Note also that the end plane (x=0) will be located in -180 and repeated in 20+dx
|
200
|
+
time : float, optional
|
201
|
+
Time at which the the last plane (x=0) is at x=box_offset_x
|
202
|
+
If None, default, time is set to the current time in HAWC2
|
203
|
+
|
204
|
+
Notes
|
205
|
+
-----
|
206
|
+
uvw must be scaled in advance to the right turbulence level
|
207
|
+
and should contain mean wind, shear, gusts, direction change etc.
|
208
|
+
and uvw(:,1) is the back plane of the turbulence box, while uvw(:,Nx) is the front plane
|
209
|
+
"""
|
210
|
+
if time is None:
|
211
|
+
time = self.get_time()
|
212
|
+
return H2LibSignatures.set_windfield(self, np.asarray(uvw, dtype=np.float32),
|
213
|
+
np.float64(box_offset_x), np.float64(time))
|
214
|
+
|
215
|
+
# ===================================================================================================================
|
216
|
+
# H2rotor
|
217
|
+
# ===================================================================================================================
|
218
|
+
|
219
|
+
def get_rotor_dims(self):
|
220
|
+
return [[self.get_nSections(r, b) for b in range(self.get_nblades(r))]
|
221
|
+
for r in range(self.get_nrotors())]
|
222
|
+
|
223
|
+
def get_nrotors(self):
|
224
|
+
return H2LibSignatures.get_nrotors(self, restype=np.int64)[1]
|
225
|
+
|
226
|
+
def get_nblades(self, rotor=0):
|
227
|
+
return H2LibSignatures.get_nblades(self, rotor + 1, restype=np.int64)[1]
|
228
|
+
|
229
|
+
def get_nSections(self, rotor=0, blade=0):
|
230
|
+
return H2LibSignatures.get_nSections(self, rotor + 1, blade + 1, restype=np.int64)[1]
|
231
|
+
|
232
|
+
def get_diameter(self, rotor=0):
|
233
|
+
return H2LibSignatures.get_diameter(self, rotor + 1, restype=np.float64)[1]
|
234
|
+
|
235
|
+
def aero_sections_data_shape(self, rotor):
|
236
|
+
if rotor not in self._aero_sections_data_shape:
|
237
|
+
self._aero_sections_data_shape[rotor] = (self.get_nblades(rotor), self.get_nSections(rotor), 3)
|
238
|
+
return self._aero_sections_data_shape[rotor]
|
239
|
+
|
240
|
+
def get_aerosections_position(self, rotor=0):
|
241
|
+
position = np.zeros(self.aero_sections_data_shape(rotor), dtype=np.float64, order='F')
|
242
|
+
return H2LibSignatures.get_aerosections_position(self, rotor + 1, position)[0][1]
|
243
|
+
|
244
|
+
def set_aerosections_windspeed(self, uvw, rotor=0):
|
245
|
+
return H2LibSignatures.set_aerosections_windspeed(self, rotor + 1, np.asarray(uvw, np.float64))
|
246
|
+
|
247
|
+
def get_aerosections_forces(self, rotor=0):
|
248
|
+
shape = self.aero_sections_data_shape(rotor)
|
249
|
+
Fxyz = np.zeros(shape, dtype=np.float64, order='F')
|
250
|
+
return H2LibSignatures.get_aerosections_forces(self, rotor + 1, Fxyz)[0][1]
|
251
|
+
|
252
|
+
def get_aerosections_moments(self, rotor=0):
|
253
|
+
shape = self.aero_sections_data_shape(rotor)
|
254
|
+
Mxyz = np.zeros(shape, dtype=np.float64, order='F')
|
255
|
+
return H2LibSignatures.get_aerosections_moments(self, rotor + 1, Mxyz)[0][1]
|
256
|
+
|
257
|
+
def get_bem_grid_dim(self, rotor=0):
|
258
|
+
"""returns (nazi, nrad)"""
|
259
|
+
return H2LibSignatures.get_bem_grid_dim(self, rotor + 1, 0, 0)[0][1:]
|
260
|
+
|
261
|
+
def get_bem_grid(self, rotor=0):
|
262
|
+
"""returns azi, rad"""
|
263
|
+
nazi, nrad = self.get_bem_grid_dim(rotor)
|
264
|
+
return H2LibSignatures.get_bem_grid(self, rotor + 1,
|
265
|
+
np.zeros(nazi, dtype=np.float64, order='F'),
|
266
|
+
np.zeros(nrad, dtype=np.float64, order='F'))[0][1:]
|
267
|
+
|
268
|
+
def get_induction_polargrid(self, rotor=0):
|
269
|
+
nazi, nrad = self.get_bem_grid_dim(rotor)
|
270
|
+
induction = np.zeros((nazi, nrad), dtype=np.float64, order='F')
|
271
|
+
return H2LibSignatures.get_induction_polargrid(self, rotor + 1, induction)[0][1]
|
272
|
+
|
273
|
+
def get_induction_axisymmetric(self, rotor=0):
|
274
|
+
nrad = self.get_bem_grid_dim(rotor)[1]
|
275
|
+
induction = np.zeros(nrad, dtype=np.float64)
|
276
|
+
return H2LibSignatures.get_induction_axisymmetric(self, rotor + 1, induction)[0][1]
|
277
|
+
|
278
|
+
def get_induction_rotoravg(self, rotor=0):
|
279
|
+
induction = np.float64(0)
|
280
|
+
return H2LibSignatures.get_induction_rotoravg(self, rotor + 1, induction)[0][1]
|
281
|
+
|
282
|
+
def get_rotor_orientation(self, rotor=0, deg=False):
|
283
|
+
"""return yaw, tilt, azi(of first blade) in rad(default) or deg"""
|
284
|
+
r = H2LibSignatures.get_rotor_orientation(self, rotor=rotor + 1, yaw=0., tilt=0., azi=0.)[0][1:]
|
285
|
+
if deg:
|
286
|
+
return np.rad2deg(r)
|
287
|
+
else:
|
288
|
+
return r
|
289
|
+
|
290
|
+
def get_rotor_position(self, rotor=0):
|
291
|
+
return H2LibSignatures.get_rotor_position(self, rotor=rotor + 1, position=np.zeros(3, dtype=np.float64))[0][1]
|
292
|
+
|
293
|
+
def get_rotor_avg_wsp(self, coo=1, rotor=0):
|
294
|
+
"""Returns the rotor averaged wind speed in global(coo=1, default) or rotor(coo=2) coordinates."""
|
295
|
+
assert self.time > 0
|
296
|
+
wsp = np.zeros(3, dtype=np.float64)
|
297
|
+
return H2LibSignatures.get_rotor_avg_wsp(self, coo=coo, rotor=rotor + 1, wsp=wsp)[0][2]
|
298
|
+
|
299
|
+
def get_rotor_avg_uvw(self, rotor=0):
|
300
|
+
vx, vy, vz = self.get_rotor_avg_wsp(1, rotor)
|
301
|
+
return [vy, vx, -vz]
|
302
|
+
|
303
|
+
|
304
|
+
@contextmanager
|
305
|
+
def set_LD_LIBRARY_PATH():
|
306
|
+
_file__ = np.__file__
|
307
|
+
old = os.environ.get('LD_LIBRARY_PATH', "")
|
308
|
+
|
309
|
+
if '/lib/' in _file__: # pragma: no cover (only on linux)
|
310
|
+
lib_path = _file__[:_file__.index("/lib/") + 5]
|
311
|
+
os.environ['LD_LIBRARY_PATH'] = f'{lib_path}:{old}'
|
312
|
+
|
313
|
+
try:
|
314
|
+
yield
|
315
|
+
finally:
|
316
|
+
os.environ['LD_LIBRARY_PATH'] = old
|
317
|
+
|
318
|
+
|
319
|
+
class H2LibProcess(ProcessClass, H2LibThread):
|
320
|
+
def __init__(self, suppress_output, filename=None, cwd='.'):
|
321
|
+
with set_LD_LIBRARY_PATH():
|
322
|
+
ProcessClass.__init__(self, cls=H2LibThread, cls_attrs=set(dir(H2LibThread)) - set(dir(ProcessClass)))
|
323
|
+
self(suppress_output=suppress_output, filename=filename, cwd=cwd)
|
324
|
+
|
325
|
+
|
326
|
+
def MultiH2Lib(N, filename=None, cwd='.', suppress_output=False):
|
327
|
+
|
328
|
+
if not hasattr(suppress_output, '__len__'):
|
329
|
+
suppress_output = [suppress_output] * N
|
330
|
+
args = [(suppress_output[i], filename, cwd) for i in range(N)]
|
331
|
+
|
332
|
+
with set_LD_LIBRARY_PATH():
|
333
|
+
from multiclass_interface import mpi_interface
|
334
|
+
if mpi_interface.mpi: # pragma: no cover
|
335
|
+
# try:
|
336
|
+
# with H2LibThread(filename):
|
337
|
+
# pass
|
338
|
+
# # LD_LIBRARY_PATH is set. Run H2LibThread directly in mpi processes
|
339
|
+
# cls = H2LibThread
|
340
|
+
# except OSError:
|
341
|
+
# # Set LD_LIBRARY_PATH in mpi workers and run H2LibThread from the workers via ProcessClass
|
342
|
+
# cls = H2LibProcess
|
343
|
+
from multiclass_interface.mpi_interface import MPIClassInterface
|
344
|
+
cls = H2LibProcess
|
345
|
+
return MPIClassInterface(cls, args)
|
346
|
+
else:
|
347
|
+
return MultiProcessClassInterface(H2LibThread, args)
|
h2lib/_version.py
ADDED
h2lib/dll_wrapper.py
ADDED
@@ -0,0 +1,329 @@
|
|
1
|
+
import numpy as np
|
2
|
+
from numpy.ctypeslib import ndpointer
|
3
|
+
import ctypes as ct
|
4
|
+
import _ctypes
|
5
|
+
import platform
|
6
|
+
import os
|
7
|
+
import ctypes
|
8
|
+
from _ctypes import POINTER
|
9
|
+
from ctypes import c_int, c_double, c_char, c_char_p, c_long, c_longlong
|
10
|
+
from contextlib import contextmanager
|
11
|
+
try:
|
12
|
+
from ctypes import windll
|
13
|
+
except ImportError:
|
14
|
+
pass
|
15
|
+
import sys
|
16
|
+
from pathlib import Path
|
17
|
+
import atexit
|
18
|
+
c_int_p = POINTER(ctypes.c_long)
|
19
|
+
c_long_p = POINTER(ctypes.c_longlong)
|
20
|
+
|
21
|
+
c_double_p = POINTER(ctypes.c_double)
|
22
|
+
c_float_p = POINTER(ctypes.c_float)
|
23
|
+
|
24
|
+
in_use = []
|
25
|
+
|
26
|
+
|
27
|
+
class SuppressStream(object):
|
28
|
+
|
29
|
+
def __init__(self, stream=sys.stderr):
|
30
|
+
self.orig_stream_fileno = stream.fileno()
|
31
|
+
self.stream = stream
|
32
|
+
|
33
|
+
def __enter__(self):
|
34
|
+
# save stream file descriptor
|
35
|
+
self.orig_stream_dup = os.dup(self.orig_stream_fileno)
|
36
|
+
self.devnull = open(os.devnull, 'w')
|
37
|
+
self.stream.flush()
|
38
|
+
os.dup2(self.devnull.fileno(), self.orig_stream_fileno)
|
39
|
+
|
40
|
+
def __exit__(self, type, value, traceback):
|
41
|
+
os.close(self.orig_stream_fileno)
|
42
|
+
os.dup2(self.orig_stream_dup, self.orig_stream_fileno)
|
43
|
+
os.close(self.orig_stream_dup)
|
44
|
+
self.devnull.flush()
|
45
|
+
self.devnull.close()
|
46
|
+
|
47
|
+
|
48
|
+
def suppress_output(f):
|
49
|
+
def wrap(*args, **kwargs):
|
50
|
+
if 'verbose' not in kwargs or not kwargs.pop('verbose'):
|
51
|
+
with SuppressStream(sys.stdout), SuppressStream(sys.stderr):
|
52
|
+
f(*args, **kwargs)
|
53
|
+
else:
|
54
|
+
f(*args, **kwargs)
|
55
|
+
return wrap
|
56
|
+
|
57
|
+
|
58
|
+
@contextmanager
|
59
|
+
def chdir(path):
|
60
|
+
oldpwd = os.getcwd()
|
61
|
+
os.chdir(path)
|
62
|
+
try:
|
63
|
+
yield
|
64
|
+
finally:
|
65
|
+
os.chdir(oldpwd)
|
66
|
+
|
67
|
+
|
68
|
+
def cwd(f):
|
69
|
+
def wrap(self, *args, **kwargs):
|
70
|
+
with chdir(self.model_path):
|
71
|
+
f(self, *args, **kwargs)
|
72
|
+
return wrap
|
73
|
+
|
74
|
+
|
75
|
+
def wrap(self, f, *args, **kwargs):
|
76
|
+
c_args = []
|
77
|
+
args = list(args)
|
78
|
+
for i, arg in enumerate(args):
|
79
|
+
if isinstance(arg, (list, tuple)):
|
80
|
+
if all([isinstance(e, int) for e in arg]):
|
81
|
+
# default to int64 which is default on linux but not windows
|
82
|
+
args[i] = np.array(arg, dtype=np.int64)
|
83
|
+
else:
|
84
|
+
args[i] = np.array(arg)
|
85
|
+
if isinstance(args[i], np.ndarray):
|
86
|
+
|
87
|
+
if self.fortran:
|
88
|
+
if not args[i].flags.f_contiguous:
|
89
|
+
sys.stderr.write(f'argument {i} for {f.__name__} not f_contiguous\n')
|
90
|
+
else:
|
91
|
+
if not args[i].flags.c_contiguous:
|
92
|
+
sys.stderr.write(f'argument {i} for {f.__name__} not c_contiguous\n')
|
93
|
+
|
94
|
+
args[i] = np.require(args[i], requirements=['C', 'F'][self.fortran])
|
95
|
+
|
96
|
+
for arg in args:
|
97
|
+
if isinstance(arg, int):
|
98
|
+
c_args.append(c_long_p(c_longlong(arg)))
|
99
|
+
elif isinstance(arg, float):
|
100
|
+
c_args.append(c_double_p(c_double(arg)))
|
101
|
+
elif isinstance(arg, str):
|
102
|
+
c_args.append(c_char_p(arg.encode('cp1252')))
|
103
|
+
# c_args.append(c_int_p(c_int(len(arg))))
|
104
|
+
|
105
|
+
elif isinstance(arg, np.ndarray):
|
106
|
+
if arg.dtype in [np.int32]:
|
107
|
+
c_args.append(arg.ctypes.data_as(c_int_p))
|
108
|
+
elif arg.dtype in [np.int64]:
|
109
|
+
c_args.append(arg.ctypes.data_as(c_long_p))
|
110
|
+
elif arg.dtype == np.float64:
|
111
|
+
c_args.append(arg.ctypes.data_as(c_double_p))
|
112
|
+
elif arg.dtype == np.float32:
|
113
|
+
c_args.append(arg.ctypes.data_as(c_float_p))
|
114
|
+
else:
|
115
|
+
raise NotImplementedError(arg.dtype)
|
116
|
+
|
117
|
+
else:
|
118
|
+
# raise NotImplementedError(arg.__class__.__name__)
|
119
|
+
c_args.append(arg)
|
120
|
+
if 'restype' in kwargs:
|
121
|
+
restype = kwargs['restype']
|
122
|
+
if hasattr(restype, 'dtype'):
|
123
|
+
restype = np.ctypeslib.as_ctypes_type(restype)
|
124
|
+
f.restype = restype
|
125
|
+
with chdir(self.cwd):
|
126
|
+
if self.suppress_output:
|
127
|
+
with SuppressStream(sys.stdout), SuppressStream(sys.stderr):
|
128
|
+
res = f(*c_args)
|
129
|
+
else:
|
130
|
+
res = f(*c_args)
|
131
|
+
ret_args = []
|
132
|
+
for arg in args:
|
133
|
+
c_arg = c_args.pop(0)
|
134
|
+
if isinstance(arg, (int, float)):
|
135
|
+
ret_args.append(c_arg.contents.value)
|
136
|
+
elif isinstance(arg, (str)):
|
137
|
+
ret_args.append(c_arg.value.decode('cp1252'))
|
138
|
+
# c_args.pop(0)
|
139
|
+
elif isinstance(arg, np.ndarray):
|
140
|
+
ret_args.append(arg)
|
141
|
+
else:
|
142
|
+
raise NotImplementedError(arg.__class__.__name__)
|
143
|
+
return ret_args, res
|
144
|
+
|
145
|
+
|
146
|
+
class DLLWrapper(object):
|
147
|
+
def __init__(self, filename, cwd='.', cdecl=True, fortran=True):
|
148
|
+
self.filename = str(filename)
|
149
|
+
if os.path.abspath(self.filename) in in_use:
|
150
|
+
raise Exception(f'{os.path.abspath(self.filename)} already in use in current process.')
|
151
|
+
self.cwd = cwd
|
152
|
+
self.cdecl = cdecl
|
153
|
+
self.fortran = fortran
|
154
|
+
self.suppress_output = False
|
155
|
+
self.open()
|
156
|
+
in_use.append(os.path.abspath(self.filename))
|
157
|
+
atexit.register(self.close)
|
158
|
+
|
159
|
+
@staticmethod
|
160
|
+
def find_dll(path, name):
|
161
|
+
p = Path(path)
|
162
|
+
|
163
|
+
# if sys.platform == "win32":
|
164
|
+
# prefixes = ['']
|
165
|
+
# if sys.maxsize > 2**32:
|
166
|
+
# suffixes = ['.dll', '_64.dll']
|
167
|
+
# else:
|
168
|
+
# suffixes = ['.dll']
|
169
|
+
# elif sys.platform == 'linux':
|
170
|
+
# prefixes = ['lib','']
|
171
|
+
# suffixes = ['.so']
|
172
|
+
# else:
|
173
|
+
# raise NotImplementedError()
|
174
|
+
|
175
|
+
dll_lst = []
|
176
|
+
file_patterns = ['*%s*.dll' % name, '*%s*.so' % name]
|
177
|
+
for fp in file_patterns:
|
178
|
+
dll_lst.extend(list(p.glob("**/" + fp)))
|
179
|
+
|
180
|
+
def use_first(dll_lst):
|
181
|
+
f = str(dll_lst[0])
|
182
|
+
print("Using ", os.path.abspath(f))
|
183
|
+
return DLLWrapper(f)
|
184
|
+
|
185
|
+
if len(dll_lst) == 1:
|
186
|
+
return use_first(dll_lst)
|
187
|
+
elif len(dll_lst) > 1:
|
188
|
+
# check if excluding dlls in hawc2-binary, i.e. "hawc2-<platform>" results in one dll
|
189
|
+
dll_lst2 = [d for d in dll_lst if not str(d).startswith('hawc2-')]
|
190
|
+
if len(dll_lst2) == 1:
|
191
|
+
return use_first(dll_lst2)
|
192
|
+
raise FileExistsError("Multiple dlls found:\n" + "\n".join([str(p) for p in dll_lst]))
|
193
|
+
else:
|
194
|
+
raise FileNotFoundError("No " + " or ".join(file_patterns) +
|
195
|
+
" files found in " + os.path.abspath(p.absolute()))
|
196
|
+
|
197
|
+
def open(self):
|
198
|
+
assert os.path.isfile(self.filename), os.path.abspath(self.filename)
|
199
|
+
if self.cdecl:
|
200
|
+
try:
|
201
|
+
# python < (3, 8) and > 3.10?:
|
202
|
+
self.lib = ct.CDLL(self.filename)
|
203
|
+
except BaseException:
|
204
|
+
self.lib = ct.CDLL(self.filename, winmode=ctypes.DEFAULT_MODE)
|
205
|
+
else:
|
206
|
+
self.lib = windll.LoadLibrary(self.filename)
|
207
|
+
|
208
|
+
def close(self):
|
209
|
+
if "FreeLibrary" in dir(_ctypes):
|
210
|
+
_ctypes.FreeLibrary(self.lib._handle)
|
211
|
+
else:
|
212
|
+
_ctypes.dlclose(self.lib._handle)
|
213
|
+
del self.lib
|
214
|
+
atexit.unregister(self.close)
|
215
|
+
in_use.remove(os.path.abspath(self.filename))
|
216
|
+
|
217
|
+
# def __enter__(self):
|
218
|
+
# self.open()
|
219
|
+
# return self
|
220
|
+
#
|
221
|
+
# def __exit__(self, type, value, traceback):
|
222
|
+
# self.close()
|
223
|
+
# return False
|
224
|
+
|
225
|
+
def __getattr__(self, name):
|
226
|
+
if name == 'lib':
|
227
|
+
raise Exception("DLL not loaded. Run using: 'with dll: ...'")
|
228
|
+
return self.get_lib_function(name)
|
229
|
+
|
230
|
+
def get_lib_function(self, name):
|
231
|
+
try:
|
232
|
+
f = getattr(self.lib, name)
|
233
|
+
except AttributeError as e:
|
234
|
+
raise AttributeError("Attribute '%s' not found in dll ('%s')" % (name, self.filename))
|
235
|
+
return lambda *args, **kwargs: wrap(self, f, *args, **kwargs)
|
236
|
+
|
237
|
+
def version(self, function_name='get_version'):
|
238
|
+
try:
|
239
|
+
f = getattr(self.lib, function_name)
|
240
|
+
f.argtypes = [c_char_p, c_long]
|
241
|
+
s = "".ljust(255)
|
242
|
+
arg = c_char_p(s.encode('utf-8'))
|
243
|
+
f(arg, len(s))
|
244
|
+
return arg.value.decode().strip()
|
245
|
+
except AttributeError:
|
246
|
+
if function_name == 'get_version':
|
247
|
+
return self.version('version')
|
248
|
+
|
249
|
+
def getFileProperties(self):
|
250
|
+
if sys.platform != "win32":
|
251
|
+
raise OSError("Only supported for Windows")
|
252
|
+
import win32api
|
253
|
+
fname = self.filename
|
254
|
+
|
255
|
+
# ==============================================================================
|
256
|
+
"""
|
257
|
+
Read all properties of the given file return them as a dictionary.
|
258
|
+
"""
|
259
|
+
propNames = ('Comments', 'InternalName', 'ProductName',
|
260
|
+
'CompanyName', 'LegalCopyright', 'ProductVersion',
|
261
|
+
'FileDescription', 'LegalTrademarks', 'PrivateBuild',
|
262
|
+
'FileVersion', 'OriginalFilename', 'SpecialBuild')
|
263
|
+
|
264
|
+
props = {'FixedFileInfo': None, 'StringFileInfo': None, 'FileVersion': None}
|
265
|
+
|
266
|
+
try:
|
267
|
+
# backslash as parm returns dictionary of numeric info corresponding to VS_FIXEDFILEINFO struc
|
268
|
+
fixedInfo = win32api.GetFileVersionInfo(fname, '\\')
|
269
|
+
props['FixedFileInfo'] = fixedInfo
|
270
|
+
props['FileVersion'] = "%d.%d.%d.%d" % (fixedInfo['FileVersionMS'] / 65536,
|
271
|
+
fixedInfo['FileVersionMS'] % 65536, fixedInfo['FileVersionLS'] / 65536,
|
272
|
+
fixedInfo['FileVersionLS'] % 65536)
|
273
|
+
|
274
|
+
# \VarFileInfo\Translation returns list of available (language, codepage)
|
275
|
+
# pairs that can be used to retreive string info. We are using only the first pair.
|
276
|
+
lang, codepage = win32api.GetFileVersionInfo(fname, '\\VarFileInfo\\Translation')[0]
|
277
|
+
|
278
|
+
# any other must be of the form \StringfileInfo\%04X%04X\parm_name, middle
|
279
|
+
# two are language/codepage pair returned from above
|
280
|
+
|
281
|
+
strInfo = {}
|
282
|
+
for propName in propNames:
|
283
|
+
strInfoPath = u'\\StringFileInfo\\%04X%04X\\%s' % (lang, codepage, propName)
|
284
|
+
# print str_info
|
285
|
+
strInfo[propName] = win32api.GetFileVersionInfo(fname, strInfoPath)
|
286
|
+
|
287
|
+
props['StringFileInfo'] = strInfo
|
288
|
+
except BaseException:
|
289
|
+
pass
|
290
|
+
|
291
|
+
return props
|
292
|
+
|
293
|
+
|
294
|
+
class Type2DllWrapper(DLLWrapper):
|
295
|
+
def __init__(self, filename, dll_subroutine_init, dll_subroutine_update,
|
296
|
+
arraysizes_init, arraysizes_update,
|
297
|
+
init_array):
|
298
|
+
super().__init__(filename)
|
299
|
+
self.dll_subroutine_init = dll_subroutine_init
|
300
|
+
self.dll_subroutine_update = dll_subroutine_update
|
301
|
+
self.arraysizes_init = arraysizes_init
|
302
|
+
self.arraysizes_update = arraysizes_update
|
303
|
+
self.init_array = init_array
|
304
|
+
|
305
|
+
def open(self):
|
306
|
+
DLLWrapper.open(self)
|
307
|
+
self.init()
|
308
|
+
|
309
|
+
def call(self, name, array, n1, n2):
|
310
|
+
f = getattr(self.lib, name)
|
311
|
+
f.argtypes = [ndpointer(shape=n1, dtype=ct.c_double, flags='FORTRAN'),
|
312
|
+
ndpointer(shape=n2, dtype=ct.c_double, flags='FORTRAN')]
|
313
|
+
f.restype = None
|
314
|
+
|
315
|
+
pad_array = np.zeros(n1)
|
316
|
+
pad_array[:len(array)] = array
|
317
|
+
arg1 = np.array(pad_array, dtype=ct.c_double, order='F')
|
318
|
+
arg2 = np.zeros(n2, dtype=ct.c_double, order='F')
|
319
|
+
|
320
|
+
f(arg1, arg2)
|
321
|
+
return arg2
|
322
|
+
|
323
|
+
def init(self):
|
324
|
+
n1, n2 = self.arraysizes_init
|
325
|
+
return self.call(self.dll_subroutine_init, self.init_array, n1, n2)
|
326
|
+
|
327
|
+
def update(self, array):
|
328
|
+
n1, n2 = self.arraysizes_update
|
329
|
+
return self.call(self.dll_subroutine_update, array, n1, n2)
|
@@ -0,0 +1,324 @@
|
|
1
|
+
# noqa
|
2
|
+
|
3
|
+
from h2lib.dll_wrapper import DLLWrapper
|
4
|
+
|
5
|
+
|
6
|
+
class H2LibSignatures():
|
7
|
+
def add_sensor(self, sensor_line, index_start, index_stop):
|
8
|
+
'''subroutine add_sensor(sensor_line, index_start, index_stop) bind(C, name="add_sensor")
|
9
|
+
integer*8 :: index_start, index_stop, i
|
10
|
+
character(kind=c_char, len=1), intent(in) :: sensor_line(1024)
|
11
|
+
end subroutine'''
|
12
|
+
return self.get_lib_function('add_sensor')(sensor_line, index_start, index_stop)
|
13
|
+
|
14
|
+
def echo_version(self, ):
|
15
|
+
'''subroutine echo_version() BIND(C, NAME='echo_version')
|
16
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: echo_version
|
17
|
+
!GCC$ ATTRIBUTES DLLEXPORT :: echo_version
|
18
|
+
type (tbuildinfo) :: b
|
19
|
+
end subroutine'''
|
20
|
+
return self.get_lib_function('echo_version')()
|
21
|
+
|
22
|
+
def extern_write_log(self, c_msg, n, dll_name, error, warning):
|
23
|
+
'''subroutine extern_write_log(c_msg, n, dll_name, error, warning) bind(C, name="extern_write_log")
|
24
|
+
integer, intent(in) :: n
|
25
|
+
character(kind=c_char, len=1), intent(in) :: c_msg(n)
|
26
|
+
character(kind=c_char), intent(in) :: dll_name(50)
|
27
|
+
logical(kind=c_bool), intent(in), optional :: error, warning
|
28
|
+
character(kind=c_char, len=1), intent(in) :: c_msg(n_msg)
|
29
|
+
integer, intent(in) :: n_msg
|
30
|
+
character(kind=c_char), intent(in) :: dll_name(50)
|
31
|
+
character(len=50) :: n
|
32
|
+
logical(kind=c_bool), intent(in), optional :: error, warning
|
33
|
+
end subroutine'''
|
34
|
+
return self.get_lib_function('extern_write_log')(c_msg, n, dll_name, error, warning)
|
35
|
+
|
36
|
+
def fail(self, str_arr): # pragma: no cover
|
37
|
+
'''subroutine fail(str_arr) bind(C, name='fail')
|
38
|
+
character(kind=c_char, len=1), intent(inout) :: str_arr(255)
|
39
|
+
end subroutine'''
|
40
|
+
return self.get_lib_function('fail')(str_arr)
|
41
|
+
|
42
|
+
def finalize(self, ):
|
43
|
+
'''SUBROUTINE finalize() bind(C, name="finalize")
|
44
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: finalize
|
45
|
+
integer:: i
|
46
|
+
real*4:: T2
|
47
|
+
END SUBROUTINE'''
|
48
|
+
return self.get_lib_function('finalize')()
|
49
|
+
|
50
|
+
def getSquare(self, val, restype):
|
51
|
+
'''function getSquare(val) result(valSquared) BIND(C, NAME='getSquare')
|
52
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: getSquare
|
53
|
+
real(RK), intent(in) :: val
|
54
|
+
real(RK) :: valSquared
|
55
|
+
end function'''
|
56
|
+
return self.get_lib_function('getSquare')(val, restype=restype)
|
57
|
+
|
58
|
+
def getState(self, restype):
|
59
|
+
'''function getState() result(val) BIND(C, NAME='getState')
|
60
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: getState
|
61
|
+
integer :: val
|
62
|
+
end function'''
|
63
|
+
return self.get_lib_function('getState')(restype=restype)
|
64
|
+
|
65
|
+
def get_aerosections_forces(self, rotor, Fxyz):
|
66
|
+
'''subroutine get_aerosections_forces(rotor, Fxyz) bind(C, name='get_aerosections_forces')
|
67
|
+
integer*8, intent(in) :: rotor
|
68
|
+
real(c_double),intent(out)::Fxyz(rotors_gl%rotor(rotor)%nbld, rotors_gl%rotor(rotor)%blade(1)%nsec, 3)
|
69
|
+
end subroutine'''
|
70
|
+
return self.get_lib_function('get_aerosections_forces')(rotor, Fxyz)
|
71
|
+
|
72
|
+
def get_aerosections_moments(self, rotor, Mxyz):
|
73
|
+
'''subroutine get_aerosections_moments(rotor, Mxyz) bind(C, name='get_aerosections_moments')
|
74
|
+
integer*8, intent(in) :: rotor
|
75
|
+
real(c_double),intent(out):: Mxyz(rotors_gl%rotor(rotor)%nbld, rotors_gl%rotor(rotor)%blade(1)%nsec, 3)
|
76
|
+
end subroutine'''
|
77
|
+
return self.get_lib_function('get_aerosections_moments')(rotor, Mxyz)
|
78
|
+
|
79
|
+
def get_aerosections_position(self, rotor, position):
|
80
|
+
'''subroutine get_aerosections_position(rotor, position) bind(C, name="get_aerosections_position")
|
81
|
+
integer*8, intent(in) :: rotor
|
82
|
+
real(c_double),intent(out) :: position(rotors_gl%rotor(rotor)%nbld, rotors_gl%rotor(rotor)%blade(1)%nsec, 3)
|
83
|
+
end subroutine'''
|
84
|
+
return self.get_lib_function('get_aerosections_position')(rotor, position)
|
85
|
+
|
86
|
+
def get_bem_grid(self, rotor, azi, rad):
|
87
|
+
'''subroutine get_bem_grid(rotor, azi, rad) bind(C, name="get_bem_grid")
|
88
|
+
integer*8, intent(in) :: rotor
|
89
|
+
real(c_double), intent(out) :: azi(rotors_gl%rotor(rotor)%dyn_induc%bem%nazi)
|
90
|
+
real(c_double), intent(out) :: rad(rotors_gl%rotor(rotor)%dyn_induc%bem%nrad)
|
91
|
+
end subroutine'''
|
92
|
+
return self.get_lib_function('get_bem_grid')(rotor, azi, rad)
|
93
|
+
|
94
|
+
def get_bem_grid_dim(self, rotor, nazi, nrad):
|
95
|
+
'''subroutine get_bem_grid_dim(rotor, nazi, nrad) bind(C, name="get_bem_grid_dim")
|
96
|
+
integer*8, intent(in) :: rotor
|
97
|
+
integer*8, intent(out) :: nazi, nrad
|
98
|
+
end subroutine'''
|
99
|
+
return self.get_lib_function('get_bem_grid_dim')(rotor, nazi, nrad)
|
100
|
+
|
101
|
+
def get_diameter(self, rotor, restype):
|
102
|
+
'''function get_diameter(rotor) bind(C, name="get_diameter")
|
103
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: get_diameter
|
104
|
+
integer*8, intent(in) :: rotor
|
105
|
+
Type (Taerorotor),pointer :: rotor_p
|
106
|
+
real(c_double) :: get_diameter
|
107
|
+
end function'''
|
108
|
+
return self.get_lib_function('get_diameter')(rotor, restype=restype)
|
109
|
+
|
110
|
+
def get_induction_axisymmetric(self, rotor, induction):
|
111
|
+
'''subroutine get_induction_axisymmetric(rotor, induction) bind(C, name="get_induction_axisymmetric")
|
112
|
+
integer*8, intent(in) :: rotor
|
113
|
+
real(c_double),intent(out) :: induction(rotors_gl%rotor(rotor)%dyn_induc%bem%nrad)
|
114
|
+
end subroutine'''
|
115
|
+
return self.get_lib_function('get_induction_axisymmetric')(rotor, induction)
|
116
|
+
|
117
|
+
def get_induction_polargrid(self, rotor, induction):
|
118
|
+
'''subroutine get_induction_polargrid(rotor, induction) bind(C, name="get_induction_polargrid")
|
119
|
+
integer*8, intent(in) :: rotor
|
120
|
+
real(c_double),intent(out) :: induction(rotors_gl%rotor(rotor)%dyn_induc%bem%nazi, rotors_gl%rotor(rotor)%dyn_induc%bem%nrad)
|
121
|
+
end subroutine'''
|
122
|
+
return self.get_lib_function('get_induction_polargrid')(rotor, induction)
|
123
|
+
|
124
|
+
def get_induction_rotoravg(self, rotor, induction):
|
125
|
+
'''subroutine get_induction_rotoravg(rotor, induction) bind(C, name="get_induction_rotoravg")
|
126
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: get_induction_rotoravg
|
127
|
+
integer*8, intent(in) :: rotor
|
128
|
+
real(c_double), intent(out) :: induction
|
129
|
+
end subroutine'''
|
130
|
+
return self.get_lib_function('get_induction_rotoravg')(rotor, induction)
|
131
|
+
|
132
|
+
def get_nSections(self, rotor, blade, restype):
|
133
|
+
'''function get_nSections(rotor, blade) bind(C, name="get_nSections")
|
134
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: get_nSections
|
135
|
+
integer*8, intent(in) :: rotor, blade
|
136
|
+
integer*8 :: get_nSections
|
137
|
+
end function'''
|
138
|
+
return self.get_lib_function('get_nSections')(rotor, blade, restype=restype)
|
139
|
+
|
140
|
+
def get_nblades(self, rotor, restype):
|
141
|
+
'''function get_nblades(rotor) bind(C, name="get_nblades")
|
142
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: get_nblades
|
143
|
+
integer*8, intent(in) :: rotor
|
144
|
+
integer*8 :: get_nblades
|
145
|
+
end function'''
|
146
|
+
return self.get_lib_function('get_nblades')(rotor, restype=restype)
|
147
|
+
|
148
|
+
def get_nrotors(self, restype):
|
149
|
+
'''function get_nrotors() bind(C, name="get_nrotors")
|
150
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: get_nrotors
|
151
|
+
integer*8 :: get_nrotors
|
152
|
+
end function'''
|
153
|
+
return self.get_lib_function('get_nrotors')(restype=restype)
|
154
|
+
|
155
|
+
def get_rotor_avg_wsp(self, coo, rotor, wsp):
|
156
|
+
'''subroutine get_rotor_avg_wsp(coo, rotor, wsp) bind(C, name="get_rotor_avg_wsp")
|
157
|
+
integer*8, intent(in) :: rotor
|
158
|
+
integer*8, intent(in) :: coo ! 1: global, 2: rotor
|
159
|
+
real(c_double), dimension(3):: wsp
|
160
|
+
end subroutine'''
|
161
|
+
return self.get_lib_function('get_rotor_avg_wsp')(coo, rotor, wsp)
|
162
|
+
|
163
|
+
def get_rotor_orientation(self, rotor, yaw, tilt, azi):
|
164
|
+
'''subroutine get_rotor_orientation(rotor, yaw, tilt, azi) bind(C, name="get_rotor_orientation")
|
165
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: get_rotor_orientation
|
166
|
+
integer*8, intent(in) :: rotor
|
167
|
+
real(c_double), intent(out) :: yaw, tilt, azi
|
168
|
+
end subroutine'''
|
169
|
+
return self.get_lib_function('get_rotor_orientation')(rotor, yaw, tilt, azi)
|
170
|
+
|
171
|
+
def get_rotor_position(self, rotor, position):
|
172
|
+
'''subroutine get_rotor_position(rotor, position) bind(C, name="get_rotor_position")
|
173
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: get_rotor_position
|
174
|
+
integer*8, intent(in) :: rotor
|
175
|
+
real(c_double), dimension(3), intent(out) :: position
|
176
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: get_rotor_avg_wsp
|
177
|
+
integer*8, intent(in) :: rotor
|
178
|
+
integer*8, intent(in) :: coo ! 1: global, 2: rotor
|
179
|
+
end subroutine'''
|
180
|
+
return self.get_lib_function('get_rotor_position')(rotor, position)
|
181
|
+
|
182
|
+
def get_sensor_info(self, id, name, unit, desc):
|
183
|
+
'''subroutine get_sensor_info(id, name, unit, desc) bind(C, name="get_sensor_info")
|
184
|
+
integer*8, intent(in) :: id
|
185
|
+
character(kind=c_char, len=1), intent(out) :: name(30), unit(10), desc(512)
|
186
|
+
end subroutine'''
|
187
|
+
return self.get_lib_function('get_sensor_info')(id, name, unit, desc)
|
188
|
+
|
189
|
+
def get_sensor_values(self, ids, values, n):
|
190
|
+
'''subroutine get_sensor_values(ids, values, n) bind(C, name="get_sensor_values")
|
191
|
+
integer*8, intent(in) :: n
|
192
|
+
integer*8, intent(in) :: ids(n)
|
193
|
+
real(c_double), intent(out) :: values(n)
|
194
|
+
end subroutine'''
|
195
|
+
return self.get_lib_function('get_sensor_values')(ids, values, n)
|
196
|
+
|
197
|
+
def get_time(self, time):
|
198
|
+
'''subroutine
|
199
|
+
subroutine'''
|
200
|
+
return self.get_lib_function('get_time')(time)
|
201
|
+
|
202
|
+
def get_version(self, s):
|
203
|
+
'''subroutine get_version(s) BIND(C, NAME='get_version')
|
204
|
+
character(kind=c_char, len=1), intent(inout) :: s(255)
|
205
|
+
end subroutine'''
|
206
|
+
return self.get_lib_function('get_version')(s)
|
207
|
+
|
208
|
+
def init(self, ):
|
209
|
+
'''subroutine init() bind(C, name="init")
|
210
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: init
|
211
|
+
end subroutine'''
|
212
|
+
return self.get_lib_function('init')()
|
213
|
+
|
214
|
+
def init_windfield(self, Nxyz, dxyz, box_offset_yz, transport_speed):
|
215
|
+
'''subroutine init_windfield(Nxyz, dxyz, box_offset_yz, transport_speed) bind(C, name="init_windfield")
|
216
|
+
integer*8, dimension(3), intent(in) :: Nxyz
|
217
|
+
real*8 :: transport_speed
|
218
|
+
end subroutine'''
|
219
|
+
return self.get_lib_function('init_windfield')(Nxyz, dxyz, box_offset_yz, transport_speed)
|
220
|
+
|
221
|
+
def loop(self, N, restype):
|
222
|
+
'''function loop(N) bind(C, Name='loop')
|
223
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: loop
|
224
|
+
integer*8, intent(in) :: N
|
225
|
+
real(c_double) :: loop,a
|
226
|
+
integer*8 :: i, j
|
227
|
+
end function'''
|
228
|
+
return self.get_lib_function('loop')(N, restype=restype)
|
229
|
+
|
230
|
+
def myfunction(self, int, dbl, restype):
|
231
|
+
'''function myfunction(int, dbl) bind(C, name='myfunction')
|
232
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: myfunction
|
233
|
+
integer*8, intent(in) :: int
|
234
|
+
real(c_double), intent(in) :: dbl
|
235
|
+
real(c_double) :: myfunction
|
236
|
+
end function'''
|
237
|
+
return self.get_lib_function('myfunction')(int, dbl, restype=restype)
|
238
|
+
|
239
|
+
def mysubroutine(self, str_arr, dbl_arr):
|
240
|
+
'''subroutine mysubroutine(str_arr, dbl_arr) bind(C, name='mysubroutine')
|
241
|
+
character(kind=c_char, len=1), intent(inout) :: str_arr(20)
|
242
|
+
real(c_double), intent(inout), dimension(2) :: dbl_arr
|
243
|
+
end subroutine'''
|
244
|
+
return self.get_lib_function('mysubroutine')(str_arr, dbl_arr)
|
245
|
+
|
246
|
+
def read_input(self, htc_path):
|
247
|
+
'''subroutine read_input(htc_path) bind(C, name="read_input")
|
248
|
+
character(kind=c_char, len=1), intent(in) :: htc_path(1024)
|
249
|
+
end subroutine'''
|
250
|
+
return self.get_lib_function('read_input')(htc_path)
|
251
|
+
|
252
|
+
def run(self, time, restype):
|
253
|
+
'''function run(time) bind(C, name='run')
|
254
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: run
|
255
|
+
real(c_double), intent(in) :: time
|
256
|
+
real(c_double) :: run, eps
|
257
|
+
end function'''
|
258
|
+
return self.get_lib_function('run')(time, restype=restype)
|
259
|
+
|
260
|
+
def setState(self, val):
|
261
|
+
'''subroutine setState(val) BIND(C, NAME='setState')
|
262
|
+
integer, intent(in) :: val
|
263
|
+
end subroutine'''
|
264
|
+
return self.get_lib_function('setState')(val)
|
265
|
+
|
266
|
+
def set_aerosections_windspeed(self, rotor, uvw):
|
267
|
+
'''subroutine set_aerosections_windspeed(rotor, uvw) bind(C, name="set_aerosections_windspeed")
|
268
|
+
integer*8, intent(in) :: rotor
|
269
|
+
real(c_double),intent(in) :: uvw(rotors_gl%rotor(rotor)%nbld, rotors_gl%rotor(rotor)%blade(1)%nsec, 3)
|
270
|
+
end subroutine'''
|
271
|
+
return self.get_lib_function('set_aerosections_windspeed')(rotor, uvw)
|
272
|
+
|
273
|
+
def set_variable_sensor_value(self, id, value):
|
274
|
+
'''subroutine set_variable_sensor_value(id, value) bind(C, name="set_variable_sensor_value")
|
275
|
+
integer*8, intent(in) :: id
|
276
|
+
real(c_double) :: value
|
277
|
+
end subroutine'''
|
278
|
+
return self.get_lib_function('set_variable_sensor_value')(id, value)
|
279
|
+
|
280
|
+
def set_windfield(self, uvw, box_offset_x, time):
|
281
|
+
'''subroutine set_windfield(uvw, box_offset_x, time) bind(C, name="set_windfield")
|
282
|
+
real*4, intent(in) :: uvw(3, gwsd%TMOD%buffer_points_x,gwsd%TMOD%buffer_points_y,gwsd%TMOD%buffer_points_z)
|
283
|
+
real*8, intent(in):: box_offset_x, time
|
284
|
+
end subroutine'''
|
285
|
+
return self.get_lib_function('set_windfield')(uvw, box_offset_x, time)
|
286
|
+
|
287
|
+
def sqr2(self, val):
|
288
|
+
'''subroutine sqr2(val) BIND(C, NAME='sqr2')
|
289
|
+
integer, intent(inout) :: val
|
290
|
+
end subroutine'''
|
291
|
+
return self.get_lib_function('sqr2')(val)
|
292
|
+
|
293
|
+
def step(self, restype):
|
294
|
+
'''function step() bind(C, name='step')
|
295
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: step
|
296
|
+
real(c_double) :: step
|
297
|
+
end function'''
|
298
|
+
return self.get_lib_function('step')(restype=restype)
|
299
|
+
|
300
|
+
def test_hdf5(self, ):
|
301
|
+
'''subroutine test_hdf5() BIND(C, NAME='test_hdf5')
|
302
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: test_hdf5
|
303
|
+
INTEGER :: hdferr ! Error flag
|
304
|
+
CHARACTER(9) :: filename = 'test.hdf5'
|
305
|
+
INTEGER(HID_T) :: file_id ! File identifier
|
306
|
+
INTEGER(HID_T) :: H5_Create_file,H5_Open_file ! File identifier
|
307
|
+
type(c_ptr) :: x
|
308
|
+
end subroutine'''
|
309
|
+
return self.get_lib_function('test_hdf5')()
|
310
|
+
|
311
|
+
def work(self, time, restype):
|
312
|
+
'''function work(time) bind(C, Name='work')
|
313
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: work
|
314
|
+
real(c_double), intent(in) :: time
|
315
|
+
real*4 :: start_time, t
|
316
|
+
integer*8 :: N, work
|
317
|
+
end function'''
|
318
|
+
return self.get_lib_function('work')(time, restype=restype)
|
319
|
+
|
320
|
+
def write_output(self, ):
|
321
|
+
'''subroutine write_output() bind(C, name="write_output")
|
322
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: write_output
|
323
|
+
end subroutine'''
|
324
|
+
return self.get_lib_function('write_output')()
|
@@ -0,0 +1,21 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: h2lib
|
3
|
+
Version: 13.1.301
|
4
|
+
Summary: Python interface to HAWC2 (13.1.3)
|
5
|
+
Download-URL:
|
6
|
+
Author: Mads M. Pedersen, S.G.Horcas and N.G.Ramos
|
7
|
+
Author-email: mmpe@dtu.dk
|
8
|
+
Maintainer:
|
9
|
+
Maintainer-email:
|
10
|
+
Project-URL: Documentation, https://hawc2.pages.windenergy.dtu.dk/HAWC2Lib/
|
11
|
+
Project-URL: Source, https://gitlab.windenergy.dtu.dk/HAWC2/HAWC2Lib
|
12
|
+
Project-URL: Tracker, https://gitlab.windenergy.dtu.dk/HAWC2/HAWC2Lib/-/issues
|
13
|
+
Requires-Dist: numpy
|
14
|
+
Requires-Dist: intel-fortran-rt ==2021.3.0
|
15
|
+
Requires-Dist: mkl ==2021.3.0
|
16
|
+
Requires-Dist: multiclass-interface >=1.5
|
17
|
+
Provides-Extra: mpi
|
18
|
+
Requires-Dist: mpi4py ; extra == 'mpi'
|
19
|
+
Provides-Extra: test
|
20
|
+
Requires-Dist: h2lib-tests ; extra == 'test'
|
21
|
+
|
@@ -0,0 +1,10 @@
|
|
1
|
+
h2lib/HAWC2Lib.so,sha256=lTo-MTGmuWWut6obARXJbwm0aUaRRavZ66_H-otJ4Fw,37990888
|
2
|
+
h2lib/__init__.py,sha256=YyJWPF22nu9ZoxkrE3ghngT9n_hl-HiAEflnZ_Ay8Q4,513
|
3
|
+
h2lib/_h2lib.py,sha256=J9eWeJTaHUEmwF5St6ce4YWquteEXNQiUWOs9hb_tII,14643
|
4
|
+
h2lib/_version.py,sha256=dpn5IZTgXLYpPqs-tx0TObc9Xbe3GmH3UCI4D3FFX68,142
|
5
|
+
h2lib/dll_wrapper.py,sha256=PxyK19SV-dO_-Fl8T6dnvKKxLFbDBzkUT1_igh38K4I,11593
|
6
|
+
h2lib/h2lib_signatures.py,sha256=wxIHaQ9adni1Vm5oOgXlsh1ULnGUPi6-GLnWtQ6gty4,14408
|
7
|
+
h2lib-13.1.301.dist-info/METADATA,sha256=X-AP77gfxWZD7SGOa7L47_c8zpFB7M1lDTjLSRf01r4,706
|
8
|
+
h2lib-13.1.301.dist-info/WHEEL,sha256=nLg6JJzHN_0h05ClOJeXqTjuASxRDcfhtJhPJzBnKyI,151
|
9
|
+
h2lib-13.1.301.dist-info/top_level.txt,sha256=y_a-tUqphEZQ_0nsWSMaSb21P8Lsd8hUxUdE9g2Dcbk,6
|
10
|
+
h2lib-13.1.301.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
h2lib
|