Skip to content

Commit d7c9946

Browse files
FEAT: Extend extreme method to accept absolute value extremes (#51)
1 parent 1107f04 commit d7c9946

4 files changed

Lines changed: 59 additions & 21 deletions

File tree

docs/user_guide/concepts_utils/directional_spectrum.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,18 @@ Calculate the mean zero-crossing period, Tz:
8080
spectrum.tz
8181
8282
Calculate extreme values using the :meth:`~waveresponse.DirectionalSpectrum.extreme`
83-
method. The method takes two arguments: the duration of the process (in seconds),
84-
and a quantile, ``q``.
83+
method. The method takes three arguments: the duration of the process (in seconds),
84+
the quantile, ``q``, and a boolean flag, ``absmax``, determining whether to compute absolute
85+
value extremes (or only consider the maxima (`default`)).
8586

8687
.. code-block:: python
8788
8889
duration = 3 * 3600 # 3 hours
8990
91+
# Extreme maximum
9092
mpm = spectrum.extreme(duration, q=0.37) # most probable maximum (MPM)
9193
q90 = spectrum.extreme(duration, q=0.90) # 90-th quantile
94+
95+
# Extreme absolute value maximum (i.e., minima are taken into account)
96+
mpm = spectrum.extreme(duration, q=0.37, absmax=True) # most probable maximum (MPM)
97+
q90 = spectrum.extreme(duration, q=0.90, absmax=True) # 90-th quantile

docs/user_guide/standardized_spectra.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ Torsethaugen
173173
------------
174174
The *Torsethaugen* spectrum allows you to set up a double-peaked spectrum that represents
175175
sea states which includes both a remotely generated swell component (with low frequency energy)
176-
and a locally generated wind component (with high frequency energy). The spectral spectral model
176+
and a locally generated wind component (with high frequency energy). The spectral model
177177
was developed based on average measured spectra for Norwegian waters (Haltenbanken and Statfjord).
178178
The Torsethaugen spectrum is described by two parameter (i.e. :math:`H_s` and :math:`T_p`), and
179179
is given by:

src/waveresponse/_core.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,7 +1471,7 @@ def tz(self):
14711471
m2 = self.moment(2, freq_hz=True)
14721472
return np.sqrt(m0 / m2)
14731473

1474-
def extreme(self, t, q=0.37):
1474+
def extreme(self, t, q=0.37, absmax=False):
14751475
"""
14761476
Compute the q-th quantile extreme value (assuming a Gaussian process).
14771477
@@ -1483,24 +1483,28 @@ def extreme(self, t, q=0.37):
14831483
of the process, and ``q`` is the quantile. Setting ``q=0.37`` yields the
14841484
most probable maximum (MPM).
14851485
1486-
The extreme value indicates a level which the maximum value of the process
1487-
amplitudes will be below with a certain probability. Note that the method
1488-
only computes extreme values for the maxima, and does not consider the minima.
1489-
14901486
Parameters
14911487
----------
14921488
t : float
14931489
Time/duration in seconds for which the of the process is observed.
14941490
q : float or array-like
14951491
Quantile or sequence of quantiles to compute. Must be between 0 and 1
14961492
(inclusive).
1493+
absmax : bool
1494+
Whether to compute absolute value extremes (i.e., taking the minima into account).
1495+
If ``False`` (default), only the maxima are considered. See Notes.
14971496
14981497
Returns
14991498
-------
15001499
x : float or array
1501-
Extreme value(s). During the given time period, the maximum value of
1502-
the process amplitudes will be below the returned value with a given
1503-
probability.
1500+
Extreme value(s). During the given time period, the maximum value (or
1501+
absolute value maximum) of the process amplitudes will be below the
1502+
returned value with the given probability.
1503+
1504+
Notes
1505+
-----
1506+
Computing absolute value extremes by setting ``absmax=True`` is equivalent
1507+
to doubling the expected zero-crossing rate, ``fz = 1 / Tz``.
15041508
15051509
Notes
15061510
-----
@@ -1512,8 +1516,14 @@ def extreme(self, t, q=0.37):
15121516
Cambridge University Press.
15131517
15141518
"""
1519+
1520+
if absmax:
1521+
tz = self.tz / 2.0
1522+
else:
1523+
tz = self.tz
1524+
15151525
q = np.asarray_chkfinite(q)
1516-
return self.std() * np.sqrt(2.0 * np.log((t / self.tz) / np.log(1.0 / q)))
1526+
return self.std() * np.sqrt(2.0 * np.log((t / tz) / np.log(1.0 / q)))
15171527

15181528

15191529
class WaveSpectrum(DirectionalSpectrum):

tests/test_core.py

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3374,13 +3374,13 @@ def test_extreme_float(self):
33743374
vals = np.ones((len(freq), len(dirs)))
33753375
spectrum = wr.DirectionalSpectrum(freq, dirs, vals, freq_hz=True, degrees=True)
33763376

3377-
sigma = spectrum.std()
3378-
tz = spectrum.tz
3379-
33803377
T = 360 * 24 * 60.0**2
33813378
q = 0.99
33823379
extreme_out = spectrum.extreme(T, q=q)
33833380

3381+
sigma = spectrum.std()
3382+
tz = spectrum.tz
3383+
33843384
extreme_expect = sigma * np.sqrt(2.0 * np.log((T / tz) / np.log(1.0 / q)))
33853385

33863386
assert extreme_out == pytest.approx(extreme_expect)
@@ -3394,13 +3394,13 @@ def test_extreme_list(self):
33943394
vals = np.ones((len(freq), len(dirs)))
33953395
spectrum = wr.DirectionalSpectrum(freq, dirs, vals, freq_hz=True, degrees=True)
33963396

3397-
sigma = spectrum.std()
3398-
tz = spectrum.tz
3399-
34003397
T = 360 * 24 * 60.0**2
34013398
q = [0.1, 0.5, 0.99]
34023399
extreme_out = spectrum.extreme(T, q=q)
34033400

3401+
sigma = spectrum.std()
3402+
tz = spectrum.tz
3403+
34043404
extreme_expect = [
34053405
sigma * np.sqrt(2.0 * np.log((T / tz) / np.log(1.0 / q[0]))),
34063406
sigma * np.sqrt(2.0 * np.log((T / tz) / np.log(1.0 / q[1]))),
@@ -3418,16 +3418,38 @@ def test_extreme_mpm(self):
34183418
vals = np.ones((len(freq), len(dirs)))
34193419
spectrum = wr.DirectionalSpectrum(freq, dirs, vals, freq_hz=True, degrees=True)
34203420

3421-
sigma = spectrum.std()
3422-
tz = spectrum.tz
3423-
34243421
T = 360 * 24 * 60.0**2
34253422
extreme_out = spectrum.extreme(T, q=0.37)
34263423

3424+
sigma = spectrum.std()
3425+
tz = spectrum.tz
3426+
34273427
extreme_expect = sigma * np.sqrt(2.0 * np.log(T / tz))
34283428

34293429
assert extreme_out == pytest.approx(extreme_expect, rel=1e-3)
34303430

3431+
def test_extreme_absmax(self):
3432+
f0 = 0.0
3433+
f1 = 2.0
3434+
3435+
freq = np.linspace(f0, f1, 20)
3436+
dirs = np.arange(5, 360, 10)
3437+
vals = np.ones((len(freq), len(dirs)))
3438+
spectrum = wr.DirectionalSpectrum(freq, dirs, vals, freq_hz=True, degrees=True)
3439+
3440+
T = 360 * 24 * 60.0**2
3441+
q = 0.99
3442+
extreme_out = spectrum.extreme(T, q=q, absmax=True)
3443+
3444+
sigma = spectrum.std()
3445+
tz_absmax = spectrum.tz / 2.0
3446+
3447+
extreme_expect = sigma * np.sqrt(
3448+
2.0 * np.log((T / tz_absmax) / np.log(1.0 / q))
3449+
)
3450+
3451+
assert extreme_out == pytest.approx(extreme_expect)
3452+
34313453

34323454
class Test_WaveSpectrum:
34333455
def test__init__(self):

0 commit comments

Comments
 (0)