Skip to content

Commit a7bef5f

Browse files
authored
actually test power solution for irregular wave (#327)
1 parent 775d273 commit a7bef5f

File tree

1 file changed

+50
-40
lines changed

1 file changed

+50
-40
lines changed

tests/test_integration.py

Lines changed: 50 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111

1212
kplim = -1e1
13-
13+
min_damping = 45
1414

1515
@pytest.fixture(scope="module")
1616
def f1():
@@ -73,10 +73,13 @@ def fb():
7373

7474

7575
@pytest.fixture(scope="module")
76-
def bem(f1, nfreq, fb):
77-
"""Boundary elemement model (Capytaine) results"""
76+
def hydro_data(f1, nfreq, fb):
77+
"""Boundary element model (Capytaine) results (with friction added)"""
7878
freq = wot.frequency(f1, nfreq, False)
79-
return wot.run_bem(fb, freq)
79+
hydro_data = wot.run_bem(fb, freq)
80+
hd = wot.add_linear_friction(hydro_data)
81+
hd = wot.check_radiation_damping(hd, min_damping=min_damping)
82+
return hd
8083

8184

8285
@pytest.fixture(scope='module')
@@ -91,36 +94,42 @@ def regular_wave(f1, nfreq):
9194

9295

9396
@pytest.fixture(scope='module')
94-
def irregular_wave(f1, nfreq):
97+
def long_crested_wave(f1, nfreq):
9598
"""Idealized (Pierson-Moskowitz) spectrum wave"""
9699
freq = wot.frequency(f1, nfreq, False)
97100
fp = 0.3
98101
hs = 0.0625*1.9
99-
spec = wot.waves.pierson_moskowitz_spectrum(freq, fp, hs)
100-
waves = wot.waves.long_crested_wave(spec)
102+
spec_fun = lambda f: wot.waves.pierson_moskowitz_spectrum(freq=f,
103+
fp=fp,
104+
hs=hs)
105+
efth = wot.waves.omnidirectional_spectrum(f1=f1, nfreq=nfreq,
106+
spectrum_func=spec_fun,
107+
)
108+
waves = wot.waves.long_crested_wave(efth, nrealizations=1)
101109
return waves
102110

103111

104112
@pytest.fixture(scope='module')
105-
def wec_from_bem(f1, nfreq, bem, fb, pto):
113+
def wec_from_bem(f1, nfreq, hydro_data, fb, pto):
106114
"""Simple WEC: 1 DOF, no constraints."""
107115
f_add = {"PTO": pto.force_on_wec}
108-
wec = wot.WEC.from_bem(bem, f_add=f_add)
116+
wec = wot.WEC.from_bem(hydro_data, f_add=f_add)
109117
return wec
110118

111119

112120
@pytest.fixture(scope='module')
113121
def wec_from_floatingbody(f1, nfreq, fb, pto):
114122
"""Simple WEC: 1 DOF, no constraints."""
115123
f_add = {"PTO": pto.force_on_wec}
116-
wec = wot.WEC.from_floating_body(fb, f1, nfreq, f_add=f_add)
124+
wec = wot.WEC.from_floating_body(fb, f1, nfreq, f_add=f_add,
125+
min_damping=min_damping)
117126
return wec
118127

119128

120129
@pytest.fixture(scope='module')
121-
def wec_from_impedance(bem, pto, fb):
130+
def wec_from_impedance(hydro_data, pto, fb):
122131
"""Simple WEC: 1 DOF, no constraints."""
123-
bemc = bem.copy()
132+
bemc = hydro_data.copy()
124133
omega = bemc['omega'].values
125134
w = np.expand_dims(omega, [1,2])
126135
A = bemc['added_mass'].values
@@ -134,17 +143,18 @@ def wec_from_impedance(bem, pto, fb):
134143

135144
freqs = omega / (2 * np.pi)
136145
impedance = (A + mass)*(1j*w) + B + K/(1j*w)
137-
exc_coeff = bem['Froude_Krylov_force'] + bem['diffraction_force']
146+
exc_coeff = hydro_data['Froude_Krylov_force'] + hydro_data['diffraction_force']
138147
f_add = {"PTO": pto.force_on_wec}
139148

140-
wec = wot.WEC.from_impedance(freqs, impedance, exc_coeff, hstiff, f_add)
149+
wec = wot.WEC.from_impedance(freqs, impedance, exc_coeff, hstiff, f_add,
150+
min_damping=min_damping)
141151
return wec
142152

143153

144154
@pytest.fixture(scope='module')
145-
def resonant_wave(f1, nfreq, fb, bem):
155+
def resonant_wave(f1, nfreq, fb, hydro_data):
146156
"""Regular wave at natural frequency of the WEC"""
147-
hd = wot.add_linear_friction(bem)
157+
hd = wot.add_linear_friction(hydro_data)
148158
Zi = wot.hydrodynamic_impedance(hd)
149159
wn = Zi['omega'][np.abs(Zi).argmin(dim='omega')].item()
150160
waves = wot.waves.regular_wave(f1, nfreq, freq=wn/2/np.pi, amplitude=0.1)
@@ -231,23 +241,21 @@ def hstiff(self, fb):
231241
return fb.compute_hydrostatic_stiffness()
232242

233243
@pytest.fixture(scope='class')
234-
def hydro_impedance(self, bem):
244+
def hydro_impedance(self, hydro_data):
235245
"""Intrinsic hydrodynamic impedance"""
236-
hd = wot.add_linear_friction(bem)
237-
hd = wot.check_radiation_damping(hd)
238-
Zi = wot.hydrodynamic_impedance(hd)
246+
Zi = wot.hydrodynamic_impedance(hydro_data)
239247
return Zi
240248

241249
def test_p_controller_resonant_wave(self,
242-
bem,
250+
hydro_data,
243251
resonant_wave,
244252
p_controller_pto,
245253
hydro_impedance):
246254
"""Proportional controller should match optimum for natural resonant
247255
wave"""
248256

249257
f_add = {"PTO": p_controller_pto.force_on_wec}
250-
wec = wot.WEC.from_bem(bem, f_add=f_add)
258+
wec = wot.WEC.from_bem(hydro_data, f_add=f_add)
251259

252260
res = wec.solve(waves=resonant_wave,
253261
obj_fun=p_controller_pto.average_power,
@@ -272,14 +280,14 @@ def test_p_controller_resonant_wave(self,
272280
assert power_sol == approx(power_optimal, rel=0.03)
273281

274282
def test_pi_controller_regular_wave(self,
275-
bem,
283+
hydro_data,
276284
regular_wave,
277285
pi_controller_pto,
278286
hydro_impedance):
279287
"""PI controller matches optimal for any regular wave"""
280288

281289
f_add = {"PTO": pi_controller_pto.force_on_wec}
282-
wec = wot.WEC.from_bem(bem, f_add=f_add)
290+
wec = wot.WEC.from_bem(hydro_data, f_add=f_add)
283291

284292
res = wec.solve(waves=regular_wave,
285293
obj_fun=pi_controller_pto.average_power,
@@ -302,20 +310,20 @@ def test_pi_controller_regular_wave(self,
302310
).squeeze().sum('omega').item()
303311

304312
assert power_sol == approx(power_optimal, rel=1e-4)
305-
def test_unstructured_controller_irregular_wave(self,
306-
fb,
307-
bem,
308-
regular_wave,
309-
pto,
310-
nfreq,
311-
hydro_impedance):
313+
314+
def test_unstructured_controller_long_crested_wave(self,
315+
hydro_data,
316+
long_crested_wave,
317+
pto,
318+
nfreq,
319+
hydro_impedance):
312320
"""Unstructured (numerical optimal) controller matches optimal for any
313-
irregular wave when unconstrained"""
321+
irregular (long crested) wave when unconstrained"""
314322

315323
f_add = {"PTO": pto.force_on_wec}
316-
wec = wot.WEC.from_bem(bem, f_add=f_add)
324+
wec = wot.WEC.from_bem(hydro_data, f_add=f_add)
317325

318-
res = wec.solve(waves=regular_wave,
326+
res = wec.solve(waves=long_crested_wave,
319327
obj_fun=pto.average_power,
320328
nstate_opt=2*nfreq,
321329
x_wec_0=1e-1*np.ones(wec.nstate_wec),
@@ -326,16 +334,18 @@ def test_unstructured_controller_irregular_wave(self,
326334

327335
power_sol = -1*res[0]['fun']
328336

329-
res_fd, _ = wec.post_process(res[0], regular_wave.sel(realization=0), nsubsteps=1)
337+
res_fd, _ = wec.post_process(res[0],
338+
long_crested_wave.sel(realization=0),
339+
nsubsteps=1)
330340
Fex = res_fd.force.sel(
331341
type=['Froude_Krylov', 'diffraction']).sum('type')
332342
power_optimal = (np.abs(Fex)**2/8 / np.real(hydro_impedance.squeeze())
333-
).squeeze().sum('omega').item()
343+
).squeeze().sum('omega').item()
334344

335-
assert power_sol == approx(power_optimal, rel=1e-3)
345+
assert power_sol == approx(power_optimal, rel=1e-2)
336346

337347
def test_saturated_pi_controller(self,
338-
bem,
348+
hydro_data,
339349
regular_wave,
340350
pto,
341351
nfreq):
@@ -357,7 +367,7 @@ def const_f_pto(wec, x_wec, x_opt, waves):
357367
f = pto['us'].force_on_wec(wec, x_wec, x_opt, waves,
358368
nsubsteps=4)
359369
return f_max - np.abs(f.flatten())
360-
wec['us'] = wot.WEC.from_bem(bem,
370+
wec['us'] = wot.WEC.from_bem(hydro_data,
361371
f_add={"PTO": pto['us'].force_on_wec},
362372
constraints=[{'type': 'ineq',
363373
'fun': const_f_pto, }])
@@ -372,7 +382,7 @@ def saturated_pi(pto, wec, x_wec, x_opt, waves=None, nsubsteps=1):
372382
pto['pi'] = wot.pto.PTO(ndof=ndof,
373383
kinematics=np.eye(ndof),
374384
controller=saturated_pi,)
375-
wec['pi'] = wot.WEC.from_bem(bem,
385+
wec['pi'] = wot.WEC.from_bem(hydro_data,
376386
f_add={"PTO": pto['pi'].force_on_wec},
377387
constraints=[])
378388

0 commit comments

Comments
 (0)