• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sandialabs / WecOptTool / 9120563447

16 May 2024 11:34PM UTC coverage: 94.538% (-0.09%) from 94.631%
9120563447

Pull #342

github

web-flow
Merge c8912d06b into c21878006
Pull Request #342: ENHANCEMENT: Implemented cyipopt minimize_ipopt

408 of 423 new or added lines in 7 files covered. (96.45%)

11 existing lines in 1 file now uncovered.

2752 of 2911 relevant lines covered (94.54%)

5.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.1
/tests/test_utilities.py
1
""" Unit tests for functions in the :python:`utilities.py` module.
2
"""
3

4
import pytest
6✔
5
import numpy as np
6✔
6
import xarray as xr
6✔
7
from matplotlib.pyplot import Figure, Axes
6✔
8
import wecopttool as wot
6✔
9
from pytest import approx
6✔
10
import capytaine as cpy
6✔
11

12

13

14
# test function in the utilities.py
15

16

17

18
@pytest.fixture(scope="module")
6✔
19
def power_flows():
6✔
20
    """Dictionary of power flows."""
21
    pflows = {'Optimal Excitation': -100,
6✔
22
                'Radiated': -20,
23
                'Actual Excitation': -70,
24
                'Electrical (solver)': -40,
25
                'Mechanical (solver)': -50,
26
                'Absorbed': -50,
27
                'Unused Potential': -30,
28
                'PTO Loss': -10
29
    }
30
    return pflows
6✔
31

32
@pytest.fixture(scope="module")
6✔
33
def f1():
6✔
34
    """Fundamental frequency [Hz]."""
35
    return 0.1
6✔
36

37

38
@pytest.fixture(scope="module")
6✔
39
def nfreq():
6✔
40
    """Number of frequencies in frequency vector."""
41
    return 5
6✔
42

43
@pytest.fixture(scope="module")
6✔
44
def ndof():
6✔
45
    """Number of degrees of freedom."""
46
    return 2
6✔
47

48
@pytest.fixture(scope="module")
6✔
49
def ndir():
6✔
50
    """Number of wave directions."""
51
    return 3
6✔
52

53
@pytest.fixture(scope='module')
6✔
54
def bem_data(f1, nfreq, ndof, ndir):
6✔
55
    """Synthetic BEM data."""
56
    # TODO - start using single BEM solution across entire test suite
57
    coords = {
6✔
58
        'omega': [2*np.pi*(ifreq+1)*f1 for ifreq in range(nfreq)],
59
        'influenced_dof': [f'DOF_{idof+1}' for idof in range(ndof)],
60
        'radiating_dof': [f'DOF_{idof+1}' for idof in range(ndof)],
61
        'wave_direction': [2*np.pi/ndir*idir for idir in range(ndir)],
62
    }
63
    radiation_dims = ['omega', 'radiating_dof', 'influenced_dof']
6✔
64
    excitation_dims = ['omega', 'influenced_dof', 'wave_direction']
6✔
65
    hydrostatics_dims = ['radiating_dof', 'influenced_dof']
6✔
66

67
    added_mass = np.ones([nfreq, ndof, ndof])
6✔
68
    radiation_damping = np.ones([nfreq, ndof, ndof])
6✔
69
    diffraction_force = np.ones([nfreq, ndof, ndir], dtype=complex) + 1j
6✔
70
    Froude_Krylov_force = np.ones([nfreq, ndof, ndir], dtype=complex) + 1j
6✔
71
    inertia_matrix = np.ones([ndof, ndof])
6✔
72
    hydrostatic_stiffness = np.ones([ndof, ndof])
6✔
73
    
74
    data_vars = {
6✔
75
        'added_mass': (radiation_dims, added_mass),
76
        'radiation_damping': (radiation_dims, radiation_damping),
77
        'diffraction_force': (excitation_dims, diffraction_force),
78
        'Froude_Krylov_force': (excitation_dims, Froude_Krylov_force),
79
        'inertia_matrix': (hydrostatics_dims, inertia_matrix),
80
        'hydrostatic_stiffness': (hydrostatics_dims, hydrostatic_stiffness)
81
    }
82
    return xr.Dataset(data_vars=data_vars, coords=coords)
6✔
83

84
@pytest.fixture(scope='module')
6✔
85
def intrinsic_impedance(bem_data):
6✔
86
    bem_data = wot.add_linear_friction(bem_data)
6✔
87
    intrinsic_impedance = wot.hydrodynamic_impedance(bem_data)
6✔
88
    return intrinsic_impedance
6✔
89

90
@pytest.fixture(scope='module')
6✔
91
def pi_controller_pto():
6✔
92
    """Basic PTO: proportional-integral (PI) controller, 1DOF, mechanical
93
    power."""
94
    ndof = 1
6✔
95
    pto = wot.pto.PTO(ndof=ndof, kinematics=np.eye(ndof),
6✔
96
                      controller=wot.pto.controller_pi,
97
                      names=["PI controller PTO"])
98
    return pto
6✔
99

100
@pytest.fixture(scope='module')
6✔
101
def regular_wave(f1, nfreq):
6✔
102
    """Single frequency wave"""
103
    wfreq = 0.3
