@@ -390,3 +390,203 @@ def _C(self, hs, tp, q):
390390 def _d (self , tp , q ):
391391 omega_p = 2.0 * np .pi / tp
392392 return (4 * q + 1 ) * omega_p ** 4 / 4.0
393+
394+
395+ class Torsethaugen (BaseSpectrum1d ):
396+ """
397+ Torsethaugen spectrum, given as:
398+
399+ ``S(w) = alpha * S_1(w; Hs_1, Tp_1) * gamma ** b + S_2(w; Hs_2, Tp_2)``
400+
401+ where,
402+
403+ ``S_i(w) = A_i / w ** 4 * exp(-B_i / w ** 4)``
404+
405+ and,
406+
407+ ``b = exp(-(w - wp_1) ** 2 / (2 * sigma ** 2 * wp_1 ** 2))``
408+
409+ Furthermore,
410+
411+ - ``A_i = 3.26 / 16 * Hs_i ** 2 * wp_i ** 3``
412+ - ``B_i = wp_i ** 4``.
413+ - ``Hs_i`` is the significant wave height of the primary and the secondary system.
414+ - ``wp_i = 2pi / Tp_i`` is the angular spectral peak frequency of the primary and the secondary system.
415+ - ``gamma`` is a peak enhancement factor.
416+ - ``alpha = (1 + 1.1 * log(gamma) ** 1.19) / gamma`` is a normalizing factor.
417+ - ``sigma`` is the spectral width parameter (established from experimental data):
418+ - ``sigma = 0.07`` for ``w <= wp_1``
419+ - ``sigma = 0.09`` for ``w > wp_1``
420+
421+ Parameters
422+ ----------
423+ freq : array-like
424+ Sequence of frequencies to use when generating the spectrum.
425+ freq_hz : bool
426+ Whether the provided frequencies are in rad/s (default) or Hz.
427+
428+ Notes
429+ -----
430+ The Torsethaugen spectrum is implemented as described in reference [1]_. All the
431+ intermediate parameters are applied as defined in Table 1 in reference [1]_.
432+
433+ References
434+ ----------
435+ .. [1] Torsethaugen K and Haver S, 2004. Simplified double peak spectral model
436+ for ocean waves, Paper No. 2004-JSC-193, ISOPE 2004 Touson, France.
437+
438+ See Also
439+ --------
440+ ModifiedPiersonMoskowitz : Modified Pierson-Moskowitz wave spectrum.
441+ JONSWAP : JONSWAP wave spectrum.
442+ OchiHubble : Ochi-Hubble (three-parameter) wave spectrum.
443+
444+ """
445+
446+ # Parameters as specified in Table 1 in reference [1].
447+ _af = 6.6
448+ _ae = 2.0
449+ _au = 25
450+ _a10 = 0.7
451+ _a1 = 0.5
452+ _kg = 35.0
453+ _b1 = 2.0
454+ _a20 = 0.6
455+ _a2 = 0.3
456+ _a3 = 6.0
457+ _g = 9.80665
458+
459+ def __call__ (self , hs , tp , freq_hz = None ):
460+ """
461+ Generate wave spectrum.
462+
463+ Parameters
464+ ----------
465+ hs : float
466+ Significant wave height, Hs.
467+ tp : float
468+ Peak period, Tp.
469+ freq_hz : bool, optional
470+ Whether to return the frequencies and spectrum in terms of Hz (`True`)
471+ or rad/s (`False`). If `None` (default), the original units of `freq` is
472+ preserved.
473+
474+ Return
475+ ------
476+ freq : 1-D array
477+ Frequencies corresponding to the spectrum values. Unit is set according
478+ to `freq_hz`.
479+ spectrum : 1-D array
480+ Spectrum values. Unit is set according to `freq_hz`.
481+
482+ Notes
483+ -----
484+ The scaling between wave spectrum in terms of Hz and rad/s is defined
485+ as:
486+
487+ ``S(f) = 2*pi*S(w)``
488+
489+ where ``S(f)`` and ``S(w)`` are the same spectrum but expressed
490+ in terms of Hz and rad/s, respectively.
491+ """
492+
493+ return super ().__call__ (hs , tp , freq_hz = freq_hz )
494+
495+ def _spectrum (self , omega , hs , tp ):
496+ tpf = self ._tpf (hs )
497+
498+ if tp <= tpf : # wind dominated
499+ hs_primary = hs * self ._rw (hs , tp )
500+ tp_primary = tp
501+ gamma = self ._gamma (hs_primary , tp_primary )
502+
503+ hs_secondary = hs * np .sqrt (1.0 - self ._rw (hs , tp ) ** 2 )
504+ tp_secondary = tpf + self ._b1
505+
506+ else : # swell dominated
507+ hs_primary = hs * self ._rs (hs , tp )
508+ tp_primary = tp
509+ gamma = self ._gamma (hs , tpf ) * (1.0 + self ._a3 * self ._eps_u (hs , tp ))
510+
511+ hs_secondary = hs * np .sqrt (1.0 - self ._rs (hs , tp ) ** 2 )
512+ tp_secondary = self ._af * hs_secondary ** (1.0 / 3.0 )
513+
514+ omega_p_primary = 2.0 * np .pi / tp_primary
515+ A_primary = (3.26 / 16.0 ) * hs_primary ** 2 * omega_p_primary ** 3
516+ B_primary = omega_p_primary ** 4
517+
518+ spectrum_primary = (
519+ self ._alpha (gamma )
520+ * A_primary
521+ / omega ** 4
522+ * np .exp (- B_primary / omega ** 4 )
523+ * gamma ** self ._b (tp_primary )
524+ )
525+
526+ omega_p_secondary = 2.0 * np .pi / tp_secondary
527+ A_secondary = (3.26 / 16.0 ) * hs_secondary ** 2 * omega_p_secondary ** 3
528+ B_secondary = omega_p_secondary ** 4
529+
530+ spectrum_secondary = (
531+ A_secondary / omega ** 4 * np .exp (- B_secondary / omega ** 4 )
532+ )
533+
534+ return spectrum_primary + spectrum_secondary
535+
536+ def _tpf (self , hs ):
537+ return self ._af * hs ** (1.0 / 3.0 )
538+
539+ def _tl (self , hs ):
540+ return self ._ae * np .sqrt (hs )
541+
542+ def _eps_l (self , hs , tp ):
543+ tpf = self ._tpf (hs )
544+ tl = self ._tl (hs )
545+
546+ eps_l = (tpf - tp ) / (tpf - tl )
547+
548+ if eps_l < 0.0 :
549+ raise ValueError ("`eps_l` not defined." )
550+
551+ return min (eps_l , 1.0 )
552+
553+ def _eps_u (self , hs , tp ):
554+ tpf = self ._tpf (hs )
555+ tu = self ._au
556+
557+ eps_u = (tp - tpf ) / (tu - tpf )
558+
559+ if eps_u < 0.0 :
560+ raise ValueError ("`eps_u` not defined." )
561+
562+ return min (eps_u , 1.0 )
563+
564+ def _rw (self , hs , tp ):
565+ eps_l = self ._eps_l (hs , tp )
566+ return self ._a10 + (1.0 - self ._a10 ) * np .exp (- ((eps_l / self ._a1 ) ** 2.0 ))
567+
568+ def _rs (self , hs , tp ):
569+ eps_u = self ._eps_u (hs , tp )
570+ return self ._a20 + (1.0 - self ._a20 ) * np .exp (- ((eps_u / self ._a2 ) ** 2.0 ))
571+
572+ def _gamma (self , hs_ , tp_ ):
573+ s = (2.0 * np .pi / self ._g ) * hs_ / tp_ ** 2.0
574+ return self ._kg * s ** (6.0 / 7.0 )
575+
576+ def _alpha (self , gamma ):
577+ return (1.0 + 1.1 * np .log (gamma ) ** 1.19 ) / gamma
578+
579+ def _b (self , tp ):
580+ omega_p = 2.0 * np .pi / tp
581+ sigma = self ._sigma (omega_p )
582+ return np .exp (- 0.5 * ((self ._freq - omega_p ) / (sigma * omega_p )) ** 2 )
583+
584+ def _sigma (self , omega_p ):
585+ """
586+ Spectral width.
587+ """
588+ arg = self ._freq <= omega_p
589+ sigma = np .empty_like (self ._freq )
590+ sigma [arg ] = 0.07
591+ sigma [~ arg ] = 0.09
592+ return sigma
0 commit comments