h2lib-tests 13.1.506__py3-none-any.whl → 13.1.1701__py3-none-any.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_tests/test_h2lib.py CHANGED
@@ -328,3 +328,26 @@ def test_fail():
328
328
  # , match=re.escape('H2LibThread process died before or while executing fail(...)')):
329
329
  with pytest.raises(Exception):
330
330
  h2.fail('MyError')
331
+
332
+
333
+ def test_dont_stop(capfd):
334
+ # This test is the same as test_error(), but instead we disable stop.
335
+ model_path = tfp + "minimal/"
336
+ htc = HTCFile(model_path + 'htc/minimal_mann_turb.htc')
337
+ htc.wind.scale_time_start = 200
338
+ htc.wind.turb_format = 1
339
+ htc.wind.mann.dont_scale = 0
340
+ htc.set_name('tmp')
341
+ htc.save()
342
+
343
+ with H2Lib() as h2:
344
+ h2.stop_on_error(False)
345
+ h2.init('htc/tmp.htc', model_path)
346
+ out, err = capfd.readouterr()
347
+ assert "*** ERROR *** Turbulence scale_time_start >= simulation length" in out
348
+
349
+ with MultiH2Lib(2) as h2:
350
+ h2.stop_on_error(False)
351
+ h2.init('htc/tmp.htc', model_path)
352
+ out, err = capfd.readouterr()
353
+ assert "*** ERROR *** Turbulence scale_time_start >= simulation length" in out
@@ -4,10 +4,11 @@ from numpy import testing as npt
4
4
  import pytest
5
5
  from wetb.gtsdf import gtsdf
6
6
 
7
- from h2lib_tests.dtu10mw import DTU10MW
7
+ from h2lib_tests.dtu10mw import DTU10MW, DTU10MWRotor, DTU10MWSimple
8
8
  from h2lib_tests.test_files import tfp
9
9
  import matplotlib.pyplot as plt
10
10
  import numpy as np
11
+ from wetb.hawc2.at_time_file import AtTimeFile
11
12
 
12
13
 
13
14
  def get_h2(htc_path='htc/DTU_10MW_RWT.htc'):
@@ -115,7 +116,7 @@ def test_rotor_avg_windspeed():
115
116
 
116
117
  def test_aerosections():
117
118
  plot = False
118
- h2 = get_h2()
119
+ h2 = get_h2(htc_path='htc/DTU_10MW_RWT_no_aerodrag.htc')
119
120
  # blade 1, global coo, r>30
120
121
  pos_ids = [h2.add_sensor(f'aero position 3 1 {xyz} 30')[0] for xyz in [1, 2, 3]]
121
122
  wsp_ids = [h2.add_sensor(f'aero windspeed 3 1 {xyz} 30')[0] for xyz in [1, 2, 3]]
@@ -173,6 +174,111 @@ def test_aerosections():
173
174
  h2.close()
174
175
 
175
176
 
