"""
This module defines two coherence models:
nwtc - The NWTC 'non-IEC' coherence model.
iec - The IEC coherence model.
"""
from .base import cohereModelBase, np, ts_float, cohereObj, ts_complex
from ..base import tslib, dbg
from ..misc import Lambda
[docs]class cohereObjNone(cohereObj):
"""
This is a 'dummy' coherence object that forces the coherence to
zero.
"""
[docs] def calc_phases(self, phases):
return phases
[docs] def calcCoh(self, f, comp, ii, jj):
return 0 * f
[docs]class none(cohereModelBase):
"""
This is a 'dummy' coherence model that forces the coherence to
zero.
"""
cohereObj = cohereObjNone
[docs]class cohereObjNWTC(cohereObj):
[docs] def calc_phases(self, phases):
"""
Compute the `correlated phases` for each grid-point from the
input `phases` based on the coherence NWTC 'non-IEC coherence
model.
Parameters
----------
phases : array_like(np, nf)
The input (generally randomized) phases for each
point for each frequency.
Returns
-------
phases : array_like(np, nf)
The correlated phases according to this cohereObj's
coherence model (see :meth:`calcCoh`).
Notes
-----
This method should not be called explicitly. It is called by
a cohereObj instance's __call__ method.
See also
--------
calcCoh : computes the coherence for individual grid-point pairs.
"""
if tslib is not None:
tmp = np.zeros((self.n_p, self.n_f), dtype=ts_complex, order='F')
u = self.grid.flatten(self.prof.u).copy(order='F')
for icomp in range(3):
tmp[:] = phases[icomp]
tslib.nonieccoh(tmp, self.grid.f,
self.grid.y, self.grid.z, u,
self.a[icomp], self.b[icomp], self.CohExp,
self.ncore, self.n_f, self.n_y, self.n_z)
phases[icomp] = tmp
else:
phases = cohereObj.calc_phases(self, phases)
return phases
[docs] def calcCoh(self, f, comp, ii, jj):
"""
The base function for calculating coherence for non-IEC
spectral models.
See the TurbSim documentation for further information.
This function is only used if the TSlib fortran library is not
available.
"""
ii = self.grid.ind2sub(ii)
jj = self.grid.ind2sub(jj)
r = self.grid.dist(ii, jj)
two = ts_float(2)
zm = (self.grid.z[ii[0]] + self.grid.z[jj[0]]) / two
um = (self.prof.u[ii] + self.prof.u[jj]) / two
#print zm
#print self.grid.z[1],self.grid.y[1],r,um,(r/zm)**self.CohExp,self.grid.f[9]
#print 'junk',self.a[comp],self.b[comp]
#print -self.a[0]*r*np.sqrt((self.grid.f[9]/um)**2+(self.b[comp])**2)
return np.exp(-self.a[comp] * (r / zm) ** self.CohExp *
np.sqrt((f * r / um) ** two + (self.b[comp] * r) ** two))
[docs]class nwtc(cohereModelBase):
"""NWTC coherence model.
This is also known as the 'non-IEC' coherence model.
Parameters
----------
a : array_like(3)
The 'a' exponential 'coherence decrement' coefficients of the
coherence function for each velocity component.
b : a
The 'b' exponential 'coherence decrement' coefficients of the
coherence function for each velocity component.
CohExp : float
The 'Coherence Exponent' parameter for the coherence function.
Notes
-----
The NWTC 'non-IEC' coherence model for velocity component 'k' between two
points (z_i,y_i) and (z_j,y_j) is
.. math::
Coh_k=exp(-a_k (r/z_m)^CohExp ((f r / u_m)^2 + (b_k r)^2) k=u,v,w
Where,
f is frequency.
r is the distance between the two points.
a_k and b_k are 'coherence decrement' input parameters for each of
the velocity components.
u_m is the average velocity of the two points.
z_m is the average height of the two points.
CohExp is the 'coherence exponent' input parameter (default is 0).
"""
__doc__ += cohereModelBase.__doc__
cohereObj = cohereObjNWTC # This must be defined for each coherence model.
def __init__(self, a=[None, None, None], b=[0., 0., 0.], CohExp=0.0):
"""
Create a NWTC 'non-IEC' coherence model.
Parameters
----------
a : 3-element array-like of floats (or None for default), optional.
The first coherence decrement input parameter for each of the
three velocity components. If an element is None, a default value
is used. The defaults are:
a[0] = uhub
a[1] = 0.75*a[0]
a[2] = 0.75*a[0]
b : 3-element array-like of floats, optional.
The second coherence decrement input parameter for each
velocity component. Each element defaults to 0.
CohExp : float, optional
"""
if CohExp is None:
self.CohExp = 0.0
else:
self.CohExp = CohExp
self.a = a
self.b = np.array(b, dtype=ts_float)
if dbg:
#self.timer=dbg.timer('tslib-cohNWTC')
self.timer = dbg.timer('roll')
def _sumfile_string(self, tsrun, ):
sumstring_format = """
Coherence model used = {dat.model_desc}
Coherence Exponent = {dat.CohExp:0.2f}
Coherence decrements (IncDec):
U (a, b) = ({coh.a[0]:0.2f}, {coh.b[0]:0.2f})
V (a, b) = ({coh.a[1]:0.2f}, {coh.b[1]:0.2f})
W (a, b) = ({coh.a[2]:0.2f}, {coh.b[2]:0.2f})
"""
return sumstring_format.format(dat=self, coh=tsrun.cohere, )
[docs] def set_coefs(self, cohereObj):
"""
This method is called by the coherence model __call__ method
just before returning the coherence instance *cohi*.
"""
cohereObj.CohExp = self.CohExp
cohereObj.b = self.b
cohereObj.a = np.empty((3), dtype=ts_float)
if self.a[0] is None:
cohereObj.a[0] = cohereObj.prof.uhub
else:
cohereObj.a[0] = self.a[0]
if self.a[1] is None:
cohereObj.a[1] = 0.75 * cohereObj.a[0]
else:
cohereObj.a[1] = self.a[1]
if self.a[2] is None:
cohereObj.a[2] = 0.75 * cohereObj.a[0]
else:
cohereObj.a[2] = self.a[2]
[docs]class cohereObjIEC(cohereObj):
[docs] def calcCoh(self, f, comp, ii, jj):
"""
Calculate the coherence for a velocity component, between two points.
Parameters
----------
f : array_like(nf,dtype=float)
comp : int {0,1,2}
indicating the velocity component for which to compute
the coherence.
ii,jj : array_like(int,2)
indicating the grid-points between which to calculate
the coherence. for example: ii=(1,3),jj=(2,3)
Returns
-------
coh : array_like(nf,dtype=float)
The coherence between the two points as a function of frequency.
Notes
-----
This method is only used if tslib is not available.
"""
if comp == 0:
r = self.grid.dist(ii, jj)
return np.exp(-self.a * np.sqrt((f * r / self.prof.uhub) ** 2
+ (0.12 * r / self.Lc) ** 2))
else:
return 0
[docs] def calc_phases(self, phases):
"""
Compute and set the full cross-coherence matrix for component
*comp* for 'coherence calculator' instance *cohi*.
Compute the coherence array for coherence instance cohi for
the IEC model.
"""
if tslib is not None:
out = phases[0].copy(order='F')
tslib.ieccoh(out, self.grid.f,
self.y, self.z, self.prof.uhub,
self.a, self.Lc,
self.ncore, self.n_f, self.n_y, self.n_z)
phases[0] = out
return phases
else:
return cohereObj.calc_phases(self, phases)
[docs]class iec(cohereModelBase):
"""IEC coherence model.
This coherence model only include u-component coherence.
Parameters
----------
IECedition : int {2, 3},
Different IEC editions have slightly different
coefficients to the spectral model.
Notes
-----
The IEC coherence is zero for the v- and w-components (coherence matrix
is the identity matrix so that auto-spectra are retained).
The form of this model is for the u-component is,
.. math::
Coh=exp(-a*((f*r/uhub)^2+(0.12*r/Lc)^2)^0.5)
Where,
f is frequency.
r is the distance between the two points.
uhub is the hub-height mean velocity.
If IECedition<=2:
a = 8.8,
Lc = 2.45*min(30m,HubHt)
If IECedition>=3:
a = 12,
Lc = 5.67*min(60m,HubHt)
"""
__doc__ += cohereModelBase.__doc__
cohereObj = cohereObjIEC
def _L(self, zhub):
"""
Calculate the 'coherence scale parameter' for hub-height *zhub*.
"""
return self._Lfactor * Lambda(zhub, self.IECedition)
def __init__(self, IECedition=3, ):
self.IECedition = IECedition
if IECedition <= 2:
# The Lambda function includes a factor of 0.7 (_Lfactor*0.7=2.45).
self._Lfactor = 3.5
self.a = 8.8
else: # 3rd edition IEC standard:
# The Lambda function includes a factor of 0.7 (_Lfactor*0.7=5.67)
self._Lfactor = 8.1
self.a = 12.
if dbg:
self.timer = dbg.timer('tslib-cohIEC')
def _sumfile_string(self, tsrun, ):
sumstring_format = """
Coherence model used = {dat.model_desc}
IEC Edition = {dat.IECedition:d}
Coherence length scale parameter = {L:0.2f} [m]
"""
return sumstring_format.format(dat=self, L=self._L(tsrun.grid.zhub))
[docs] def set_coefs(self, cohereObj):
"""
Initialize a coherence instance for the IEC coherence model.
"""
cohereObj.Lc = self._L(cohereObj.grid.zhub)
cohereObj.a = self.a