You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1997 lines
67 KiB
Python
1997 lines
67 KiB
Python
15 years ago
|
"""
|
||
|
Models module
|
||
|
-------------
|
||
|
|
||
|
Dispersion relation
|
||
|
-------------------
|
||
|
k2w - Translates from wave number to frequency
|
||
|
w2k - Translates from frequency to wave number
|
||
|
|
||
|
Model spectra
|
||
|
-------------
|
||
|
Bretschneider - Bretschneider spectral density.
|
||
|
Jonswap - JONSWAP spectral density
|
||
|
McCormick - McCormick spectral density.
|
||
|
OchiHubble - OchiHubble bimodal spectral density model.
|
||
|
Tmaspec - JONSWAP spectral density for finite water depth
|
||
|
Torsethaugen - Torsethaugen double peaked (swell + wind) spectrum model
|
||
|
Wallop - Wallop spectral density.
|
||
|
demospec - Loads a precreated spectrum of chosen type
|
||
|
jonswap_peakfact - Jonswap peakedness factor Gamma given Hm0 and Tp
|
||
|
jonswap_seastate - jonswap seastate from windspeed and fetch
|
||
|
|
||
|
Directional spreading functions
|
||
|
-------------------------------
|
||
|
Spreading - Directional spreading function.
|
||
|
|
||
|
"""
|
||
|
|
||
|
|
||
|
#-------------------------------------------------------------------------------
|
||
|
# Name: models
|
||
|
# Purpose: Interface to various spectrum models
|
||
|
#
|
||
|
# Author: pab
|
||
|
#
|
||
|
# Created: 29.08.2008
|
||
|
# Copyright: (c) pab 2008
|
||
|
# Licence: <your licence>
|
||
|
#-------------------------------------------------------------------------------
|
||
|
#!/usr/bin/env python
|
||
|
from __future__ import division
|
||
|
|
||
|
import warnings
|
||
|
from scipy.interpolate import interp1d
|
||
|
import scipy.optimize as optimize
|
||
|
import scipy.integrate as integrate
|
||
|
import scipy.special as sp
|
||
|
from scipy.fftpack import fft
|
||
|
#from scipy.misc import ppimport
|
||
|
#import numpy as np
|
||
|
from numpy import (inf, atleast_1d, newaxis, any, minimum, maximum, array, #@UnresolvedImport
|
||
|
asarray, exp, log, sqrt, where, pi, arange, linspace, sin, cos, abs, sinh, #@UnresolvedImport
|
||
|
isfinite, mod, expm1, tanh, cosh, finfo, ones, ones_like, isnan, #@UnresolvedImport
|
||
|
zeros_like, flatnonzero, sinc, hstack, vstack, real, flipud, clip) #@UnresolvedImport
|
||
|
from dispersion_relation import w2k
|
||
|
#ppimport.enable()
|
||
|
#_wafospectrum = ppimport.ppimport('wafo.spectrum')
|
||
|
from core import SpecData1D
|
||
|
sech = lambda x: 1.0/cosh(x)
|
||
|
|
||
|
eps = finfo(float).eps
|
||
|
|
||
|
|
||
|
__all__ = ['Bretschneider','Jonswap','Torsethaugen','Wallop','McCormick','OchiHubble',
|
||
|
'Tmaspec','jonswap_peakfact','jonswap_seastate','spreading',
|
||
|
'w2k','k2w','phi1']
|
||
|
|
||
|
# Model spectra
|
||
|
|
||
|
def _gengamspec(wn, N=5, M=4):
|
||
|
''' Return Generalized gamma spectrum in dimensionless form
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
wn : arraylike
|
||
|
normalized frequencies, w/wp.
|
||
|
N : scalar
|
||
|
defining the decay of the high frequency part.
|
||
|
M : scalar
|
||
|
defining the spectral width around the peak.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
S : arraylike
|
||
|
spectral values, same size as wn.
|
||
|
|
||
|
The generalized gamma spectrum in non-
|
||
|
dimensional form is defined as:
|
||
|
|
||
|
S = G0.*wn.**(-N).*exp(-B*wn.**(-M)) for wn > 0
|
||
|
= 0 otherwise
|
||
|
where
|
||
|
B = N/M
|
||
|
C = (N-1)/M
|
||
|
G0 = B**C*M/gamma(C), Normalizing factor related to Bretschneider form
|
||
|
|
||
|
Note that N = 5, M = 4 corresponds to a normalized
|
||
|
Bretschneider spectrum.
|
||
|
|
||
|
Examples
|
||
|
--------
|
||
|
>>> import numpy as np
|
||
|
>>> wn = np.linspace(0,4,5)
|
||
|
>>> _gengamspec(wn, N=6, M=2)
|
||
|
array([ 0. , 1.16765216, 0.17309961, 0.02305179, 0.00474686])
|
||
|
|
||
|
See also
|
||
|
--------
|
||
|
Bretschneider
|
||
|
Jonswap,
|
||
|
Torsethaugen
|
||
|
|
||
|
|
||
|
References
|
||
|
----------
|
||
|
Torsethaugen, K. (2004)
|
||
|
"Simplified Double Peak Spectral Model for Ocean Waves"
|
||
|
In Proc. 14th ISOPE
|
||
|
'''
|
||
|
w = atleast_1d(wn)
|
||
|
S = zeros_like(w)
|
||
|
|
||
|
##for w>0 # avoid division by zero
|
||
|
k = flatnonzero(w>0.0)
|
||
|
if k.size>0:
|
||
|
B = N/M
|
||
|
C = (N-1.0)/M
|
||
|
|
||
|
# # A = Normalizing factor related to Bretschneider form
|
||
|
# A = B**C*M/gamma(C)
|
||
|
# S(k) = A*wn(k)**(-N)*exp(-B*wn(k)**(-M))
|
||
|
logwn = log(w.take(k))
|
||
|
logA = (C*log(B)+log(M)-sp.gammaln(C))
|
||
|
S.put(k,exp(logA-N*logwn-B*exp(-M*logwn)))
|
||
|
return S
|
||
|
|
||
|
class ModelSpectrum(object):
|
||
|
def __init__(self, Hm0=7.0, Tp=11.0, **kwds):
|
||
|
self.Hm0 = Hm0
|
||
|
self.Tp = Tp
|
||
|
self.type = 'ModelSpectrum'
|
||
|
def tospecdata(self, w=None, wc=None, nw=257):
|
||
|
'''
|
||
|
Return SpecData1D object from ModelSpectrum
|
||
|
|
||
|
Parameter
|
||
|
---------
|
||
|
w : arraylike
|
||
|
vector of angular frequencies used in the discretization of spectrum
|
||
|
wc : scalar
|
||
|
cut off frequency (default 33/Tp)
|
||
|
nw : int
|
||
|
number of frequencies
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
S : SpecData1D object
|
||
|
member attributes of model spectrum are copied to S.workspace
|
||
|
'''
|
||
|
|
||
|
if w is None:
|
||
|
if wc is None:
|
||
|
wc = 33./self.Tp
|
||
|
w = linspace(0,wc,nw)
|
||
|
S = SpecData1D(self.__call__(w),w)
|
||
|
try:
|
||
|
h = self.h
|
||
|
S.h = h
|
||
|
except:
|
||
|
pass
|
||
|
S.labels.title = self.type + ' ' + S.labels.title
|
||
|
S.workspace = self.__dict__.copy()
|
||
|
return S
|
||
|
|
||
|
def chk_seastate(self):
|
||
|
''' Check if seastate is valid
|
||
|
'''
|
||
|
|
||
|
if self.Hm0<0:
|
||
|
raise ValueError('Hm0 can not be negative!')
|
||
|
|
||
|
if self.Tp<=0:
|
||
|
raise ValueError('Tp must be positve!')
|
||
|
|
||
|
if self.Hm0==0.0:
|
||
|
warnings.warn('Hm0 is zero!')
|
||
|
|
||
|
self._chk_extra_param()
|
||
|
|
||
|
def _chk_extra_param(self):
|
||
|
pass
|
||
|
|
||
|
class Bretschneider(ModelSpectrum):
|
||
|
'''
|
||
|
Bretschneider spectral density model
|
||
|
|
||
|
Member variables
|
||
|
----------------
|
||
|
Hm0 : significant wave height (default 7 (m))
|
||
|
Tp : peak period (default 11 (sec))
|
||
|
N : scalar defining decay of high frequency part. (default 5)
|
||
|
M : scalar defining spectral width around the peak. (default 4)
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
w : array-like
|
||
|
angular frequencies [rad/s]
|
||
|
|
||
|
|
||
|
The Bretschneider spectrum is defined as
|
||
|
|
||
|
S(w) = A * G0 * wn**(-N)*exp(-N/(M*wn**M))
|
||
|
where
|
||
|
G0 = Normalizing factor related to Bretschneider form
|
||
|
A = (Hm0/4)**2 / wp (Normalization factor)
|
||
|
wn = w/wp
|
||
|
wp = 2*pi/Tp, angular peak frequency
|
||
|
|
||
|
This spectrum is a suitable model for fully developed sea,
|
||
|
i.e. a sea state where the wind has been blowing long enough over a
|
||
|
sufficiently open stretch of water, so that the high-frequency waves have
|
||
|
reached an equilibrium. In the part of the spectrum where the frequency is
|
||
|
greater than the peak frequency (w>wp), the energy distribution is
|
||
|
proportional to w**-5.
|
||
|
The spectrum is identical with ITTC (International Towing Tank
|
||
|
Conference), ISSC (International Ship and Offshore Structures Congress)
|
||
|
and Pierson-Moskowitz, wave spectrum given Hm0 and Tm01. It is also identical
|
||
|
with JONSWAP when the peakedness factor, gamma, is one.
|
||
|
For this spectrum, the following relations exist between the mean
|
||
|
period Tm01 = 2*pi*m0/m1, the peak period Tp and the mean
|
||
|
zero-upcrossing period Tz:
|
||
|
|
||
|
Tm01 = 1.086*Tz, Tp = 1.408*Tz and Tp=1.2965*Tm01
|
||
|
|
||
|
Examples
|
||
|
--------
|
||
|
>>> S = Bretschneider(Hm0=6.5,Tp=10)
|
||
|
>>> S((0,1,2,3))
|
||
|
array([ 0. , 1.69350993, 0.06352698, 0.00844783])
|
||
|
|
||
|
See also
|
||
|
--------
|
||
|
Jonswap,
|
||
|
Torsethaugen
|
||
|
'''
|
||
|
def __init__(self, Hm0=7.0, Tp=11.0, N=5, M=4, chk_seastate=True, **kwds):
|
||
|
self.type = 'Bretschneider'
|
||
|
self.Hm0 = Hm0
|
||
|
self.Tp = Tp
|
||
|
self.N = N
|
||
|
self.M = M
|
||
|
if chk_seastate:
|
||
|
self.chk_seastate()
|
||
|
|
||
|
|
||
|
def __call__(self,wi):
|
||
|
''' Return Bretschnieder spectrum
|
||
|
'''
|
||
|
w = atleast_1d(wi)
|
||
|
if self.Hm0>0:
|
||
|
wp = 2*pi/self.Tp
|
||
|
wn = w/wp
|
||
|
S = (self.Hm0/4.0)**2/wp * _gengamspec(wn,self.N,self.M)
|
||
|
else:
|
||
|
S = zeros_like(w)
|
||
|
return S
|
||
|
|
||
|
def jonswap_peakfact(Hm0,Tp):
|
||
|
''' Jonswap peakedness factor, gamma, given Hm0 and Tp
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
Hm0 : significant wave height [m].
|
||
|
Tp : peak period [s]
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
gamma : Peakedness parameter of the JONSWAP spectrum
|
||
|
|
||
|
Details
|
||
|
-------
|
||
|
A standard value for GAMMA is 3.3. However, a more correct approach is
|
||
|
to relate GAMMA to Hm0 and Tp:
|
||
|
D = 0.036-0.0056*Tp/sqrt(Hm0)
|
||
|
gamma = exp(3.484*(1-0.1975*D*Tp**4/(Hm0**2)))
|
||
|
This parameterization is based on qualitative considerations of deep water
|
||
|
wave data from the North Sea, see Torsethaugen et. al. (1984)
|
||
|
Here GAMMA is limited to 1..7.
|
||
|
|
||
|
NOTE: The size of GAMMA is the common shape of Hm0 and Tp.
|
||
|
|
||
|
Examples
|
||
|
--------
|
||
|
>>> import pylab as plb
|
||
|
>>> Tp,Hs = plb.meshgrid(range(4,8),range(2,6))
|
||
|
>>> gam = jonswap_peakfact(Hs,Tp)
|
||
|
|
||
|
>>> Hm0 = plb.linspace(1,20)
|
||
|
>>> Tp = Hm0
|
||
|
>>> [T,H] = plb.meshgrid(Tp,Hm0)
|
||
|
>>> gam = jonswap_peakfact(H,T)
|
||
|
>>> v = plb.arange(0,8)
|
||
|
>>> h = plb.contourf(Tp,Hm0,gam,v);h=plb.colorbar()
|
||
|
|
||
|
>>> Hm0 = plb.arange(1,11)
|
||
|
>>> Tp = plb.linspace(2,16)
|
||
|
>>> T,H = plb.meshgrid(Tp,Hm0)
|
||
|
>>> gam = jonswap_peakfact(H,T)
|
||
|
>>> h = plb.plot(Tp,gam.T)
|
||
|
>>> h = plb.xlabel('Tp [s]')
|
||
|
>>> h = plb.ylabel('Peakedness parameter')
|
||
|
|
||
|
>>> plb.close('all')
|
||
|
|
||
|
See also
|
||
|
--------
|
||
|
jonswap
|
||
|
'''
|
||
|
Hm0,Tp = atleast_1d(Hm0,Tp)
|
||
|
|
||
|
x = Tp/sqrt(Hm0)
|
||
|
|
||
|
gam = ones_like(x)
|
||
|
|
||
|
k1 = flatnonzero(x<=5.14285714285714)
|
||
|
if k1.size>0: # #limiting gamma to [1 7]
|
||
|
xk = x.take(k1)
|
||
|
D = 0.036-0.0056*xk # # approx 5.061*Hm0**2/Tp**4*(1-0.287*log(gam))
|
||
|
gam.put(k1,minimum(exp(3.484*( 1.0-0.1975*D*xk**4.0 ) ),7.0)) # # gamma
|
||
|
|
||
|
return gam
|
||
|
def jonswap_seastate(u10, fetch=150000., method='lewis', g=9.81, output='dict'):
|
||
|
'''
|
||
|
Return Jonswap seastate from windspeed and fetch
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
U10 : real scalar
|
||
|
windspeed at 10 m above mean water surface [m/s]
|
||
|
fetch : real scalar
|
||
|
fetch [m]
|
||
|
method : 'hasselman73' seastate according to Hasselman et. al. 1973
|
||
|
'hasselman76' seastate according to Hasselman et. al. 1976
|
||
|
'lewis' seastate according to Lewis and Allos 1990
|
||
|
g : real scalar
|
||
|
accelaration of gravity [m/s**2]
|
||
|
output : 'dict' or 'list'
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
seastate: dict where
|
||
|
Hm0 : significant wave height [m]
|
||
|
Tp : peak period [s]
|
||
|
gamma : jonswap peak enhancement factor.
|
||
|
sigmaA,
|
||
|
sigmaB : jonswap spectral width parameters.
|
||
|
Ag : jonswap alpha, normalization factor.
|
||
|
|
||
|
Example
|
||
|
--------
|
||
|
>>> fetch = 10000; u10 = 10
|
||
|
>>> ss = jonswap_seastate(u10, fetch, output='dict')
|
||
|
>>> ss
|
||
|
{'Ag': 0.016257903375341734,
|
||
|
'Hm0': 0.51083679198275533,
|
||
|
'Tp': 2.7727680999585265,
|
||
|
'gamma': 2.4824142635861119,
|
||
|
'sigmaA': 0.075317331395172021,
|
||
|
'sigmaB': 0.091912084512251344}
|
||
|
>>> S = Jonswap(**ss)
|
||
|
>>> S.Hm0
|
||
|
0.51083679198275533
|
||
|
|
||
|
# Alternatively
|
||
|
>>> ss1 = jonswap_seastate(u10, fetch, output='list')
|
||
|
>>> S1 = Jonswap(*ss1)
|
||
|
>>> S1.Hm0
|
||
|
0.51083679198275533
|
||
|
|
||
|
See also
|
||
|
--------
|
||
|
Jonswap
|
||
|
|
||
|
|
||
|
References
|
||
|
----------
|
||
|
Lewis, A. W. and Allos, R.N. (1990)
|
||
|
JONSWAP's parameters: sorting out the inconscistencies.
|
||
|
Ocean Engng, Vol 17, No 4, pp 409-415
|
||
|
|
||
|
Hasselmann et al. (1973)
|
||
|
Measurements of Wind-Wave Growth and Swell Decay during the Joint
|
||
|
North Sea Project (JONSWAP).
|
||
|
Ergansungsheft, Reihe A(8), Nr. 12, Deutschen Hydrografischen Zeitschrift.
|
||
|
|
||
|
Hasselmann et al. (1976)
|
||
|
A parametric wave prediction model.
|
||
|
J. phys. oceanogr. Vol 6, pp 200-228
|
||
|
|
||
|
'''
|
||
|
|
||
|
# The following formulas are from Lewis and Allos 1990:
|
||
|
|
||
|
zeta = g*fetch/(u10**2) # dimensionless fetch, Table 1
|
||
|
#zeta = min(zeta, 2.414655013429281e+004)
|
||
|
if method.startswith('h'):
|
||
|
if method[-1]=='3': # Hasselman et.al (1973)
|
||
|
A = 0.076*zeta**(-0.22)
|
||
|
ny= 3.5*zeta**(-0.33) # dimensionless peakfrequency, Table 1
|
||
|
epsilon1 = 9.91e-8*zeta**1.1 # dimensionless surface variance, Table 1
|
||
|
else: # Hasselman et.al (1976)
|
||
|
A = 0.0662*zeta**(-0.2)
|
||
|
ny = 2.84*zeta**(-0.3) # dimensionless peakfrequency, Table 1
|
||
|
epsilon1 = 1.6e-7*zeta # dimensionless surface variance, Eq.4
|
||
|
|
||
|
sa = 0.07
|
||
|
sb = 0.09
|
||
|
gam = 3.3
|
||
|
else:
|
||
|
A = 0.074*zeta**(-0.22) # Eq. 10
|
||
|
ny = 3.57*zeta**(-0.33) # dimensionless peakfrequency, Eq. 11
|
||
|
epsilon1 = 3.512e-4*A*ny**(-4.)*zeta**(-0.1) # dimensionless surface variance, Eq.12
|
||
|
sa = 0.05468*ny**(-0.32) # Eq. 13
|
||
|
sb = 0.078314*ny**(-0.16) # Eq. 14
|
||
|
gam = maximum(17.54*zeta**(-0.28384),1) # Eq. 15
|
||
|
|
||
|
Tp = u10/(ny*g) # Table 1
|
||
|
Hm0 = 4*sqrt(epsilon1)*u10**2./g # Table 1
|
||
|
if output[0]=='l':
|
||
|
return Hm0,Tp,gam,sa,sb,A
|
||
|
else:
|
||
|
return dict(Hm0=Hm0,Tp=Tp,gamma=gam,sigmaA=sa,sigmaB=sb,Ag=A)
|
||
|
|
||
|
class Jonswap(ModelSpectrum):
|
||
|
'''
|
||
|
Jonswap spectral density model
|
||
|
|
||
|
Member variables
|
||
|
----------------
|
||
|
Hm0 : significant wave height (default 7 (m))
|
||
|
Tp : peak period (default 11 (sec))
|
||
|
gamma : peakedness factor determines the concentraton
|
||
|
of the spectrum on the peak frequency.
|
||
|
Usually in the range 1 <= gamma <= 7.
|
||
|
default depending on Hm0, Tp, see jonswap_peakedness)
|
||
|
sigmaA : spectral width parameter for w<wp (default 0.07)
|
||
|
sigmaB : spectral width parameter for w<wp (default 0.09)
|
||
|
Ag : normalization factor used when gamma>1:
|
||
|
N : scalar defining decay of high frequency part. (default 5)
|
||
|
M : scalar defining spectral width around the peak. (default 4)
|
||
|
method : String defining method used to estimate Ag when gamma>1
|
||
|
'integrate' : Ag = 1/gaussq(Gf*ggamspec(wn,N,M),0,wnc) (default)
|
||
|
'parametric': Ag = (1+f1(N,M)*log(gamma)**f2(N,M))/gamma
|
||
|
'custom' : Ag = Ag
|
||
|
wnc : wc/wp normalized cut off frequency used when calculating Ag
|
||
|
by integration (default 6)
|
||
|
Parameters
|
||
|
----------
|
||
|
w : array-like
|
||
|
angular frequencies [rad/s]
|
||
|
|
||
|
Description
|
||
|
-----------
|
||
|
The JONSWAP spectrum is defined as
|
||
|
|
||
|
S(w) = A * Gf * G0 * wn**(-N)*exp(-N/(M*wn**M))
|
||
|
where
|
||
|
G0 = Normalizing factor related to Bretschneider form
|
||
|
A = Ag * (Hm0/4)**2 / wp (Normalization factor)
|
||
|
Gf = j**exp(-.5*((wn-1)/s)**2) (Peak enhancement factor)
|
||
|
wn = w/wp
|
||
|
wp = angular peak frequency
|
||
|
s = sigmaA for wn <= 1
|
||
|
sigmaB for 1 < wn
|
||
|
j = gamma, (j=1, => Bretschneider spectrum)
|
||
|
|
||
|
The JONSWAP spectrum is assumed to be especially suitable for the North Sea,
|
||
|
and does not represent a fully developed sea. It is a reasonable model for
|
||
|
wind generated sea when the seastate is in the so called JONSWAP range, i.e.,
|
||
|
3.6*sqrt(Hm0) < Tp < 5*sqrt(Hm0)
|
||
|
|
||
|
The relation between the peak period and mean zero-upcrossing period
|
||
|
may be approximated by
|
||
|
Tz = Tp/(1.30301-0.01698*gamma+0.12102/gamma)
|
||
|
|
||
|
Examples
|
||
|
---------
|
||
|
>>> import pylab as plb
|
||
|
>>> S = Jonswap(Hm0=7, Tp=11,gamma=1)
|
||
|
>>> w = plb.linspace(0,5)
|
||
|
>>> h = plb.plot(w,S(w))
|
||
|
|
||
|
>>> S2 = Bretschneider(Hm0=7, Tp=11)
|
||
|
>>> assert(all(abs(S(w)-S2(w))<1.e-7),'JONSWAP with gamma=1 differs from Bretscneider, should be equal!')
|
||
|
>>> plb.close('all')
|
||
|
|
||
|
See also
|
||
|
--------
|
||
|
Bretschneider
|
||
|
Tmaspec
|
||
|
Torsethaugen
|
||
|
|
||
|
References
|
||
|
-----------
|
||
|
Torsethaugen et al. (1984)
|
||
|
Characteristica for extreme Sea States on the Norwegian continental shelf.
|
||
|
Report No. STF60 A84123. Norwegian Hydrodyn. Lab., Trondheim
|
||
|
|
||
|
Hasselmann et al. (1973)
|
||
|
Measurements of Wind-Wave Growth and Swell Decay during the Joint
|
||
|
North Sea Project (JONSWAP).
|
||
|
Ergansungsheft, Reihe A(8), Nr. 12, Deutschen Hydrografischen Zeitschrift.
|
||
|
'''
|
||
|
def __init__(self, Hm0=7.0, Tp=11.0, gamma=None, sigmaA=0.07, sigmaB=0.09,
|
||
|
Ag=None, N=5, M=4, method='integration', wnc=6.0,
|
||
|
chk_seastate=True):
|
||
|
|
||
|
self.type = 'Jonswap'
|
||
|
self.Hm0 = Hm0
|
||
|
self.Tp = Tp
|
||
|
self.N = N
|
||
|
self.M = M
|
||
|
self.sigmaA = sigmaA
|
||
|
self.sigmaB = sigmaB
|
||
|
self.gamma = gamma
|
||
|
self.Ag = Ag
|
||
|
self.method = method
|
||
|
self.wnc = wnc
|
||
|
|
||
|
if self.gamma==None or not isfinite(self.gamma) or self.gamma<1:
|
||
|
self.gamma = jonswap_peakfact(Hm0,Tp)
|
||
|
|
||
|
self._preCalculateAg()
|
||
|
|
||
|
if chk_seastate:
|
||
|
self.chk_seastate()
|
||
|
|
||
|
def _chk_extra_param(self):
|
||
|
Tp = self.Tp
|
||
|
Hm0 = self.Hm0
|
||
|
gam = self.gamma
|
||
|
outsideJonswapRange = Tp>5*sqrt(Hm0) or Tp<3.6*sqrt(Hm0)
|
||
|
if outsideJonswapRange:
|
||
|
txt0 = '''
|
||
|
Hm0,Tp is outside the JONSWAP range.
|
||
|
The validity of the spectral density is questionable.
|
||
|
'''
|
||
|
warnings.warn(txt0)
|
||
|
|
||
|
if gam<1 or 7 < gam:
|
||
|
txt = '''
|
||
|
The peakedness factor, gamma, is possibly too large.
|
||
|
The validity of the spectral density is questionable.
|
||
|
'''
|
||
|
warnings.warn(txt)
|
||
|
|
||
|
|
||
|
def _localspec(self,wn):
|
||
|
Gf = self.peak_e_factor(wn)
|
||
|
return Gf*_gengamspec(wn,self.N, self.M)
|
||
|
|
||
|
def _preCalculateAg(self):
|
||
|
''' PRECALCULATEAG Precalculate normalization.
|
||
|
'''
|
||
|
if self.gamma==1:
|
||
|
self.Ag = 1.0
|
||
|
self.method = 'parametric'
|
||
|
elif self.Ag != None:
|
||
|
self.method = 'custom'
|
||
|
if self.Ag<=0:
|
||
|
raise ValueError('Ag must be larger than 0!')
|
||
|
elif self.method[0]=='i':
|
||
|
# normalizing by integration
|
||
|
self.method = 'integration'
|
||
|
if self.wnc<1.0:
|
||
|
raise ValueError('Normalized cutoff frequency, wnc, must be larger than one!')
|
||
|
area1, unused_err1 = integrate.quad(self._localspec, 0, 1)
|
||
|
area2, unused_err2 = integrate.quad(self._localspec, 1, self.wnc)
|
||
|
area = area1 + area2
|
||
|
self.Ag = 1.0/area
|
||
|
elif self.method[1]=='p':
|
||
|
self.method = 'parametric'
|
||
|
## # Original normalization
|
||
|
## # NOTE: that Hm0**2/16 generally is not equal to intS(w)dw
|
||
|
## # with this definition of Ag if sa or sb are changed from the
|
||
|
## # default values
|
||
|
N = self.N
|
||
|
M = self.M
|
||
|
gammai = self.gamma
|
||
|
parametersOK = (3<=N and N<=50) or (2<=M and M <=9.5) and (1<= gammai and gammai<=20)
|
||
|
if parametersOK:
|
||
|
f1NM = 4.1*(N-2*M**0.28+5.3)**(-1.45*M**0.1+0.96)
|
||
|
f2NM = (2.2*M**(-3.3) + 0.57)*N**(-0.58*M**0.37+0.53)-1.04*M**(-1.9)+0.94
|
||
|
self.Ag = (1+ f1NM*log(gammai)**f2NM)/gammai
|
||
|
|
||
|
### elseif N == 5 && M == 4,
|
||
|
### options.Ag = (1+1.0*log(gammai).**1.16)/gammai
|
||
|
### #options.Ag = (1-0.287*log(gammai))
|
||
|
### options.normalizeMethod = 'Three'
|
||
|
### elseif N == 4 && M == 4,
|
||
|
### options.Ag = (1+1.1*log(gammai).**1.19)/gammai
|
||
|
else:
|
||
|
raise ValueError('Not knowing the normalization because N, M or peakedness parameter is out of bounds!')
|
||
|
|
||
|
if self.sigmaA!=0.07 or self.sigmaB!=0.09:
|
||
|
warnings.warn('Use integration to calculate Ag when sigmaA~=0.07 or sigmaB~=0.09')
|
||
|
|
||
|
|
||
|
|
||
|
def peak_e_factor(self,wn):
|
||
|
''' PEAKENHANCEMENTFACTOR
|
||
|
'''
|
||
|
w = maximum(atleast_1d(wn),0.0)
|
||
|
sab = where(w>1,self.sigmaB,self.sigmaA)
|
||
|
|
||
|
wnm12 = 0.5*((w-1.0)/sab)**2.0
|
||
|
Gf = self.gamma**(exp(-wnm12))
|
||
|
return Gf
|
||
|
|
||
|
def __call__(self,wi):
|
||
|
''' JONSWAP spectral density
|
||
|
'''
|
||
|
w = atleast_1d(wi)
|
||
|
if (self.Hm0>0.0):
|
||
|
|
||
|
N = self.N
|
||
|
M = self.M
|
||
|
wp = 2*pi/self.Tp
|
||
|
wn = w/wp
|
||
|
Ag = self.Ag
|
||
|
Hm0 = self.Hm0
|
||
|
Gf = self.peak_e_factor(wn)
|
||
|
S = ((Hm0/4.0)**2/wp*Ag)*Gf*_gengamspec(wn,N,M)
|
||
|
else:
|
||
|
S = zeros_like(w)
|
||
|
return S
|
||
|
|
||
|
def phi1(wi, h, g=9.81):
|
||
|
''' Factor transforming spectra to finite water depth spectra.
|
||
|
|
||
|
CALL: tr = phi1(w,h)
|
||
|
|
||
|
Input
|
||
|
-----
|
||
|
w : arraylike
|
||
|
angular frequency [rad/s]
|
||
|
h : scalar
|
||
|
water depth [m]
|
||
|
g : scalar
|
||
|
acceleration of gravity [m/s**2]
|
||
|
Returns
|
||
|
-------
|
||
|
tr : arraylike
|
||
|
transformation factors
|
||
|
|
||
|
Example:
|
||
|
-------
|
||
|
Transform a JONSWAP spectrum to a spectrum for waterdepth = 30 m
|
||
|
|
||
|
>>> S = Jonswap()
|
||
|
>>> w = range(3.0)
|
||
|
>>> S(w)*phi1(w,30.0)
|
||
|
array([ 0. , 1.0358056 , 0.03796281])
|
||
|
|
||
|
|
||
|
Reference
|
||
|
---------
|
||
|
Buows, E., Gunther, H., Rosenthal, W. and Vincent, C.L. (1985)
|
||
|
'Similarity of the wind wave spectrum in finite depth water: 1 spectral form.'
|
||
|
J. Geophys. Res., Vol 90, No. C1, pp 975-986
|
||
|
|
||
|
'''
|
||
|
w = atleast_1d(wi)
|
||
|
if h == inf: # % special case infinite water depth
|
||
|
return ones_like(w)
|
||
|
|
||
|
k1 = w2k(w,0,inf,g=g)[0]
|
||
|
dw1 = 2.0*w/g # % dw/dk|h=inf
|
||
|
k2 = w2k(w,0,h,g=g)[0]
|
||
|
|
||
|
k2h = k2*h
|
||
|
dw2 = where(k1!=0,dw1/(tanh(k2h)+k2h/cosh(k2h)**2.0),0) # dw/dk|h=h0
|
||
|
|
||
|
return where(k1!=0,(k1/k2)**3.0*dw2/dw1,0)
|
||
|
|
||
|
class Tmaspec(Jonswap):
|
||
|
''' JONSWAP spectrum for finite water depth
|
||
|
|
||
|
Member variables
|
||
|
----------------
|
||
|
h = water depth (default 42 [m])
|
||
|
g : acceleration of gravity [m/s**2]
|
||
|
Hm0 = significant wave height (default 7 [m])
|
||
|
Tp = peak period (default 11 (sec))
|
||
|
gamma = peakedness factor determines the concentraton
|
||
|
of the spectrum on the peak frequency.
|
||
|
Usually in the range 1 <= gamma <= 7.
|
||
|
default depending on Hm0, Tp, see getjonswappeakedness)
|
||
|
sigmaA = spectral width parameter for w<wp (default 0.07)
|
||
|
sigmaB = spectral width parameter for w<wp (default 0.09)
|
||
|
Ag = normalization factor used when gamma>1:
|
||
|
N = scalar defining decay of high frequency part. (default 5)
|
||
|
M = scalar defining spectral width around the peak. (default 4)
|
||
|
method = String defining method used to estimate Ag when gamma>1
|
||
|
'integrate' : Ag = 1/gaussq(Gf.*ggamspec(wn,N,M),0,wnc) (default)
|
||
|
'parametric': Ag = (1+f1(N,M)*log(gamma)^f2(N,M))/gamma
|
||
|
'custom' : Ag = Ag
|
||
|
wnc = wc/wp normalized cut off frequency used when calculating Ag
|
||
|
by integration (default 6)
|
||
|
Parameters
|
||
|
----------
|
||
|
w : array-like
|
||
|
angular frequencies [rad/s]
|
||
|
|
||
|
Description
|
||
|
------------
|
||
|
The evaluated spectrum is
|
||
|
S(w) = Sj(w)*phi(w,h)
|
||
|
where
|
||
|
Sj = jonswap spectrum
|
||
|
phi = modification due to water depth
|
||
|
|
||
|
The concept is based on a similarity law, and its validity is verified
|
||
|
through analysis of 3 data sets from: TEXEL, MARSEN projects (North
|
||
|
Sea) and ARSLOE project (Duck, North Carolina, USA). The data include
|
||
|
observations at water depths ranging from 6 m to 42 m.
|
||
|
|
||
|
Example
|
||
|
--------
|
||
|
>>> import pylab as plb
|
||
|
>>> w = plb.linspace(0,2.5)
|
||
|
>>> S = Tmaspec(h=10,gamma=1) # Bretschneider spectrum Hm0=7, Tp=11
|
||
|
>>> o=plb.plot(w,S(w))
|
||
|
>>> o=plb.plot(w,S(w,h=21))
|
||
|
>>> o=plb.plot(w,S(w,h=42))
|
||
|
>>> plb.show()
|
||
|
>>> plb.close('all')
|
||
|
|
||
|
See also
|
||
|
---------
|
||
|
Bretschneider,
|
||
|
Jonswap,
|
||
|
phi1,
|
||
|
Torsethaugen
|
||
|
|
||
|
References:
|
||
|
Buows, E., Gunther, H., Rosenthal, W., and Vincent, C.L. (1985)
|
||
|
'Similarity of the wind wave spectrum in finite depth water: 1 spectral form.'
|
||
|
J. Geophys. Res., Vol 90, No. C1, pp 975-986
|
||
|
|
||
|
Hasselman et al. (1973)
|
||
|
Measurements of Wind-Wave Growth and Swell Decay during the Joint
|
||
|
North Sea Project (JONSWAP).
|
||
|
Ergansungsheft, Reihe A(8), Nr. 12, deutschen Hydrografischen
|
||
|
Zeitschrift.
|
||
|
|
||
|
'''
|
||
|
def __init__(self, Hm0=7.0, Tp=11.0, gamma=None, sigmaA=0.07, sigmaB=0.09,
|
||
|
Ag=None, N=5, M=4, method='integration', wnc=6.0,
|
||
|
chk_seastate=True, h=42, g=9.81):
|
||
|
self.g = g
|
||
|
self.h = h
|
||
|
super(Tmaspec, self).__init__(Hm0,Tp,gamma,sigmaA,sigmaB,Ag,N,M,method,wnc,chk_seastate)
|
||
|
self.type = 'TMA'
|
||
|
|
||
|
def phi(self,w,h=None,g=None):
|
||
|
if h==None:
|
||
|
h = self.h
|
||
|
if g==None:
|
||
|
g = self.g
|
||
|
return phi1(w,h,g)
|
||
|
|
||
|
def __call__(self,w,h=None,g=None):
|
||
|
jonswap = super(Tmaspec, self).__call__(w)
|
||
|
return jonswap*self.phi(w,h,g)
|
||
|
|
||
|
class Torsethaugen(ModelSpectrum):
|
||
|
'''
|
||
|
Torsethaugen double peaked (swell + wind) spectrum model
|
||
|
|
||
|
Member variables
|
||
|
----------------
|
||
|
Hm0 : significant wave height (default 7 (m))
|
||
|
Tp : peak period (default 11 (sec))
|
||
|
wnc : wc/wp normalized cut off frequency used when calculating Ag
|
||
|
by integration (default 6)
|
||
|
method : String defining method used to estimate normalization factors, Ag,
|
||
|
in the the modified JONSWAP spectra when gamma>1
|
||
|
'integrate' : Ag = 1/quad(Gf.*gengamspec(wn,N,M),0,wnc)
|
||
|
'parametric': Ag = (1+f1(N,M)*log(gamma)**f2(N,M))/gamma
|
||
|
Parameters
|
||
|
----------
|
||
|
w : array-like
|
||
|
angular frequencies [rad/s]
|
||
|
|
||
|
Description
|
||
|
-----------
|
||
|
The double peaked (swell + wind) Torsethaugen spectrum is
|
||
|
modelled as S(w) = Ss(w) + Sw(w) where Ss and Sw are modified
|
||
|
JONSWAP spectrums for swell and wind peak, respectively.
|
||
|
The energy is divided between the two peaks according
|
||
|
to empirical parameters, which peak that is primary depends on parameters.
|
||
|
The empirical parameters are found for classes of Hm0 and Tp,
|
||
|
originating from a dataset consisting of 20 000 spectra divided
|
||
|
into 146 different classes of Hm0 and Tp. (Data measured at the
|
||
|
Statfjord field in the North Sea in a period from 1980 to 1989.)
|
||
|
The range of the measured Hm0 and Tp for the dataset
|
||
|
are from 0.5 to 11 meters and from 3.5 to 19 sec, respectively.
|
||
|
|
||
|
Preliminary comparisons with spectra from other areas indicate that
|
||
|
some of the empirical parameters are dependent on geographical location.
|
||
|
Thus the model must be used with care for other areas than the
|
||
|
North Sea and sea states outside the area where measured data
|
||
|
are available.
|
||
|
|
||
|
Example
|
||
|
-------
|
||
|
>>> import pylab as plb
|
||
|
>>> w = plb.linspace(0,4)
|
||
|
>>> S = Torsethaugen(Hm0=6, Tp=8)
|
||
|
>>> h=plb.plot(w,S(w),w,S.wind(w),w,S.swell(w))
|
||
|
|
||
|
See also
|
||
|
--------
|
||
|
Bretschneider
|
||
|
Jonswap
|
||
|
|
||
|
|
||
|
References
|
||
|
----------
|
||
|
Torsethaugen, K. (2004)
|
||
|
"Simplified Double Peak Spectral Model for Ocean Waves"
|
||
|
In Proc. 14th ISOPE
|
||
|
|
||
|
Torsethaugen, K. (1996)
|
||
|
Model for a doubly peaked wave spectrum
|
||
|
Report No. STF22 A96204. SINTEF Civil and Environm. Engineering, Trondheim
|
||
|
|
||
|
Torsethaugen, K. (1994)
|
||
|
'Model for a doubly peaked spectrum. Lifetime and fatigue strength
|
||
|
estimation implications.'
|
||
|
International Workshop on Floating Structures in Coastal zone,
|
||
|
Hiroshima, November 1994.
|
||
|
|
||
|
Torsethaugen, K. (1993)
|
||
|
'A two peak wave spectral model.'
|
||
|
In proceedings OMAE, Glasgow
|
||
|
|
||
|
'''
|
||
|
|
||
|
def __init__(self, Hm0=7, Tp=11, method='integration', wnc=6, gravity=9.81,
|
||
|
chk_seastate=True, **kwds):
|
||
|
self.type = 'Torsethaugen'
|
||
|
self.Hm0 = Hm0
|
||
|
self.Tp = Tp
|
||
|
self.method = method
|
||
|
self.wnc = wnc
|
||
|
self.gravity = gravity
|
||
|
self.wind = None
|
||
|
self.swell = None
|
||
|
if chk_seastate:
|
||
|
self.chk_seastate()
|
||
|
|
||
|
self._init_spec()
|
||
|
|
||
|
def __call__(self,w):
|
||
|
''' TORSETHAUGEN spectral density
|
||
|
'''
|
||
|
return self.wind(w)+self.swell(w)
|
||
|
|
||
|
def _chk_extra_param(self):
|
||
|
Hm0 = self.Hm0
|
||
|
Tp = self.Tp
|
||
|
if Hm0>11 or Hm0>max((Tp/3.6)**2, (Tp-2)*12/11):
|
||
|
txt0 = '''Hm0 is outside the valid range.
|
||
|
The validity of the spectral density is questionable'''
|
||
|
warnings.warn(txt0)
|
||
|
|
||
|
if Tp>20 or Tp<3:
|
||
|
txt1 = '''Tp is outside the valid range.
|
||
|
The validity of the spectral density is questionable'''
|
||
|
warnings.warn(txt1)
|
||
|
|
||
|
def _init_spec(self):
|
||
|
''' Initialize swell and wind part of Torsethaugen spectrum
|
||
|
'''
|
||
|
monitor = 0
|
||
|
Hm0 = self.Hm0
|
||
|
Tp = self.Tp
|
||
|
gravity1 = self.gravity # m/s**2
|
||
|
|
||
|
min = minimum
|
||
|
max = maximum
|
||
|
|
||
|
# The parameter values below are found comparing the
|
||
|
# model to average measured spectra for the Statfjord Field
|
||
|
# in the Northern North Sea.
|
||
|
Af = 6.6 #m**(-1/3)*sec
|
||
|
AL = 2 #sec/sqrt(m)
|
||
|
Au = 25 #sec
|
||
|
KG = 35
|
||
|
KG0 = 3.5
|
||
|
KG1 = 1 # m
|
||
|
r = 0.857 # 6/7
|
||
|
K0 = 0.5 #1/sqrt(m)
|
||
|
K00 = 3.2
|
||
|
|
||
|
M0 = 4
|
||
|
B1 = 2 #sec
|
||
|
B2 = 0.7
|
||
|
B3 = 3.0 #m
|
||
|
S0 = 0.08 #m**2*s
|
||
|
S1 = 3 #m
|
||
|
|
||
|
# Preliminary comparisons with spectra from other areas indicate that
|
||
|
# the parameters on the line below can be dependent on geographical location
|
||
|
A10 = 0.7; A1 = 0.5; A20 = 0.6; A2 = 0.3; A3 = 6
|
||
|
|
||
|
Tf = Af*(Hm0)**(1.0/3.0)
|
||
|
Tl = AL*sqrt(Hm0) # lower limit
|
||
|
Tu = Au # upper limit
|
||
|
|
||
|
#Non-dimensional scales
|
||
|
# New call pab April 2005
|
||
|
El = min(max((Tf-Tp)/(Tf-Tl),0),1) #wind sea
|
||
|
Eu = min(max((Tp-Tf)/(Tu-Tf),0),1) #Swell
|
||
|
|
||
|
|
||
|
|
||
|
if Tp<Tf: # Wind dominated seas
|
||
|
# Primary peak (wind dominated)
|
||
|
Nw = K0*sqrt(Hm0)+K00 # high frequency exponent
|
||
|
Mw = M0 # spectral width exponent
|
||
|
Rpw = min((1-A10)*exp(-(El/A1)**2)+A10,1)
|
||
|
Hpw = Rpw*Hm0 # significant waveheight wind
|
||
|
Tpw = Tp # primary peak period
|
||
|
# peak enhancement factor
|
||
|
gammaw = KG*(1+KG0*exp(-Hm0/KG1))*(2*pi/gravity1*Rpw*Hm0/(Tp**2))**r
|
||
|
gammaw = max(gammaw,1)
|
||
|
# Secondary peak (swell)
|
||
|
Ns = Nw # high frequency exponent
|
||
|
Ms = Mw # spectral width exponent
|
||
|
Rps = sqrt(1.0-Rpw**2.0)
|
||
|
Hps = Rps*Hm0 # significant waveheight swell
|
||
|
Tps = Tf+B1
|
||
|
gammas = 1.0
|
||
|
|
||
|
if monitor:
|
||
|
if Rps > 0.1:
|
||
|
print(' Spectrum for Wind dominated sea')
|
||
|
else:
|
||
|
print(' Spectrum for pure wind sea')
|
||
|
else: #swell dominated seas
|
||
|
|
||
|
# Primary peak (swell)
|
||
|
Ns = K0*sqrt(Hm0)+K00 #high frequency exponent
|
||
|
Ms = M0 #spectral width exponent
|
||
|
Rps = min((1-A20)*exp(-(Eu/A2)**2)+A20,1)
|
||
|
Hps = Rps*Hm0 # significant waveheight swell
|
||
|
Tps = Tp # primary peak period
|
||
|
# peak enhancement factor
|
||
|
gammas = KG*(1+KG0*exp(-Hm0/KG1))*(2*pi/gravity1*Hm0/(Tf**2))**r*(1+A3*Eu)
|
||
|
gammas = max(gammas,1)
|
||
|
|
||
|
# Secondary peak (wind)
|
||
|
Nw = Ns # high frequency exponent
|
||
|
Mw = M0*(1-B2*exp(-Hm0/B3)) # spectral width exponent
|
||
|
Rpw = sqrt(1-Rps**2)
|
||
|
Hpw = Rpw*Hm0 # significant waveheight wind
|
||
|
|
||
|
C = (Nw-1)/Mw
|
||
|
B = Nw/Mw
|
||
|
G0w = B**C*Mw/sp.gamma(C)#normalizing factor
|
||
|
#G0w = exp(C*log(B)+log(Mw)-gammaln(C))
|
||
|
#G0w = Mw/((B)**(-C)*gamma(C))
|
||
|
|
||
|
if Hpw>0:
|
||
|
Tpw = (16*S0*(1-exp(-Hm0/S1))*(0.4)**Nw/( G0w*Hpw**2))**(-1.0/(Nw-1.0))
|
||
|
else:
|
||
|
Tpw = inf
|
||
|
|
||
|
#Tpw = max(Tpw,2.5)
|
||
|
gammaw = 1
|
||
|
if monitor:
|
||
|
if Rpw > 0.1:
|
||
|
print(' Spectrum for swell dominated sea')
|
||
|
else:
|
||
|
print(' Spectrum for pure swell sea')
|
||
|
|
||
|
|
||
|
if monitor:
|
||
|
if (3.6*sqrt(Hm0)<= Tp & Tp<=5*sqrt(Hm0)):
|
||
|
print(' Jonswap range')
|
||
|
|
||
|
print('Hm0 = %g' % Hm0)
|
||
|
print('Ns, Ms = %g, %g Nw, Mw = %g, %g' % (Ns, Ms, Nw, Mw))
|
||
|
print('gammas = %g gammaw = ' % (gammas,gammaw))
|
||
|
print('Rps = %g Rpw = %g' % (Rps,Rpw))
|
||
|
print('Hps = %g Hpw = %g' % (Hps, Hpw))
|
||
|
print('Tps = %g Tpw = %g' % (Tps, Tpw))
|
||
|
|
||
|
|
||
|
#G0s=Ms/((Ns/Ms)**(-(Ns-1)/Ms)*gamma((Ns-1)/Ms )) #normalizing factor
|
||
|
|
||
|
# Wind part
|
||
|
self.wind = Jonswap(Hm0=Hpw, Tp=Tpw, gamma=gammaw, N=Nw, M=Mw,
|
||
|
method=self.method, chk_seastate=False)
|
||
|
# Swell part
|
||
|
self.swell = Jonswap(Hm0=Hps, Tp=Tps, gamma=gammas, N=Ns, M=Ms,
|
||
|
method=self.method, chk_seastate=False)
|
||
|
|
||
|
class McCormick(Bretschneider):
|
||
|
''' McCormick spectral density model
|
||
|
|
||
|
Member variables
|
||
|
----------------
|
||
|
Hm0 = significant wave height (default 7 (m))
|
||
|
Tp = peak period (default 11 (sec))
|
||
|
Tz = zero-down crossing period (default 0.8143*Tp)
|
||
|
M = scalar defining spectral width around the peak.
|
||
|
(default depending on Tp and Tz)
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
w : array-like
|
||
|
angular frequencies [rad/s]
|
||
|
|
||
|
Description
|
||
|
-----------
|
||
|
The McCormick spectrum parameterization is a modification of the Bretschneider
|
||
|
spectrum and defined as
|
||
|
|
||
|
S(w) = (M+1)*(Hm0/4)^2/wp*(wp./w)^(M+1)*exp(-(M+1)/M*(wp/w)^M)
|
||
|
where
|
||
|
Tp/Tz=(1+1/M)^(1/M)/gamma(1+1/M)
|
||
|
|
||
|
|
||
|
Example:
|
||
|
--------
|
||
|
>>> S = McCormick(Hm0=6.5,Tp=10)
|
||
|
>>> S(range(4))
|
||
|
array([ 0. , 1.87865908, 0.15050447, 0.02994663])
|
||
|
|
||
|
|
||
|
See also
|
||
|
--------
|
||
|
Bretschneider
|
||
|
Jonswap,
|
||
|
Torsethaugen
|
||
|
|
||
|
|
||
|
References:
|
||
|
-----------
|
||
|
M.E. McCormick (1999)
|
||
|
"Application of the Generic Spectral Formula to Fetch-Limited Seas"
|
||
|
Marine Technology Society, Vol 33, No. 3, pp 27-32
|
||
|
'''
|
||
|
|
||
|
def __init__(self, Hm0=7, Tp=11, Tz=None, M=None, chk_seastate=True):
|
||
|
self.type = 'McCormick'
|
||
|
self.Hm0 = Hm0
|
||
|
self.Tp = Tp
|
||
|
if Tz==None:
|
||
|
Tz = 0.8143*Tp
|
||
|
|
||
|
self.Tz = Tz
|
||
|
if chk_seastate:
|
||
|
self.chk_seastate()
|
||
|
|
||
|
if M==None and self.Hm0>0:
|
||
|
self._TpdTz = Tp/Tz
|
||
|
M = 1.0/optimize.fminbound(self._localoptfun,0.01,5)
|
||
|
self.M = M
|
||
|
self.N = M+1.0
|
||
|
|
||
|
def _localoptfun(self,x):
|
||
|
#LOCALOPTFUN Local function to optimize.
|
||
|
y = 1.0+x
|
||
|
return (y**(x)/sp.gamma(y)-self._TpdTz)**2.0
|
||
|
|
||
|
class OchiHubble(ModelSpectrum):
|
||
|
''' OchiHubble bimodal spectral density model.
|
||
|
|
||
|
Member variables
|
||
|
----------------
|
||
|
|
||
|
Hm0 : significant wave height (default 7 (m))
|
||
|
par : integer defining the parametrization (default 0)
|
||
|
0 : The most probable spectrum
|
||
|
1,2,...10 : gives 95% Confidence spectra
|
||
|
|
||
|
The OchiHubble bimodal spectrum is modelled as
|
||
|
S(w) = Ss(w) + Sw(w) where Ss and Sw are modified Bretschneider
|
||
|
spectra for swell and wind peak, respectively.
|
||
|
|
||
|
The OH spectrum is a six parameter spectrum, all functions of Hm0.
|
||
|
The values of these parameters are determined from a analysis of data
|
||
|
obtained in the North Atlantic. The source of the data is the same as
|
||
|
that for the development of the Pierson-Moskowitz spectrum, but
|
||
|
analysis is carried out on over 800 spectra including those in
|
||
|
partially developed seas and those having a bimodal shape. From a
|
||
|
statistical analysis of the data, a family of wave spectra consisting
|
||
|
of 11 members is generated for a desired sea severity (Hm0) with the
|
||
|
coefficient of 0.95.
|
||
|
A significant advantage of using a family of spectra for design of
|
||
|
marine systems is that one of the family members yields the largest
|
||
|
response such as motions or wave induced forces for a specified sea
|
||
|
severity, while another yields the smallest response with confidence
|
||
|
coefficient of 0.95.
|
||
|
|
||
|
Examples
|
||
|
--------
|
||
|
>>> S = OchiHubble(par=2)
|
||
|
>>> S(range(4))
|
||
|
array([ 0. , 0.90155636, 0.04185445, 0.00583207])
|
||
|
|
||
|
|
||
|
See also
|
||
|
--------
|
||
|
Bretschneider,
|
||
|
Jonswap,
|
||
|
Torsethaugen
|
||
|
|
||
|
References:
|
||
|
----------
|
||
|
Ochi, M.K. and Hubble, E.N. (1976)
|
||
|
'On six-parameter wave spectra.'
|
||
|
In Proc. 15th Conf. Coastal Engng., Vol.1, pp301-328
|
||
|
|
||
|
'''
|
||
|
|
||
|
def __init__(self, Hm0=7, par=1, chk_seastate=True):
|
||
|
self.type = 'Ochi Hubble'
|
||
|
self.Hm0 = Hm0
|
||
|
self.Tp = 1
|
||
|
self.par = par
|
||
|
self.wind = None
|
||
|
self.swell = None
|
||
|
|
||
|
if chk_seastate:
|
||
|
self.chk_seastate()
|
||
|
self._init_spec()
|
||
|
|
||
|
def __call__(self,w):
|
||
|
return self.wind(w)+self.swell(w)
|
||
|
|
||
|
|
||
|
def _init_spec(self):
|
||
|
|
||
|
hp = array([[0.84, 0.54],
|
||
|
[0.84, 0.54],
|
||
|
[0.84, 0.54],
|
||
|
[0.84, 0.54],
|
||
|
[0.84, 0.54],
|
||
|
[0.95, 0.31],
|
||
|
[0.65, 0.76],
|
||
|
[0.90, 0.44],
|
||
|
[0.77, 0.64],
|
||
|
[0.73,0.68],
|
||
|
[0.92, 0.39]])
|
||
|
wa = array([ [0.7, 1.15],
|
||
|
[0.93, 1.5],
|
||
|
[0.41, 0.88],
|
||
|
[0.74, 1.3],
|
||
|
[0.62, 1.03],
|
||
|
[0.70, 1.50],
|
||
|
[0.61, 0.94],
|
||
|
[0.81, 1.60],
|
||
|
[0.54, 0.61],
|
||
|
[0.70, 0.99],
|
||
|
[0.70, 1.37]])
|
||
|
wb = array([ [0.046, 0.039],
|
||
|
[0.056, 0.046],
|
||
|
[0.016, 0.026],
|
||
|
[0.052, 0.039],
|
||
|
[0.039, 0.030],
|
||
|
[0.046, 0.046],
|
||
|
[0.039, 0.036],
|
||
|
[0.052, 0.033],
|
||
|
[0.039, 0.000],
|
||
|
[0.046, 0.039],
|
||
|
[0.046, 0.039]])
|
||
|
Lpar = array([[3.00, 1.54,-0.062],
|
||
|
[3.00, 2.77,-0.112],
|
||
|
[2.55, 1.82,-0.089],
|
||
|
[2.65, 3.90,-0.085],
|
||
|
[2.60, 0.53,-0.069],
|
||
|
[1.35, 2.48,-0.102],
|
||
|
[4.95, 2.48,-0.102],
|
||
|
[1.80, 2.95,-0.105],
|
||
|
[4.50, 1.95,-0.082],
|
||
|
[6.40, 1.78,-0.069],
|
||
|
[0.70, 1.78,-0.069]])
|
||
|
Hm0 = self.Hm0
|
||
|
Lpari = Lpar[self.par]
|
||
|
Li = hstack((Lpari[0],Lpari[1]*exp(Lpari[2]*Hm0)))
|
||
|
|
||
|
Hm0i = hp[self.par]*Hm0
|
||
|
Tpi = 2*pi*exp(wb[self.par]*Hm0)/wa[self.par]
|
||
|
Ni = 4*Li+1
|
||
|
Mi = [4, 4]
|
||
|
|
||
|
self.swell = Bretschneider(Hm0=Hm0i[0], Tp=Tpi[0], N=Ni[0], M=Mi[0])
|
||
|
self.wind = Bretschneider(Hm0=Hm0i[1], Tp=Tpi[1], N=Ni[1], M=Mi[1])
|
||
|
|
||
|
def _chk_extra_param(self):
|
||
|
if self.par<0 or 10<self.par:
|
||
|
raise ValueError('Par must be an integer from 0 to 10!')
|
||
|
|
||
|
class Wallop(Bretschneider):
|
||
|
'''Wallop spectral density model.
|
||
|
|
||
|
Member variables
|
||
|
----------------
|
||
|
Hm0 = significant wave height (default 7 (m))
|
||
|
Tp = peak period (default 11 (sec))
|
||
|
N = shape factor, i.e. slope for the high frequency
|
||
|
% part (default depending on Hm0 and Tp, see below)
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
w : array-like
|
||
|
angular frequencies [rad/s]
|
||
|
|
||
|
Description
|
||
|
-----------
|
||
|
The WALLOP spectrum parameterization is a modification of the Bretschneider
|
||
|
spectrum and defined as
|
||
|
|
||
|
S(w) = A * G0 * wn**(-N)*exp(-N/(4*wn**4))
|
||
|
where
|
||
|
G0 = Normalizing factor related to Bretschneider form
|
||
|
A = (Hm0/4)^2 / wp (Normalization factor)
|
||
|
wn = w/wp
|
||
|
wp = 2*pi/Tp, angular peak frequency
|
||
|
N = abs((log(2*pi^2)+2*log(Hm0/4)-2*log(Lp))/log(2))
|
||
|
Lp = wave length corresponding to the peak frequency, wp.
|
||
|
|
||
|
If N=5 it becomes the same as the JONSWAP spectrum with
|
||
|
peak enhancement factor gamma=1 or the Bretschneider
|
||
|
(Pierson-Moskowitz) spectrum.
|
||
|
|
||
|
Example:
|
||
|
--------
|
||
|
>>> S = Wallop(Hm0=6.5, Tp=10)
|
||
|
>>> S(range(4))
|
||
|
array([ 0.00000000e+00, 9.36921871e-01, 2.76991078e-03,
|
||
|
7.72996150e-05])
|
||
|
|
||
|
See also
|
||
|
--------
|
||
|
Bretschneider
|
||
|
Jonswap,
|
||
|
Torsethaugen
|
||
|
|
||
|
References:
|
||
|
-----------
|
||
|
Huang, N.E., Long, S.R., Tung, C.C, Yuen, Y. and Bilven, L.F. (1981)
|
||
|
"A unified two parameter wave spectral model for a generous sea state"
|
||
|
J. Fluid Mechanics, Vol.112, pp 203-224
|
||
|
'''
|
||
|
|
||
|
def __init__(self, Hm0=7, Tp=11, N=None, chk_seastate=True):
|
||
|
self.type = 'Wallop'
|
||
|
self.Hm0 = Hm0
|
||
|
self.Tp = Tp
|
||
|
self.M = 4
|
||
|
if N is None:
|
||
|
wp = 2.*pi/Tp
|
||
|
kp = w2k(wp,0,inf)[0] # wavenumber at peak frequency
|
||
|
Lp = 2.*pi/kp # wave length at the peak frequency
|
||
|
N = abs((log(2.*pi**2.)+2*log(Hm0/4)-2.0*log(Lp))/log(2))
|
||
|
|
||
|
self.N = N
|
||
|
|
||
|
if chk_seastate:
|
||
|
self.chk_seastate()
|
||
|
|
||
|
class Spreading(object):
|
||
|
'''
|
||
|
Directional spreading function.
|
||
|
|
||
|
Member variables
|
||
|
----------------
|
||
|
Returns
|
||
|
--------
|
||
|
D = Directional spreading function returning
|
||
|
S = D(theta,w,wc) where S is a Nt X Nw matrix with the principal
|
||
|
direction always along the x-axis.
|
||
|
Member varialbes
|
||
|
----------------
|
||
|
type = type of spreading function, see options below (default 'cos2s')
|
||
|
'cos2s' : cos-2s spreading N(S)*[cos((theta-theta0)/2)]**(2*S) (0 < S)
|
||
|
'box' : Box-car spreading N(A)*I( -A < theta-theta0 < A) (0 < A < pi)
|
||
|
'mises' : von Mises spreading N(K)*exp(K*cos(theta-theta0)) (0 < K)
|
||
|
'poisson': Poisson spreading N(X)/(1-2*X*cos(theta-theta0)+X**2) (0 < X < 1)
|
||
|
'sech2' : sech-2 spreading N(B)*sech(B*(theta-theta0))**2 (0 < B)
|
||
|
'wnormal': Wrapped Normal
|
||
|
[1 + 2*sum exp(-(n*D1)^2/2)*cos(n*(theta-theta0))]/(2*pi) (0 < D1)
|
||
|
(N(.) = normalization factor)
|
||
|
(the first letter is enough for unique identification)
|
||
|
|
||
|
theta0 = function handle, inline object, matrix or a scalar defining
|
||
|
average direction given in radians at every angular frequency.
|
||
|
(length 1 or length == length(wn)) (default 0)
|
||
|
method = Defines function used for direcional spreading parameter:
|
||
|
0, None : S(wn) = spa, frequency independent
|
||
|
1, 'mitsuyasu': S(wn) frequency dependent (default)
|
||
|
2, 'donelan' : B(wn) frequency dependent
|
||
|
3, 'banner' : B(wn) frequency dependent
|
||
|
S(wn) = spa *(wn)^ma, : wnlo <= wn < wnc
|
||
|
= spb *(wn)^mb, : wnc <= wn < wnup
|
||
|
= 0 : wnup <= wn
|
||
|
B(wn) = S(wn) : wnlo <= wn < wnup
|
||
|
= spb*wnup^mb : wnup <= wn, method = 2
|
||
|
= sc*F(wn) : wnup <= wn , method = 3
|
||
|
where F(wn) = 10^(-0.4+0.8393*exp(-0.567*log(wn^2))) and sc is
|
||
|
scalefactor to make the spreading funtion continous.
|
||
|
wnlimits = [wnlo wnc wnup] limits used in the function defining the
|
||
|
directional spreading parameter.
|
||
|
wnc is the normalized cutover frequency (default [0 1 inf])
|
||
|
sp = [spa,spb] maximum spread parameters (default [15 15])
|
||
|
m = [ma,mb] shape parameters (default [5 -2.5])
|
||
|
|
||
|
SPREADING Return function handle to a Directional spreading function.
|
||
|
Here the S- or B-parameter, of the COS-2S and SECH-2 spreading function,
|
||
|
respectively, is used as a measure of spread. All the parameters of the
|
||
|
other distributions are related to this parameter through the first Fourier
|
||
|
coefficient, R1, of the directional distribution as follows:
|
||
|
R1 = S/(S+1) or S = R1/(1-R1).
|
||
|
where
|
||
|
Box-car spreading : R1 = sin(A)/A
|
||
|
Von Mises spreading: R1 = besseli(1,K)/besseli(0,K),
|
||
|
Poisson spreading : R1 = X
|
||
|
sech-2 spreading : R1 = pi/(2*B*sinh(pi/(2*B))
|
||
|
Wrapped Normal : R1 = exp(-D1^2/2)
|
||
|
|
||
|
A value of S = 15 corresponds to
|
||
|
'box' : A=0.62, 'sech2' : B=0.89
|
||
|
'mises' : K=8.3, 'poisson': X=0.94
|
||
|
'wnormal': D=0.36
|
||
|
|
||
|
The COS2S is the most frequently used spreading in engineering practice.
|
||
|
Apart from the current meter/pressure cell data in WADIC all
|
||
|
instruments seem to support the 'cos2s' distribution for heavier sea
|
||
|
states, (Krogstad and Barstow, 1999). For medium sea states
|
||
|
a spreading function between COS2S and POISSON seem appropriate,
|
||
|
while POISSON seems appropriate for swell.
|
||
|
For the COS2S Mitsuyasu et al. parameterized SPa = SPb =
|
||
|
11.5*(U10/Cp) where Cp = g/wp is the deep water phase speed at wp and
|
||
|
U10 the wind speed at reference height 10m. Hasselman et al. (1980)
|
||
|
parameterized mb = -2.33-1.45*(U10/Cp-1.17).
|
||
|
Mitsuyasu et al. (1975) showed that SP for wind waves varies from
|
||
|
5 to 30 being a function of dimensionless wind speed.
|
||
|
However, Goda and Suzuki (1975) proposed SP = 10 for wind waves, SP = 25
|
||
|
for swell with short decay distance and SP = 75 for long decay distance.
|
||
|
Compared to experiments Krogstad et al. (1998) found that ma = 5 +/- eps and
|
||
|
that -1< mb < -3.5.
|
||
|
Values given in the litterature: [spa spb ma mb wlim(1:3) ]
|
||
|
(Mitsuyasu: spa == spb) (cos-2s) [15 15 5 -2.5 0 1 3 ]
|
||
|
(Hasselman: spa ~= spb) (cos-2s) [6.97 9.77 4.06 -2.3 0 1.05 3 ]
|
||
|
(Banner : spa ~= spb) (sech2) [2.61 2.28 1.3 -1.3 0.56 0.95 1.6]
|
||
|
|
||
|
Examples :
|
||
|
|
||
|
>>> import pylab as plb
|
||
|
>>> D = Spreading('cos2s',s_a=10.0)
|
||
|
|
||
|
>>> w = plb.linspace(0,3,257)
|
||
|
>>> theta = plb.linspace(-pi,pi,129)
|
||
|
>>> t = plb.contour(D(theta,w)[0].squeeze())
|
||
|
|
||
|
# Make frequency dependent direction
|
||
|
>>> theta0 = lambda w: w*plb.pi/6.0
|
||
|
>>> D2 = Spreading('cos2s',theta0=theta0)
|
||
|
>>> t = plb.contour(D2(theta,w)[0])
|
||
|
|
||
|
# Plot all spreading functions
|
||
|
>>> alltypes = ('cos2s','box','mises','poisson','sech2','wrap_norm')
|
||
|
>>> for ix in range(len(alltypes)):
|
||
|
... D3 = Spreading(alltypes[ix])
|
||
|
... t = plb.figure(ix)
|
||
|
... t = plb.contour(D3(theta,w)[0])
|
||
|
... t = plb.title(alltypes[ix])
|
||
|
>>> plb.close('all')
|
||
|
|
||
|
|
||
|
See also mkdspec, plotspec, spec2spec
|
||
|
|
||
|
References
|
||
|
Krogstad, H.E. and Barstow, S.F. (1999)
|
||
|
"Directional Distributions in Ocean Wave Spectra"
|
||
|
Proceedings of the 9th ISOPE Conference, Vol III, pp. 79-86
|
||
|
|
||
|
Goda, Y. (1999)
|
||
|
"Numerical simulation of ocean waves for statistical analysis"
|
||
|
Marine Tech. Soc. Journal, Vol. 33, No. 3, pp 5--14
|
||
|
|
||
|
Banner, M.L. (1990)
|
||
|
"Equilibrium spectra of wind waves."
|
||
|
J. Phys. Ocean, Vol 20, pp 966--984
|
||
|
Donelan M.A., Hamilton J, Hui W.H. (1985)
|
||
|
"Directional spectra of wind generated waves."
|
||
|
Phil. Trans. Royal Soc. London, Vol A315, pp 387--407
|
||
|
|
||
|
Hasselmann D, Dunckel M, Ewing JA (1980)
|
||
|
"Directional spectra observed during JONSWAP."
|
||
|
J. Phys. Ocean, Vol.10, pp 1264--1280
|
||
|
|
||
|
Mitsuyasu, H, et al. (1975)
|
||
|
"Observation of the directional spectrum of ocean waves using a
|
||
|
coverleaf buoy."
|
||
|
J. Physical Oceanography, Vol.5, No.4, pp 750--760
|
||
|
Some of this might be included in help header:
|
||
|
cos-2s:
|
||
|
NB! The generally strong frequency dependence in directional spread
|
||
|
makes it questionable to run load tests of ships and structures with a
|
||
|
directional spread independent of frequency (Krogstad and Barstow, 1999).
|
||
|
'''
|
||
|
##% Parameterization of B
|
||
|
##% def = 2 Donelan et al freq. parametrization for 'sech2'
|
||
|
##% def = 3 Banner freq. parametrization for 'sech2'
|
||
|
##% (spa ~= spb) (sech-2) [2.61 2.28 1.3 -1.3 0.56 0.95 1.6]
|
||
|
##
|
||
|
##
|
||
|
##% Tested on: Matlab 7.0
|
||
|
##% History:
|
||
|
##% revised pab jan 2007
|
||
|
##% - renamed from spreading to mkspreading
|
||
|
##% - the function now return a function handle to the actual spreading function.
|
||
|
##% - removed wc, the cut over frequency -> input is now assumed as normalized frequency, w/wc.
|
||
|
##% revised pab 17.06.2001
|
||
|
##% - added wrapped normal spreading
|
||
|
##% revised pab 6 April 2001
|
||
|
##% - added fourier2distpar
|
||
|
##% - Fixed the normalization of sech2 spreading
|
||
|
##% revised by PAB and IR 1 April 2001: Introducing the azymuth as a
|
||
|
##% standard parameter in order to avoid rotations of the directions
|
||
|
##% theta. The x-axis is always pointing into the principal direction
|
||
|
##% as defined in the spreading function D(omega,theta). The actual
|
||
|
##% principal direction is defined by means of field D.phi.
|
||
|
##% revised es 06.06.2000, commented away: if ((ma==0) & (mb==0)), ...,
|
||
|
##% hoping that the check is unnecessary
|
||
|
##% revised pab 13.06.2000
|
||
|
##% - fixed a serious bug: made sure -pi<= th-th0 <=pi
|
||
|
##% revised pab 16.02.2000
|
||
|
##% -fixed default value for Hasselman parametrization
|
||
|
##% revised pab 02.02.2000
|
||
|
##% - Nt or th may be specified + check on th
|
||
|
##% - added frequency dependence for sech-2
|
||
|
##% - th0 as separate input
|
||
|
##% - updated header info
|
||
|
##% - changed check for nargins
|
||
|
##% - added the possibility of nan's in data vector
|
||
|
##% Revised by jr 2000.01.25
|
||
|
##% - changed check of nargins
|
||
|
##% - frequency dependence only for cos-2s
|
||
|
##% - updated information
|
||
|
##% By es, jr 1999.11.25
|
||
|
|
||
|
|
||
|
def __init__(self,type='cos2s',theta0=0,method='mitsuyasu',s_a=15.,s_b=15.,m_a=5.,m_b=-2.5,wn_lo=0.0,wn_c=1.,wn_up=inf):
|
||
|
|
||
|
self.type = type
|
||
|
self.theta0 = theta0
|
||
|
self.method = method
|
||
|
self.s_a = s_a
|
||
|
self.s_b = s_b
|
||
|
self.m_a = m_a
|
||
|
self.m_b = m_b
|
||
|
self.wn_lo = wn_lo
|
||
|
self.wn_c = wn_c
|
||
|
self.wn_up = wn_up
|
||
|
|
||
|
methods = dict(n=None, m='mitsuyasu', d='donelan', b='banner')
|
||
|
methodslist = (None, 'mitsuyasu', 'donelan', 'banner')
|
||
|
|
||
|
if isinstance(self.method,str):
|
||
|
if not self.method[0] in methods:
|
||
|
raise ValueError('Unknown method')
|
||
|
self.method = methods[self.method[0]]
|
||
|
elif self.method == None:
|
||
|
pass
|
||
|
else:
|
||
|
if method<0 or 3<method:
|
||
|
method = 2
|
||
|
self.method = methodslist[method]
|
||
|
|
||
|
self._spreadfun = dict(c=self.cos2s, b=self.box, m=self.mises,
|
||
|
p=self.poisson, s=self.sech2, w=self.wrap_norm)
|
||
|
self._fourierdispatch = dict(b=self.fourier2a, m=self.fourier2k,
|
||
|
p=self.fourier2x, s=self.fourier2b,
|
||
|
w=self.fourier2d)
|
||
|
|
||
|
def __call__(self,*args):
|
||
|
spreadfun = self._spreadfun[self.type[0]]
|
||
|
return spreadfun(*args)
|
||
|
|
||
|
def chk_input(self,theta,w=1,wc=1): # [s_par,TH,phi0,Nt] =
|
||
|
''' CHK_INPUT
|
||
|
|
||
|
CALL [s_par,TH,phi0,Nt] = inputchk(theta,w,wc)
|
||
|
'''
|
||
|
|
||
|
wn = atleast_1d(w/wc)
|
||
|
theta = theta.ravel()
|
||
|
Nt = len(theta)
|
||
|
|
||
|
# Make sure theta is from -pi to pi
|
||
|
phi0 = 0.0
|
||
|
theta = mod(theta+pi,2*pi)-pi
|
||
|
|
||
|
|
||
|
if hasattr(self.theta0, '__call__'):
|
||
|
th0 = self.theta0(wn.flatten())
|
||
|
else:
|
||
|
th0 = atleast_1d(self.theta0).flatten()
|
||
|
|
||
|
Nt0 = th0.size
|
||
|
Nw = w.size
|
||
|
isFreqDepDir = (Nt0==Nw)
|
||
|
if isFreqDepDir:
|
||
|
# frequency dependent spreading and/or
|
||
|
# frequency dependent direction
|
||
|
# make sure -pi<=TH<pi
|
||
|
TH = mod(theta[:,newaxis]-th0[newaxis,:]+pi,2*pi)-pi
|
||
|
elif Nt0!=1:
|
||
|
raise ValueError('The length of theta0 must equal to 1 or the length of w')
|
||
|
else:
|
||
|
TH = mod(theta-th0+pi,2*pi)-pi # make sure -pi<=TH<pi
|
||
|
if self.method!=None: # frequency dependent spreading
|
||
|
TH = TH[:,newaxis]
|
||
|
|
||
|
# Get spreading parameter
|
||
|
#~~~~~~~~~~~~~~~~
|
||
|
s = self.spread_par_s(wn)
|
||
|
|
||
|
if self.type[0]=='c': # cos2s
|
||
|
s_par = s
|
||
|
else:
|
||
|
r1 = abs(s/(s+1)) #% First Fourier coefficient of the directional spreading function.
|
||
|
#% Find distribution parameter from first Fourier coefficient.
|
||
|
s_par = self.fourier2distpar(r1)
|
||
|
if self.method!=None:
|
||
|
s_par = s_par[newaxis,:]
|
||
|
return s_par, TH, phi0, Nt
|
||
|
|
||
|
|
||
|
def cos2s(self, theta, w=1, wc=1): # [D, phi0] =
|
||
|
''' COS2S spreading function
|
||
|
|
||
|
CALL [D, phi0] = cos2s(theta,w,wc)
|
||
|
[D, phi0] = cos2s(Nt,w)
|
||
|
|
||
|
D = matrix of directonal spreading function, COS2S, defined as
|
||
|
|
||
|
cos2s(theta,w) = N(S)*[cos((theta-theta0)/2)]^(2*S) (0 < S)
|
||
|
|
||
|
where N() is a normalization factor and S is the spreading parameter
|
||
|
possibly dependent on w. The principal direction of D is always along
|
||
|
the x-axis. size Nt X Nw.
|
||
|
phi0 = Parameter defining the actual principal direction of D.
|
||
|
theta = vector of angles given in radians. Lenght Nt
|
||
|
w = vector of angular frequencies given rad/s. Length Nw.
|
||
|
'''
|
||
|
S, TH, phi0, unused_Nt = self.chk_input(theta, w, wc)
|
||
|
|
||
|
## if not self.method[0]=='n':
|
||
|
## S = S[newaxis,:]
|
||
|
gammaln = sp.gammaln
|
||
|
|
||
|
D = (exp(gammaln(S+1)-gammaln(S+1.0/2.0))/(2*sqrt(pi)))*cos(TH/2.0)**(2.0*S)
|
||
|
return D, phi0
|
||
|
|
||
|
|
||
|
|
||
|
def poisson(self,theta,w=1,wc=1): # [D,phi0] =
|
||
|
''' POISSON spreading function
|
||
|
|
||
|
CALL [D, phi0] = poisson(theta,w,wc)
|
||
|
|
||
|
D = matrix of directonal spreading function, POISSON, defined as
|
||
|
|
||
|
poisson(theta,w) = N(X)/(1-2*X*cos(theta-theta0)+X^2) (0 < X < 1)
|
||
|
|
||
|
where N() is a normalization factor and X is the spreading parameter
|
||
|
possibly dependent on w. The principal direction of D is always along
|
||
|
the x-axis. size Nt X Nw.
|
||
|
phi0 = Parameter defining the actual principal direction of D.
|
||
|
|
||
|
'''
|
||
|
[X, TH, phi0, unused_Nt] = self.chk_input(theta,w,wc)
|
||
|
|
||
|
## if not self.method[0]=='n':
|
||
|
## X = X[newaxis,:]
|
||
|
|
||
|
|
||
|
D = (1-X**2.)/(1.-(2.*cos(TH)-X)*X)/(2.*pi)
|
||
|
return D, phi0
|
||
|
|
||
|
|
||
|
def wrap_norm(self,theta,w=1,wc=1):
|
||
|
''' Wrapped Normal spreading function
|
||
|
|
||
|
CALL [D, phi0] = wnormal(theta,w,wc)
|
||
|
|
||
|
D = matrix of directonal spreading function, WNORMAL, defined as
|
||
|
|
||
|
wnormal(theta,w) = N(D1)*[1 + 2*sum exp(-(n*D1)^2/2)*cos(n*(theta-theta0))] (0 < D1)
|
||
|
|
||
|
where N() is a normalization factor and D1 is the spreading parameter
|
||
|
possibly dependent on w. The principal direction of D is always along
|
||
|
the x-axis. size Nt X Nw.
|
||
|
phi0 = Parameter defining the actual principal direction of D.
|
||
|
'''
|
||
|
|
||
|
|
||
|
|
||
|
[par,TH,phi0,Nt] = self.chk_input(theta,w,wc)
|
||
|
|
||
|
D1 = par**2./2.
|
||
|
## if not self.method(1)=='n':
|
||
|
## D1 = D1[newaxis,:]
|
||
|
|
||
|
|
||
|
ix = arange(1,Nt)
|
||
|
ix2 = ix**2
|
||
|
Nd2 = D1.size
|
||
|
Fcof = vstack( (ones((1,Nd2))/2, exp(-ix2[:,newaxis]*D1)))/pi
|
||
|
|
||
|
cor = exp(1j*ix[:,newaxis]*TH[0,:])
|
||
|
Pcor = vstack( (ones((1,TH.shape[1]) ), cor ) ) # % correction term to get
|
||
|
#% the correct integration limits
|
||
|
Fcof = Fcof*Pcor.conj()
|
||
|
D = real(fft(Fcof,axis=0))
|
||
|
D[D<0]=0
|
||
|
return D, phi0
|
||
|
|
||
|
def sech2(self,theta,w=1,wc=1):
|
||
|
'''Sech**2 spreading function
|
||
|
|
||
|
CALL [D, phi0] = sech2(theta,w,wc)
|
||
|
|
||
|
D = matrix of directonal spreading function, SECH2, defined as
|
||
|
|
||
|
sech2(theta,w) = N(B)*0.5*B*sech(B*(theta-theta0))^2 (0 < B)
|
||
|
|
||
|
where N() is a normalization factor and X is the spreading parameter
|
||
|
possibly dependent on w. The principal direction of D is always along
|
||
|
the x-axis. size Nt X Nw.
|
||
|
phi0 = Parameter defining the actual principal direction of D.
|
||
|
'''
|
||
|
|
||
|
|
||
|
[B, TH, phi0, unused_Nt] = self.chk_input(theta,w,wc)
|
||
|
NB = tanh(pi*B) #% Normalization factor.
|
||
|
NB = where(NB==0,1.0,NB) # Avoid division by zero
|
||
|
## if not self.method[0]=='n':
|
||
|
## B = B[newaxis,:]
|
||
|
## NB = NB[newaxis,:]
|
||
|
|
||
|
D = 0.5*B*sech(B*TH)**2./NB
|
||
|
return D, phi0
|
||
|
|
||
|
def mises(self,theta,w=1,wc=1):
|
||
|
'''Mises spreading function
|
||
|
|
||
|
CALL [D, phi0] = mises(theta,w,wc)
|
||
|
|
||
|
D = matrix of directonal spreading function, MISES, defined as
|
||
|
|
||
|
mises(theta,w) = N(K)*exp(K*cos(theta-theta0)) (0 < K)
|
||
|
|
||
|
where N() is a normalization factor and K is the spreading parameter
|
||
|
possibly dependent on w. The principal direction of D is always along
|
||
|
the x-axis. size Nt X Nw.
|
||
|
phi0 = Parameter defining the actual principal direction of D.
|
||
|
'''
|
||
|
|
||
|
[K, TH, phi0, unused_Nt] = self.chk_input(theta,w,wc)
|
||
|
## if not self.method[0]=='n':
|
||
|
## K = K[newaxis,:]
|
||
|
|
||
|
D = exp(K*(cos(TH)-1.))/(2*pi*sp.ive(0,K))
|
||
|
return D, phi0
|
||
|
|
||
|
|
||
|
|
||
|
def box(self,theta,w=1,wc=1):
|
||
|
''' Box car spreading function
|
||
|
|
||
|
CALL [D, phi0] = box(theta,w,wc)
|
||
|
|
||
|
D = matrix of directonal spreading function, SECH2, defined as
|
||
|
|
||
|
box(theta,w) = N(A)*I( -A < theta-theta0 < A) (0 < A < pi)
|
||
|
|
||
|
where N() is a normalization factor and A is the spreading parameter
|
||
|
possibly dependent on w. The principal direction of D is always along
|
||
|
the x-axis. size Nt X Nw.
|
||
|
phi0 = Parameter defining the actual principal direction of D.
|
||
|
'''
|
||
|
|
||
|
|
||
|
|
||
|
[A,TH,phi0,unused_Nt] = self.chk_input(theta,w,wc)
|
||
|
|
||
|
## if not self.method[0]=='n':
|
||
|
## A = A[newaxis,:]
|
||
|
|
||
|
D = ((-A<=TH) & (TH<=A))/(2.*A)
|
||
|
return D, phi0
|
||
|
|
||
|
# Local sub functions
|
||
|
|
||
|
def fourier2distpar(self,r1):
|
||
|
''' Fourier coefficients to distribution parameter
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
r1 = corresponding fourier coefficient.
|
||
|
type = string defining spreading function
|
||
|
'box'
|
||
|
'mises'
|
||
|
'poisson'
|
||
|
'sech2'
|
||
|
'wnormal'
|
||
|
Returns
|
||
|
x = distribution parameter
|
||
|
|
||
|
The S-parameter of the COS-2S spreading function is used as a measure of
|
||
|
spread in MKSPREADING. All the parameters of the other distributions are
|
||
|
related to this S-parameter through the first Fourier coefficient, R1, of the
|
||
|
directional distribution as follows:
|
||
|
R1 = S/(S+1) or S = R1/(1-R1).
|
||
|
where
|
||
|
Box-car spreading : R1 = sin(A)/A
|
||
|
Von Mises spreading: R1 = besseli(1,K)/besseli(0,K),
|
||
|
Poisson spreading : R1 = X
|
||
|
sech-2 spreading : R1 = pi/(2*B*sinh(pi/(2*B))
|
||
|
Wrapped Normal : R1 = exp(-D1^2/2)
|
||
|
'''
|
||
|
fourierfun = self._fourierdispatch.get(self.type[0])
|
||
|
return fourierfun(r1)
|
||
|
|
||
|
def fourier2x(self,r1):
|
||
|
''' Returns the solution of r1 = x.
|
||
|
'''
|
||
|
X = r1
|
||
|
if any(X>=1):
|
||
|
raise ValueError('POISSON spreading: X value must be less than 1')
|
||
|
return X
|
||
|
|
||
|
def fourier2a(self,r1):
|
||
|
''' Returns the solution of R1 = sin(A)/A.
|
||
|
'''
|
||
|
A0 = flipud(linspace(0,pi+0.1,1025))
|
||
|
funA = interp1d(sinc(A0/pi),A0)
|
||
|
A0 = funA(r1.ravel())
|
||
|
A = asarray(A0)
|
||
|
|
||
|
# Newton-Raphson
|
||
|
da = ones_like(r1)
|
||
|
|
||
|
max_count = 100
|
||
|
ix = flatnonzero(A)
|
||
|
for unused_iy in range(max_count):
|
||
|
Ai = A[ix]
|
||
|
da[ix] = (sin(Ai) -Ai*r1[ix])/(cos(Ai)-r1[ix])
|
||
|
Ai = Ai - da[ix]
|
||
|
# Make sure that the current guess is larger than zero and less than pi
|
||
|
#x(ix) = xi + 0.1*(dx(ix) - 9*xi).*(xi<=0) + 0.38*(dx(ix)-6.2*xi +6.2).*(xi>pi)
|
||
|
# Make sure that the current guess is larger than zero.
|
||
|
A[ix] = Ai + 0.5*(da[ix] - Ai)*(Ai<=0.0)
|
||
|
|
||
|
ix = flatnonzero((abs(da) > sqrt(eps)*abs(A))*(abs(da) > sqrt(eps)))
|
||
|
if ix.size==0:
|
||
|
if any(A>pi):
|
||
|
raise ValueError('BOX-CAR spreading: The A value must be less than pi')
|
||
|
return A.clip(min=1e-16,max=pi)
|
||
|
|
||
|
|
||
|
warnings.warn('Newton raphson method did not converge.')
|
||
|
return A.clip(min=1e-16) # Avoid division by zero
|
||
|
|
||
|
def fourier2k(self, r1):
|
||
|
'''
|
||
|
Returns the solution of R1 = besseli(1,K)/besseli(0,K),
|
||
|
'''
|
||
|
K0 = hstack((linspace(0,10,513), linspace(10.00001,100)))
|
||
|
fun0 = lambda x : sp.ive(1,x)/sp.ive(0,x)
|
||
|
funK = interp1d(fun0(K0),K0)
|
||
|
K0 = funK(r1.ravel())
|
||
|
k1 = flatnonzero(isnan(K0))
|
||
|
if (k1.size>0):
|
||
|
K0[k1] = 0.0
|
||
|
K0[k1] = K0.max()
|
||
|
|
||
|
ix0 = flatnonzero(r1!=0.0)
|
||
|
K = zeros_like(r1)
|
||
|
fun = lambda x : fun0(x)-r1[ix]
|
||
|
for ix in ix0:
|
||
|
K[ix] = optimize.fsolve(fun,K0[ix])
|
||
|
return K
|
||
|
|
||
|
def fourier2b(self,r1):
|
||
|
''' Returns the solution of R1 = pi/(2*B*sinh(pi/(2*B)).
|
||
|
'''
|
||
|
B0 = hstack((linspace(eps,5,513), linspace(5.0001,100)))
|
||
|
funB = interp1d(self._r1ofsech2(B0),B0)
|
||
|
|
||
|
B0 = funB(r1.ravel())
|
||
|
k1 = flatnonzero(isnan(B0))
|
||
|
if (k1.size>0):
|
||
|
B0[k1] = 0.0
|
||
|
B0[k1] = max(B0)
|
||
|
|
||
|
ix0 = flatnonzero(r1!=0.0)
|
||
|
B = zeros_like(r1)
|
||
|
fun = lambda x : 0.5*pi/(sinh(.5*pi/x))-x*r1[ix]
|
||
|
for ix in ix0:
|
||
|
B[ix] = abs(optimize.fsolve(fun,B0[ix]))
|
||
|
return B
|
||
|
|
||
|
def fourier2d(self,r1):
|
||
|
''' Returns the solution of R1 = exp(-D**2/2).
|
||
|
'''
|
||
|
r = clip(r1,0.,1.0)
|
||
|
return where(r<=0,inf,sqrt(-2.0*log(r)))
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
def spread_par_s(self,wn):
|
||
|
''' Return spread parameter, S, of COS2S function
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
wn : array_like
|
||
|
normalized frequencies.
|
||
|
Returns
|
||
|
-------
|
||
|
S : ndarray
|
||
|
spread parameter of COS2S functions
|
||
|
'''
|
||
|
if self.method==None:
|
||
|
# no frequency dependent spreading,
|
||
|
# but possible frequency dependent direction
|
||
|
s = atleast_1d(self.s_a)
|
||
|
else:
|
||
|
wn_lo = self.wn_lo
|
||
|
wn_up = self.wn_up
|
||
|
wn_c = self.wn_c
|
||
|
|
||
|
spa = self.s_a
|
||
|
spb = self.s_b
|
||
|
ma = self.m_a
|
||
|
mb = self.m_b
|
||
|
|
||
|
|
||
|
# Mitsuyasu et. al and Hasselman et. al parametrization of
|
||
|
# frequency dependent spreading
|
||
|
s = where(wn<=wn_c,spa*wn**ma,spb*wn**mb)
|
||
|
s[wn<=wn_lo] = 0.0
|
||
|
|
||
|
k = flatnonzero(wn_up<wn)
|
||
|
if k.size>0:
|
||
|
if self.method[0]=='d':
|
||
|
# Donelan et. al. parametrization for B in SECH-2
|
||
|
s[k] = spb*(wn_up)**mb
|
||
|
|
||
|
# Convert to S-paramater in COS-2S distribution
|
||
|
r1 = self.r1ofsech2(s)
|
||
|
s = r1/(1.-r1)
|
||
|
|
||
|
elif self.method[0]=='b':
|
||
|
# Banner parametrization for B in SECH-2
|
||
|
s3m = spb*(wn_up)**mb
|
||
|
s3p = self._donelan(wn_up)
|
||
|
scale = s3m/s3p #% Scale so that parametrization will be continous
|
||
|
s[k] = scale*self.donelan(wn[k])
|
||
|
r1 = self.r1ofsech2(s)
|
||
|
|
||
|
#% Convert to S-paramater in COS-2S distribution
|
||
|
s = r1/(1.-r1)
|
||
|
else:
|
||
|
s[k] = 0.0
|
||
|
|
||
|
if any(s<0):
|
||
|
raise ValueError('The COS2S spread parameter, S(w), value must be larger than 0')
|
||
|
return s
|
||
|
|
||
|
|
||
|
def _donelan(self, wn):
|
||
|
''' High frequency decay of B of sech2 paramater
|
||
|
'''
|
||
|
return 10.0**(-0.4+0.8393*exp(-0.567*log(wn**2)))
|
||
|
|
||
|
def _r1ofsech2(self, B):
|
||
|
''' R1OFSECH2 Computes R1 = pi./(2*B.*sinh(pi./(2*B)))
|
||
|
'''
|
||
|
realmax = finfo(float).max
|
||
|
tiny = 1./realmax
|
||
|
x = clip(2.*B,tiny,realmax)
|
||
|
xk = pi/x
|
||
|
return where(x<100.,xk/sinh(xk),-2.*xk/(exp(xk)*expm1(-2.*xk)))
|
||
|
|
||
|
|
||
|
|
||
|
def test_some_spectra():
|
||
|
S = Jonswap()
|
||
|
|
||
|
w = arange(3.0)
|
||
|
S(w)*phi1(w,30.0)
|
||
|
S1 = S.tospecdata(w)
|
||
|
S1.plot()
|
||
|
|
||
|
|
||
|
import pylab as plb
|
||
|
w = plb.linspace(0,2.5)
|
||
|
S = Tmaspec(h=10,gamma=1) # Bretschneider spectrum Hm0=7, Tp=11
|
||
|
plb.plot(w,S(w))
|
||
|
plb.plot(w,S(w,h=21))
|
||
|
plb.plot(w,S(w,h=42))
|
||
|
plb.show()
|
||
|
plb.close('all')
|
||
|
|
||
|
|
||
|
|
||
|
import pylab as plb
|
||
|
#w = plb.linspace(0,3)
|
||
|
w,th = plb.ogrid[0:4,0:6]
|
||
|
k,k2 = w2k(w,th)
|
||
|
k1,k12 = w2k(w,th,h=20)
|
||
|
plb.plot(w,k,w,k2)
|
||
|
|
||
|
plb.show()
|
||
|
|
||
|
plb.close('all')
|
||
|
w = plb.linspace(0,2,100)
|
||
|
S = Torsethaugen(Hm0=6, Tp=8)
|
||
|
plb.plot(w,S(w),w,S.wind(w),w,S.swell(w))
|
||
|
|
||
|
S1 = Jonswap(Hm0=7, Tp=11,gamma=1)
|
||
|
w = plb.linspace(0,2,100)
|
||
|
plb.plot(w,S1(w))
|
||
|
plb.show()
|
||
|
plb.close('all')
|
||
|
|
||
|
|
||
|
Hm0 = plb.arange(1,11)
|
||
|
Tp = plb.linspace(2,16)
|
||
|
T,H = plb.meshgrid(Tp,Hm0)
|
||
|
gam = jonswap_peakfact(H,T)
|
||
|
plb.plot(Tp,gam.T)
|
||
|
plb.xlabel('Tp [s]')
|
||
|
plb.ylabel('Peakedness parameter')
|
||
|
|
||
|
Hm0 = plb.linspace(1,20)
|
||
|
Tp = Hm0
|
||
|
[T,H] = plb.meshgrid(Tp,Hm0)
|
||
|
gam = jonswap_peakfact(H,T)
|
||
|
v = plb.arange(0,8)
|
||
|
plb.contourf(Tp,Hm0,gam,v)
|
||
|
plb.colorbar()
|
||
|
plb.show()
|
||
|
plb.close('all')
|
||
|
|
||
|
def test_spreading():
|
||
|
import pylab as plb
|
||
|
pi = plb.pi
|
||
|
w = plb.linspace(0,3,257)
|
||
|
theta = plb.linspace(-pi,pi,129)
|
||
|
theta0 = lambda w: w*plb.pi/6.0
|
||
|
D2 = Spreading('cos2s',theta0=theta0)
|
||
|
d1 =D2(theta,w)[0]
|
||
|
t = plb.contour(d1.squeeze())
|
||
|
|
||
|
pi = plb.pi
|
||
|
D = Spreading('wrap_norm',s_a=10.0)
|
||
|
|
||
|
w = plb.linspace(0,3,257)
|
||
|
theta = plb.linspace(-pi,pi,129)
|
||
|
d1 = D(theta,w)
|
||
|
plb.contour(d1[0])
|
||
|
plb.show()
|
||
|
|
||
|
def main():
|
||
|
if False: # True: #
|
||
|
test_some_spectra()
|
||
|
else:
|
||
|
import doctest
|
||
|
doctest.testmod()
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main()
|