Skip to content

Commit d8b049f

Browse files
enh: calculate response with binned wave spectrum (#82)
1 parent aa8d512 commit d8b049f

3 files changed

Lines changed: 289 additions & 167 deletions

File tree

docs/user_guide/calculate_response.rst

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,18 @@ This function is roughly equivalent to:
5252
5353
Parameters
5454
----------
55-
rao : obj
56-
``RAO`` object.
57-
wave : obj
58-
``WaveSpectrum`` object.
55+
rao : RAO
56+
Response amplitude operator (RAO).
57+
wave : WaveSpectrum
58+
Wave spectrum.
5959
heading : float
60-
Heading of vessel relative to wave spectrum coordinate system.
60+
Heading of vessel relative to wave spectrum reference frame.
6161
heading_degrees : bool
6262
Whether the heading is given in 'degrees'. If ``False``, 'radians' is assumed.
6363
6464
Returns
6565
-------
66-
obj :
66+
DirectionalSpectrum :
6767
Response spectrum.
6868
"""
6969
@@ -73,10 +73,7 @@ This function is roughly equivalent to:
7373
# Ensure that ``rao`` and ``wave`` has the same 'wave convention'
7474
wave_body.set_wave_convention(**rao.wave_convention)
7575
76-
# Reshape ``rao`` and ``wave`` so that they share the same frequency/direction
77-
# coordinates. In this example, ``wave`` will dictate the coordinates, and
78-
# the ``rao`` object will be interpolated to match these coordinates.
79-
#
76+
# Reshape the RAO to match the wave spectrum's frequency/direction coordinates.
8077
# It is recommended to reshape (i.e., interpolate) the magnitude-squared
8178
# version of the RAO when estimating response, since this has shown best
8279
# results:
@@ -85,9 +82,8 @@ This function is roughly equivalent to:
8582
dirs = wave_body.dirs(degrees=False)
8683
rao_squared = (rao * rao.conjugate()).real
8784
rao_squared = rao_squared.reshape(freq, dirs, freq_hz=False, degrees=False)
88-
wave_body = wave_body.reshape(freq, dirs, freq_hz=False, degrees=False)
8985
90-
return wr.multiply(rao_squared, wave_body, output_type="directional_spectrum")
86+
return wr.multiply(rao_squared, wave_body, output_type="DirectionalSpectrum")
9187
9288
The response is returned as a :class:`~waveresponse.DirectionalSpectrum` object,
9389
and provides useful spectrum operations, such as:

src/waveresponse/_core.py

Lines changed: 92 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2305,60 +2305,122 @@ def dirm(self, degrees=None):
23052305
return dirm
23062306

23072307

2308+
def _calculate_response_deprecated(rao, wave_body, coord_freq, coord_dirs):
2309+
# TODO: Deprecated. Remove this function in a future release.
2310+
2311+
if coord_freq == "wave":
2312+
freq = wave_body._freq
2313+
elif coord_freq == "rao":
2314+
freq = rao._freq
2315+
else:
2316+
raise ValueError("Invalid `coord_freq` value. Should be 'wave' or 'rao'.")
2317+
if coord_dirs == "wave":
2318+
dirs = wave_body._dirs
2319+
elif coord_dirs == "rao":
2320+
dirs = rao._dirs
2321+
else:
2322+
raise ValueError("Invalid `coord_dirs` value. Should be 'wave' or 'rao'.")
2323+
2324+
rao_squared = (rao * rao.conjugate()).real
2325+
rao_squared = rao_squared.reshape(freq, dirs, freq_hz=False, degrees=False)
2326+
wave_body = wave_body.reshape(freq, dirs, freq_hz=False, degrees=False)
2327+
2328+
return multiply(rao_squared, wave_body, output_type="DirectionalSpectrum")
2329+
2330+
23082331
def calculate_response(
2309-
rao, wave, heading, heading_degrees=False, coord_freq="wave", coord_dirs="wave"
2332+
rao,
2333+
wave,
2334+
heading,
2335+
heading_degrees=False,
2336+
reshape="rao_squared",
2337+
coord_freq=None,
2338+
coord_dirs=None,
23102339
):
23112340
"""
23122341
Calculate response spectrum.
23132342
2343+
The response spectrum is calculated according to:
2344+
2345+
S_x(w, theta) = H(w, theta) * H*(w, theta) * S_w(w, theta)
2346+
2347+
where S_x(w, theta) denotes the response spectrum, H(w, theta) denotes the RAO,
2348+
H*(w, theta) denotes the RAO conjugate, and S_w(w, theta) denotes the wave
2349+
spectrum (expressed in the RAO's reference frame).
2350+
2351+
The frequency and direction coordinates are dictatated by the wave spectrum.
2352+
I.e., the RAO (or the magnitude-squared verison of it) is interpolated to match
2353+
the grid coordinates of the wave spectrum.
2354+
23142355
Parameters
23152356
----------
2316-
rao : obj
2317-
Response amplitude operator (RAO) as a :class:`~waveresponse.RAO` object.
2318-
wave : obj
2319-
2-D wave spectrum as a :class:`~waveresponse.WaveSpectrum` object.
2357+
rao : RAO
2358+
Response amplitude operator (RAO).
2359+
wave : WaveSpectrum or WaveBinSpectrum
2360+
2-D wave spectrum.
23202361
heading : float
23212362
Heading of vessel relative to wave spectrum coordinate system.
23222363
heading_degrees : bool
23232364
Whether the heading is given in 'degrees'. If ``False``, 'radians' is assumed.
2365+
reshape : {'rao', 'rao_squared'}, default 'rao_squared'
2366+
Determines whether to reshape the RAO or the magnitude-squared version of
2367+
the RAO before pairing with the wave spectrum. Linear interpolation is
2368+
performed to match the frequency and direction coordinates of the wave
2369+
spectrum.
23242370
coord_freq : str, optional
2325-
Frequency coordinates for interpolation. Should be 'wave' or 'rao'. Determines
2326-
if it is the wave spectrum or the RAO that should dictate which frequencies
2327-
to use in response calculation. The other object will be interpolated to
2328-
match these frequencies.
2371+
Deprecated; use `reshape` instead. Frequency coordinates for interpolation.
2372+
Should be 'wave' or 'rao'. Determines if it is the wave spectrum or the
2373+
RAO that should dictate which frequencies to use in response calculation.
2374+
The other object will be interpolated to match these frequencies.
23292375
coord_dirs : str, optional
2330-
Direction coordinates for interpolation. Should be 'wave' or 'rao'. Determines
2331-
if it is the wave spectrum or the RAO that should dictate which directions
2332-
to use in response calculation. The other object will be interpolated to
2333-
match these directions.
2376+
Deprecated; use `reshape` instead. Direction coordinates for interpolation.
2377+
Should be 'wave' or 'rao'. Determines if it is the wave spectrum or the
2378+
RAO that should dictate which directions to use in response calculation.
2379+
The other object will be interpolated to match these directions.
23342380
23352381
Returns
23362382
-------
2337-
obj :
2338-
Response spectrum as :class:`DirectionalSpectrum` object.
2383+
DirectionalSpectrum or DirectionalBinSpectrum :
2384+
Response spectrum.
23392385
"""
23402386
wave_body = wave.rotate(heading, degrees=heading_degrees)
23412387
wave_body.set_wave_convention(**rao.wave_convention)
23422388

2343-
if coord_freq.lower() == "wave":
2344-
freq = wave_body._freq
2345-
elif coord_freq.lower() == "rao":
2346-
freq = rao._freq
2389+
# TODO: Remove once the deprecation period is over
2390+
if coord_freq and coord_dirs:
2391+
warnings.warn(
2392+
"The `coord_freq` and `coord_dirs` parameters are deprecated and will be removed in a future release."
2393+
"Use the `reshape` parameter instead.",
2394+
DeprecationWarning,
2395+
stacklevel=2,
2396+
)
2397+
return _calculate_response_deprecated(rao, wave_body, coord_freq, coord_dirs)
2398+
elif coord_freq or coord_dirs:
2399+
raise ValueError("Both `coord_freq` and `coord_dirs` must be provided.")
2400+
2401+
freq, dirs = wave_body._freq, wave_body._dirs
2402+
if reshape == "rao":
2403+
rao = rao.reshape(freq, dirs, freq_hz=False, degrees=False)
2404+
rao_squared = (rao * rao.conjugate()).real
2405+
elif reshape == "rao_squared":
2406+
rao_squared = (rao * rao.conjugate()).real
2407+
rao_squared = rao_squared.reshape(freq, dirs, freq_hz=False, degrees=False)
23472408
else:
2348-
raise ValueError("Invalid `coord_freq` value. Should be 'wave' or 'rao'.")
2409+
raise ValueError("Invalid `reshape` value. Should be 'rao' or 'rao_squared'.")
23492410

2350-
if coord_dirs.lower() == "wave":
2351-
dirs = wave_body._dirs
2352-
elif coord_dirs.lower() == "rao":
2353-
dirs = rao._dirs
2354-
else:
2355-
raise ValueError("Invalid `coord_dirs` value. Should be 'wave' or 'rao'.")
2411+
TYPE_MAP = {
2412+
WaveSpectrum: "DirectionalSpectrum",
2413+
WaveBinSpectrum: "DirectionalBinSpectrum",
2414+
}
23562415

2357-
rao_squared = (rao * rao.conjugate()).real
2358-
rao_squared = rao_squared.reshape(freq, dirs, freq_hz=False, degrees=False)
2359-
wave_body = wave_body.reshape(freq, dirs, freq_hz=False, degrees=False)
2416+
try:
2417+
type_ = TYPE_MAP[type(wave)]
2418+
except KeyError:
2419+
raise ValueError(
2420+
"Invalid `wave` type. Should be 'WaveSpectrum' or 'WaveBinSpectrum'."
2421+
)
23602422

2361-
return multiply(rao_squared, wave_body, output_type="directional_spectrum")
2423+
return multiply(rao_squared, wave_body, output_type=type_)
23622424

23632425

23642426
class BaseSpreading(ABC):

0 commit comments

Comments
 (0)