Module ocean_science_utilities.wavespectra.estimators.mem
Expand source code
import numpy as np
from numba import njit # type: ignore
def mem(
directions_radians: np.ndarray,
a1: np.ndarray,
b1: np.ndarray,
a2: np.ndarray,
b2: np.ndarray,
progress,
**kwargs
) -> np.ndarray:
number_of_frequencies = a1.shape[-1]
number_of_points = a1.shape[0]
directional_distribution = np.zeros(
(number_of_points, number_of_frequencies, len(directions_radians))
)
for ipoint in range(0, number_of_points):
progress.update(1)
directional_distribution[ipoint, :, :] = _mem(
directions_radians,
a1[ipoint, :],
b1[ipoint, :],
a2[ipoint, :],
b2[ipoint, :],
)
return directional_distribution
def _mem(
directions_radians: np.ndarray,
a1: np.ndarray,
b1: np.ndarray,
a2: np.ndarray,
b2: np.ndarray,
) -> np.ndarray:
"""
This function uses the maximum entropy method by Lygre and Krogstadt (1986,JPO)
to estimate the directional shape of the spectrum. Enthropy is defined in the
Boltzmann sense (log D)
Lygre, A., & Krogstad, H. E. (1986). Maximum entropy estimation of the directional
distribution in ocean wave spectra. Journal of Physical Oceanography, 16(12),
2052-2060.
:param directions_radians: 1d array of wave directions in radians,
length[number_of_directions]. (going to, anti-clockswise from east)
:param a1: 1d array of cosine directional moment as function of frequency,
length [number_of_frequencies]
:param b1: 1d array of sine directional moment as function of frequency,
length [number_of_frequencies]
:param a2: 1d array of double angle cosine directional moment as function
of frequency, length [number_of_frequencies]
:param b2: 1d array of double angle sine directional moment as function of
frequency, length [number_of_frequencies]
:return: array with shape [number_of_frequencies,number_of_direction]
representing the directional distribution of the waves at each frequency.
Maximize the enthrophy of the solution with entrophy defined as:
integrate log(D) over directions
such that the resulting distribution D reproduces the observed moments.
:return: Directional distribution as a np array
Note that:
d1 = a1; d2 =b1; d3 = a2 and d4=b2 in the defining equations 10.
"""
number_of_directions = len(directions_radians)
c1 = a1 + 1j * b1
c2 = a2 + 1j * b2
#
# Eq. 13 L&K86
#
Phi1 = (c1 - c2 * np.conj(c1)) / (1 - c1 * np.conj(c1))
Phi2 = c2 - Phi1 * c1
#
e1 = np.exp(-directions_radians * 1j)
e2 = np.exp(-directions_radians * 2j)
numerator = 1 - Phi1 * np.conj(c1) - Phi2 * np.conj(c2)
denominator = (
np.abs(1 - Phi1[:, None] * e1[None, :] - Phi2[:, None] * e2[None, :]) ** 2
)
D = np.real(numerator[:, None] / denominator) / np.pi / 2
# Normalize to 1. in discrete sense
integralApprox = np.sum(D, axis=-1) * np.pi * 2.0 / number_of_directions
D = D / integralApprox[:, None]
return np.squeeze(D)
@njit(cache=True)
def numba_mem(
directions_radians: np.ndarray,
a1: float,
b1: float,
a2: float,
b2: float,
) -> np.ndarray:
"""
This function uses the maximum entropy method by Lygre and Krogstadt (1986,JPO)
to estimate the directional shape of the spectrum. Enthropy is defined in the
Boltzmann sense (log D)
Lygre, A., & Krogstad, H. E. (1986). Maximum entropy estimation of the directional
distribution in ocean wave spectra. Journal of Physical Oceanography, 16(12),
2052-2060.
:param directions_radians: 1d array of wave directions in radians,
length[number_of_directions]. (going to, anti-clockswise from east)
:param a1: 1d array of cosine directional moment as function of frequency,
length [number_of_frequencies]
:param b1: 1d array of sine directional moment as function of frequency,
length [number_of_frequencies]
:param a2: 1d array of double angle cosine directional moment as function
of frequency, length [number_of_frequencies]
:param b2: 1d array of double angle sine directional moment as function of
frequency, length [number_of_frequencies]
:return: array with shape [number_of_frequencies,number_of_direction]
representing the directional distribution of the waves at each frequency.
Maximize the enthrophy of the solution with entrophy defined as:
integrate log(D) over directions
such that the resulting distribution D reproduces the observed moments.
:return: Directional distribution as a np array
Note that:
d1 = a1; d2 =b1; d3 = a2 and d4=b2 in the defining equations 10.
"""
number_of_directions = len(directions_radians)
c1 = a1 + 1j * b1
c2 = a2 + 1j * b2
#
# Eq. 13 L&K86
#
Phi1 = (c1 - c2 * np.conj(c1)) / (1 - c1 * np.conj(c1))
Phi2 = c2 - Phi1 * c1
#
e1 = np.exp(-directions_radians * 1j)
e2 = np.exp(-directions_radians * 2j)
numerator = 1 - Phi1 * np.conj(c1) - Phi2 * np.conj(c2)
denominator = np.abs(1 - Phi1 * e1 - Phi2 * e2) ** 2
D = np.real(numerator / denominator) / np.pi / 2
# Normalize to 1. in discrete sense
integralApprox = np.sum(D, axis=-1) * np.pi * 2.0 / number_of_directions
D = D / integralApprox
return D
Functions
def mem(directions_radians: numpy.ndarray, a1: numpy.ndarray, b1: numpy.ndarray, a2: numpy.ndarray, b2: numpy.ndarray, progress, **kwargs) ‑> numpy.ndarray
-
Expand source code
def mem( directions_radians: np.ndarray, a1: np.ndarray, b1: np.ndarray, a2: np.ndarray, b2: np.ndarray, progress, **kwargs ) -> np.ndarray: number_of_frequencies = a1.shape[-1] number_of_points = a1.shape[0] directional_distribution = np.zeros( (number_of_points, number_of_frequencies, len(directions_radians)) ) for ipoint in range(0, number_of_points): progress.update(1) directional_distribution[ipoint, :, :] = _mem( directions_radians, a1[ipoint, :], b1[ipoint, :], a2[ipoint, :], b2[ipoint, :], ) return directional_distribution
def numba_mem(directions_radians: numpy.ndarray, a1: float, b1: float, a2: float, b2: float) ‑> numpy.ndarray
-
This function uses the maximum entropy method by Lygre and Krogstadt (1986,JPO) to estimate the directional shape of the spectrum. Enthropy is defined in the Boltzmann sense (log D)
Lygre, A., & Krogstad, H. E. (1986). Maximum entropy estimation of the directional distribution in ocean wave spectra. Journal of Physical Oceanography, 16(12), 2052-2060.
:param directions_radians: 1d array of wave directions in radians, length[number_of_directions]. (going to, anti-clockswise from east)
:param a1: 1d array of cosine directional moment as function of frequency, length [number_of_frequencies]
:param b1: 1d array of sine directional moment as function of frequency, length [number_of_frequencies]
:param a2: 1d array of double angle cosine directional moment as function of frequency, length [number_of_frequencies]
:param b2: 1d array of double angle sine directional moment as function of frequency, length [number_of_frequencies]
:return: array with shape [number_of_frequencies,number_of_direction] representing the directional distribution of the waves at each frequency.
Maximize the enthrophy of the solution with entrophy defined as:
integrate log(D) over directions
such that the resulting distribution D reproduces the observed moments.
:return: Directional distribution as a np array
Note that: d1 = a1; d2 =b1; d3 = a2 and d4=b2 in the defining equations 10.
Expand source code
@njit(cache=True) def numba_mem( directions_radians: np.ndarray, a1: float, b1: float, a2: float, b2: float, ) -> np.ndarray: """ This function uses the maximum entropy method by Lygre and Krogstadt (1986,JPO) to estimate the directional shape of the spectrum. Enthropy is defined in the Boltzmann sense (log D) Lygre, A., & Krogstad, H. E. (1986). Maximum entropy estimation of the directional distribution in ocean wave spectra. Journal of Physical Oceanography, 16(12), 2052-2060. :param directions_radians: 1d array of wave directions in radians, length[number_of_directions]. (going to, anti-clockswise from east) :param a1: 1d array of cosine directional moment as function of frequency, length [number_of_frequencies] :param b1: 1d array of sine directional moment as function of frequency, length [number_of_frequencies] :param a2: 1d array of double angle cosine directional moment as function of frequency, length [number_of_frequencies] :param b2: 1d array of double angle sine directional moment as function of frequency, length [number_of_frequencies] :return: array with shape [number_of_frequencies,number_of_direction] representing the directional distribution of the waves at each frequency. Maximize the enthrophy of the solution with entrophy defined as: integrate log(D) over directions such that the resulting distribution D reproduces the observed moments. :return: Directional distribution as a np array Note that: d1 = a1; d2 =b1; d3 = a2 and d4=b2 in the defining equations 10. """ number_of_directions = len(directions_radians) c1 = a1 + 1j * b1 c2 = a2 + 1j * b2 # # Eq. 13 L&K86 # Phi1 = (c1 - c2 * np.conj(c1)) / (1 - c1 * np.conj(c1)) Phi2 = c2 - Phi1 * c1 # e1 = np.exp(-directions_radians * 1j) e2 = np.exp(-directions_radians * 2j) numerator = 1 - Phi1 * np.conj(c1) - Phi2 * np.conj(c2) denominator = np.abs(1 - Phi1 * e1 - Phi2 * e2) ** 2 D = np.real(numerator / denominator) / np.pi / 2 # Normalize to 1. in discrete sense integralApprox = np.sum(D, axis=-1) * np.pi * 2.0 / number_of_directions D = D / integralApprox return D