6✔
104
    wamp = 0.0625
6✔
105
    wphase = 0
6✔
106
    wdir = 0
6✔
107
    waves = wot.waves.regular_wave(f1, nfreq, wfreq, wamp, wphase, wdir)
6✔
108
    return waves
6✔
109

110
@pytest.fixture(scope="module")
6✔
111
def fb():
6✔
112
    """Capytaine FloatingBody object"""
113
    try:
6✔
114
        import wecopttool.geom as geom
6✔
NEW
115
    except ImportError:
×
NEW
116
        pytest.skip(
×
117
            'Skipping integration tests due to missing optional geometry ' +
118
            'dependencies. Run `pip install wecopttool[geometry]` to run ' +
119
            'these tests.'
120
            )
121
    mesh_size_factor = 0.5
6✔
122
    wb = geom.WaveBot()
6✔
123
    mesh = wb.mesh(mesh_size_factor)
6✔
124
    fb = cpy.FloatingBody.from_meshio(mesh, name="WaveBot")
6✔
125
    fb.add_translation_dof(name="Heave")
6✔
126
    return fb
6✔
127

128

129
@pytest.fixture(scope="module")
6✔
130
def wb_bem(f1, nfreq, fb):
6✔
131
    """Boundary elemement model (Capytaine) results"""
132
    freq = wot.frequency(f1, nfreq, False)
6✔
133
    return wot.run_bem(fb, freq)
6✔
134

135
@pytest.fixture(scope='class')
6✔
136
def wb_hydro_impedance(wb_bem):
6✔
137
    """Intrinsic hydrodynamic impedance"""
138
    hd = wot.add_linear_friction(wb_bem)
6✔
139
    hd = wot.check_radiation_damping(hd)
6✔
140
    Zi = wot.hydrodynamic_impedance(hd)
6✔
141
    return Zi
6✔
142

143

144

145

146
def test_plot_hydrodynamic_coefficients(bem_data,ndof):
6✔
147
    bem_figure_list = wot.utilities.plot_hydrodynamic_coefficients(bem_data)
6✔
148
    correct_len = ndof*(ndof+1)/2   #using only the subdiagonal elements
6✔
149
    #added mass
150
    fig_am = bem_figure_list[0][0]
6✔
151
    assert correct_len == len(fig_am.axes)
6✔
152
    assert isinstance(fig_am,Figure)
6✔
153
    #radiation damping
154
    fig_rd = bem_figure_list[1][0]
6✔
155
    assert correct_len == len(fig_rd.axes)
6✔
156
    assert isinstance(fig_rd,Figure)
6✔
157
    #radiation damping
158
    fig_ex = bem_figure_list[2][0]
6✔
159
    assert ndof == len(fig_ex.axes)
6✔
160
    assert isinstance(fig_ex,Figure)
6✔
161

162
def test_plot_bode_impedance(intrinsic_impedance, ndof):
6✔
163
    fig_Zi, axes_Zi = wot.utilities.plot_bode_impedance(intrinsic_impedance)    
6✔
164
  
165
    assert 2*ndof*ndof == len(fig_Zi.axes)
6✔
166
    assert isinstance(fig_Zi,Figure)
6✔
167
    assert all([isinstance(ax, Axes) for ax in np.reshape(axes_Zi,-1)])
6✔
168

169

170
def test_plot_power_flow(power_flows):
6✔
171
    fig_sankey, ax_sankey = wot.utilities.plot_power_flow(power_flows)    
6✔
172
  
173
    assert isinstance(fig_sankey, Figure)
6✔
174
    assert isinstance(ax_sankey, Axes) 
6✔
175

176
def test_calculate_power_flow(wb_bem,
6✔
177
                              regular_wave,
178
                              pi_controller_pto,
179
                              wb_hydro_impedance):
180
    """PI controller matches optimal for any regular wave, 
181
        thus we check if the radiated power is equal the absorber power
182
        and if the Optimal excitation is equal the actual excitation"""
183

184
    f_add = {"PTO": pi_controller_pto.force_on_wec}
6✔
185
    wec = wot.WEC.from_bem(wb_bem, f_add=f_add)
6✔
186

187
    res = wec.solve(waves=regular_wave,
6✔
188
                    obj_fun=pi_controller_pto.average_power,
189
                    nstate_opt=2,
190
                    x_wec_0=1e-1*np.ones(wec.nstate_wec),
191
                    x_opt_0=[-1e3, 1e4],
192
                    scale_x_wec=1e2,
193
                    scale_x_opt=1e-3,
194
                    scale_obj=1e-2,
195
                    optim_options={'maxiter': 50},
196
                    bounds_opt=((-1e4, 0), (0, 2e4),)
197
                    )
198

199
    pflows = wot.utilities.calculate_power_flows(wec, 
6✔
200
                          pi_controller_pto, 
201
                          res, 
202
                          regular_wave, 
203
                          wb_hydro_impedance)
204

205
    assert pflows['Absorbed'] == approx(pflows['Radiated'], rel=1e-4)
6✔
206
    assert pflows['Optimal Excitation'] == approx(pflows['Actual Excitation'], rel=1e-4)
6✔
207

208

209

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc