Skip to content
Merged
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
a5459a6
Merge commit 'd3497e352a069470cba8645444e52958a9b4400f'
rgcoe Mar 16, 2022
dc63ad8
Merge commit '6f11bd30fa0fcde98a0c67ecb41b8407a20fe381'
rgcoe Mar 23, 2022
4671cde
Merge remote-tracking branch 'upstream/main'
rgcoe Apr 7, 2022
91bf3e2
Merge commit '7132f8ea404dc5f006b7191164e70794eb767c5f'
rgcoe Apr 12, 2022
ae4a807
Merge remote-tracking branch 'upstream/main'
rgcoe Jun 16, 2022
5f36d5b
Merge remote-tracking branch 'upstream/main'
rgcoe Oct 25, 2022
5dc756d
Merge remote-tracking branch 'upstream/main'
rgcoe Nov 1, 2022
06b0650
Merge remote-tracking branch 'upstream/main'
rgcoe Nov 2, 2022
0c043f6
Merge remote-tracking branch 'upstream/main'
rgcoe Nov 22, 2022
e6e9a5a
Merge remote-tracking branch 'upstream/main'
rgcoe Nov 23, 2022
f599401
Merge remote-tracking branch 'upstream/main'
rgcoe Dec 8, 2022
828b26a
Merge remote-tracking branch 'upstream/main'
rgcoe Dec 16, 2022
d53fefe
Merge commit 'abb2097c910db0aac04e398acd6bc29a240adde6'
rgcoe Dec 28, 2022
84de794
Merge remote-tracking branch 'upstream/main'
rgcoe Jan 4, 2023
f11963f
Merge remote-tracking branch 'upstream/main'
rgcoe Jan 31, 2023
fdbd233
Merge remote-tracking branch 'upstream/main'
rgcoe Feb 22, 2023
76f1eaa
Merge remote-tracking branch 'upstream/main'
rgcoe Apr 11, 2023
c83bc45
Merge remote-tracking branch 'upstream/main'
rgcoe Apr 13, 2023
cdd3aa5
Merge remote-tracking branch 'upstream/main'
rgcoe May 5, 2023
b48465c
Merge remote-tracking branch 'sandialabs/main'
rgcoe May 25, 2023
84793cc
Merge remote-tracking branch 'sandialabs/main'
rgcoe Jul 13, 2023
6c9b852
Merge remote-tracking branch 'upstream/main'
rgcoe Oct 6, 2023
c36083a
Merge commit 'c74e4fcb1084d1a21c1709aee38005da935194a7'
rgcoe Oct 19, 2023
0d04f32
Merge commit 'e5e291f848f41589e0b63affe04726d1b49720c5'
rgcoe Nov 1, 2023
eeed5a9
Merge commit '618d7ebad0166cbc3a62371c3713bba8bc2348e1'
rgcoe Nov 13, 2023
2ef25f4
Merge remote-tracking branch 'upstream/main'
rgcoe Feb 5, 2024
7c7f452
use long_crested irregular wave
rgcoe Apr 2, 2024
4099c1f
loosen tolerance
rgcoe Apr 2, 2024
0b489f7
update docstring
rgcoe Apr 2, 2024
f462c68
remove unused argument
rgcoe Apr 2, 2024
561e1aa
Merge remote-tracking branch 'upstream/dev' into test_unstructured_co…
rgcoe Apr 2, 2024
014ca33
use consistent damping shift
rgcoe Apr 2, 2024
2e4f4c4
Merge commit '775d2734de3e1280e52675cbeaa1ab6192af0eb9' into test_uns…
rgcoe Apr 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 50 additions & 40 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@


kplim = -1e1

min_damping = 45

@pytest.fixture(scope="module")
def f1():
Expand Down Expand Up @@ -73,10 +73,13 @@ def fb():


@pytest.fixture(scope="module")
def bem(f1, nfreq, fb):
"""Boundary elemement model (Capytaine) results"""
def hydro_data(f1, nfreq, fb):
"""Boundary element model (Capytaine) results (with friction added)"""
freq = wot.frequency(f1, nfreq, False)
return wot.run_bem(fb, freq)
hydro_data = wot.run_bem(fb, freq)
hd = wot.add_linear_friction(hydro_data)
hd = wot.check_radiation_damping(hd, min_damping=min_damping)
return hd


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


@pytest.fixture(scope='module')
def irregular_wave(f1, nfreq):
def long_crested_wave(f1, nfreq):
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note that this is actually a long_crested_wave in our nomenclature

"""Idealized (Pierson-Moskowitz) spectrum wave"""
freq = wot.frequency(f1, nfreq, False)
fp = 0.3
hs = 0.0625*1.9
spec = wot.waves.pierson_moskowitz_spectrum(freq, fp, hs)
waves = wot.waves.long_crested_wave(spec)
spec_fun = lambda f: wot.waves.pierson_moskowitz_spectrum(freq=f,
fp=fp,
hs=hs)
efth = wot.waves.omnidirectional_spectrum(f1=f1, nfreq=nfreq,
spectrum_func=spec_fun,
)
waves = wot.waves.long_crested_wave(efth, nrealizations=1)
return waves