177
+ def test_compare_aerosection_coupling():
178
+ """Compare simulations with 1) htc wind and 2) similar wind set to aerodynamic sections
179
+
180
+ - yaw=20, tilt=10, cone=5
181
+ - two blades (to check that xyz/uvw are not mixed up with number of blades)
182
+ - stiff structure, fixed rotor speed and pitch
183
+ - linear shear and no turb
184
+ - aero_calc=1, induction=0, tiploss=0, dynstall=2
185
+ - aerodrag turned off (requires wind speed at aerodrag sections, not implemented yet)
186
+ """
187
+ dtu10 = DTU10MWSimple(rotor_speed=.6, pitch=0, nbodies=1)
188
+ dtu10.set_stiff()
189
+
190
+ dtu10.set_wind(8, tint=0, turb_format=0, shear=(4, .01))
191
+ dtu10.set_tilt_cone_yaw(tilt=10, cone=5, yaw=20)
192
+ # remove third blade
193
+ dtu10.aero.nblades = 2
194
+ dtu10.aero.link__3.delete()
195
+
196
+ dtu10.aerodrag.delete()
197
+
198
+ T = 20
199
+ dtu10.set_time(0, T)
200
+ dtu10.set_aero(aero_calc=1, induction=0, tiploss=0, dynstall=2)
201
+
202
+ for coo in [3, 4]:
203
+ for xyz in [1, 2, 3]:
204
+ dtu10.output.add_sensor('aero', 'windspeed', [coo, 1, xyz, 72, 1])
205
+ for coo in [3]:
206
+ for xyz in [1, 2, 3]:
207
+ dtu10.output.add_sensor('aero', 'position', [coo, 1, xyz, 72, 1])
208
+
209
+ # At time sensors
210
+ at = dtu10.add_section(f'output_at_time aero {T}')
211
+ at.filename = "tmp1_at"
212
+ for sensor in ['vrel', 'alfa', 'alfadot', 'cl', 'cd', 'cm', 'lift', 'drag', 'moment', 'ct_local', 'cq_local', 'tiploss_f',
213
+ 'chord', 'inflow_angle', 'dcldalfa', 'dcddalfa', 'twist']:
214
+ at.add_sensor('', sensor, [1])
215
+
216
+ for sensor in ['inipos']:
217
+ for xyz in [1, 2, 3]:
218
+ at.add_sensor('', sensor, [1, xyz])
219
+ for sensor in ['secforce', 'secmoment', 'int_moment', 'int_force', 'position', 'velocity', 'acceleration', 'induc',
220
+ 'windspeed']:
221
+ for coo in [1, 2, 3, 4]:
222
+ for xyz in [1, 2, 3]:
223
+ at.add_sensor('', sensor, [1, xyz, coo])
224
+
225
+ dtu10.set_name('tmp1')
226
+ dtu10.save()
227
+ with H2Lib(suppress_output=True) as h2:
228
+ h2.init(dtu10.filename, dtu10.modelpath)
229
+ h2.run(T)
230
+
231
+ dtu10.wind.wsp = 20 # ensure htc wind speed is different and induction is large in case it by mistake is not turned off
232
+ at.filename = "tmp2_at"
233
+ dtu10.set_name('tmp2')
234
+ dtu10.save()
235
+
236
+ with H2Lib(suppress_output=True) as h2:
237
+ h2.init(dtu10.filename, dtu10.modelpath)
238
+ last_pos_gl_xyz = np.array(h2.get_aerosections_position(), order='F')
239
+ while h2.time < T:
240
+ pos_gl_xyz = np.array(h2.get_aerosections_position(), order='F')
241
+ uvw = np.asfortranarray(pos_gl_xyz * 0)
242
+ dpos_gl_xyz = (pos_gl_xyz - last_pos_gl_xyz)
243
+ next_pos_gl_xyz = pos_gl_xyz + dpos_gl_xyz
244
+ uvw[:, :, 0] = (-next_pos_gl_xyz[:, :, 2] - 119) * .01 + 8
245
+ last_pos_gl_xyz = pos_gl_xyz.copy()
246
+ h2.set_aerosections_windspeed(uvw)
247
+ h2.step()
248
+
249
+ time, data1, info = gtsdf.load(tfp + 'DTU_10_MW/res/tmp1.hdf5')
250
+ time, data2, info = gtsdf.load(tfp + 'DTU_10_MW/res/tmp2.hdf5')
251
+ # exclude first time step where position extrapolation is not active
252
+ for n, c1, c2 in zip(info['attribute_names'], data1[1:].T, data2[1:].T):
253
+ if n not in ['WSP gl. coo.,Vx', 'WSP gl. coo.,Vy', 'WSP gl. coo.,Vz']: # nan
254
+ max_rel_err = np.abs(c2 - c1).max() / np.maximum(np.abs(c2).max(), 1)
255
+ try:
256
+ assert max_rel_err < 0.00001, n
257
+ except BaseException:
258
+ if 0:
259
+ plt.title(n)
260
+ plt.plot(c1)
261
+ plt.plot(c2)
262
+ plt.plot((c1 - c2))
263
+ plt.show()
264
+ raise
265
+
266
+ at1 = AtTimeFile(tfp + 'DTU_10_MW/tmp1_at.dat')
267
+ at2 = AtTimeFile(tfp + 'DTU_10_MW/tmp2_at.dat')
268
+ for n, c1, c2 in zip(at1.attribute_names, at1.data.T, at2.data.T):
269
+ npt.assert_allclose(c2, c1, atol=1e-6, rtol=0.0001, err_msg=n)
270
+ try:
271
+ assert max_rel_err < 0.00001, n
272
+ except BaseException:
273
+ if 1:
274
+ plt.title(n)
275
+ plt.plot(c1)
276
+ plt.plot(c2)
277
+ plt.plot(c1 - c2)
278
+ plt.show()
279
+ raise
280
+
281
+
176
282
  def test_iea15MW():
