h2lib 13.1.502__py3-none-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 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,534 @@
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
+ uvw = np.asarray(uvw, dtype=np.float32)
213
+ assert np.all(np.isfinite(uvw)), "uvw passed to h2lib.set_windfield contains nan or inf"
214
+ return H2LibSignatures.set_windfield(self, np.asarray(uvw, dtype=np.float32),
215
+ np.float64(box_offset_x), np.float64(time))
216
+
217
+ # ===================================================================================================================
218
+ # H2rotor
219
+ # ===================================================================================================================
220
+
221
+ def get_rotor_dims(self):
222
+ return [[self.get_nSections(r, b) for b in range(self.get_nblades(r))]
223
+ for r in range(self.get_nrotors())]
224
+
225
+ def get_nrotors(self):
226
+ return H2LibSignatures.get_nrotors(self, restype=np.int64)[1]
227
+
228
+ def get_nblades(self, rotor=0):
229
+ return H2LibSignatures.get_nblades(self, rotor + 1, restype=np.int64)[1]
230
+
231
+ def get_nSections(self, rotor=0, blade=0):
232
+ return H2LibSignatures.get_nSections(self, rotor + 1, blade + 1, restype=np.int64)[1]
233
+
234
+ def get_diameter(self, rotor=0):
235
+ return H2LibSignatures.get_diameter(self, rotor + 1, restype=np.float64)[1]
236
+
237
+ def aero_sections_data_shape(self, rotor):
238
+ if rotor not in self._aero_sections_data_shape:
239
+ self._aero_sections_data_shape[rotor] = (self.get_nblades(rotor), self.get_nSections(rotor), 3)
240
+ return self._aero_sections_data_shape[rotor]
241
+
242
+ def get_aerosections_position(self, rotor=0):
243
+ position = np.zeros(self.aero_sections_data_shape(rotor), dtype=np.float64, order='F')
244
+ return H2LibSignatures.get_aerosections_position(self, rotor + 1, position)[0][1]
245
+
246
+ def set_aerosections_windspeed(self, uvw, rotor=0):
247
+ return H2LibSignatures.set_aerosections_windspeed(self, rotor + 1, np.asarray(uvw, np.float64))
248
+
249
+ def get_aerosections_forces(self, rotor=0):
250
+ shape = self.aero_sections_data_shape(rotor)
251
+ Fxyz = np.zeros(shape, dtype=np.float64, order='F')
252
+ return H2LibSignatures.get_aerosections_forces(self, rotor + 1, Fxyz)[0][1]
253
+
254
+ def get_aerosections_moments(self, rotor=0):
255
+ shape = self.aero_sections_data_shape(rotor)
256
+ Mxyz = np.zeros(shape, dtype=np.float64, order='F')
257
+ return H2LibSignatures.get_aerosections_moments(self, rotor + 1, Mxyz)[0][1]
258
+
259
+ def get_bem_grid_dim(self, rotor=0):
260
+ """returns (nazi, nrad)"""
261
+ return H2LibSignatures.get_bem_grid_dim(self, rotor + 1, 0, 0)[0][1:]
262
+
263
+ def get_bem_grid(self, rotor=0):
264
+ """returns azi, rad"""
265
+ nazi, nrad = self.get_bem_grid_dim(rotor)
266
+ return H2LibSignatures.get_bem_grid(self, rotor + 1,
267
+ np.zeros(nazi, dtype=np.float64, order='F'),
268
+ np.zeros(nrad, dtype=np.float64, order='F'))[0][1:]
269
+
270
+ def get_induction_polargrid(self, rotor=0):
271
+ nazi, nrad = self.get_bem_grid_dim(rotor)
272
+ induction = np.zeros((nazi, nrad), dtype=np.float64, order='F')
273
+ return H2LibSignatures.get_induction_polargrid(self, rotor + 1, induction)[0][1]
274
+
275
+ def get_induction_axisymmetric(self, rotor=0):
276
+ nrad = self.get_bem_grid_dim(rotor)[1]
277
+ induction = np.zeros(nrad, dtype=np.float64)
278
+ return H2LibSignatures.get_induction_axisymmetric(self, rotor + 1, induction)[0][1]
279
+
280
+ def get_induction_rotoravg(self, rotor=0):
281
+ induction = np.float64(0)
282
+ return H2LibSignatures.get_induction_rotoravg(self, rotor + 1, induction)[0][1]
283
+
284
+ def get_rotor_orientation(self, rotor=0, deg=False):
285
+ """return yaw, tilt, azi(of first blade) in rad(default) or deg"""
286
+ r = H2LibSignatures.get_rotor_orientation(self, rotor=rotor + 1, yaw=0., tilt=0., azi=0.)[0][1:]
287
+ if deg:
288
+ return np.rad2deg(r)
289
+ else:
290
+ return r
291
+
292
+ def get_rotor_position(self, rotor=0):
293
+ return H2LibSignatures.get_rotor_position(self, rotor=rotor + 1, position=np.zeros(3, dtype=np.float64))[0][1]
294
+
295
+ def get_rotor_avg_wsp(self, coo=1, rotor=0):
296
+ """Returns the rotor averaged wind speed in global(coo=1, default) or rotor(coo=2) coordinates."""
297
+ assert self.time > 0
298
+ wsp = np.zeros(3, dtype=np.float64)
299
+ return H2LibSignatures.get_rotor_avg_wsp(self, coo=coo, rotor=rotor + 1, wsp=wsp)[0][2]
300
+
301
+ def get_rotor_avg_uvw(self, rotor=0):
302
+ vx, vy, vz = self.get_rotor_avg_wsp(1, rotor)
303
+ return [vy, vx, -vz]
304
+
305
+ def init_static_solver(self):
306
+ """
307
+ Initialize the static solver.
308
+
309
+ Raises
310
+ ------
311
+ RuntimeError
312
+ If the static solver has already been initialized.
313
+
314
+ Returns
315
+ -------
316
+ None.
317
+
318
+ """
319
+ error_code = H2LibSignatures.init_static_solver(self, restype=np.int64)[1]
320
+ if error_code > 0:
321
+ if error_code == 102:
322
+ raise RuntimeError("STATIC_SOLVER_ALREADY_INITIALIZED")
323
+ raise RuntimeError(error_code) # pragma: no cover
324
+
325
+ def get_number_of_bodies_and_constraints(self):
326
+ """
327
+ Get number of bodies and constraints.
328
+
329
+ Raises
330
+ ------
331
+ RuntimeError
332
+ If the structure is confidential.
333
+
334
+ Returns
335
+ -------
336
+ nbdy : int
337
+ Number of bodies.
338
+ ncst : int
339
+ Number of constraints.
340
+
341
+ """
342
+ nbdy = -1
343
+ ncst = -1
344
+ error_code = -1
345
+ (
346
+ nbdy,
347
+ ncst,
348
+ error_code,
349
+ ) = H2LibSignatures.get_number_of_bodies_and_constraints(
350
+ self, nbdy, ncst, error_code
351
+ )[
352
+ 0
353
+ ]
354
+ if error_code > 0:
355
+ if error_code == 4:
356
+ raise RuntimeError("STRUCTURE_IS_CONFIDENTIAL")
357
+ raise RuntimeError(error_code) # pragma: no cover
358
+ return nbdy, ncst
359
+
360
+ def get_number_of_elements(self):
361
+ """
362
+ Get the number of elements for each body.
363
+
364
+ Raises
365
+ ------
366
+ RuntimeError
367
+ If the structure is confidential.
368
+
369
+ Returns
370
+ -------
371
+ nelem : (nbdy) ndarray, int
372
+ Number of elements for each body.
373
+
374
+ """
375
+ nbdy, _ = self.get_number_of_bodies_and_constraints()
376
+
377
+ nelem = np.zeros((nbdy, ), dtype=np.int64, order="F")
378
+ error_code = -1
379
+ _, nelem, error_code = H2LibSignatures.get_number_of_elements(
380
+ self, nbdy, nelem, error_code
381
+ )[0]
382
+
383
+ if error_code > 0:
384
+ if error_code == 4: # pragma: no cover
385
+ # This cannot happen because if the structure is confidential we will
386
+ # get this error from get_number_of_bodies_and_constraints().
387
+ raise RuntimeError("STRUCTURE_IS_CONFIDENTIAL") # pragma: no cover
388
+ elif error_code == 7: # pragma: no cover
389
+ # This cannot happen because we call get_number_of_bodies_and_constraints().
390
+ raise ValueError("WRONG_NUMBER_OF_BODIES") # pragma: no cover
391
+ raise RuntimeError(error_code) # pragma: no cover
392
+ return nelem
393
+
394
+ def get_timoshenko_location(self, ibdy, ielem):
395
+ """
396
+ Get the location and orientation of an element.
397
+
398
+ Parameters
399
+ ----------
400
+ ibdy : int
401
+ Body index, starting from 0.
402
+ ielem : int
403
+ Element index, starting from 0.
404
+
405
+ Raises
406
+ ------
407
+ RuntimeError
408
+ If the structure is confidential.
409
+ IndexError
410
+ If the body or the element do not exist.
411
+
412
+ Returns
413
+ -------
414
+ l : float
415
+ Element length.
416
+ r1 : (3) ndarray
417
+ Location of node 1.
418
+ r12 : (3) ndarray
419
+ Vector from node 1 to node 2.
420
+ tes : (3, 3) ndarray
421
+ Transformation matrix describing orientation.
422
+
423
+ """
424
+
425
+ l = 0.0
426
+ r1 = np.zeros((3), order="F")
427
+ r12 = np.zeros((3), order="F")
428
+ tes = np.zeros((3, 3), order="F")
429
+ error_code = -1
430
+ (
431
+ _,
432
+ _,
433
+ l,
434
+ r1,
435
+ r12,
436
+ tes,
437
+ error_code,
438
+ ) = H2LibSignatures.get_timoshenko_location(
439
+ self, ibdy + 1, ielem + 1, l, r1, r12, tes, error_code
440
+ )[
441
+ 0
442
+ ]
443
+ if error_code > 0:
444
+ if error_code == 4:
445
+ raise RuntimeError("STRUCTURE_IS_CONFIDENTIAL")
446
+ elif error_code == 5:
447
+ raise IndexError("BODY_DOES_NOT_EXIST")
448
+ elif error_code == 6:
449
+ raise IndexError("ELEMENT_DOES_NOT_EXIST")
450
+ raise RuntimeError(error_code) # pragma: no cover
451
+
452
+ return l, r1, r12, tes
453
+
454
+ def get_body_rotation_tensor(self, ibdy):
455
+ """
456
+ Get the rotation tensor of the requested body, that transforms from local to global base.
457
+
458
+ Parameters
459
+ ----------
460
+ ibdy : int
461
+ Body index, starting from 0.
462
+
463
+ Raises
464
+ ------
465
+ RuntimeError
466
+ If the structure is confidential.
467
+ IndexError
468
+ If the body does not exist.
469
+
470
+ Returns
471
+ -------
472
+ amat : (3, 3) ndarray
473
+ Rotation tensor.
474
+
475
+ """
476
+ amat = np.zeros((3, 3), order="F")
477
+ error_code = -1
478
+ _, amat, error_code = H2LibSignatures.get_body_rotation_tensor(
479
+ self, ibdy + 1, amat, error_code
480
+ )[0]
481
+ if error_code > 0:
482
+ if error_code == 4:
483
+ raise RuntimeError("STRUCTURE_IS_CONFIDENTIAL")
484
+ elif error_code == 5:
485
+ raise IndexError("BODY_DOES_NOT_EXIST")
486
+ raise RuntimeError(error_code) # pragma: no cover
487
+
488
+ return amat
489
+
490
+
491
+ @contextmanager
492
+ def set_LD_LIBRARY_PATH():
493
+ _file__ = np.__file__
494
+ old = os.environ.get('LD_LIBRARY_PATH', "")
495
+
496
+ if '/lib/' in _file__: # pragma: no cover (only on linux)
497
+ lib_path = _file__[:_file__.index("/lib/") + 5]
498
+ os.environ['LD_LIBRARY_PATH'] = f'{lib_path}:{old}'
499
+
500
+ try:
501
+ yield
502
+ finally:
503
+ os.environ['LD_LIBRARY_PATH'] = old
504
+
505
+
506
+ class H2LibProcess(ProcessClass, H2LibThread):
507
+ def __init__(self, suppress_output, filename=None, cwd='.'):
508
+ with set_LD_LIBRARY_PATH():
509
+ ProcessClass.__init__(self, cls=H2LibThread, cls_attrs=set(dir(H2LibThread)) - set(dir(ProcessClass)))
510
+ self(suppress_output=suppress_output, filename=filename, cwd=cwd)
511
+
512
+
513
+ def MultiH2Lib(N, filename=None, cwd='.', suppress_output=False):
514
+
515
+ if not hasattr(suppress_output, '__len__'):
516
+ suppress_output = [suppress_output] * N
517
+ args = [(suppress_output[i], filename, cwd) for i in range(N)]
518
+
519
+ with set_LD_LIBRARY_PATH():
520
+ from multiclass_interface import mpi_interface
521
+ if mpi_interface.mpi: # pragma: no cover
522
+ # try:
523
+ # with H2LibThread(filename):
524
+ # pass
525
+ # # LD_LIBRARY_PATH is set. Run H2LibThread directly in mpi processes
526
+ # cls = H2LibThread
527
+ # except OSError:
528
+ # # Set LD_LIBRARY_PATH in mpi workers and run H2LibThread from the workers via ProcessClass
529
+ # cls = H2LibProcess
530
+ from multiclass_interface.mpi_interface import MPIClassInterface
531
+ cls = H2LibProcess
532
+ return MPIClassInterface(cls, args)
533
+ else:
534
+ return MultiProcessClassInterface(H2LibThread, args)
h2lib/_version.py ADDED
@@ -0,0 +1,4 @@
1
+ # This file is autogenerated and should not be modified manually
2
+ __version__ = '13.1.502'
3
+ h2lib_version = '13.1.502'
4
+ hawc2_version = '13.1.5+4-g20eca1a'
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
+ import tempfile
12
+ try:
13
+ from ctypes import windll
14
+ except ImportError:
15
+ pass
16
+ import sys
17
+ from pathlib import Path
18
+ import atexit
19
+ c_int_p = POINTER(ctypes.c_long)
20
+ c_long_p = POINTER(ctypes.c_longlong)
21
+
22
+ c_double_p = POINTER(ctypes.c_double)
23
+ c_float_p = POINTER(ctypes.c_float)
24
+
25
+ in_use = []
26
+
27
+
28
+ class SuppressStream(object):
29
+
30
+ def __init__(self, suppressed_output_file, stream=sys.stderr):
31
+ self.orig_stream_fileno = stream.fileno()
32
+ self.stream = stream
33
+ self.suppressed_output_file = suppressed_output_file
34
+
35
+ def __enter__(self):
36
+ # save stream file descriptor
37
+ self.orig_stream_dup = os.dup(self.orig_stream_fileno)
38
+ self.stream.flush()
39
+ os.dup2(self.suppressed_output_file.fileno(), self.orig_stream_fileno)
40
+
41
+ def __exit__(self, type, value, traceback):
42
+ os.dup2(self.orig_stream_dup, self.orig_stream_fileno)
43
+ os.close(self.orig_stream_dup)
44
+
45
+
46
+ def suppress_output(f):
47
+ def wrap(*args, **kwargs):
48
+ if 'verbose' not in kwargs or not kwargs.pop('verbose'):
49
+ with SuppressStream(sys.stdout), SuppressStream(sys.stderr):
50
+ f(*args, **kwargs)
51
+ else:
52
+ f(*args, **kwargs)
53
+ return wrap
54
+
55
+
56
+ @contextmanager
57
+ def chdir(path):
58
+ oldpwd = os.getcwd()
59
+ os.chdir(path)
60
+ try:
61
+ yield
62
+ finally:
63
+ os.chdir(oldpwd)
64
+
65
+
66
+ def cwd(f):
67
+ def wrap(self, *args, **kwargs):
68
+ with chdir(self.model_path):
69
+ f(self, *args, **kwargs)
70
+ return wrap
71
+
72
+
73
+ def wrap(self, f, *args, **kwargs):
74
+ c_args = []
75
+ args = list(args)
76
+ for i, arg in enumerate(args):
77
+ if isinstance(arg, (list, tuple)):
78
+ if all([isinstance(e, int) for e in arg]):
79
+ # default to int64 which is default on linux but not windows
80
+ args[i] = np.array(arg, dtype=np.int64)
81
+ else:
82
+ args[i] = np.array(arg)
83
+ if isinstance(args[i], np.ndarray):
84
+
85
+ if self.fortran:
86
+ if not args[i].flags.f_contiguous:
87
+ sys.stderr.write(f'argument {i} for {f.__name__} not f_contiguous\n')
88
+ else:
89
+ if not args[i].flags.c_contiguous:
90
+ sys.stderr.write(f'argument {i} for {f.__name__} not c_contiguous\n')
91
+
92
+ args[i] = np.require(args[i], requirements=['C', 'F'][self.fortran])
93
+
94
+ for arg in args:
95
+ if isinstance(arg, int):
96
+ c_args.append(c_long_p(c_longlong(arg)))
97
+ elif isinstance(arg, float):
98
+ c_args.append(c_double_p(c_double(arg)))
99
+ elif isinstance(arg, str):
100
+ c_args.append(c_char_p(arg.encode('cp1252')))
101
+ # c_args.append(c_int_p(c_int(len(arg))))
102
+
103
+ elif isinstance(arg, np.ndarray):
104
+ if arg.dtype in [np.int32]:
105
+ c_args.append(arg.ctypes.data_as(c_int_p))
106
+ elif arg.dtype in [np.int64]:
107
+ c_args.append(arg.ctypes.data_as(c_long_p))
108
+ elif arg.dtype == np.float64:
109
+ c_args.append(arg.ctypes.data_as(c_double_p))
110
+ elif arg.dtype == np.float32:
111
+ c_args.append(arg.ctypes.data_as(c_float_p))
112
+ else:
113
+ raise NotImplementedError(arg.dtype)
114
+
115
+ else:
116
+ # raise NotImplementedError(arg.__class__.__name__)
117
+ c_args.append(arg)
118
+ if 'restype' in kwargs:
119
+ restype = kwargs['restype']
120
+ if hasattr(restype, 'dtype'):
121
+ restype = np.ctypeslib.as_ctypes_type(restype)
122
+ f.restype = restype
123
+ with chdir(self.cwd):
124
+ if self.suppress_output:
125
+ with SuppressStream(self.suppressed_output_file, sys.stdout), SuppressStream(self.suppressed_output_file, sys.stderr):
126
+ res = f(*c_args)
127
+ else:
128
+ res = f(*c_args)
129
+ ret_args = []
130
+ for arg in args:
131
+ c_arg = c_args.pop(0)
132
+ if isinstance(arg, (int, float)):
133
+ ret_args.append(c_arg.contents.value)
134
+ elif isinstance(arg, (str)):
135
+ ret_args.append(c_arg.value.decode('cp1252'))
136
+ # c_args.pop(0)
137
+ elif isinstance(arg, np.ndarray):
138
+ ret_args.append(arg)
139
+ else:
140
+ raise NotImplementedError(arg.__class__.__name__)
141
+ return ret_args, res
142
+
143
+
144
+ class DLLWrapper(object):
145
+ def __init__(self, filename, cwd='.', cdecl=True, fortran=True):
146
+ self.filename = str(filename)
147
+ if os.path.abspath(self.filename) in in_use:
148
+ raise Exception(f'{os.path.abspath(self.filename)} already in use in current process.')
149
+ self.cwd = cwd
150
+ self.cdecl = cdecl
151
+ self.fortran = fortran
152
+ self.suppress_output = False
153
+ self.suppressed_output_file = tempfile.TemporaryFile('w')
154
+ self.open()
155
+ in_use.append(os.path.abspath(self.filename))
156
+ atexit.register(self.close)
157
+
158
+ @staticmethod
159
+ def find_dll(path, name):
160
+ p = Path(path)
161
+
162
+ # if sys.platform == "win32":
163
+ # prefixes = ['']
164
+ # if sys.maxsize > 2**32:
165
+ # suffixes = ['.dll', '_64.dll']
166
+ # else:
167
+ # suffixes = ['.dll']
168
+ # elif sys.platform == 'linux':
169
+ # prefixes = ['lib','']
170
+ # suffixes = ['.so']
171
+ # else:
172
+ # raise NotImplementedError()
173
+
174
+ dll_lst = []
175
+ file_patterns = ['*%s*.dll' % name, '*%s*.so' % name]
176
+ for fp in file_patterns:
177
+ dll_lst.extend(list(p.glob("**/" + fp)))
178
+
179
+ def use_first(dll_lst):
180
+ f = str(dll_lst[0])
181
+ print("Using ", os.path.abspath(f))
182
+ return DLLWrapper(f)
183
+
184
+ if len(dll_lst) == 1:
185
+ return use_first(dll_lst)
186
+ elif len(dll_lst) > 1:
187
+ # check if excluding dlls in hawc2-binary, i.e. "hawc2-<platform>" results in one dll
188
+ dll_lst2 = [d for d in dll_lst if not str(d).startswith('hawc2-')]
189
+ if len(dll_lst2) == 1:
190
+ return use_first(dll_lst2)
191
+ raise FileExistsError("Multiple dlls found:\n" + "\n".join([str(p) for p in dll_lst]))
192
+ else:
193
+ raise FileNotFoundError("No " + " or ".join(file_patterns) +
194
+ " files found in " + os.path.abspath(p.absolute()))
195
+
196
+ def open(self):
197
+ assert os.path.isfile(self.filename), os.path.abspath(self.filename)
198
+ if self.cdecl:
199
+ try:
200
+ # python < (3, 8) and > 3.10?:
201
+ self.lib = ct.CDLL(self.filename)
202
+ except BaseException:
203
+ self.lib = ct.CDLL(self.filename, winmode=ctypes.DEFAULT_MODE)
204
+ else:
205
+ self.lib = windll.LoadLibrary(self.filename)
206
+
207
+ def close(self):
208
+ if "FreeLibrary" in dir(_ctypes):
209
+ _ctypes.FreeLibrary(self.lib._handle)
210
+ else:
211
+ _ctypes.dlclose(self.lib._handle)
212
+ del self.lib
213
+ self.suppressed_output_file.close()
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,366 @@
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_body_rotation_tensor(self, ibdy, amat, error_code):
102
+ '''subroutine get_body_rotation_tensor(ibdy, amat, error_code) &
103
+ integer(kind=8), intent(in) :: ibdy
104
+ real(kind=c_double), dimension(3, 3), intent(out) :: amat
105
+ integer(kind=8), intent(out) :: error_code
106
+ end subroutine'''
107
+ return self.get_lib_function('get_body_rotation_tensor')(ibdy, amat, error_code)
108
+
109
+ def get_diameter(self, rotor, restype):
110
+ '''function get_diameter(rotor) bind(C, name="get_diameter")
111
+ !DEC$ ATTRIBUTES DLLEXPORT :: get_diameter
112
+ integer*8, intent(in) :: rotor
113
+ Type (Taerorotor),pointer :: rotor_p
114
+ real(c_double) :: get_diameter
115
+ end function'''
116
+ return self.get_lib_function('get_diameter')(rotor, restype=restype)
117
+
118
+ def get_induction_axisymmetric(self, rotor, induction):
119
+ '''subroutine get_induction_axisymmetric(rotor, induction) bind(C, name="get_induction_axisymmetric")
120
+ integer*8, intent(in) :: rotor
121
+ real(c_double),intent(out) :: induction(rotors_gl%rotor(rotor)%dyn_induc%bem%nrad)
122
+ end subroutine'''
123
+ return self.get_lib_function('get_induction_axisymmetric')(rotor, induction)
124
+
125
+ def get_induction_polargrid(self, rotor, induction):
126
+ '''subroutine get_induction_polargrid(rotor, induction) bind(C, name="get_induction_polargrid")
127
+ integer*8, intent(in) :: rotor
128
+ real(c_double),intent(out) :: induction(rotors_gl%rotor(rotor)%dyn_induc%bem%nazi, rotors_gl%rotor(rotor)%dyn_induc%bem%nrad)
129
+ end subroutine'''
130
+ return self.get_lib_function('get_induction_polargrid')(rotor, induction)
131
+
132
+ def get_induction_rotoravg(self, rotor, induction):
133
+ '''subroutine get_induction_rotoravg(rotor, induction) bind(C, name="get_induction_rotoravg")
134
+ !DEC$ ATTRIBUTES DLLEXPORT :: get_induction_rotoravg
135
+ integer*8, intent(in) :: rotor
136
+ real(c_double), intent(out) :: induction
137
+ end subroutine'''
138
+ return self.get_lib_function('get_induction_rotoravg')(rotor, induction)
139
+
140
+ def get_nSections(self, rotor, blade, restype):
141
+ '''function get_nSections(rotor, blade) bind(C, name="get_nSections")
142
+ !DEC$ ATTRIBUTES DLLEXPORT :: get_nSections
143
+ integer*8, intent(in) :: rotor, blade
144
+ integer*8 :: get_nSections
145
+ end function'''
146
+ return self.get_lib_function('get_nSections')(rotor, blade, restype=restype)
147
+
148
+ def get_nblades(self, rotor, restype):
149
+ '''function get_nblades(rotor) bind(C, name="get_nblades")
150
+ !DEC$ ATTRIBUTES DLLEXPORT :: get_nblades
151
+ integer*8, intent(in) :: rotor
152
+ integer*8 :: get_nblades
153
+ end function'''
154
+ return self.get_lib_function('get_nblades')(rotor, restype=restype)
155
+
156
+ def get_nrotors(self, restype):
157
+ '''function get_nrotors() bind(C, name="get_nrotors")
158
+ !DEC$ ATTRIBUTES DLLEXPORT :: get_nrotors
159
+ integer*8 :: get_nrotors
160
+ end function'''
161
+ return self.get_lib_function('get_nrotors')(restype=restype)
162
+
163
+ def get_number_of_bodies_and_constraints(self, nbdy, ncst, error_code):
164
+ '''subroutine get_number_of_bodies_and_constraints(nbdy, ncst, error_code) &
165
+ integer(kind=8), intent(out) :: nbdy
166
+ integer(kind=8), intent(out) :: ncst
167
+ integer(kind=8), intent(out) :: error_code
168
+ end subroutine'''
169
+ return self.get_lib_function('get_number_of_bodies_and_constraints')(nbdy, ncst, error_code)
170
+
171
+ def get_number_of_elements(self, nbdy, nelem, error_code):
172
+ '''subroutine get_number_of_elements(nbdy, nelem, error_code) &
173
+ integer(kind=8), intent(in) :: nbdy
174
+ integer(kind=8), dimension(nbdy), intent(out) :: nelem
175
+ integer(kind=8), intent(out) :: error_code
176
+ end subroutine'''
177
+ return self.get_lib_function('get_number_of_elements')(nbdy, nelem, error_code)
178
+
179
+ def get_rotor_avg_wsp(self, coo, rotor, wsp):
180
+ '''subroutine get_rotor_avg_wsp(coo, rotor, wsp) bind(C, name="get_rotor_avg_wsp")
181
+ integer*8, intent(in) :: rotor
182
+ integer*8, intent(in) :: coo ! 1: global, 2: rotor
183
+ real(c_double), dimension(3):: wsp
184
+ end subroutine'''
185
+ return self.get_lib_function('get_rotor_avg_wsp')(coo, rotor, wsp)
186
+
187
+ def get_rotor_orientation(self, rotor, yaw, tilt, azi):
188
+ '''subroutine get_rotor_orientation(rotor, yaw, tilt, azi) bind(C, name="get_rotor_orientation")
189
+ !DEC$ ATTRIBUTES DLLEXPORT :: get_rotor_orientation
190
+ integer*8, intent(in) :: rotor
191
+ real(c_double), intent(out) :: yaw, tilt, azi
192
+ end subroutine'''
193
+ return self.get_lib_function('get_rotor_orientation')(rotor, yaw, tilt, azi)
194
+
195
+ def get_rotor_position(self, rotor, position):
196
+ '''subroutine get_rotor_position(rotor, position) bind(C, name="get_rotor_position")
197
+ !DEC$ ATTRIBUTES DLLEXPORT :: get_rotor_position
198
+ integer*8, intent(in) :: rotor
199
+ real(c_double), dimension(3), intent(out) :: position
200
+ !DEC$ ATTRIBUTES DLLEXPORT :: get_rotor_avg_wsp
201
+ integer*8, intent(in) :: rotor
202
+ integer*8, intent(in) :: coo ! 1: global, 2: rotor
203
+ end subroutine'''
204
+ return self.get_lib_function('get_rotor_position')(rotor, position)
205
+
206
+ def get_sensor_info(self, id, name, unit, desc):
207
+ '''subroutine get_sensor_info(id, name, unit, desc) bind(C, name="get_sensor_info")
208
+ integer*8, intent(in) :: id
209
+ character(kind=c_char, len=1), intent(out) :: name(30), unit(10), desc(512)
210
+ end subroutine'''
211
+ return self.get_lib_function('get_sensor_info')(id, name, unit, desc)
212
+
213
+ def get_sensor_values(self, ids, values, n):
214
+ '''subroutine get_sensor_values(ids, values, n) bind(C, name="get_sensor_values")
215
+ integer*8, intent(in) :: n
216
+ integer*8, intent(in) :: ids(n)
217
+ real(c_double), intent(out) :: values(n)
218
+ end subroutine'''
219
+ return self.get_lib_function('get_sensor_values')(ids, values, n)
220
+
221
+ def get_time(self, time):
222
+ '''subroutine
223
+ subroutine'''
224
+ return self.get_lib_function('get_time')(time)
225
+
226
+ def get_timoshenko_location(self, ibdy, ielem, l, r1, r12, tes, error_code):
227
+ '''subroutine get_timoshenko_location(ibdy, ielem, l, r1, r12, tes, error_code) &
228
+ integer(kind=8), intent(in) :: ibdy
229
+ integer(kind=8), intent(in) :: ielem
230
+ real(kind=c_double), intent(out) :: l
231
+ real(kind=c_double), dimension(3), intent(out) :: r1
232
+ real(kind=c_double), dimension(3), intent(out) :: r12
233
+ real(kind=c_double), dimension(3,3), intent(out) :: tes
234
+ integer(kind=8), intent(out) :: error_code
235
+ end subroutine'''
236
+ return self.get_lib_function('get_timoshenko_location')(ibdy, ielem, l, r1, r12, tes, error_code)
237
+
238
+ def get_version(self, s):
239
+ '''subroutine get_version(s) BIND(C, NAME='get_version')
240
+ character(kind=c_char, len=1), intent(inout) :: s(255)
241
+ end subroutine'''
242
+ return self.get_lib_function('get_version')(s)
243
+
244
+ def init(self, ):
245
+ '''subroutine init() bind(C, name="init")
246
+ !DEC$ ATTRIBUTES DLLEXPORT :: init
247
+ end subroutine'''
248
+ return self.get_lib_function('init')()
249
+
250
+ def init_static_solver(self, restype):
251
+ '''function init_static_solver() result(error_code) &
252
+ !DEC$ ATTRIBUTES DLLEXPORT :: init_static_solver
253
+ end function'''
254
+ return self.get_lib_function('init_static_solver')(restype=restype)
255
+
256
+ def init_windfield(self, Nxyz, dxyz, box_offset_yz, transport_speed):
257
+ '''subroutine init_windfield(Nxyz, dxyz, box_offset_yz, transport_speed) bind(C, name="init_windfield")
258
+ integer*8, dimension(3), intent(in) :: Nxyz
259
+ real*8 :: transport_speed
260
+ end subroutine'''
261
+ return self.get_lib_function('init_windfield')(Nxyz, dxyz, box_offset_yz, transport_speed)
262
+
263
+ def loop(self, N, restype):
264
+ '''function loop(N) bind(C, Name='loop')
265
+ !DEC$ ATTRIBUTES DLLEXPORT :: loop
266
+ integer*8, intent(in) :: N
267
+ real(c_double) :: loop,a
268
+ integer*8 :: i, j
269
+ end function'''
270
+ return self.get_lib_function('loop')(N, restype=restype)
271
+
272
+ def myfunction(self, int, dbl, restype):
273
+ '''function myfunction(int, dbl) bind(C, name='myfunction')
274
+ !DEC$ ATTRIBUTES DLLEXPORT :: myfunction
275
+ integer*8, intent(in) :: int
276
+ real(c_double), intent(in) :: dbl
277
+ real(c_double) :: myfunction
278
+ end function'''
279
+ return self.get_lib_function('myfunction')(int, dbl, restype=restype)
280
+
281
+ def mysubroutine(self, str_arr, dbl_arr):
282
+ '''subroutine mysubroutine(str_arr, dbl_arr) bind(C, name='mysubroutine')
283
+ character(kind=c_char, len=1), intent(inout) :: str_arr(20)
284
+ real(c_double), intent(inout), dimension(2) :: dbl_arr
285
+ end subroutine'''
286
+ return self.get_lib_function('mysubroutine')(str_arr, dbl_arr)
287
+
288
+ def read_input(self, htc_path):
289
+ '''subroutine read_input(htc_path) bind(C, name="read_input")
290
+ character(kind=c_char, len=1), intent(in) :: htc_path(1024)
291
+ end subroutine'''
292
+ return self.get_lib_function('read_input')(htc_path)
293
+
294
+ def run(self, time, restype):
295
+ '''function run(time) bind(C, name='run')
296
+ !DEC$ ATTRIBUTES DLLEXPORT :: run
297
+ real(c_double), intent(in) :: time
298
+ real(c_double) :: run, eps
299
+ end function'''
300
+ return self.get_lib_function('run')(time, restype=restype)
301
+
302
+ def setState(self, val):
303
+ '''subroutine setState(val) BIND(C, NAME='setState')
304
+ integer, intent(in) :: val
305
+ end subroutine'''
306
+ return self.get_lib_function('setState')(val)
307
+
308
+ def set_aerosections_windspeed(self, rotor, uvw):
309
+ '''subroutine set_aerosections_windspeed(rotor, uvw) bind(C, name="set_aerosections_windspeed")
310
+ integer*8, intent(in) :: rotor
311
+ real(c_double),intent(in) :: uvw(rotors_gl%rotor(rotor)%nbld, rotors_gl%rotor(rotor)%blade(1)%nsec, 3)
312
+ end subroutine'''
313
+ return self.get_lib_function('set_aerosections_windspeed')(rotor, uvw)
314
+
315
+ def set_variable_sensor_value(self, id, value):
316
+ '''subroutine set_variable_sensor_value(id, value) bind(C, name="set_variable_sensor_value")
317
+ integer*8, intent(in) :: id
318
+ real(c_double) :: value
319
+ end subroutine'''
320
+ return self.get_lib_function('set_variable_sensor_value')(id, value)
321
+
322
+ def set_windfield(self, uvw, box_offset_x, time):
323
+ '''subroutine set_windfield(uvw, box_offset_x, time) bind(C, name="set_windfield")
324
+ real*4, intent(in) :: uvw(3, gwsd%TMOD%buffer_points_x,gwsd%TMOD%buffer_points_y,gwsd%TMOD%buffer_points_z)
325
+ real*8, intent(in):: box_offset_x, time
326
+ end subroutine'''
327
+ return self.get_lib_function('set_windfield')(uvw, box_offset_x, time)
328
+
329
+ def sqr2(self, val):
330
+ '''subroutine sqr2(val) BIND(C, NAME='sqr2')
331
+ integer, intent(inout) :: val
332
+ end subroutine'''
333
+ return self.get_lib_function('sqr2')(val)
334
+
335
+ def step(self, restype):
336
+ '''function step() bind(C, name='step')
337
+ !DEC$ ATTRIBUTES DLLEXPORT :: step
338
+ real(c_double) :: step
339
+ end function'''
340
+ return self.get_lib_function('step')(restype=restype)
341
+
342
+ def test_hdf5(self, ):
343
+ '''subroutine test_hdf5() BIND(C, NAME='test_hdf5')
344
+ !DEC$ ATTRIBUTES DLLEXPORT :: test_hdf5
345
+ INTEGER :: hdferr ! Error flag
346
+ CHARACTER(9) :: filename = 'test.hdf5'
347
+ INTEGER(HID_T) :: file_id ! File identifier
348
+ INTEGER(HID_T) :: H5_Create_file,H5_Open_file ! File identifier
349
+ type(c_ptr) :: x
350
+ end subroutine'''
351
+ return self.get_lib_function('test_hdf5')()
352
+
353
+ def work(self, time, restype):
354
+ '''function work(time) bind(C, Name='work')
355
+ !DEC$ ATTRIBUTES DLLEXPORT :: work
356
+ real(c_double), intent(in) :: time
357
+ real*4 :: start_time, t
358
+ integer*8 :: N, work
359
+ end function'''
360
+ return self.get_lib_function('work')(time, restype=restype)
361
+
362
+ def write_output(self, ):
363
+ '''subroutine write_output() bind(C, name="write_output")
364
+ !DEC$ ATTRIBUTES DLLEXPORT :: write_output
365
+ end subroutine'''
366
+ return self.get_lib_function('write_output')()
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.1
2
+ Name: h2lib
3
+ Version: 13.1.502
4
+ Summary: Python interface to HAWC2 (13.1.5+4-g20eca1a)
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=ZOO_WZAenl4I1XmuG5zjQ7_NVaEHlalo_zJJ1MrGvqU,37991032
2
+ h2lib/__init__.py,sha256=YyJWPF22nu9ZoxkrE3ghngT9n_hl-HiAEflnZ_Ay8Q4,513
3
+ h2lib/_h2lib.py,sha256=ad2d83NMwmLYQbx6C95CZrcDpZAJWc83ul2eHtYcZ8I,20024
4
+ h2lib/_version.py,sha256=DnjpfNE4USjsrcXL_S34wybMKe5H_kI6B_qIN9y4ssE,153
5
+ h2lib/dll_wrapper.py,sha256=lCxinGa1KDId8kDOJIDolA_c_FrN8Pw2hdouNyxbydk,11732
6
+ h2lib/h2lib_signatures.py,sha256=FyD6a1lbVZOKhBuY3VWM75j_Vs4HwVDIML_k63Pau4A,16492
7
+ h2lib-13.1.502.dist-info/METADATA,sha256=7_9jjwsoaaBSfEmRoADbD_Ys09UqWQsaUD2XoPdMp5Y,717
8
+ h2lib-13.1.502.dist-info/WHEEL,sha256=i5OLz_nY6LYJdhup5CNR0jiQepm8jaO24sNeH6xy2cs,105
9
+ h2lib-13.1.502.dist-info/top_level.txt,sha256=y_a-tUqphEZQ_0nsWSMaSb21P8Lsd8hUxUdE9g2Dcbk,6
10
+ h2lib-13.1.502.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.43.0)
3
+ Root-Is-Purelib: false
4
+ Tag: cp312-cp312-linux_x86_64
5
+
@@ -0,0 +1 @@
1
+ h2lib