@pytest.fixture(scope='module')
def wec_from_bem(f1, nfreq, bem, fb, pto):
def wec_from_bem(f1, nfreq, hydro_data, fb, pto):
"""Simple WEC: 1 DOF, no constraints."""
f_add = {"PTO": pto.force_on_wec}
wec = wot.WEC.from_bem(bem, f_add=f_add)
wec = wot.WEC.from_bem(hydro_data, f_add=f_add)
return wec


@pytest.fixture(scope='module')
def wec_from_floatingbody(f1, nfreq, fb, pto):
"""Simple WEC: 1 DOF, no constraints."""
f_add = {"PTO": pto.force_on_wec}
wec = wot.WEC.from_floating_body(fb, f1, nfreq, f_add=f_add)
wec = wot.WEC.from_floating_body(fb, f1, nfreq, f_add=f_add,
min_damping=min_damping)
return wec


@pytest.fixture(scope='module')
def wec_from_impedance(bem, pto, fb):
def wec_from_impedance(hydro_data, pto, fb):
"""Simple WEC: 1 DOF, no constraints."""
bemc = bem.copy()
bemc = hydro_data.copy()
omega = bemc['omega'].values
w = np.expand_dims(omega, [1,2])
A = bemc['added_mass'].values
Expand All @@ -134,17 +143,18 @@ def wec_from_impedance(bem, pto, fb):

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

wec = wot.WEC.from_impedance(freqs, impedance, exc_coeff, hstiff, f_add)
wec = wot.WEC.from_impedance(freqs, impedance, exc_coeff, hstiff, f_add,
min_damping=min_damping)
return wec


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

@pytest.fixture(scope='class')
def hydro_impedance(self, bem):
def hydro_impedance(self, hydro_data):
"""Intrinsic hydrodynamic impedance"""
hd = wot.add_linear_friction(bem)
hd = wot.check_radiation_damping(hd)
Zi = wot.hydrodynamic_impedance(hd)
Zi = wot.hydrodynamic_impedance(hydro_data)
return Zi

def test_p_controller_resonant_wave(self,
bem,
hydro_data,
resonant_wave,
p_controller_pto,
hydro_impedance):
"""Proportional controller should match optimum for natural resonant
wave"""

f_add = {"PTO": p_controller_pto.force_on_wec}
wec = wot.WEC.from_bem(bem, f_add=f_add)
wec = wot.WEC.from_bem(hydro_data, f_add=f_add)

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

def test_pi_controller_regular_wave(self,
bem,
hydro_data,
regular_wave,
pi_controller_pto,
hydro_impedance):
"""PI controller matches optimal for any regular wave"""

f_add = {"PTO": pi_controller_pto.force_on_wec}
wec = wot.WEC.from_bem(bem, f_add=f_add)
wec = wot.WEC.from_bem(hydro_data, f_add=f_add)

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

assert power_sol == approx(power_optimal, rel=1e-4)
def test_unstructured_controller_irregular_wave(self,
fb,
bem,
regular_wave,
pto,
nfreq,
hydro_impedance):
def test_unstructured_controller_long_crested_wave(self,
hydro_data,
long_crested_wave,
pto,
nfreq,
hydro_impedance):
"""Unstructured (numerical optimal) controller matches optimal for any
irregular wave when unconstrained"""
irregular (long crested) wave when unconstrained"""

f_add = {"PTO": pto.force_on_wec}
wec = wot.WEC.from_bem(bem, f_add=f_add)
wec = wot.WEC.from_bem(hydro_data, f_add=f_add)

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

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

res_fd, _ = wec.post_process(res[0], regular_wave.sel(realization=0), nsubsteps=1)
res_fd, _ = wec.post_process(res[0],
long_crested_wave.sel(realization=0),
nsubsteps=1)
Fex = res_fd.force.sel(
type=['Froude_Krylov', 'diffraction']).sum('type')
power_optimal = (np.abs(Fex)**2/8 / np.real(hydro_impedance.squeeze())
).squeeze().sum('omega').item()
).squeeze().sum('omega').item()

assert power_sol == approx(power_optimal, rel=1e-3)
assert power_sol == approx(power_optimal, rel=1e-2)

def test_saturated_pi_controller(self,
bem,
hydro_data,
regular_wave,
pto,
nfreq):
Expand All @@ -357,7 +367,7 @@ def const_f_pto(wec, x_wec, x_opt, waves):
f = pto['us'].force_on_wec(wec, x_wec, x_opt, waves,
nsubsteps=4)
return f_max - np.abs(f.flatten())
wec['us'] = wot.WEC.from_bem(bem,
wec['us'] = wot.WEC.from_bem(hydro_data,
f_add={"PTO": pto['us'].force_on_wec},
constraints=[{'type': 'ineq',
'fun': const_f_pto, }])
Expand All @@ -372,7 +382,7 @@ def saturated_pi(pto, wec, x_wec, x_opt, waves=None, nsubsteps=1):
pto['pi'] = wot.pto.PTO(ndof=ndof,
kinematics=np.eye(ndof),
controller=saturated_pi,)
wec['pi'] = wot.WEC.from_bem(bem,
wec['pi'] = wot.WEC.from_bem(hydro_data,
f_add={"PTO": pto['pi'].force_on_wec},
constraints=[])

Expand Down