Skip to content

Commit c3cd678

Browse files
enh: add DirectionalBinSpectrum class (#76)
1 parent 6d6a7c8 commit c3cd678

3 files changed

Lines changed: 1031 additions & 5 deletions

File tree

src/waveresponse/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
BinGrid,
44
CosineFullSpreading,
55
CosineHalfSpreading,
6+
DirectionalBinSpectrum,
67
DirectionalSpectrum,
78
Grid,
89
WaveSpectrum,
@@ -37,6 +38,7 @@
3738
"CosineFullSpreading",
3839
"CosineHalfSpreading",
3940
"DirectionalSpectrum",
41+
"DirectionalBinSpectrum",
4042
"Grid",
4143
"BinGrid",
4244
"JONSWAP",

src/waveresponse/_core.py

Lines changed: 164 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,8 +1486,7 @@ class DirectionalSpectrum(_SpectrumMixin, Grid):
14861486
class, and is a two-dimentional frequency/(wave)direction grid. The spectrum values
14871487
represents spectrum density.
14881488
1489-
Proper scaling is performed such that the total "energy" is kept constant at
1490-
all times.
1489+
Proper scaling is applied to ensure that the total "energy" remains constant at all times.
14911490
14921491
Parameters
14931492
----------
@@ -1747,6 +1746,168 @@ def _full_range_dir(x):
17471746
return x
17481747

17491748

1749+
class DirectionalBinSpectrum(_SpectrumMixin, BinGrid):
1750+
"""
1751+
Directional binned spectrum.
1752+
1753+
The ``DirectionalBinSpectrum`` class extends the :class:`~waveresponse.BinGrid`
1754+
class and represents a two-dimensional frequency/wave-direction grid. The spectrum values
1755+
represent spectral density as a function of frequency, binned by direction.
1756+
1757+
Proper scaling is applied to ensure that the total "energy" remains constant at all times.
1758+
1759+
Parameters
1760+
----------
1761+
freq : array-like
1762+
1-D array of grid frequency coordinates. Positive and monotonically increasing.
1763+
dirs : array-like
1764+
1-D array of grid direction coordinates. Positive and monotonically increasing.
1765+
Must cover the directional range [0, 360) degrees (or [0, 2 * numpy.pi) radians).
1766+
vals : array-like (N, M)
1767+
Spectrum density values associated with the grid. Should be a 2-D array
1768+
of shape (N, M), such that ``N=len(freq)`` and ``M=len(dirs)``.
1769+
freq_hz : bool
1770+
If frequency is given in 'Hz'. If ``False``, 'rad/s' is assumed.
1771+
degrees : bool
1772+
If direction is given in 'degrees'. If ``False``, 'radians' is assumed.
1773+
clockwise : bool
1774+
If positive directions are defined to be 'clockwise' (``True``) or 'counterclockwise'
1775+
(``False``). Clockwise means that the directions follow the right-hand rule
1776+
with an axis pointing downwards.
1777+
waves_coming_from : bool
1778+
If waves are 'coming from' the given directions. If ``False``, 'going towards'
1779+
convention is assumed.
1780+
"""
1781+
1782+
def __init__(
1783+
self,
1784+
freq,
1785+
dirs,
1786+
vals,
1787+
freq_hz=False,
1788+
degrees=False,
1789+
clockwise=False,
1790+
waves_coming_from=True,
1791+
):
1792+
super().__init__(
1793+
freq,
1794+
dirs,
1795+
vals,
1796+
freq_hz=freq_hz,
1797+
degrees=degrees,
1798+
clockwise=clockwise,
1799+
waves_coming_from=waves_coming_from,
1800+
)
1801+
1802+
if freq_hz:
1803+
self._vals = 1.0 / (2.0 * np.pi) * self._vals
1804+
1805+
def __repr__(self):
1806+
return "DirectionalBinSpectrum"
1807+
1808+
def _freq_spectrum(self, freq_hz=None):
1809+
"""
1810+
Integrate the spectrum over the directional domain to obtain the non-directional
1811+
spectrum.
1812+
1813+
Parameters
1814+
----------
1815+
freq_hz : bool
1816+
If frequencies should be returned in 'Hz'. If ``False``, 'rad/s' is
1817+
used. Defaults to original unit used during initialization.
1818+
1819+
Returns
1820+
-------
1821+
f : array
1822+
1-D array of frequency coordinates in 'Hz' or 'rad/s'.
1823+
s : array
1824+
1-D array of spectral density values in 'm^2/Hz' or 'm^2/(rad/s)'.
1825+
"""
1826+
1827+
if freq_hz is None:
1828+
freq_hz = self._freq_hz
1829+
1830+
f, _, vv = self.grid(freq_hz=freq_hz, degrees=False)
1831+
s = vv.sum(axis=1)
1832+
1833+
return f, s
1834+
1835+
def grid(self, freq_hz=False, degrees=False):
1836+
"""
1837+
Return a copy of the spectrum's frequency/direction coordinates and corresponding
1838+
values.
1839+
1840+
Parameters
1841+
----------
1842+
freq_hz : bool
1843+
If frequencies should be returned in 'Hz'. If ``False``, 'rad/s' is used.
1844+
degrees : bool
1845+
If directions should be returned in 'degrees'. If ``False``, 'radians'
1846+
is used.
1847+
1848+
Returns
1849+
-------
1850+
freq : array
1851+
1-D array of grid frequency coordinates.
1852+
dirs : array
1853+
1-D array of grid direction coordinates.
1854+
vals : array (N, M)
1855+
Spectrum density values as 2-D array of shape (N, M), such that ``N=len(freq)``
1856+
and ``M=len(dirs)``.
1857+
"""
1858+
freq, dirs, vals = super().grid(freq_hz=freq_hz, degrees=degrees)
1859+
1860+
if freq_hz:
1861+
vals *= 2.0 * np.pi
1862+
1863+
return freq, dirs, vals
1864+
1865+
def interpolate(
1866+
self,
1867+
freq,
1868+
freq_hz=False,
1869+
fill_value=0.0,
1870+
**kwargs,
1871+
):
1872+
"""
1873+
Interpolate (linear) the spectrum values to match the given frequency and direction
1874+
coordinates.
1875+
1876+
A 'fill value' is used for extrapolation (i.e. `freq` outside the bounds
1877+
of the provided 2-D grid). Directions are treated as periodic.
1878+
1879+
Parameters
1880+
----------
1881+
freq : array-like
1882+
1-D array of grid frequency coordinates. Positive and monotonically increasing.
1883+
dirs : array-like
1884+
1-D array of grid direction coordinates. Positive and monotonically increasing.
1885+
freq_hz : bool
1886+
If frequency is given in 'Hz'. If ``False``, 'rad/s' is assumed.
1887+
fill_value : float or None
1888+
The value used for extrapolation (i.e., `freq` outside the bounds of
1889+
the provided grid). If ``None``, values outside the frequency domain
1890+
are extrapolated via nearest-neighbor extrapolation. Note that directions
1891+
are treated as periodic (and will not need extrapolation).
1892+
1893+
Returns
1894+
-------
1895+
array :
1896+
Interpolated spectrum density values.
1897+
"""
1898+
1899+
vals = super().interpolate(
1900+
freq,
1901+
freq_hz=freq_hz,
1902+
fill_value=fill_value,
1903+
)
1904+
1905+
if freq_hz:
1906+
vals *= 2.0 * np.pi
1907+
1908+
return vals
1909+
1910+
17501911
class WaveSpectrum(DisableComplexMixin, DirectionalSpectrum):
17511912
"""
17521913
Wave spectrum.
@@ -1755,9 +1916,7 @@ class WaveSpectrum(DisableComplexMixin, DirectionalSpectrum):
17551916
class, and is a two-dimentional frequency/(wave)direction grid. The spectrum values
17561917
represents spectrum density. Only real and positive values allowed.
17571918
1758-
Proper scaling is performed such that the total "energy" is kept constant at
1759-
all times.
1760-
1919+
Proper scaling is applied to ensure that the total "energy" remains constant at all times.
17611920
17621921
Parameters
17631922
----------

0 commit comments

Comments
 (0)