use ndarray::Array1;
use numpy::{IntoPyArray, PyArray1, PyArray2, PyReadonlyArray1, PyReadonlyArray2};
use pyo3::prelude::*;
use pyo3::types::IntoPyDict;
use pyo3::{pyclass, pymethods, PyResult, Python};
use crate::prelude as spec;
#[pyclass]
#[derive(Clone)]
pub struct FrequencyResponse(pub spec::FrequencyResponse);
#[pymethods]
impl FrequencyResponse {
pub fn to_dict(&self, py: Python) -> PyObject {
[
("std_dev", self.0.std_dev),
("Tm02", self.0.Tm02),
("Xs", self.0.As),
("Xmpm", self.0.Ampm),
]
.into_py_dict(py)
.to_object(py)
}
#[getter]
fn std_dev(&self) -> PyResult<f64> {
Ok(self.0.std_dev)
}
#[getter]
#[pyo3(name = "Tm02")]
fn tm02(&self) -> PyResult<f64> {
Ok(self.0.Tm02)
}
#[getter]
#[pyo3(name = "As")]
fn a_s(&self) -> PyResult<f64> {
Ok(self.0.As)
}
#[getter]
#[pyo3(name = "Ampm")]
fn a_mpm(&self) -> PyResult<f64> {
Ok(self.0.Ampm)
}
fn __repr__(&self) -> String {
format!(
"FrequencyResponse(
std_dev: {},
Tm02: {},
As: {},
Ampm: {}
)",
self.0.std_dev, self.0.Tm02, self.0.As, self.0.Ampm
)
}
fn __dict__(&self, py: Python) -> PyObject {
[
("std_dev", self.0.std_dev),
("Tm02", self.0.Tm02),
("As", self.0.As),
("Ampm", self.0.Ampm),
]
.into_py_dict(py)
.to_object(py)
}
}
#[pyfunction]
pub fn maxhs(tp: f64) -> f64 {
spec::maxhs(tp)
}
#[pyfunction]
pub fn bretschneider<'py>(
py: Python<'py>,
omega: PyReadonlyArray1<f64>,
hs: f64,
tp: f64,
) -> &'py PyArray1<f64> {
spec::bretschneider::energy(omega.as_array(), hs, tp).into_pyarray(py)
}
#[pyfunction]
pub fn jonswap<'py>(
py: Python<'py>,
omega: PyReadonlyArray1<f64>,
hs: f64,
tp: f64,
gamma: f64,
sigma_a: f64,
sigma_b: f64,
) -> &'py PyArray1<f64> {
spec::jonswap::energy(omega.as_array(), hs, tp, gamma, sigma_a, sigma_b).into_pyarray(py)
}
#[pyfunction]
pub fn gaussian<'a>(
py: Python<'a>,
omega: PyReadonlyArray1<f64>,
hs: f64,
tp: f64,
sigma_g: f64,
) -> &'a PyArray1<f64> {
spec::gaussian_spectrum(omega.as_array(), hs, tp, sigma_g).into_pyarray(py)
}
#[pyfunction]
pub fn lewis_allos(hs: f64, tp: f64) -> PyResult<(f64, f64, f64, f64)> {
Ok(spec::lewis_allos(hs, tp))
}
#[pyfunction]
pub fn spread_cos_n<'py>(
py: Python<'py>,
theta: PyReadonlyArray1<f64>,
theta_p: f64,
n: f64,
) -> &'py PyArray1<f64> {
spec::spread_cos_n(theta.as_array(), theta_p, n).into_pyarray(py)
}
#[pyfunction]
pub fn spread_cos_2s<'py>(
py: Python<'py>,
theta: PyReadonlyArray1<f64>,
theta_p: f64,
s: f64,
) -> &'py PyArray1<f64> {
spec::spread_cos_2s(theta.as_array(), theta_p, s).into_pyarray(py)
}
#[pyfunction]
#[pyo3(name = "convert_Tp_to_Tz")]
#[pyo3(signature=(tp, gamma), text_signature = "(Tp: float, gamma: float) -> float")]
pub fn convert_tp_to_tz(tp: f64, gamma: f64) -> f64 {
spec::convert_tp_to_tz(tp, gamma)
}
#[pyfunction]
#[pyo3(name = "convert_Tz_to_Tp")]
#[pyo3(signature=(tz, gamma), text_signature = "(Tz: float, gamma: float) -> float")]
pub fn convert_tz_to_tp(tz: f64, gamma: f64) -> f64 {
spec::convert_tz_to_tp(tz, gamma)
}
#[pyfunction]
#[pyo3(name = "convert_Tp_to_Tm")]
#[pyo3(signature=(tp, gamma), text_signature = "(Tp: float, gamma: float) -> float")]
pub fn convert_tp_to_t1(tp: f64, gamma: f64) -> f64 {
spec::convert_tp_to_t1(tp, gamma)
}
#[pyfunction]
#[pyo3(name = "convert_Tm_to_Tp")]
#[pyo3(signature=(t1, gamma), text_signature = "(Tm: float, gamma: float) -> float")]
pub fn convert_t1_to_tp(t1: f64, gamma: f64) -> f64 {
spec::convert_t1_to_tp(t1, gamma)
}
#[pyfunction]
pub fn froya_10min<'a>(
py: Python<'a>,
omega: PyReadonlyArray1<f64>,
wind_speed: f64,
) -> &'a PyArray1<f64> {
spec::froya_10min(omega.as_array(), wind_speed).into_pyarray(py)
}
#[pyfunction]
pub fn froya_1hr<'a>(
py: Python<'a>,
omega: PyReadonlyArray1<f64>,
wind_speed: f64,
elevation: f64,
) -> &'a PyArray1<f64> {
spec::froya_1hr(omega.as_array(), wind_speed, elevation).into_pyarray(py)
}
#[pyclass]
pub struct Jonswap(spec::Jonswap);
#[pymethods]
impl Jonswap {
#[new]
fn new(hs: f64, tp: f64) -> Self {
Jonswap(spec::Jonswap::new(hs, tp))
}
#[staticmethod]
fn from_3p(hs: f64, tp: f64, gamma: f64) -> Self {
Jonswap(spec::Jonswap::from_3p(hs, tp, gamma))
}
#[staticmethod]
fn from_5p(hs: f64, tp: f64, gamma: f64, sigma_a: f64, sigma_b: f64) -> Self {
Jonswap(spec::Jonswap::from_5p(hs, tp, gamma, sigma_a, sigma_b))
}
fn __repr__(&self) -> PyResult<String> {
let n = self.0.omega.len();
Ok(format!(
"Jonswap(hs: {:?}, tp: {:?}, gamma: {:?}, sigma_a: {:?}, sigma_b: {:?}), omega: [{:?},...,{:?}](len={:?})",
self.0.hs, self.0.tp, self.0.gamma, self.0.sigma_a, self.0.sigma_b,
self.0.omega[0], self.0.omega[n-1], n))
}
#[getter]
fn hs(&self) -> f64 {
self.0.hs
}
#[getter]
fn tp(&self) -> f64 {
self.0.tp
}
#[getter]
fn gamma(&self) -> f64 {
self.0.gamma
}
#[getter]
fn sigma_a(&self) -> f64 {
self.0.sigma_a
}
#[getter]
fn sigma_b(&self) -> f64 {
self.0.sigma_b
}
#[getter]
fn omega<'py>(&self, py: Python<'py>) -> &'py PyArray1<f64> {
self.0.omega.clone().into_pyarray(py)
}
fn set_hs(&mut self, hs: f64) {
self.0.hs = hs;
}
fn set_tp(&mut self, tp: f64) {
self.0.tp = tp;
}
fn set_gamma(&mut self, gamma: f64) {
self.0.gamma = gamma;
}
fn set_sigma_a(&mut self, sigma_a: f64) {
self.0.sigma_a = sigma_a;
}
fn set_sigma_b(&mut self, sigma_b: f64) {
self.0.sigma_b = sigma_b;
}
fn set_omega(&mut self, omega: Vec<f64>) {
self.0.omega = omega.into();
}
fn tz(&self) -> PyResult<f64> {
Ok(self.0.tz())
}
fn t1(&self) -> PyResult<f64> {
Ok(self.0.t1())
}
fn set_tp_from_tz(&mut self, tz: f64) {
self.0.set_tp_from_tz(tz);
}
fn set_tp_from_t1(&mut self, t1: f64) {
self.0.set_tp_from_t1(t1);
}
fn energy<'py>(&self, py: Python<'py>) -> &'py PyArray1<f64> {
self.0.energy().into_pyarray(py)
}
fn abs_error(&self) -> PyResult<f64> {
Ok(self.0.abs_error())
}
fn to_spec1d(&self) -> Spectrum1D {
let spec = self.0.to_spec1d();
Spectrum1D::new(spec.omega.to_vec(), spec.energy.to_vec())
}
fn to_spec2d(&self, py: Python, spreading: &Spreading) -> Spectrum2D {
let spec = self.0.to_spec2d(&spreading.0);
Spectrum2D::new(
spec.omega.to_vec(),
spec.theta.to_vec(),
spec.energy.into_pyarray(py).readonly(),
)
}
}
#[pyclass]
pub struct Spreading(pub spec::Spreading);
#[pymethods]
impl Spreading {
#[new]
pub fn new(theta_p: f64, n: f64) -> Self {
Self(spec::Spreading::new(theta_p, n))
}
fn __repr__(&self) -> PyResult<String> {
let n = self.0.theta.len();
Ok(format!(
"Spreading(theta_p: {:?}, n: {:?}, s: {:?}), theta: [{:?},...,{:?}](len={:?})",
self.0.theta_p,
self.0.n,
self.0.s,
self.0.theta[0],
self.0.theta[n - 1],
n
))
}
#[getter]
fn theta_p(&self) -> f64 {
self.0.theta_p
}
#[getter]
fn n(&self) -> f64 {
self.0.n
}
#[getter]
fn s(&self) -> f64 {
self.0.s
}
#[getter]
fn theta<'py>(&self, py: Python<'py>) -> &'py PyArray1<f64> {
self.0.theta.clone().into_pyarray(py)
}
fn set_theta(&mut self, theta: Vec<f64>) {
self.0.theta = theta.into();
}
fn set_n(&mut self, n: f64) {
self.0.set_n(n);
}
fn set_theta_p(&mut self, theta_p: f64) {
self.0.set_theta_p(theta_p);
}
fn set_s(&mut self, s: f64) {
self.0.set_s(s);
}
fn distribution<'py>(&self, py: Python<'py>) -> &'py PyArray1<f64> {
self.0.distribution().into_pyarray(py)
}
fn d1_form<'py>(&self, py: Python<'py>) -> &'py PyArray1<f64> {
self.0.d1_form().into_pyarray(py)
}
fn d2_form<'py>(&self, py: Python<'py>) -> &'py PyArray1<f64> {
self.0.d2_form().into_pyarray(py)
}
fn abs_error(&self) -> f64 {
self.0.abs_error()
}
}
#[derive(Clone)]
#[pyclass]
pub struct Spectrum1D(pub spec::Spectrum1D);
#[pymethods]
impl Spectrum1D {
#[pyo3(signature = (omega, energy))]
#[new]
pub fn new(omega: Vec<f64>, energy: Vec<f64>) -> Self {
Spectrum1D(spec::Spectrum1D {
omega: Array1::from(omega),
energy: Array1::from(energy),
})
}
#[getter]
fn omega<'py>(&self, py: Python<'py>) -> &'py PyArray1<f64> {
self.0.omega.clone().into_pyarray(py)
}
#[getter]
fn energy<'py>(&self, py: Python<'py>) -> &'py PyArray1<f64> {
self.0.energy.clone().into_pyarray(py)
}
fn area(&self) -> PyResult<f64> {
Ok(self.0.area())
}
fn spectral_moment(&self, n: u8) -> PyResult<f64> {
Ok(self.0.spectral_moment(n))
}
#[allow(non_snake_case)]
fn M0(&self) -> PyResult<f64> {
Ok(self.0.M0())
}
#[allow(non_snake_case)]
fn M1(&self) -> PyResult<f64> {
Ok(self.0.M1())
}
#[allow(non_snake_case)]
fn M2(&self) -> PyResult<f64> {
Ok(self.0.M2())
}
#[allow(non_snake_case)]
fn M4(&self) -> PyResult<f64> {
Ok(self.0.M4())
}
fn std_dev(&self) -> PyResult<f64> {
Ok(self.0.std_dev())
}
#[allow(non_snake_case)]
fn As(&self) -> PyResult<f64> {
Ok(self.0.As())
}
#[allow(non_snake_case)]
fn Xs(&self) -> PyResult<f64> {
Ok(self.0.Xs())
}
#[allow(non_snake_case)]
fn Tp(&self) -> PyResult<f64> {
Ok(self.0.Tp())
}
#[allow(non_snake_case)]
fn T_mean(&self) -> PyResult<f64> {
Ok(self.0.Tm01())
}
#[allow(non_snake_case)]
fn Tm02(&self) -> PyResult<f64> {
Ok(self.0.Tm02())
}
#[allow(non_snake_case)]
#[pyo3(signature = (time_window=10800.0, /), text_signature = "(time_window = 10800.0, /)")]
fn Ampm(&self, time_window: f64) -> PyResult<f64> {
Ok(self.0.Ampm(time_window))
}
#[allow(non_snake_case)]
#[pyo3(signature = (time_window=10800.0, /),
text_signature = "(time_window = 10800.0, /)")]
fn Xmpm(&self, time_window: f64) -> PyResult<f64> {
Ok(self.0.Xmpm(time_window))
}
#[pyo3(signature = (fractile=0.36787944117144233, time_window=10800.0, /),
text_signature = "(fractile=np.exp(-1), time_window = 10800.0, /)")]
fn fractile_extreme(&self, fractile: f64, time_window: f64) -> PyResult<f64> {
Ok(self.0.fractile_extreme(fractile, time_window))
}
#[allow(non_snake_case)]
#[pyo3(signature = (time_window=10800.0, /), text_signature = "(time_window = 10800.0, /)")]
fn X50(&self, time_window: f64) -> PyResult<f64> {
Ok(self.0.fractile_extreme(0.50, time_window))
}
#[allow(non_snake_case)]
#[pyo3(signature = (time_window=10800.0, /), text_signature = "(time_window = 10800.0, /)")]
fn X90(&self, time_window: f64) -> PyResult<f64> {
Ok(self.0.fractile_extreme(0.90, time_window))
}
#[allow(non_snake_case)]
#[pyo3(signature = (time_window=10800.0, /), text_signature = "(time_window = 10800.0, /)")]
fn X95(&self, time_window: f64) -> PyResult<f64> {
Ok(self.0.fractile_extreme(0.95, time_window))
}
#[pyo3(signature = (time_window=10800.0, /), text_signature = "(time_window = 10800.0, /)")]
fn response(&self, time_window: f64) -> FrequencyResponse {
FrequencyResponse(spec::FrequencyResponse {
std_dev: self.0.std_dev(),
Tm02: self.0.Tm02(),
As: self.0.As(),
Ampm: self.0.Ampm(time_window),
})
}
}
#[pyclass]
pub struct Spectrum2D(pub spec::Spectrum2D);
#[pymethods]
impl Spectrum2D {
#[new]
pub fn new(omega: Vec<f64>, theta: Vec<f64>, energy: PyReadonlyArray2<f64>) -> Self {
Spectrum2D(spec::Spectrum2D {
omega: Array1::from(omega),
theta: Array1::from(theta),
energy: energy.as_array().to_owned(),
})
}
#[getter]
fn omega<'a>(&self, py: Python<'a>) -> &'a PyArray1<f64> {
PyArray1::from_array(py, &self.0.omega)
}
#[getter]
fn theta<'a>(&self, py: Python<'a>) -> &'a PyArray1<f64> {
PyArray1::from_array(py, &self.0.theta)
}
#[getter]
fn energy<'a>(&self, py: Python<'a>) -> &'a PyArray2<f64> {
PyArray2::from_array(py, &self.0.energy)
}
fn area(&self) -> f64 {
self.0.area()
}
#[allow(non_snake_case)]
fn M0(&self) -> PyResult<f64> {
Ok(self.0.M0())
}
#[allow(non_snake_case)]
fn M1(&self) -> PyResult<f64> {
Ok(self.0.M1())
}
#[allow(non_snake_case)]
fn M2(&self) -> PyResult<f64> {
Ok(self.0.M2())
}
#[allow(non_snake_case)]
fn M4(&self) -> PyResult<f64> {
Ok(self.0.M4())
}
fn std_dev(&self) -> PyResult<f64> {
Ok(self.0.std_dev())
}
#[allow(non_snake_case)]
fn As(&self) -> PyResult<f64> {
Ok(self.0.As())
}
#[allow(non_snake_case)]
fn Xs(&self) -> PyResult<f64> {
Ok(self.0.Xs())
}
#[allow(non_snake_case)]
fn Tp(&self) -> PyResult<f64> {
Ok(self.0.Tp())
}
fn theta_p(&self) -> PyResult<f64> {
Ok(self.0.theta_p())
}
#[allow(non_snake_case)]
fn T_mean(&self) -> PyResult<f64> {
Ok(self.0.T_mean())
}
#[allow(non_snake_case)]
fn Tz(&self) -> PyResult<f64> {
Ok(self.0.Tz())
}
#[allow(non_snake_case)]
fn Ampm(&self, time_window: f64) -> PyResult<f64> {
Ok(self.0.Ampm(time_window))
}
#[allow(non_snake_case)]
fn Xmpm(&self, time_window: f64) -> PyResult<f64> {
Ok(self.0.Xmpm(time_window))
}
#[allow(non_snake_case)]
fn X50(&self, time_window: f64) -> PyResult<f64> {
Ok(self.0.X50(time_window))
}
#[allow(non_snake_case)]
fn X90(&self, time_window: f64) -> PyResult<f64> {
Ok(self.0.X90(time_window))
}
#[allow(non_snake_case)]
fn X95(&self, time_window: f64) -> PyResult<f64> {
Ok(self.0.X95(time_window))
}
fn fractile_extreme(&self, fractile: f64, time_window: f64) -> PyResult<f64> {
Ok(self.0.fractile_extreme(fractile, time_window))
}
fn rotate(&mut self, angle: f64) -> PyResult<()> {
self.0.rotate(angle);
Ok(())
}
}