10
10
11
11
12
12
kplim = - 1e1
13
-
13
+ min_damping = 45
14
14
15
15
@pytest .fixture (scope = "module" )
16
16
def f1 ():
@@ -73,10 +73,13 @@ def fb():
73
73
74
74
75
75
@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) """
78
78
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
80
83
81
84
82
85
@pytest .fixture (scope = 'module' )
@@ -91,36 +94,42 @@ def regular_wave(f1, nfreq):
91
94
92
95
93
96
@pytest .fixture (scope = 'module' )
94
- def irregular_wave (f1 , nfreq ):
97
+ def long_crested_wave (f1 , nfreq ):
95
98
"""Idealized (Pierson-Moskowitz) spectrum wave"""
96
99
freq = wot .frequency (f1 , nfreq , False )
97
100
fp = 0.3
98
101
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 )
101
109
return waves
102
110
103
111
104
112
@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 ):
106
114
"""Simple WEC: 1 DOF, no constraints."""
107
115
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 )
109
117
return wec
110
118
111
119
112
120
@pytest .fixture (scope = 'module' )
113
121
def wec_from_floatingbody (f1 , nfreq , fb , pto ):
114
122
"""Simple WEC: 1 DOF, no constraints."""
115
123
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 )
117
126
return wec
118
127
119
128
120
129
@pytest .fixture (scope = 'module' )
121
- def wec_from_impedance (bem , pto , fb ):
130
+ def wec_from_impedance (hydro_data , pto , fb ):
122
131
"""Simple WEC: 1 DOF, no constraints."""
123
- bemc = bem .copy ()
132
+ bemc = hydro_data .copy ()
124
133
omega = bemc ['omega' ].values
125
134
w = np .expand_dims (omega , [1 ,2 ])
126
135
A = bemc ['added_mass' ].values
@@ -134,17 +143,18 @@ def wec_from_impedance(bem, pto, fb):
134
143
135
144
freqs = omega / (2 * np .pi )
136
145
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' ]
138
147
f_add = {"PTO" : pto .force_on_wec }
139
148
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 )
141
151
return wec
142
152
143
153
144
154
@pytest .fixture (scope = 'module' )
145
- def resonant_wave (f1 , nfreq , fb , bem ):
155
+ def resonant_wave (f1 , nfreq , fb , hydro_data ):
146
156
"""Regular wave at natural frequency of the WEC"""
147
- hd = wot .add_linear_friction (bem )
157
+ hd = wot .add_linear_friction (hydro_data )
148
158
Zi = wot .hydrodynamic_impedance (hd )
149
159
wn = Zi ['omega' ][np .abs (Zi ).argmin (dim = 'omega' )].item ()
150
160
waves = wot .waves .regular_wave (f1 , nfreq , freq = wn / 2 / np .pi , amplitude = 0.1 )
@@ -231,23 +241,21 @@ def hstiff(self, fb):
231
241
return fb .compute_hydrostatic_stiffness ()
232
242
233
243
@pytest .fixture (scope = 'class' )
234
- def hydro_impedance (self , bem ):
244
+ def hydro_impedance (self , hydro_data ):
235
245
"""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 )
239
247
return Zi
240
248
241
249
def test_p_controller_resonant_wave (self ,
242
- bem ,
250
+ hydro_data ,
243
251
resonant_wave ,
244
252
p_controller_pto ,
245
253
hydro_impedance ):
246
254
"""Proportional controller should match optimum for natural resonant
247
255
wave"""
248
256
249
257
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 )
251
259
252
260
res = wec .solve (waves = resonant_wave ,
253
261
obj_fun = p_controller_pto .average_power ,
@@ -272,14 +280,14 @@ def test_p_controller_resonant_wave(self,
272
280
assert power_sol == approx (power_optimal , rel = 0.03 )
273
281
274
282
def test_pi_controller_regular_wave (self ,
275
- bem ,
283
+ hydro_data ,
276
284
regular_wave ,
277
285
pi_controller_pto ,
278
286
hydro_impedance ):
279
287
"""PI controller matches optimal for any regular wave"""
280
288
281
289
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 )
283
291
284
292
res = wec .solve (waves = regular_wave ,
285
293
obj_fun = pi_controller_pto .average_power ,
@@ -302,20 +310,20 @@ def test_pi_controller_regular_wave(self,
302
310
).squeeze ().sum ('omega' ).item ()
303
311
304
312
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 ):
312
320
"""Unstructured (numerical optimal) controller matches optimal for any
313
- irregular wave when unconstrained"""
321
+ irregular (long crested) wave when unconstrained"""
314
322
315
323
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 )
317
325
318
- res = wec .solve (waves = regular_wave ,
326
+ res = wec .solve (waves = long_crested_wave ,
319
327
obj_fun = pto .average_power ,
320
328
nstate_opt = 2 * nfreq ,
321
329
x_wec_0 = 1e-1 * np .ones (wec .nstate_wec ),
@@ -326,16 +334,18 @@ def test_unstructured_controller_irregular_wave(self,
326
334
327
335
power_sol = - 1 * res [0 ]['fun' ]
328
336
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 )
330
340
Fex = res_fd .force .sel (
331
341
type = ['Froude_Krylov' , 'diffraction' ]).sum ('type' )
332
342
power_optimal = (np .abs (Fex )** 2 / 8 / np .real (hydro_impedance .squeeze ())
333
- ).squeeze ().sum ('omega' ).item ()
343
+ ).squeeze ().sum ('omega' ).item ()
334
344
335
- assert power_sol == approx (power_optimal , rel = 1e-3 )
345
+ assert power_sol == approx (power_optimal , rel = 1e-2 )
336
346
337
347
def test_saturated_pi_controller (self ,
338
- bem ,
348
+ hydro_data ,
339
349
regular_wave ,
340
350
pto ,
341
351
nfreq ):
@@ -357,7 +367,7 @@ def const_f_pto(wec, x_wec, x_opt, waves):
357
367
f = pto ['us' ].force_on_wec (wec , x_wec , x_opt , waves ,
358
368
nsubsteps = 4 )
359
369
return f_max - np .abs (f .flatten ())
360
- wec ['us' ] = wot .WEC .from_bem (bem ,
370
+ wec ['us' ] = wot .WEC .from_bem (hydro_data ,
361
371
f_add = {"PTO" : pto ['us' ].force_on_wec },
362
372
constraints = [{'type' : 'ineq' ,
363
373
'fun' : const_f_pto , }])
@@ -372,7 +382,7 @@ def saturated_pi(pto, wec, x_wec, x_opt, waves=None, nsubsteps=1):
372
382
pto ['pi' ] = wot .pto .PTO (ndof = ndof ,
373
383
kinematics = np .eye (ndof ),
374
384
controller = saturated_pi ,)
375
- wec ['pi' ] = wot .WEC .from_bem (bem ,
385
+ wec ['pi' ] = wot .WEC .from_bem (hydro_data ,
376
386
f_add = {"PTO" : pto ['pi' ].force_on_wec },
377
387
constraints = [])
378
388
0 commit comments