h2lib 13.1.506__py3-none-win_amd64.whl → 13.1.1701__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- h2lib/HAWC2Lib.dll +0 -0
- h2lib/_h2lib.py +388 -38
- h2lib/_version.py +3 -3
- h2lib/dll_wrapper.py +21 -1
- h2lib/h2lib_signatures.py +94 -0
- {h2lib-13.1.506.dist-info → h2lib-13.1.1701.dist-info}/METADATA +8 -9
- h2lib-13.1.1701.dist-info/RECORD +10 -0
- {h2lib-13.1.506.dist-info → h2lib-13.1.1701.dist-info}/WHEEL +1 -1
- h2lib-13.1.506.dist-info/RECORD +0 -10
- {h2lib-13.1.506.dist-info → h2lib-13.1.1701.dist-info}/top_level.txt +0 -0
h2lib/HAWC2Lib.dll
CHANGED
Binary file
|
h2lib/_h2lib.py
CHANGED
@@ -6,6 +6,28 @@ import sys
|
|
6
6
|
|
7
7
|
from multiclass_interface.multiprocess_interface import MultiProcessClassInterface, ProcessClass
|
8
8
|
import numpy as np
|
9
|
+
from pathlib import Path
|
10
|
+
|
11
|
+
_ERROR_CODES = {
|
12
|
+
1: ValueError("WRONG_NUMBER_OF_COLUMNS"),
|
13
|
+
2: ValueError("MAIN_BODY_NOT_FOUND"),
|
14
|
+
3: RuntimeError("NOT_IMPLEMENTED_ERROR"),
|
15
|
+
4: RuntimeError("STRUCTURE_IS_CONFIDENTIAL"),
|
16
|
+
5: IndexError("BODY_DOES_NOT_EXIST"),
|
17
|
+
6: IndexError("ELEMENT_DOES_NOT_EXIST"),
|
18
|
+
7: ValueError("WRONG_NUMBER_OF_BODIES"),
|
19
|
+
100: RuntimeError("STATIC_SOLVER_DID_NOT_CONVERGE"),
|
20
|
+
101: RuntimeError("STATIC_SOLVER_NOT_INITIALIZED"),
|
21
|
+
300: ValueError("TOO_FEW_SECTIONS_IN_C2DEF"),
|
22
|
+
301: ValueError("BEAM_TOO_SHORT"),
|
23
|
+
302: ValueError("DIFFERENT_NSEC"),
|
24
|
+
500: ValueError("RELATIVE_ROTATION_NOT_FOUND"),
|
25
|
+
700: RuntimeError("SYSTEM_NOT_LINEARIZED"),
|
26
|
+
701: RuntimeError("SYSTEM_EIGENANALYSIS_NOT_DONE"),
|
27
|
+
702: ValueError("TOO_MANY_MODES_REQUESTED"),
|
28
|
+
703: ValueError("WRONG_TOTAL_DOF"),
|
29
|
+
704: ValueError("WRONG_REDUCED_DOF")
|
30
|
+
}
|
9
31
|
|
10
32
|
|
11
33
|
def H2Lib(suppress_output=False, subprocess=True):
|
@@ -26,9 +48,9 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
|
|
26
48
|
# doubles the speed of single instances and 2N of N instances on linux
|
27
49
|
os.environ['MKL_THREADING_LAYER'] = 'sequential'
|
28
50
|
filename = os.path.abspath(filename)
|
29
|
-
|
30
|
-
|
31
|
-
|
51
|
+
for f in [sys.base_prefix, sys.prefix]:
|
52
|
+
if os.path.isdir(os.path.join(f, 'Library/bin')):
|
53
|
+
os.add_dll_directory(os.path.join(f, 'Library/bin'))
|
32
54
|
DLLWrapper.__init__(self, filename, cwd=cwd, cdecl=True)
|
33
55
|
self.suppress_output = suppress_output
|
34
56
|
self._initialized = False
|
@@ -66,6 +88,23 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
|
|
66
88
|
s = " " * 255
|
67
89
|
return H2LibSignatures.get_version(self, s)[0][0].strip()
|
68
90
|
|
91
|
+
def stop_on_error(self, flag):
|
92
|
+
"""
|
93
|
+
Control if HAWC2 will terminate the execution upon encountering an error. The default HAWC2 behavior is to stop.
|
94
|
+
|
95
|
+
Parameters
|
96
|
+
----------
|
97
|
+
flag : bool
|
98
|
+
If set to `True` an error will cause HAWC2 to terminate the execution with status code 1.
|
99
|
+
If set to `False` HAWC2 will still print a log message but not stop.
|
100
|
+
|
101
|
+
Returns
|
102
|
+
-------
|
103
|
+
None.
|
104
|
+
|
105
|
+
"""
|
106
|
+
H2LibSignatures.stop_on_error(self, bool(flag))
|
107
|
+
|
69
108
|
def get_wind_speed(self, pos_g):
|
70
109
|
return self.get_lib_function('get_wind_speed')(np.asarray(pos_g, dtype=np.float64),
|
71
110
|
np.asarray([0, 0, 0], dtype=np.float64))[0][1]
|
@@ -98,6 +137,134 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
|
|
98
137
|
self.time = np.round(H2LibSignatures.run(self, np.float64(time), restype=np.float64)[1], 6)
|
99
138
|
return self.time
|
100
139
|
|
140
|
+
def linearize(self):
|
141
|
+
"""
|
142
|
+
Linearize the system, as done by the system eigen-analysis.
|
143
|
+
|
144
|
+
Returns
|
145
|
+
-------
|
146
|
+
n_tdofs : int
|
147
|
+
Total number of degrees of freedom in the system.
|
148
|
+
n_rdofs : int
|
149
|
+
Number of degrees of freedom in the reduced order system.
|
150
|
+
|
151
|
+
"""
|
152
|
+
n_tdofs = -1
|
153
|
+
n_rdofs = -1
|
154
|
+
res = H2LibSignatures.linearize(self, n_tdofs, n_rdofs)[0]
|
155
|
+
return res
|
156
|
+
|
157
|
+
def do_system_eigenanalysis(self, n_modes, include_damping=True):
|
158
|
+
"""
|
159
|
+
Do the system eigen-analysis.
|
160
|
+
|
161
|
+
Parameters
|
162
|
+
----------
|
163
|
+
n_modes : int
|
164
|
+
Number of modes to output.
|
165
|
+
include_damping : bool, optional
|
166
|
+
`True` to include damping, `False` otherwise. The default is `True`.
|
167
|
+
|
168
|
+
Raises
|
169
|
+
------
|
170
|
+
RuntimeError
|
171
|
+
Call `linearize` first.
|
172
|
+
ValueError
|
173
|
+
If too many modes are requested.
|
174
|
+
|
175
|
+
Returns
|
176
|
+
-------
|
177
|
+
natural_frequencies : (n_modes,) ndarray
|
178
|
+
Natural frequencies, in Hz.
|
179
|
+
damping_ratios : (n_modes,) ndarray
|
180
|
+
Damping ratios (nondimensional).
|
181
|
+
Only returned if `include_damping=True`.
|
182
|
+
|
183
|
+
"""
|
184
|
+
natural_frequencies = np.zeros((n_modes,), dtype=np.float64, order="F")
|
185
|
+
damping_ratios = np.zeros((n_modes,), dtype=np.float64, order="F")
|
186
|
+
error_code = -1
|
187
|
+
|
188
|
+
_, _, natural_frequencies, damping_ratios, error_code = (
|
189
|
+
H2LibSignatures.do_system_eigenanalysis(
|
190
|
+
self,
|
191
|
+
include_damping,
|
192
|
+
n_modes,
|
193
|
+
natural_frequencies,
|
194
|
+
damping_ratios,
|
195
|
+
error_code,
|
196
|
+
)[0]
|
197
|
+
)
|
198
|
+
|
199
|
+
if error_code > 0:
|
200
|
+
raise _ERROR_CODES[error_code]
|
201
|
+
|
202
|
+
if include_damping:
|
203
|
+
return natural_frequencies, damping_ratios
|
204
|
+
else:
|
205
|
+
return natural_frequencies
|
206
|
+
|
207
|
+
def get_system_eigenvalues_and_eigenvectors(
|
208
|
+
self, n_modes, n_rdofs, include_damping=True
|
209
|
+
):
|
210
|
+
"""
|
211
|
+
Get the system eigenvalues and eigenvectors from system_eigenanalysis.
|
212
|
+
|
213
|
+
This function must be called after `do_system_eigenanalysis`, with the same value of `include_damping`.
|
214
|
+
|
215
|
+
Parameters
|
216
|
+
----------
|
217
|
+
n_modes : int
|
218
|
+
Number of modes to output.
|
219
|
+
n_rdofs : int
|
220
|
+
Number of degrees of freedom in the reduced order system.
|
221
|
+
As returned by `linearize`.
|
222
|
+
include_damping : bool, optional
|
223
|
+
`True` to include damping, `False` otherwise. The default is `True`.
|
224
|
+
|
225
|
+
Raises
|
226
|
+
------
|
227
|
+
RuntimeError
|
228
|
+
If the structure is confidential or if `linearize` and `do_system_eigenanalysis` have not been called first.
|
229
|
+
ValueError
|
230
|
+
Either `n_modes` or `n_rdofs` is wrong.
|
231
|
+
|
232
|
+
Returns
|
233
|
+
-------
|
234
|
+
eigenvalues : (n_modes,) ndarray
|
235
|
+
Eigenvalues. Real array without damping and complex array otherwise.
|
236
|
+
eigenvectors : (n_modes, ny)
|
237
|
+
Eigenvectors. Real array without damping and complex array otherwise.
|
238
|
+
Only returned if the structure is not confidential.
|
239
|
+
|
240
|
+
"""
|
241
|
+
if include_damping:
|
242
|
+
ny = 2 * n_rdofs
|
243
|
+
dtype = np.complex128
|
244
|
+
f = H2LibSignatures.get_system_eigval_eigvec_with_damping
|
245
|
+
else:
|
246
|
+
ny = n_rdofs
|
247
|
+
dtype = np.float64
|
248
|
+
f = H2LibSignatures.get_system_eigval_eigvec_without_damping
|
249
|
+
|
250
|
+
error_code = -1
|
251
|
+
eigenvalues = np.zeros((n_modes,), dtype=dtype, order="F")
|
252
|
+
eigenvectors = np.zeros((n_modes, ny), dtype=dtype, order="F")
|
253
|
+
|
254
|
+
_, _, eigenvalues, eigenvectors, error_code = f(
|
255
|
+
self, n_modes, ny, eigenvalues, eigenvectors, error_code
|
256
|
+
)[0]
|
257
|
+
|
258
|
+
if error_code > 0:
|
259
|
+
if error_code == 4:
|
260
|
+
# The structure is confidential.
|
261
|
+
# The eigenvectors have not been returned by the Fortran code.
|
262
|
+
return eigenvalues
|
263
|
+
else:
|
264
|
+
raise _ERROR_CODES[error_code]
|
265
|
+
|
266
|
+
return eigenvalues, eigenvectors
|
267
|
+
|
101
268
|
def solver_static_init(self):
|
102
269
|
"""
|
103
270
|
Initialize the static solver.
|
@@ -126,9 +293,7 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
|
|
126
293
|
error_code = -1
|
127
294
|
error_code = H2LibSignatures.solver_static_update(self, error_code)[0][0]
|
128
295
|
if error_code > 0:
|
129
|
-
|
130
|
-
raise RuntimeError("STATIC_SOLVER_NOT_INITIALIZED")
|
131
|
-
raise RuntimeError(error_code) # pragma: no cover
|
296
|
+
raise _ERROR_CODES[error_code]
|
132
297
|
|
133
298
|
def solver_static_solve(self):
|
134
299
|
"""
|
@@ -147,9 +312,7 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
|
|
147
312
|
error_code = -1
|
148
313
|
error_code = H2LibSignatures.solver_static_solve(self, error_code)[0][0]
|
149
314
|
if error_code > 0:
|
150
|
-
|
151
|
-
raise RuntimeError("STATIC_SOLVER_NOT_INITIALIZED")
|
152
|
-
raise RuntimeError(error_code) # pragma: no cover
|
315
|
+
raise _ERROR_CODES[error_code]
|
153
316
|
|
154
317
|
def solver_static_delete(self):
|
155
318
|
"""
|
@@ -179,9 +342,7 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
|
|
179
342
|
error_code = -1
|
180
343
|
error_code = H2LibSignatures.solver_static_run(self, error_code)[0][0]
|
181
344
|
if error_code > 0:
|
182
|
-
|
183
|
-
raise RuntimeError("STATIC_SOLVER_DID_NOT_CONVERGE")
|
184
|
-
raise RuntimeError(error_code) # pragma: no cover
|
345
|
+
raise _ERROR_CODES[error_code]
|
185
346
|
|
186
347
|
def add_sensor(self, sensor_line):
|
187
348
|
"""Add sensor to hawc2. The sensor will be accessible from h2lib but will not show up in the output file of HAWC2
|
@@ -231,6 +392,167 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
|
|
231
392
|
def set_variable_sensor_value(self, id, value):
|
232
393
|
return H2LibSignatures.set_variable_sensor_value(self, id, np.float64(value))
|
233
394
|
|
395
|
+
def set_orientation_base(
|
396
|
+
self,
|
397
|
+
main_body,
|
398
|
+
mbdy_eulerang_table=None,
|
399
|
+
angles_in_deg=True,
|
400
|
+
reset_orientation=False,
|
401
|
+
mbdy_ini_rotvec_d1=None,
|
402
|
+
):
|
403
|
+
"""
|
404
|
+
Set an `orientation` / `base` command.
|
405
|
+
|
406
|
+
Function equivalent to the HAWC2 command `orientation` / `base`.
|
407
|
+
For further details see the HAWC2 documentation.
|
408
|
+
We assume that this base orientation is already present in the htc file,
|
409
|
+
and therefore modify it here instead of creating a new one.
|
410
|
+
|
411
|
+
Parameters
|
412
|
+
----------
|
413
|
+
main_body : str
|
414
|
+
Main body name. Same as HAWC2 `mbdy` parameter.
|
415
|
+
mbdy_eulerang_table : (:, 3) ndarray, optional
|
416
|
+
A sequence of Euler angles, one per row.
|
417
|
+
Equivalent to HAWC2 command `mbdy_eulerang`.
|
418
|
+
A 1D array with 3 elements will be interpreted as 1 row.
|
419
|
+
This table is additive with respect to the orientation / base command in the htc file,
|
420
|
+
unless the flag `reset_orientation` is used.
|
421
|
+
The default is `[0, 0, 0]`, which means that no rotation is applied.
|
422
|
+
angles_in_deg : bool, optional
|
423
|
+
`True` if the angles in `mbdy_eulerang_table` are provided in degrees.
|
424
|
+
`False` if they are in radians.
|
425
|
+
The default is `True`.
|
426
|
+
reset_orientation : bool, optional,
|
427
|
+
If `True` this function will reset the orientation to the global frame
|
428
|
+
before applying `mbdy_eulerang_table`. The default is `False`.
|
429
|
+
mbdy_ini_rotvec_d1 : (4) ndarray, optional
|
430
|
+
Angular velocity. First 3 elements for the direction and last for the magnitude.
|
431
|
+
Equivalent to HAWC2 command `mbdy_ini_rotvec_d1`.
|
432
|
+
The default is 0 speed.
|
433
|
+
|
434
|
+
Raises
|
435
|
+
------
|
436
|
+
ValueError
|
437
|
+
If the `orientation` / `base` command cannot be found.
|
438
|
+
|
439
|
+
Returns
|
440
|
+
-------
|
441
|
+
None.
|
442
|
+
|
443
|
+
"""
|
444
|
+
if mbdy_eulerang_table is None:
|
445
|
+
mbdy_eulerang_table = np.zeros((1, 3), dtype=np.float64, order="F")
|
446
|
+
if mbdy_ini_rotvec_d1 is None:
|
447
|
+
mbdy_ini_rotvec_d1 = np.zeros((4,), dtype=np.float64, order="F")
|
448
|
+
# 1D arrays are converted to 2D with 1 row.
|
449
|
+
mbdy_eulerang_table = np.atleast_2d(mbdy_eulerang_table)
|
450
|
+
error_code = -1
|
451
|
+
error_code = H2LibSignatures.set_orientation_base(
|
452
|
+
self,
|
453
|
+
main_body,
|
454
|
+
mbdy_eulerang_table.shape[0],
|
455
|
+
np.asfortranarray(mbdy_eulerang_table.astype(np.float64)),
|
456
|
+
angles_in_deg,
|
457
|
+
reset_orientation,
|
458
|
+
np.asfortranarray(mbdy_ini_rotvec_d1.astype(np.float64)),
|
459
|
+
error_code,
|
460
|
+
)[0][-1]
|
461
|
+
|
462
|
+
if error_code > 0:
|
463
|
+
raise _ERROR_CODES[error_code]
|
464
|
+
|
465
|
+
def set_orientation_relative(
|
466
|
+
self,
|
467
|
+
main_body_1,
|
468
|
+
node_1,
|
469
|
+
main_body_2,
|
470
|
+
node_2,
|
471
|
+
mbdy2_eulerang_table=None,
|
472
|
+
angles_in_deg=True,
|
473
|
+
reset_orientation=False,
|
474
|
+
mbdy2_ini_rotvec_d1=None,
|
475
|
+
):
|
476
|
+
"""
|
477
|
+
Set an `orientation` / `relative` command.
|
478
|
+
|
479
|
+
Function equivalent to the HAWC2 command `orientation` / `relative`.
|
480
|
+
For further details see the HAWC2 documentation.
|
481
|
+
We assume that this relative orientation is already present in the htc file,
|
482
|
+
and therefore modify it here instead of creating a new one.
|
483
|
+
|
484
|
+
Parameters
|
485
|
+
----------
|
486
|
+
main_body_1 : str
|
487
|
+
Main body name to which the next main body is attached.
|
488
|
+
node_1 : int, str
|
489
|
+
Node number of `main_body_1` that is used for connection, starting from 0.
|
490
|
+
`"last"` can be specified which ensures that the last node on the main_body
|
491
|
+
is used, and `-1` refers to the origin of the main body coordinate system.
|
492
|
+
main_body_2 : str
|
493
|
+
Main_body name of the `main_body` that is positioned
|
494
|
+
in space by the relative command.
|
495
|
+
node_2 : int, str
|
496
|
+
Node number of `main_body_2` that is used for connection, starting from 0.
|
497
|
+
`"last"` can be specified which ensures that the last node on the main_body
|
498
|
+
is used, and `-1` refers to the origin of the main body coordinate system.
|
499
|
+
mbdy2_eulerang_table : : (:, 3) ndarray, optional
|
500
|
+
A sequence of Euler angles, one per row.
|
501
|
+
Equivalent to HAWC2 command `mbdy2_eulerang`.
|
502
|
+
A 1D array with 3 elements will be interpreted as 1 row.
|
503
|
+
This table is additive with respect to the orientation / relative command in the htc file,
|
504
|
+
unless the flag `reset_orientation` is used.
|
505
|
+
The default is `[0, 0, 0]`, which means that no rotation is applied.
|
506
|
+
angles_in_deg : bool, optional
|
507
|
+
`True` if the angles in `mbdy2_eulerang_table` are provided in degrees.
|
508
|
+
`False` if they are in radians.
|
509
|
+
The default is `True`.
|
510
|
+
reset_orientation : bool, optional,
|
511
|
+
If `True` this function will reset the orientation to no rotation
|
512
|
+
before applying `mbdy2_eulerang_table`. The default is `False`.
|
513
|
+
mbdy2_ini_rotvec_d1 : (4) ndarray, optional
|
514
|
+
Angular velocity. First 3 elements for the direction and last for the magnitude.
|
515
|
+
Equivalent to HAWC2 command `mbdy2_ini_rotvec_d1`.
|
516
|
+
The default is 0 speed.
|
517
|
+
|
518
|
+
Raises
|
519
|
+
------
|
520
|
+
ValueError
|
521
|
+
If the `orientation` / `relative` command cannot be found,
|
522
|
+
or if the main bodies do not exist.
|
523
|
+
|
524
|
+
Returns
|
525
|
+
-------
|
526
|
+
None.
|
527
|
+
|
528
|
+
"""
|
529
|
+
if mbdy2_eulerang_table is None:
|
530
|
+
mbdy2_eulerang_table = np.zeros((1, 3), dtype=np.float64, order="F")
|
531
|
+
if mbdy2_ini_rotvec_d1 is None:
|
532
|
+
mbdy2_ini_rotvec_d1 = np.zeros((4,), dtype=np.float64, order="F")
|
533
|
+
# 1D arrays are converted to 2D with 1 row.
|
534
|
+
mbdy2_eulerang_table = np.atleast_2d(mbdy2_eulerang_table)
|
535
|
+
# Convert node_1 and 2 to int.
|
536
|
+
if node_1 == "last":
|
537
|
+
node_1 = -2
|
538
|
+
if node_2 == "last":
|
539
|
+
node_2 = -2
|
540
|
+
error_code = -1
|
541
|
+
error_code = H2LibSignatures.set_orientation_relative(
|
542
|
+
self,
|
543
|
+
main_body_1,
|
544
|
+
node_1 + 1,
|
545
|
+
main_body_2,
|
546
|
+
node_2 + 1,
|
547
|
+
mbdy2_eulerang_table.shape[0],
|
548
|
+
np.asfortranarray(mbdy2_eulerang_table.astype(np.float64)),
|
549
|
+
bool(angles_in_deg),
|
550
|
+
reset_orientation,
|
551
|
+
np.asfortranarray(mbdy2_ini_rotvec_d1.astype(np.float64)),
|
552
|
+
error_code)[0][-1]
|
553
|
+
if error_code > 0:
|
554
|
+
raise _ERROR_CODES[error_code]
|
555
|
+
|
234
556
|
def init_windfield(self, Nxyz, dxyz, box_offset_yz, transport_speed):
|
235
557
|
"""Initialize wind field which afterwards can be set using set_windfield
|
236
558
|
|
@@ -325,10 +647,12 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
|
|
325
647
|
return self._aero_sections_data_shape[rotor]
|
326
648
|
|
327
649
|
def get_aerosections_position(self, rotor=0):
|
650
|
+
"""Global xyz position of aero sections. Shape=(#blades, #sections, 3)"""
|
328
651
|
position = np.zeros(self.aero_sections_data_shape(rotor), dtype=np.float64, order='F')
|
329
652
|
return H2LibSignatures.get_aerosections_position(self, rotor + 1, position)[0][1]
|
330
653
|
|
331
654
|
def set_aerosections_windspeed(self, uvw, rotor=0):
|
655
|
+
"""Update wind speed at aero sections. uvw shape=(#blades, #sections, 3)"""
|
332
656
|
return H2LibSignatures.set_aerosections_windspeed(self, rotor + 1, np.asarray(uvw, np.float64))
|
333
657
|
|
334
658
|
def get_aerosections_forces(self, rotor=0):
|
@@ -417,9 +741,7 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
|
|
417
741
|
0
|
418
742
|
]
|
419
743
|
if error_code > 0:
|
420
|
-
|
421
|
-
raise RuntimeError("STRUCTURE_IS_CONFIDENTIAL")
|
422
|
-
raise RuntimeError(error_code) # pragma: no cover
|
744
|
+
raise _ERROR_CODES[error_code]
|
423
745
|
return nbdy, ncst
|
424
746
|
|
425
747
|
def get_number_of_elements(self):
|
@@ -445,15 +767,9 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
|
|
445
767
|
self, nbdy, nelem, error_code
|
446
768
|
)[0]
|
447
769
|
|
448
|
-
if error_code > 0:
|
449
|
-
|
450
|
-
|
451
|
-
# get this error from get_number_of_bodies_and_constraints().
|
452
|
-
raise RuntimeError("STRUCTURE_IS_CONFIDENTIAL") # pragma: no cover
|
453
|
-
elif error_code == 7: # pragma: no cover
|
454
|
-
# This cannot happen because we call get_number_of_bodies_and_constraints().
|
455
|
-
raise ValueError("WRONG_NUMBER_OF_BODIES") # pragma: no cover
|
456
|
-
raise RuntimeError(error_code) # pragma: no cover
|
770
|
+
if error_code > 0: # pragma: no cover
|
771
|
+
# This cannot happen because exceptions are raised by get_number_of_bodies_and_constraints().
|
772
|
+
raise _ERROR_CODES[error_code] # pragma: no cover
|
457
773
|
return nelem
|
458
774
|
|
459
775
|
def get_timoshenko_location(self, ibdy, ielem):
|
@@ -506,14 +822,7 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
|
|
506
822
|
0
|
507
823
|
]
|
508
824
|
if error_code > 0:
|
509
|
-
|
510
|
-
raise RuntimeError("STRUCTURE_IS_CONFIDENTIAL")
|
511
|
-
elif error_code == 5:
|
512
|
-
raise IndexError("BODY_DOES_NOT_EXIST")
|
513
|
-
elif error_code == 6:
|
514
|
-
raise IndexError("ELEMENT_DOES_NOT_EXIST")
|
515
|
-
raise RuntimeError(error_code) # pragma: no cover
|
516
|
-
|
825
|
+
raise _ERROR_CODES[error_code]
|
517
826
|
return l, r1, r12, tes
|
518
827
|
|
519
828
|
def get_body_rotation_tensor(self, ibdy):
|
@@ -544,14 +853,55 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
|
|
544
853
|
self, ibdy + 1, amat, error_code
|
545
854
|
)[0]
|
546
855
|
if error_code > 0:
|
547
|
-
|
548
|
-
raise RuntimeError("STRUCTURE_IS_CONFIDENTIAL")
|
549
|
-
elif error_code == 5:
|
550
|
-
raise IndexError("BODY_DOES_NOT_EXIST")
|
551
|
-
raise RuntimeError(error_code) # pragma: no cover
|
552
|
-
|
856
|
+
raise _ERROR_CODES[error_code]
|
553
857
|
return amat
|
554
858
|
|
859
|
+
def get_system_matrices(self, n_tdofs, n_rdofs):
|
860
|
+
"""
|
861
|
+
Get the system structural matrices computed during the system_eigenanalysis.
|
862
|
+
|
863
|
+
This function must be called after `linearize()`.
|
864
|
+
|
865
|
+
Parameters
|
866
|
+
----------
|
867
|
+
n_tdofs : int
|
868
|
+
Total number of degrees of freedom in the system.
|
869
|
+
n_rdofs : int
|
870
|
+
Number of degrees of freedom in the reduced order system.
|
871
|
+
|
872
|
+
Raises
|
873
|
+
------
|
874
|
+
RuntimeError
|
875
|
+
If the linearizetion has not been done or the structure is confidential.
|
876
|
+
ValueError
|
877
|
+
If the total or reduced number of degrees of freedom is wrong.
|
878
|
+
|
879
|
+
Returns
|
880
|
+
-------
|
881
|
+
M : (n_rdofs, n_rdofs) ndarray
|
882
|
+
Mass matrix.
|
883
|
+
C : (n_rdofs, n_rdofs) ndarray
|
884
|
+
Damping matrix.
|
885
|
+
K : (n_rdofs, n_rdofs) ndarray
|
886
|
+
Stiffness matrix.
|
887
|
+
R : (n_tdofs, n_rdofs) ndarray
|
888
|
+
Transformation between reduced and all DOFs.
|
889
|
+
|
890
|
+
"""
|
891
|
+
M = np.zeros((n_rdofs, n_rdofs), dtype=np.float64, order="F")
|
892
|
+
C = np.zeros((n_rdofs, n_rdofs), dtype=np.float64, order="F")
|
893
|
+
K = np.zeros((n_rdofs, n_rdofs), dtype=np.float64, order="F")
|
894
|
+
R = np.zeros((n_tdofs, n_rdofs), dtype=np.float64, order="F")
|
895
|
+
error_code = -1
|
896
|
+
|
897
|
+
_, _, M, C, K, R, error_code = H2LibSignatures.get_system_matrices(
|
898
|
+
self, n_tdofs, n_rdofs, M, C, K, R, error_code
|
899
|
+
)[0]
|
900
|
+
|
901
|
+
if error_code > 0:
|
902
|
+
raise _ERROR_CODES[error_code]
|
903
|
+
return M, C, K, R
|
904
|
+
|
555
905
|
|
556
906
|
@contextmanager
|
557
907
|
def set_LD_LIBRARY_PATH():
|
h2lib/_version.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
1
|
# This file is autogenerated and should not be modified manually
|
2
|
-
__version__ = '13.1.
|
3
|
-
h2lib_version = '13.1.
|
4
|
-
hawc2_version = '13.1.
|
2
|
+
__version__ = '13.1.1701'
|
3
|
+
h2lib_version = '13.1.1701'
|
4
|
+
hawc2_version = '13.1.17'
|
h2lib/dll_wrapper.py
CHANGED
@@ -6,7 +6,7 @@ import platform
|
|
6
6
|
import os
|
7
7
|
import ctypes
|
8
8
|
from _ctypes import POINTER
|
9
|
-
from ctypes import c_int, c_double, c_char, c_char_p, c_long, c_longlong
|
9
|
+
from ctypes import c_int, c_double, c_char, c_char_p, c_long, c_longlong, Structure
|
10
10
|
from contextlib import contextmanager
|
11
11
|
import tempfile
|
12
12
|
try:
|
@@ -22,6 +22,24 @@ c_long_p = POINTER(ctypes.c_longlong)
|
|
22
22
|
c_double_p = POINTER(ctypes.c_double)
|
23
23
|
c_float_p = POINTER(ctypes.c_float)
|
24
24
|
|
25
|
+
|
26
|
+
# Add support for complex numbers to ctypes.
|
27
|
+
# This solution is copied from: https://stackoverflow.com/a/65743183/3676517
|
28
|
+
class c_double_complex(Structure):
|
29
|
+
"""complex is a c structure
|
30
|
+
https://docs.python.org/3/library/ctypes.html#module-ctypes suggests
|
31
|
+
to use ctypes.Structure to pass structures (and, therefore, complex)
|
32
|
+
"""
|
33
|
+
|
34
|
+
_fields_ = [("real", c_double), ("imag", c_double)]
|
35
|
+
|
36
|
+
@property
|
37
|
+
def value(self):
|
38
|
+
return self.real + 1j * self.imag # fields declared above
|
39
|
+
|
40
|
+
|
41
|
+
c_double_complex_p = POINTER(c_double_complex)
|
42
|
+
|
25
43
|
in_use = []
|
26
44
|
|
27
45
|
|
@@ -109,6 +127,8 @@ def wrap(self, f, *args, **kwargs):
|
|
109
127
|
c_args.append(arg.ctypes.data_as(c_double_p))
|
110
128
|
elif arg.dtype == np.float32:
|
111
129
|
c_args.append(arg.ctypes.data_as(c_float_p))
|
130
|
+
elif arg.dtype == np.complex128:
|
131
|
+
c_args.append(arg.ctypes.data_as(c_double_complex_p))
|
112
132
|
else:
|
113
133
|
raise NotImplementedError(arg.dtype)
|
114
134
|
|
h2lib/h2lib_signatures.py
CHANGED
@@ -11,6 +11,16 @@ class H2LibSignatures():
|
|
11
11
|
end subroutine'''
|
12
12
|
return self.get_lib_function('add_sensor')(sensor_line, index_start, index_stop)
|
13
13
|
|
14
|
+
def do_system_eigenanalysis(self, include_damping, n_modes, natural_frequencies, damping_ratios, error_code):
|
15
|
+
'''subroutine do_system_eigenanalysis(include_damping, n_modes, natural_frequencies, damping_ratios, error_code) &
|
16
|
+
logical(kind=c_bool), intent(in) :: include_damping
|
17
|
+
integer(kind=4), intent(in) :: n_modes
|
18
|
+
real(kind=c_double), dimension(n_modes), intent(out) :: natural_frequencies
|
19
|
+
real(kind=c_double), dimension(n_modes), intent(out) :: damping_ratios
|
20
|
+
integer(kind=8), intent(out) :: error_code
|
21
|
+
end subroutine'''
|
22
|
+
return self.get_lib_function('do_system_eigenanalysis')(include_damping, n_modes, natural_frequencies, damping_ratios, error_code)
|
23
|
+
|
14
24
|
def echo_version(self, ):
|
15
25
|
'''subroutine echo_version() BIND(C, NAME='echo_version')
|
16
26
|
!DEC$ ATTRIBUTES DLLEXPORT :: echo_version
|
@@ -218,6 +228,38 @@ end subroutine'''
|
|
218
228
|
end subroutine'''
|
219
229
|
return self.get_lib_function('get_sensor_values')(ids, values, n)
|
220
230
|
|
231
|
+
def get_system_eigval_eigvec_with_damping(self, n_modes, ny, eigenvalues, eigenvectors, error_code):
|
232
|
+
'''subroutine get_system_eigval_eigvec_with_damping(n_modes, ny, eigenvalues, eigenvectors, error_code) &
|
233
|
+
integer(kind=4), intent(in) :: n_modes
|
234
|
+
integer(kind=4), intent(in) :: ny
|
235
|
+
complex(kind=c_double_complex), dimension(n_modes), intent(out) :: eigenvalues
|
236
|
+
complex(kind=c_double_complex), dimension(ny, n_modes), intent(out) :: eigenvectors
|
237
|
+
integer(kind=8), intent(out) :: error_code
|
238
|
+
end subroutine'''
|
239
|
+
return self.get_lib_function('get_system_eigval_eigvec_with_damping')(n_modes, ny, eigenvalues, eigenvectors, error_code)
|
240
|
+
|
241
|
+
def get_system_eigval_eigvec_without_damping(self, n_modes, ny, eigenvalues, eigenvectors, error_code):
|
242
|
+
'''subroutine get_system_eigval_eigvec_without_damping(n_modes, ny, eigenvalues, eigenvectors, error_code) &
|
243
|
+
integer(kind=4), intent(in) :: n_modes
|
244
|
+
integer(kind=4), intent(in) :: ny
|
245
|
+
real(kind=c_double), dimension(n_modes), intent(out) :: eigenvalues
|
246
|
+
real(kind=c_double), dimension(ny, n_modes), intent(out) :: eigenvectors
|
247
|
+
integer(kind=8), intent(out) :: error_code
|
248
|
+
end subroutine'''
|
249
|
+
return self.get_lib_function('get_system_eigval_eigvec_without_damping')(n_modes, ny, eigenvalues, eigenvectors, error_code)
|
250
|
+
|
251
|
+
def get_system_matrices(self, n_tdofs, n_rdofs, M, C, K, R, error_code):
|
252
|
+
'''subroutine get_system_matrices(n_tdofs, n_rdofs, M, C, K, R, error_code) &
|
253
|
+
integer(kind=4), intent(in) :: n_tdofs
|
254
|
+
integer(kind=4), intent(in) :: n_rdofs
|
255
|
+
real(kind=c_double), dimension(n_rdofs, n_rdofs), intent(out) :: M
|
256
|
+
real(kind=c_double), dimension(n_rdofs, n_rdofs), intent(out) :: C
|
257
|
+
real(kind=c_double), dimension(n_rdofs, n_rdofs), intent(out) :: K
|
258
|
+
real(kind=c_double), dimension(n_tdofs, n_rdofs), intent(out) :: R
|
259
|
+
integer(kind=8), intent(out) :: error_code
|
260
|
+
end subroutine'''
|
261
|
+
return self.get_lib_function('get_system_matrices')(n_tdofs, n_rdofs, M, C, K, R, error_code)
|
262
|
+
|
221
263
|
def get_time(self, time):
|
222
264
|
'''subroutine
|
223
265
|
subroutine'''
|
@@ -254,6 +296,13 @@ end subroutine'''
|
|
254
296
|
end subroutine'''
|
255
297
|
return self.get_lib_function('init_windfield')(Nxyz, dxyz, box_offset_yz, transport_speed)
|
256
298
|
|
299
|
+
def linearize(self, n_tdofs, n_rdofs):
|
300
|
+
'''subroutine linearize(n_tdofs, n_rdofs) bind(C, name="linearize")
|
301
|
+
integer(kind=8), intent(out) :: n_tdofs
|
302
|
+
integer(kind=8), intent(out) :: n_rdofs
|
303
|
+
end subroutine'''
|
304
|
+
return self.get_lib_function('linearize')(n_tdofs, n_rdofs)
|
305
|
+
|
257
306
|
def loop(self, N, restype):
|
258
307
|
'''function loop(N) bind(C, Name='loop')
|
259
308
|
!DEC$ ATTRIBUTES DLLEXPORT :: loop
|
@@ -306,6 +355,45 @@ end subroutine'''
|
|
306
355
|
end subroutine'''
|
307
356
|
return self.get_lib_function('set_aerosections_windspeed')(rotor, uvw)
|
308
357
|
|
358
|
+
def set_orientation_base(self, main_body_name,
|
359
|
+
n_rows, mbdy_eulerang_table, angles_in_deg, reset_orientation, mbdy_ini_rotvec_d1,
|
360
|
+
error_code):
|
361
|
+
'''subroutine set_orientation_base(main_body_name, &
|
362
|
+
character(kind=c_char, len=1), dimension(256), intent(in) :: main_body_name
|
363
|
+
real(kind=c_double), dimension(n_rows, 3), intent(in) :: mbdy_eulerang_table
|
364
|
+
logical, intent(in) :: angles_in_deg
|
365
|
+
logical, intent(in) :: reset_orientation
|
366
|
+
real(kind=c_double), dimension(4), intent(in) :: mbdy_ini_rotvec_d1
|
367
|
+
end subroutine'''
|
368
|
+
return self.get_lib_function('set_orientation_base')(main_body_name,
|
369
|
+
n_rows, mbdy_eulerang_table, angles_in_deg, reset_orientation, mbdy_ini_rotvec_d1,
|
370
|
+
error_code)
|
371
|
+
|
372
|
+
def set_orientation_relative(self, main_body_1_name, node_1, main_body_2_name, node_2,
|
373
|
+
n_rows, mbdy2_eulerang_table, angles_in_deg,
|
374
|
+
reset_orientation,
|
375
|
+
mbdy2_ini_rotvec_d1,
|
376
|
+
error_code):
|
377
|
+
'''subroutine set_orientation_relative(main_body_1_name, node_1, main_body_2_name, node_2, &
|
378
|
+
character(kind=c_char, len=1), dimension(256), intent(in ) :: main_body_1_name ! Defined as an array of length 1 characters because of bind.
|
379
|
+
character(kind=c_char, len=1), dimension(256), intent(in ) :: main_body_2_name ! Defined as an array of length 1 characters because of bind.
|
380
|
+
integer(kind=8), intent(in ) :: node_1
|
381
|
+
integer(kind=8), intent(in ) :: node_2
|
382
|
+
real(kind=c_double), dimension(n_rows, 3), intent(in ) :: mbdy2_eulerang_table
|
383
|
+
logical, intent(in ) :: angles_in_deg
|
384
|
+
character(kind=c_char, len=256) :: mbdy_1_name ! Same as main_body_1_name, but as string instead of an array of characters.
|
385
|
+
character(kind=c_char, len=256) :: mbdy_2_name ! Same as main_body_2_name, but as string instead of an array of characters.
|
386
|
+
type(Tmain_body_input), pointer :: main_body_1 ! The main body pointer associated to main_body_1_name.
|
387
|
+
type(Tmain_body_input), pointer :: main_body_2 ! The main body pointer associated to main_body_1_name.
|
388
|
+
integer(kind=4) :: node_1_local, node_2_local ! Internal copy of node_1 and node_2.
|
389
|
+
real*8, dimension(3) :: eulerang ! Euler angles associated to 1 row of mbdy2_eulerang_table.
|
390
|
+
end subroutine'''
|
391
|
+
return self.get_lib_function('set_orientation_relative')(main_body_1_name, node_1, main_body_2_name, node_2,
|
392
|
+
n_rows, mbdy2_eulerang_table, angles_in_deg,
|
393
|
+
reset_orientation,
|
394
|
+
mbdy2_ini_rotvec_d1,
|
395
|
+
error_code)
|
396
|
+
|
309
397
|
def set_variable_sensor_value(self, id, value):
|
310
398
|
'''subroutine set_variable_sensor_value(id, value) bind(C, name="set_variable_sensor_value")
|
311
399
|
integer*8, intent(in) :: id
|
@@ -363,6 +451,12 @@ end subroutine'''
|
|
363
451
|
end function'''
|
364
452
|
return self.get_lib_function('step')(restype=restype)
|
365
453
|
|
454
|
+
def stop_on_error(self, flag):
|
455
|
+
'''subroutine stop_on_error(flag) bind(C, name="stop_on_error")
|
456
|
+
logical, intent(in) :: flag
|
457
|
+
end subroutine'''
|
458
|
+
return self.get_lib_function('stop_on_error')(flag)
|
459
|
+
|
366
460
|
def test_hdf5(self, ):
|
367
461
|
'''subroutine test_hdf5() BIND(C, NAME='test_hdf5')
|
368
462
|
!DEC$ ATTRIBUTES DLLEXPORT :: test_hdf5
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: h2lib
|
3
|
-
Version: 13.1.
|
4
|
-
Summary: Python interface to HAWC2 (13.1.
|
3
|
+
Version: 13.1.1701
|
4
|
+
Summary: Python interface to HAWC2 (13.1.17)
|
5
5
|
Download-URL:
|
6
6
|
Author: Mads M. Pedersen, S.G.Horcas and N.G.Ramos
|
7
7
|
Author-email: mmpe@dtu.dk
|
@@ -11,11 +11,10 @@ Project-URL: Documentation, https://hawc2.pages.windenergy.dtu.dk/HAWC2Lib/
|
|
11
11
|
Project-URL: Source, https://gitlab.windenergy.dtu.dk/HAWC2/HAWC2Lib
|
12
12
|
Project-URL: Tracker, https://gitlab.windenergy.dtu.dk/HAWC2/HAWC2Lib/-/issues
|
13
13
|
Requires-Dist: numpy
|
14
|
-
Requires-Dist: intel-fortran-rt
|
15
|
-
Requires-Dist: mkl
|
16
|
-
Requires-Dist:
|
17
|
-
Provides-Extra: mpi
|
18
|
-
Requires-Dist: mpi4py ; extra == 'mpi'
|
14
|
+
Requires-Dist: intel-fortran-rt==2021.3.0
|
15
|
+
Requires-Dist: mkl==2021.3.0
|
16
|
+
Requires-Dist: multiclass_interface>=1.5
|
19
17
|
Provides-Extra: test
|
20
|
-
Requires-Dist:
|
21
|
-
|
18
|
+
Requires-Dist: h2lib_tests; extra == "test"
|
19
|
+
Provides-Extra: mpi
|
20
|
+
Requires-Dist: mpi4py; extra == "mpi"
|
@@ -0,0 +1,10 @@
|
|
1
|
+
h2lib/HAWC2Lib.dll,sha256=2f3ye1UAvxStkuQdfZ45KsPuWatlk6OKQIRGFRM-qD4,30801920
|
2
|
+
h2lib/__init__.py,sha256=f3fO4I6IEFRM9LaV2O3w9Pioj3GPI8qRl7P5Tg5ONtE,528
|
3
|
+
h2lib/_h2lib.py,sha256=oCWMTpkui3KIxuZrQcyecBAv-KBKx0exTf3UC1WTJzc,35053
|
4
|
+
h2lib/_version.py,sha256=aoq7oNXs_pDNUhj3g7OPtlrQRPyElXusqp2iqfeyvps,149
|
5
|
+
h2lib/dll_wrapper.py,sha256=CfuRfDPEmmfYlEGKUmiXiuMhNiMcf24ripPHgqd8CiE,12761
|
6
|
+
h2lib/h2lib_signatures.py,sha256=1CuaSNfaTgnbhqcSaehQGNVHhKpvLFwgs2UucKWVQJE,24289
|
7
|
+
h2lib-13.1.1701.dist-info/METADATA,sha256=LiH31EtB7-lMnREX8IcRQ3Sj1V7F5HhJJ8W_yEjiF7s,722
|
8
|
+
h2lib-13.1.1701.dist-info/WHEEL,sha256=pWXrJbnZSH-J-PhYmKs2XNn4DHCPNBYq965vsBJBFvA,101
|
9
|
+
h2lib-13.1.1701.dist-info/top_level.txt,sha256=y_a-tUqphEZQ_0nsWSMaSb21P8Lsd8hUxUdE9g2Dcbk,6
|
10
|
+
h2lib-13.1.1701.dist-info/RECORD,,
|
h2lib-13.1.506.dist-info/RECORD
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
h2lib/HAWC2Lib.dll,sha256=_ECzaJeq1hmHTNyfA2oiyBf5qZKkeyepyF4Y8cyKLyc,30728192
|
2
|
-
h2lib/__init__.py,sha256=f3fO4I6IEFRM9LaV2O3w9Pioj3GPI8qRl7P5Tg5ONtE,528
|
3
|
-
h2lib/_h2lib.py,sha256=AVZODCr2c-NEosVTeqjZNU206MpnAVpmn_t3PolwjqM,22203
|
4
|
-
h2lib/_version.py,sha256=rV968fg9Lfv32R9TQD6ussF8dTsA74ZCbW8VTanCuus,146
|
5
|
-
h2lib/dll_wrapper.py,sha256=RC5_gJ1cwHXVfUaSvmsatyQrvks-aZJFAiXrG4B-FEI,12061
|
6
|
-
h2lib/h2lib_signatures.py,sha256=mqAqgg93ZEiglibECu8yDk-hy3MU8XDfAeXg-aokLk8,17961
|
7
|
-
h2lib-13.1.506.dist-info/METADATA,sha256=D3B2YjuywPU_q7nHchHr-2t5b2xOAU471mbaBI1j5UY,727
|
8
|
-
h2lib-13.1.506.dist-info/WHEEL,sha256=3vidnDuZ-QSnHIxLhNbI1gIM-KgyEcMHuZuv1mWPd_Q,101
|
9
|
-
h2lib-13.1.506.dist-info/top_level.txt,sha256=y_a-tUqphEZQ_0nsWSMaSb21P8Lsd8hUxUdE9g2Dcbk,6
|
10
|
-
h2lib-13.1.506.dist-info/RECORD,,
|
File without changes
|