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.
pywafo/wafo/wavemodels.py

269 lines
9.0 KiB
Python

'''
Created on 13. mar. 2018
@author: pab
'''
import numpy as np
from numpy import pi, sqrt
import wafo.transform.estimation as te
import wafo.transform as wt
from wafo.containers import PlotData
from wafo.kdetools.kernels import qlevels
from wafo.misc import tranproc
import warnings
def _set_default_t_h_g(t, h, g, m0, m2):
if g is None:
y = np.linspace(-5, 5)
x = sqrt(m0) * y + 0
g = wt.TrData(y, x)
if t is None:
tt1 = 2 * pi * sqrt(m0 / m2)
t = np.linspace(0, 1.7 * tt1, 51)
if h is None:
px = g.gauss2dat([0, 4.])
px = abs(px[1] - px[0])
h = np.linspace(0, 1.3 * px, 41)
return h, t, g
def lh83pdf(t=None, h=None, mom=None, g=None):
"""
LH83PDF Longuet-Higgins (1983) approximation of the density (Tc,Ac)
in a stationary Gaussian transform process X(t) where
Y(t) = g(X(t)) (Y zero-mean Gaussian, X non-Gaussian).
CALL: f = lh83pdf(t,h,[m0,m1,m2],g);
f = density of wave characteristics of half-wavelength
in a stationary Gaussian transformed process X(t),
where Y(t) = g(X(t)) (Y zero-mean Gaussian)
t,h = vectors of periods and amplitudes, respectively.
default depending on the spectral moments
m0,m1,m2 = the 0'th,1'st and 2'nd moment of the spectral density
with angular frequency.
g = space transformation, Y(t)=g(X(t)), default: g is identity
transformation, i.e. X(t) = Y(t) is Gaussian,
The transformation, g, can be estimated using lc2tr
or dat2tr or given apriori by ochi.
Example
-------
>>> import wafo.spectrum.models as sm
>>> Sj = sm.Jonswap()
>>> w = np.linspace(0,4,256)
>>> S = Sj.tospecdata(w) #Make spectrum object from numerical values
>>> S = sm.SpecData1D(Sj(w),w) # Alternatively do it manually
>>> mom, mom_txt = S.moment(nr=2, even=False)
>>> f = lh83pdf(mom=mom)
>>> f.plot()
See also
--------
cav76pdf, lc2tr, dat2tr
References
----------
Longuet-Higgins, M.S. (1983)
"On the joint distribution wave periods and amplitudes in a
random wave field", Proc. R. Soc. A389, pp 24--258
Longuet-Higgins, M.S. (1975)
"On the joint distribution wave periods and amplitudes of sea waves",
J. geophys. Res. 80, pp 2688--2694
"""
# tested on: matlab 5.3
# History:
# Revised pab 01.04.2001
# - Added example
# - Better automatic scaling for h,t
# revised by IR 18.06.2000, fixing transformation and transposing t and h to fit simpson req.
# revised by pab 28.09.1999
# made more efficient calculation of f
# by Igor Rychlik
m0, m1, m2 = mom
h, t, g = _set_default_t_h_g(t, h, g, m0, m2)
L0 = m0
L1 = m1 / (2 * pi)
L2 = m2 / (2 * pi)**2
eps2 = sqrt((L2 * L0) / (L1**2) - 1)
if np.any(~np.isreal(eps2)):
raise ValueError('input moments are not correct')
const = 4 / sqrt(pi) / eps2 / (1 + 1 / sqrt(1 + eps2**2))
a = len(h)
b = len(t)
der = np.ones((a, 1))
h_lh = g.dat2gauss(h.ravel(), der.ravel())
der = abs(h_lh[1]) # abs(h_lh[:, 1])
h_lh = h_lh[0]
# Normalization + transformation of t and h ???????
# Without any transformation
t_lh = t / (L0 / L1)
#h_lh = h_lh/sqrt(2*L0)
h_lh = h_lh / sqrt(2)
t_lh = 2 * t_lh
# Computation of the distribution
T, H = np.meshgrid(t_lh[1:b], h_lh)
f_th = np.zeros((a, b))
tmp = const * der[:, None] * (H / T)**2 * np.exp(-H**2. *
(1 + ((1 - 1. / T) / eps2)**2)) / ((L0 / L1) * sqrt(2) / 2)
f_th[:, 1:b] = tmp
f = PlotData(f_th, (t, h),
xlab='Tc', ylab='Ac',
title='Joint density of (Tc,Ac) - Longuet-Higgins (1983)',
plot_kwds=dict(plotflag=1))
return _add_contour_levels(f)
def cav76pdf(t=None, h=None, mom=None, g=None):
"""
CAV76PDF Cavanie et al. (1976) approximation of the density (Tc,Ac)
in a stationary Gaussian transform process X(t) where
Y(t) = g(X(t)) (Y zero-mean Gaussian, X non-Gaussian).
CALL: f = cav76pdf(t,h,[m0,m2,m4],g);
f = density of wave characteristics of half-wavelength
in a stationary Gaussian transformed process X(t),
where Y(t) = g(X(t)) (Y zero-mean Gaussian)
t,h = vectors of periods and amplitudes, respectively.
default depending on the spectral moments
m0,m2,m4 = the 0'th, 2'nd and 4'th moment of the spectral density
with angular frequency.
g = space transformation, Y(t)=g(X(t)), default: g is identity
transformation, i.e. X(t) = Y(t) is Gaussian,
The transformation, g, can be estimated using lc2tr
or dat2tr or given a priori by ochi.
[] = default values are used.
Example
-------
>>> import wafo.spectrum.models as sm
>>> Sj = sm.Jonswap()
>>> w = np.linspace(0,4,256)
>>> S = Sj.tospecdata(w) #Make spectrum object from numerical values
>>> S = sm.SpecData1D(Sj(w),w) # Alternatively do it manually
>>> mom, mom_txt = S.moment(nr=4, even=True)
>>> f = cav76pdf(mom=mom)
>>> f.plot()
See also
--------
lh83pdf, lc2tr, dat2tr
References
----------
Cavanie, A., Arhan, M. and Ezraty, R. (1976)
"A statistical relationship between individual heights and periods of
storm waves".
In Proceedings Conference on Behaviour of Offshore Structures,
Trondheim, pp. 354--360
Norwegian Institute of Technology, Trondheim, Norway
Lindgren, G. and Rychlik, I. (1982)
Wave Characteristics Distributions for Gaussian Waves --
Wave-lenght, Amplitude and Steepness, Ocean Engng vol 9, pp. 411-432.
"""
# tested on: matlab 5.3 NB! note
# History:
# revised pab 04.11.2000
# - fixed xlabels i.e. f.labx={'Tc','Ac'}
# revised by IR 4 X 2000. fixed transform and normalisation
# using Lindgren & Rychlik (1982) paper.
# At the end of the function there is a text with derivation of the density.
#
# revised by jr 21.02.2000
# - Introduced cell array for f.x for use with pdfplot
# by pab 28.09.1999
m0, m2, m4 = mom
h, t, g = _set_default_t_h_g(t, h, g, m0, m2)
eps4 = 1.0 - m2**2 / (m0 * m4)
alfa = m2 / sqrt(m0 * m4)
if np.any(~np.isreal(eps4)):
raise ValueError('input moments are not correct')
a = len(h)
b = len(t)
der = np.ones((a, 1))
h_lh = g.dat2gauss(h.ravel(), der.ravel())
der = abs(h_lh[1])
h_lh = h_lh[0]
# Normalization + transformation of t and h
pos = 2 / (1 + alfa) # inverse of a fraction of positive maxima
cons = 2 * pi**4 * pos / sqrt(2 * pi) / m4 / sqrt((1 - alfa**2))
# Tm=2*pi*sqrt(m0/m2)/alpha; #mean period between positive maxima
t_lh = t
h_lh = sqrt(m0) * h_lh
# Computation of the distribution
T, H = np.meshgrid(t_lh[1:b], h_lh)
f_th = np.zeros((a, b))
f_th[:, 1:b] = cons * der[:, None] * (H**2 / (T**5)) * np.exp(-0.5 * (
H / T**2)**2. * ((T**2 - pi**2 * m2 / m4)**2 / (m0 * (1 - alfa**2)) + pi**4 / m4))
f = PlotData(f_th, (t, h),
xlab='Tc', ylab='Ac',
title='Joint density of (Tc,Ac) - Cavanie et al. (1976)',
plot_kwds=dict(plotflag=1))
return _add_contour_levels(f)
def _add_contour_levels(f):
p_levels = np.r_[10:90:20, 95, 99, 99.9]
try:
c_levels = qlevels(f.data, p=p_levels)
f.clevels = c_levels
f.plevels = p_levels
except ValueError as e:
msg = "Could not calculate contour levels!. ({})".format(str(e))
warnings.warn(msg)
return f
# Let U,Z be the height and second derivative (curvature) at a local maximum in a Gaussian proces
# with spectral moments m0,m2,m4. The conditional density ($U>0$) has the following form
#$$
# f(z,u)=c \frac{1}{\sqrt{2\pi}}\frac{1}{\sqrt{m0(1-\alpha^2)}}\exp(-0.5\left(\frac{u-z(m2/m4)}
# {\sqrt{m0(1-\alpha^2)}}\right)^2)\frac{|z|}{m4}\exp(-0.5z^2/m4), \quad z<0,
#$$
# where $c=2/(1+\alpha)$, $\alpha=m2/\sqrt{m0\cdot m4}$.
#
# The cavanie approximation is based on the model $X(t)=U \cos(\pi t/T)$, consequently
# we have $U=H$ and by twice differentiation $Z=-U(\pi^2/T)^2\cos(0)$. The variable change has Jacobian
# $2\pi^2 H/T^3$ giving the final formula for the density of $T,H$
#$$
# f(t,h)=c \frac{2\pi^4}{\sqrt{2\pi}}\frac{1}{m4\sqrt{m0(1-\alpha^2)}}\frac{h^2}{t^5}
# \exp(-0.5\frac{h^2}{t^4}\left(\left(\frac{t^2-\pi^2(m2/m4)}
# {\sqrt{m0(1-\alpha^2)}}\right)^2+\frac{\pi^4}{m4}\right)).
#$$
#
#
def test_docstrings():
import doctest
print('Testing docstrings in %s' % __file__)
doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE)
if __name__ == '__main__':
test_docstrings()