177
283
  with H2Lib(suppress_output=True) as h2:
178
284
  h2.read_input(htc_path='htc/IEA_15MW_RWT_Onshore.htc', model_path=tfp + 'IEA-15-240-RWT-Onshore')
@@ -0,0 +1,191 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Test the system-eigenanalysis.
4
+
5
+ @author: ricriv
6
+ """
7
+
8
+ # Here we are relying on the default behavior of pytest, which is to execute
9
+ # the tests in the same order that they are specified.
10
+ # If one day this will not be the case anymore, we can enforce the order by
11
+ # using the solution proposed at: https://stackoverflow.com/a/77793427/3676517
12
+
13
+ import pytest
14
+
15
+ import numpy as np
16
+ from numpy import testing as npt
17
+
18
+ from h2lib._h2lib import H2Lib
19
+ from h2lib_tests.test_files import tfp
20
+
21
+
22
+ def test_system_not_linearized_1(h2_dtu_10mw_only_blade):
23
+ with pytest.raises(RuntimeError, match="SYSTEM_NOT_LINEARIZED"):
24
+ h2_dtu_10mw_only_blade.do_system_eigenanalysis(2)
25
+
26
+
27
+ def test_system_not_linearized_2(h2_dtu_10mw_only_blade):
28
+ with pytest.raises(RuntimeError, match="SYSTEM_NOT_LINEARIZED"):
29
+ h2_dtu_10mw_only_blade.get_system_eigenvalues_and_eigenvectors(2, 2)
30
+
31
+
32
+ def test_system_not_linearized_3(h2_dtu_10mw_only_blade):
33
+ with pytest.raises(RuntimeError, match="SYSTEM_NOT_LINEARIZED"):
34
+ h2_dtu_10mw_only_blade.get_system_matrices(312, 156)
35
+
36
+
37
+ def test_linearize(h2_dtu_10mw_only_blade):
38
+ n_tdofs, n_rdofs = h2_dtu_10mw_only_blade.linearize()
39
+ assert n_rdofs == 26 * 6 # = number of nodes * 6
40
+ assert n_tdofs == 26 * 6 * 2 # times 2 because of speed.
41
+
42
+
43
+ def test_too_many_modes(h2_dtu_10mw_only_blade):
44
+ with pytest.raises(ValueError, match="TOO_MANY_MODES_REQUESTED"):
45
+ h2_dtu_10mw_only_blade.do_system_eigenanalysis(n_modes=1000)
46
+
47
+
48
+ def test_sys_eig_not_done(h2_dtu_10mw_only_blade):
49
+ with pytest.raises(RuntimeError, match="SYSTEM_EIGENANALYSIS_NOT_DONE"):
50
+ h2_dtu_10mw_only_blade.get_system_eigenvalues_and_eigenvectors(2, 2)
51
+
52
+
53
+ def test_sys_eig_no_damping(h2_dtu_10mw_only_blade):
54
+ natural_frequencies = h2_dtu_10mw_only_blade.do_system_eigenanalysis(
55
+ n_modes=4, include_damping=False
56
+ )
57
+ # Test against: result at the time of writing.
58
+ npt.assert_allclose(
59
+ natural_frequencies,
60
+ np.array([0.610409, 0.930466, 1.739094, 2.761632]),
61
+ rtol=1e-6,
62
+ )
63
+
64
+
65
+ def test_sys_eig_no_damping_wrong_n_modes(h2_dtu_10mw_only_blade):
66
+ with pytest.raises(ValueError, match="TOO_MANY_MODES_REQUESTED"):
67
+ h2_dtu_10mw_only_blade.get_system_eigenvalues_and_eigenvectors(
68
+ 1000, 156
69
+ )
70
+
71
+
72
+ def test_sys_eig_no_damping_wrong_ny(h2_dtu_10mw_only_blade):
73
+ with pytest.raises(ValueError, match="WRONG_REDUCED_DOF"):
74
+ h2_dtu_10mw_only_blade.get_system_eigenvalues_and_eigenvectors(4, 2)
75
+
76
+
77
+ def test_sys_eig_no_damping_eigv(h2_dtu_10mw_only_blade):
78
+ n_modes = 4
79
+ n_rdofs = 156
80
+ eig_val, eig_vec = (
81
+ h2_dtu_10mw_only_blade.get_system_eigenvalues_and_eigenvectors(
82
+ n_modes, n_rdofs, include_damping=False
83
+ )
84
+ )
85
+ assert eig_val.size == n_modes
86
+ assert eig_vec.shape == (n_modes, n_rdofs)
87
+ assert eig_val.dtype == np.float64
88
+ assert eig_vec.dtype == np.float64
89
+ npt.assert_allclose(
90
+ eig_val,
91
+ np.array([3.83531, 5.846293, 10.927047, 17.351849]),
92
+ )
93
+
94
+
95
+ def test_sys_eig_with_damping(h2_dtu_10mw_only_blade):
96
+ freq, damp = h2_dtu_10mw_only_blade.do_system_eigenanalysis(
97
+ n_modes=4, include_damping=True
98
+ )
99
+ # Test against: result at the time of writing.
100
+ npt.assert_allclose(
101
+ freq, np.array([0.610409, 0.930468, 1.739098, 2.761702]), rtol=1e-6
102
+ )
103
+ npt.assert_allclose(
104
+ damp, np.array([0.004826, 0.004758, 0.013395, 0.014194]), atol=1e-6
105
+ )
106
+
107
+
108
+ def test_sys_eig_with_damping_eigv(h2_dtu_10mw_only_blade):
109
+ n_modes = 4
110
+ n_rdofs = 156
111
+ eig_val, eig_vec = (
112
+ h2_dtu_10mw_only_blade.get_system_eigenvalues_and_eigenvectors(
113
+ n_modes, n_rdofs, include_damping=True
114
+ )
115
+ )
116
+ assert eig_val.size == n_modes
117
+ assert eig_vec.shape == (n_modes, 2 * n_rdofs)
118
+ assert eig_val.dtype == np.complex128
119
+ assert eig_vec.dtype == np.complex128
120
+ npt.assert_allclose(
121
+ eig_val,
122
+ np.array(
123
+ [
124
+ -0.01851 - 3.835266j,
125
+ -0.027817 - 5.846237j,
126
+ -0.146367 - 10.926094j,
127
+ -0.246296 - 17.350536j,
128
+ ]
129
+ ),
130
+ atol=1e-6,
131
+ )
132
+
133
+
134
+ def test_get_system_matrices_wrong_nt(h2_dtu_10mw_only_blade):
135
+ with pytest.raises(ValueError, match="WRONG_TOTAL_DOF"):
136
+ h2_dtu_10mw_only_blade.get_system_matrices(300, 156)
137
+
138
+
139
+ def test_get_system_matrices_wrong_nr(h2_dtu_10mw_only_blade):
140
+ with pytest.raises(ValueError, match="WRONG_REDUCED_DOF"):
141
+ h2_dtu_10mw_only_blade.get_system_matrices(312, 150)
142
+
143
+
144
+ def test_get_system_matrices(h2_dtu_10mw_only_blade):
145
+ n_rdofs = 26 * 6
146
+ n_tdofs = 2 * n_rdofs
147
+ M, C, K, R = h2_dtu_10mw_only_blade.get_system_matrices(n_tdofs, n_rdofs)
148
+ assert M.shape == (n_rdofs, n_rdofs)
149
+ assert C.shape == (n_rdofs, n_rdofs)
150
+ assert K.shape == (n_rdofs, n_rdofs)
151
+ assert R.shape == (n_tdofs, n_rdofs)
152
+
153
+
154
+ def test_sys_eig_encrypted(h2_dtu_10mw_only_tower_encrypted):
155
+ n_tdofs, n_rdofs = h2_dtu_10mw_only_tower_encrypted.linearize()
156
+ n_modes = 4
157
+ freq, damp = h2_dtu_10mw_only_tower_encrypted.do_system_eigenanalysis(
158
+ n_modes=n_modes, include_damping=True
159
+ )
160
+ eig_val = h2_dtu_10mw_only_tower_encrypted.get_system_eigenvalues_and_eigenvectors(
161
+ n_modes=n_modes, n_rdofs=n_rdofs, include_damping=True
162
+ )
163
+ npt.assert_allclose(
164
+ freq,
165
+ np.array([0.770592, 0.770592, 3.449993, 3.449993]),
166
+ rtol=1e-6,
167
+ )
168
+
169
+ npt.assert_allclose(
170
+ damp,
171
+ np.array([0.010006, 0.010006, 0.044675, 0.044675]),
172
+ atol=1e-6,
173
+ )
174
+ npt.assert_allclose(
175
+ eig_val,
176
+ np.array(
177
+ [
178
+ -0.048444 - 4.84153j,
179
+ -0.048444 - 4.84153j,
180
+ -0.968409 - 21.6553j,
181
+ -0.968409 - 21.6553j,
182
+ ]
183
+ ),
184
+ atol=1e-6,
185
+ )
186
+
187
+
188
+ def test_test_get_system_matrices_encrypted(h2_dtu_10mw_only_tower_encrypted):
189
+ n_tdofs, n_rdofs = h2_dtu_10mw_only_tower_encrypted.linearize()
190
+ with pytest.raises(RuntimeError, match="STRUCTURE_IS_CONFIDENTIAL"):
191
+ h2_dtu_10mw_only_tower_encrypted.get_system_matrices(n_tdofs, n_rdofs)
h2lib_tests/test_mpi.py CHANGED
@@ -110,7 +110,7 @@ def ellipsys_mpi_dummy_workflow():
110
110
 
111
111
  with MultiH2Lib(N, suppress_output=True) as h2:
112
112
  el = Ellipsys()
113
- htc = HTCFile(tfp + 'DTU_10_MW/htc/DTU_10MW_RWT.htc')
113
+ htc = HTCFile(tfp + 'DTU_10_MW/htc/DTU_10MW_RWT_no_aerodrag.htc')
114
114
  for i in range(N):
115
115
  htc.set_name(f'wt{i}')
116
116
  htc.save()
@@ -18,31 +18,6 @@ from numpy import testing as npt
18
18
  from h2lib._h2lib import H2Lib
19
19
  from h2lib_tests.test_files import tfp
20
20
 
21
- from .test_write_htc import (
22
- write_dtu10mw_only_blade,
23
- write_dtu10mw_only_blade_low_max_iter,
24
- )
25
-
26
-
27
- @pytest.fixture(scope="module")
28
- def h2_dtu_10mw_only_blade(write_dtu10mw_only_blade):
29
- h2 = H2Lib(suppress_output=True)
30
- model_path = f"{tfp}DTU_10_MW/"
31
- htc_path = "htc/DTU_10MW_RWT_only_blade.htc"
32
- h2.init(htc_path=htc_path, model_path=model_path)
33
- yield h2
34
- h2.close()
35
-
36
-
37
- @pytest.fixture(scope="module")
38
- def h2_dtu10mw_only_blade_low_max_iter(write_dtu10mw_only_blade_low_max_iter):
39
- h2 = H2Lib(suppress_output=True)
40
- model_path = f"{tfp}DTU_10_MW/"
41
- htc_path = "htc/DTU_10MW_RWT_only_blade_low_max_iter.htc"
42
- h2.init(htc_path=htc_path, model_path=model_path)
43
- yield h2
44
- h2.close()
45
-
46
21
 
47
22
  def test_solver_static_update_no_init(h2_dtu_10mw_only_blade):
48
23
  with pytest.raises(RuntimeError, match="STATIC_SOLVER_NOT_INITIALIZED"):
@@ -77,7 +52,13 @@ def test_solver_static_delete(h2_dtu_10mw_only_blade):
77
52
  h2_dtu_10mw_only_blade.solver_static_delete()
78
53
 
79
54
 
80
- def test_static_solver_run(h2_dtu_10mw_only_blade):
55
+ def test_static_solver_run_fail(h2_dtu10mw_only_blade_low_max_iter):
56
+ with pytest.raises(RuntimeError, match="STATIC_SOLVER_DID_NOT_CONVERGE"):
57
+ h2_dtu10mw_only_blade_low_max_iter.solver_static_run()
58
+
59
+
60
+ def test_static_solver_run_1(h2_dtu_10mw_only_blade):
61
+ # Use gravity to deflect the clamped blade.
81
62
  # Add a sensor for the blade root moment, in this case only due to gravity.
82
63
  id = h2_dtu_10mw_only_blade.add_sensor("mbdy momentvec blade1 1 1 blade1")
83
64
 
@@ -93,6 +74,52 @@ def test_static_solver_run(h2_dtu_10mw_only_blade):
93
74
  )
94
75
 
95
76
 
96
- def test_static_solver_run_fail(h2_dtu10mw_only_blade_low_max_iter):
97
- with pytest.raises(RuntimeError, match="STATIC_SOLVER_DID_NOT_CONVERGE"):
98
- h2_dtu10mw_only_blade_low_max_iter.solver_static_run()
77
+ def test_static_solver_run_2(h2_dtu_10mw_only_blade_rotate_base):
78
+ # Apply centrifugal loading with the base command.
79
+ # Add a sensor for the blade root force, in this case only due to centrifugal force.
80
+ id = h2_dtu_10mw_only_blade_rotate_base.add_sensor("mbdy forcevec blade1 1 1 blade1")
81
+
82
+ # Run the static solver.
83
+ h2_dtu_10mw_only_blade_rotate_base.solver_static_run()
84
+
85
+ # Do 1 step to get the output.
86
+ h2_dtu_10mw_only_blade_rotate_base.step()
87
+ val = h2_dtu_10mw_only_blade_rotate_base.get_sensor_values(id)
88
+ # Test against: result at the time of writing.
89
+ npt.assert_allclose(
90
+ val, np.array([10879.129998, 383.43168, 989.68145])
91
+ )
92
+
93
+
94
+ def test_static_solver_run_3(h2_dtu_10mw_only_blade_rotate_relative):
95
+ # Apply centrifugal loading with the relative command.
96
+ # Add a sensor for the blade root force, in this case only due to centrifugal force.
97
+ id = h2_dtu_10mw_only_blade_rotate_relative.add_sensor("mbdy forcevec blade1 1 1 blade1")
98
+
99
+ # Run the static solver.
100
+ h2_dtu_10mw_only_blade_rotate_relative.solver_static_run()
101
+
102
+ # Do 1 step to get the output.
103
+ h2_dtu_10mw_only_blade_rotate_relative.step()
104
+ val = h2_dtu_10mw_only_blade_rotate_relative.get_sensor_values(id)
105
+ # Test against: result at the time of writing.
106
+ npt.assert_allclose(
107
+ val, np.array([10879.083576, 383.430039, 989.67935])
108
+ )
109
+
110
+
111
+ def test_static_solver_run_4(h2_dtu_10mw_only_blade_rotate_bearing3):
112
+ # Apply centrifugal loading with the bearing3 command.
113
+ # Add a sensor for the blade root moment, in this case only due to centrifugal force.
114
+ id = h2_dtu_10mw_only_blade_rotate_bearing3.add_sensor("mbdy momentvec blade1 1 1 blade1")
115
+
116
+ # Run the static solver.
117
+ h2_dtu_10mw_only_blade_rotate_bearing3.solver_static_run()
118
+
119
+ # Do 1 step to get the output.
120
+ h2_dtu_10mw_only_blade_rotate_bearing3.step()
121
+ val = h2_dtu_10mw_only_blade_rotate_bearing3.get_sensor_values(id)
122
+ # Test against: result at the time of writing.
123
+ npt.assert_allclose(
124
+ val, np.array([-3094.986918, 115414.095937, 325.296806])
125
+ )