Skip to content

Commit 00c6603

Browse files
Ryan CoeH0R5E
andauthored
correct negative damping in BEM results (#134)
* add function to check nemoh results currently checks for negative vals in diagonal FRFs * don't issue warnings may need to further consider whether/how to pass a warning up to higher level functions and/or set debug/verbosity level across WecOptTool * legend for debugging plot * Allow fixing of negative damping values to be switched off This is done through the parametric geometry option, which takes an option called fixNegative, that defaults to true. * add some inline comments to explain workflow * Test for convergence if negative damping is fixed. Doesn't seem to work. * Check the value of the exitflag * indent all functions * comment out testPSNoConverge our test case parameters for this do not currently create a non- convergent solution, so we must wait to find a set of parameters that result in such an error * Update parametric test to PS case that might fail and organize DeviceModel tests into new subpackage. * Move tests * Repose ParametricPSTest as a bug test * Remove negative values on diagonal of damping matrix from NEMOH * Test alternative formulation of CC equations * Get meshes, where generated, from the device design routines and simplify damping control equation * Add mesh plotting function * All tests passing. Needs a write up then conversion to active PR. * Add description and test to plotMesh. Use plotmesh in RM3/optimization.m example. Fix other descriptions of the mesh output throughout. * Remove incorrect docstring in WaveBot/Performance class * Fix reference to removed types namespace and function * Add copyright boilerplate * Bug fix * Fix Hydrodynamics docstring and add to API docs * Minor docstring edit * Update example docs * Remove TODOs * Reintroduce getAmplitudeSpectrum method into SeaState, but leave interpolation to the user. * Add getAmplitudeSpectrum to class docstring and give return value * some minor typos * use complex array for excitation * explicitly set variable with load statement Co-authored-by: Mathew Topper <damm_horse@yahoo.co.uk>
1 parent f0ceabb commit 00c6603

25 files changed

+998
-347
lines changed

docs/_static/example_meshes.svg

Lines changed: 259 additions & 0 deletions
Loading

docs/user/api.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ WecOptTool
1010
.. mat:autoclass:: +WecOptTool.AutoFolder
1111
:members:
1212

13+
.. mat:autoclass:: +WecOptTool.Hydrodynamics
14+
:members:
15+
1316
.. mat:autoclass:: +WecOptTool.SeaState
1417
:members:
1518

docs/user/optimization.rst

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,9 @@ complete code is as follows:
155155

156156
.. literalinclude:: /../examples/RM3/optimization.m
157157
:language: matlab
158-
:lines: 63-91
158+
:lines: 65-93
159159
:linenos:
160-
:lineno-start: 63
160+
:lineno-start: 65
161161

162162
The following subsections will describe each stage of setting up the objective
163163
function.
@@ -202,9 +202,9 @@ object array. These inputs are combined and then added as arguments to the
202202

203203
.. literalinclude:: /../examples/RM3/optimization.m
204204
:language: matlab
205-
:lines: 69-72
205+
:lines: 71-74
206206
:linenos:
207-
:lineno-start: 69
207+
:lineno-start: 71
208208

209209
Calculate controlled device performance
210210
---------------------------------------
@@ -249,9 +249,9 @@ as follows:
249249

250250
.. literalinclude:: /../examples/RM3/optimization.m
251251
:language: matlab
252-
:lines: 74-78
252+
:lines: 76-80
253253
:linenos:
254-
:lineno-start: 74
254+
:lineno-start: 76
255255

256256
Define the objective function value
257257
-----------------------------------
@@ -262,17 +262,17 @@ all spectra in the given seastate:
262262

263263
.. literalinclude:: /../examples/RM3/optimization.m
264264
:language: matlab
265-
:lines: 88-91
265+
:lines: 92-95
266266
:linenos:
267-
:lineno-start: 88
267+
:lineno-start: 92
268268

269269
Then, to make a minimisation problem, the negation of this value returned:
270270

271271
.. literalinclude:: /../examples/RM3/optimization.m
272272
:language: matlab
273-
:lines: 80
273+
:lines: 82
274274
:linenos:
275-
:lineno-start: 80
275+
:lineno-start: 82
276276

277277
.. note::
278278
**Objective function:** The chosen objective function in |optimization.m|_
@@ -292,9 +292,9 @@ and then stash it for recovery later:
292292

293293
.. literalinclude:: /../examples/RM3/optimization.m
294294
:language: matlab
295-
:lines: 82-84
295+
:lines: 84-88
296296
:linenos:
297-
:lineno-start: 82
297+
:lineno-start: 84
298298

299299
Set optimization solver
300300
=======================
@@ -371,7 +371,7 @@ optimisation, the :mat:meth:`~+WecOptTool.AutoFolder.recoverVar` method of the
371371

372372
.. literalinclude:: /../examples/RM3/optimization.m
373373
:language: matlab
374-
:lines: 50-51
374+
:lines: 50-52
375375
:linenos:
376376
:lineno-start: 50
377377

@@ -381,24 +381,29 @@ match is found, as follows:
381381

382382
.. literalinclude:: /../examples/RM3/optimization.m
383383
:language: matlab
384-
:lines: 53-59
384+
:lines: 54-60
385385
:linenos:
386-
:lineno-start: 53
386+
:lineno-start: 54
387387

388-
Finally, by using the :mat:func:`+WecOptTool.+plot.powerPerFreq` function, the
389-
spectral distribution of energy absorbed by the resulting design for each of
390-
the eight sea states can be shown.
388+
Finally, by using the :mat:func:`+WecOptTool.+plot.powerPerFreq` and
389+
:mat:func:`+WecOptTool.+plot.plotMesh` functions, the spectral distribution of
390+
energy absorbed by the resulting design for each of the eight sea states can be
391+
shown, alongside the simulated meshes.
391392

392393
.. literalinclude:: /../examples/RM3/optimization.m
393394
:language: matlab
394-
:lines: 61
395+
:lines: 62-63
395396
:linenos:
396-
:lineno-start: 61
397+
:lineno-start: 62
397398

398399
.. image:: /_static/example_spectralPowerPlot.svg
399400
:width: 400pt
400401
:alt: Absorbed Spectral power distribution for each sea state
401402

403+
.. image:: /_static/example_meshes.svg
404+
:width: 400pt
405+
:alt: Absorbed Spectral power distribution for each sea state
406+
402407
.. [Falnes] Falnes, Johannes. Ocean waves and oscillating systems: linear
403408
interactions including wave-energy extraction. Cambridge University
404409
Press, 2002.

examples/RM3/designDevice.m

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
function hydro = designDevice(type, varargin)
1+
function [hydro, meshes] = designDevice(type, varargin)
22

3+
meshes = [];
4+
35
switch type
46

57
case 'existing'
68
hydro = WecOptTool.geometry.existingNEMOH(varargin{:});
79
case 'scalar'
810
hydro = getHydroScalar(varargin{:});
911
case 'parametric'
10-
hydro = getHydroParametric(varargin{:});
12+
[hydro, meshes] = getHydroParametric(varargin{:});
1113

1214
end
1315

@@ -20,7 +22,7 @@
2022
[filepath, ~, ~] = fileparts(p);
2123
dataPath = fullfile(filepath, 'RM3_BEM.mat');
2224

23-
load(dataPath, 'hydro');
25+
hydro = struct2array(load(dataPath, 'hydro'));
2426

2527
% dimensionalize w/ WEC-Sim built-in function
2628
hydro.rho = 1025;
@@ -34,15 +36,11 @@
3436
hydro.B = hydro.B .* lambda^2.5;
3537
hydro.A = hydro.A .* lambda^3;
3638
hydro.ex = complex(hydro.ex_re,hydro.ex_im) .* lambda^2;
37-
hydro.ex_ma = abs(hydro.ex);
38-
hydro.ex_ph = angle(hydro.ex);
39-
hydro.ex_re = real(hydro.ex);
40-
hydro.ex_im = imag(hydro.ex);
41-
39+
hydro = rmfield(hydro,{'ex_re','ex_im'});
4240
end
4341

4442

45-
function hydro = getHydroParametric(folder, r1, r2, d1, d2, w)
43+
function [hydro, meshes] = getHydroParametric(folder, r1, r2, d1, d2, w)
4644

4745
% Float
4846

examples/RM3/optimization.m

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
[x, fval] = fmincon(objFun, x0, A, B, Aeq, Beq, lb, ub, NONLCON, opts);
4949

5050
%% Recover device object of best simulation and plot its power per freq
51+
%% and mesh
5152
performances = folder.recoverVar("performances");
5253

5354
for i = 1:length(performances)
@@ -59,6 +60,7 @@
5960
end
6061

6162
WecOptTool.plot.powerPerFreq(bestPerformances);
63+
WecOptTool.plot.plotMesh(bestPerformances(1).meshes);
6264

6365
%% Define objective function
6466
% This can take any form that complies with the requirements of the MATLAB
@@ -69,7 +71,7 @@
6971
w = seastate.getRegularFrequencies(0.5);
7072
geomParams = [folder.path num2cell(x) w];
7173

72-
deviceHydro = designDevice('parametric', geomParams{:});
74+
[deviceHydro, meshes] = designDevice('parametric', geomParams{:});
7375

7476
for j = 1:length(seastate)
7577
performances(j) = simulateDevice(deviceHydro, ...
@@ -81,6 +83,8 @@
8183

8284
[performances(:).w] = seastate.w;
8385
performances(1).x = x;
86+
performances(1).meshes = meshes;
87+
8488
folder.stashVar(performances);
8589

8690
end

examples/RM3/simulateDevice.m

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function performance = simulateDevice(hydro, seastate, controlType, varargin)
1+
function [performance, motion] = simulateDevice(hydro, seastate, controlType, varargin)
22

33
static = getStaticModel(hydro);
44
motion = getDynamicModel(static, hydro, seastate);
@@ -48,9 +48,7 @@
4848

4949
function result = interp_ex(hydro, dof, w)
5050

51-
h = complex(squeeze(hydro.ex_re(dof, 1, :)), ...
52-
squeeze(hydro.ex_im(dof, 1, :)));
53-
51+
h = squeeze(hydro.ex(dof, 1, :));
5452
result = interp1(hydro.w, h ,w, 'linear', 0);
5553

5654
end
@@ -89,6 +87,13 @@
8987

9088
B33 = interp_rad(hydro, 3, 3, w) * hydro.rho .* w;
9189
A33 = interp_mass(hydro, 3, 3, w) * hydro.rho;
90+
91+
% Check radiation damping
92+
if max(abs(B39)) > max(max(B33), max(B99))
93+
warning('WecOptTool:RM3:BadDamping', ...
94+
['Coupled radiation damping magnitude exceeds maximum ' ...
95+
'of single body values. Results may be unphysical.']);
96+
end
9297

9398
% Excitation
9499
H3 = interp_ex(hydro, 3, w) * hydro.g * hydro.rho;
@@ -162,22 +167,26 @@
162167
end
163168

164169
function out = dampingControl(motion)
165-
166-
% Max Power for a given Damping Coeffcient [Falnes 2002
167-
% (p.51-52)]
168-
P_max = @(b) -0.5 * b * ...
169-
sum(abs(motion.F0 ./ (motion.Zi + b)) .^ 2);
170-
171-
% Optimize the linear damping coeffcient(B)
172-
B_opt = fminsearch(P_max, max(real(motion.Zi)));
173170

174-
% Power per frequency at optimial damping?
175-
out.powPerFreq = 0.5 * B_opt * ...
176-
(abs(motion.F0 ./ (motion.Zi + B_opt)) .^ 2);
171+
% Power per frequency at optimial damping
172+
out.powPerFreq = 0.25 * abs(motion.F0) .^ 2 ./ ...
173+
(real(motion.Zi) + abs(motion.Zi));
177174

178175
end
179176

180-
function out = pseudoSpectralControl(motion, delta_Zmax, delta_Fmax)
177+
function out = pseudoSpectralControl(motion, ...
178+
delta_Zmax, ...
179+
delta_Fmax, ...
180+
display, ...
181+
OptimalityTolerance)
182+
183+
arguments
184+
motion
185+
delta_Zmax
186+
delta_Fmax
187+
display = "off"
188+
OptimalityTolerance = 1e-5
189+
end
181190

182191
% PSEUDOSPECTRAL Pseudo spectral control
183192
% Returns power per frequency and frequency bins
@@ -202,7 +211,10 @@
202211
for ind_ph = 1 : n_ph
203212

204213
ph = ph_mat(:, ind_ph);
205-
[~, phasePowPerFreq] = getPSPhasePower(motion, ph);
214+
[~, phasePowPerFreq] = getPSPhasePower(motion, ...
215+
ph, ...
216+
display, ...
217+
OptimalityTolerance);
206218

207219
for ind_freq = 1 : n_freqs
208220
powPerFreqMat(ind_ph, ind_freq) = phasePowPerFreq(ind_freq);
@@ -328,7 +340,10 @@
328340

329341
end
330342

331-
function [pow, powPerFreq] = getPSPhasePower(motion, ph)
343+
function [pow, powPerFreq] = getPSPhasePower(motion, ...
344+
ph, ...
345+
display, ...
346+
OptimalityTolerance)
332347
%Calculates power using the pseudospectral method given a phase and
333348
% a descrption of the body movement. Returns total phase power and
334349
% power per frequency
@@ -356,11 +371,10 @@
356371
% constrained optimiztion
357372
qp_options = optimoptions('fmincon', ...
358373
'Algorithm', 'sqp', ...
359-
'Display', 'off', ...
374+
'Display', display, ...
360375
'MaxIterations', 1e3, ...
361376
'MaxFunctionEvaluations', 1e5, ...
362-
'OptimalityTolerance', 1e-8, ...
363-
'StepTolerance', 1e-6);
377+
'OptimalityTolerance', OptimalityTolerance);
364378

365379
siz = size(motion.A_ineq);
366380
X0 = zeros(siz(2),1);

0 commit comments

Comments
 (0)