use ndarray::{Array1, ArrayView1};
use std::f64::consts::PI;
use crate::core::integration::trapz;
use crate::spectrums::{Spectrum1D, Spectrum2D};
use crate::waves::spreading::Spreading;
const N_FREQ: usize = 256;
pub struct Bretschneider {
pub hs: f64,
pub tp: f64,
pub omega: Array1<f64>,
}
pub fn energy(omega: ArrayView1<f64>, hs: f64, tp: f64) -> Array1<f64> {
let wp = 2. * PI / tp;
let a = 5. / 16. * hs.powf(2f64) * wp.powf(4f64);
let energy: Array1<f64> = omega
.iter()
.map(|w_i| a * w_i.powf(-5.) * (-5. / 4. * (wp / w_i).powf(4.)).exp())
.collect();
energy
}
impl Default for Bretschneider {
fn default() -> Self {
Bretschneider {
hs: 1.0,
tp: 10.0,
omega: Array1::<f64>::linspace(0.1, PI, N_FREQ),
}
}
}
impl Bretschneider {
pub fn new(hs: f64, tp: f64) -> Self {
Bretschneider {
hs,
tp,
..Default::default()
}
}
pub fn energy(&self) -> Array1<f64> {
energy(self.omega.view(), self.hs, self.tp)
}
pub fn set_hs(&mut self, hs: f64) -> &mut Self {
self.hs = hs;
self
}
pub fn set_tp(&mut self, tp: f64) -> &mut Self {
self.tp = tp;
self
}
pub fn set_omega(&mut self, omega: Array1<f64>) -> &mut Self {
self.omega = omega;
self
}
pub fn set_parameters(&mut self, hs: f64, tp: f64) -> &mut Self {
self.set_hs(hs).set_tp(tp)
}
pub fn abs_error(&self) -> f64 {
let area = trapz(self.energy().view(), self.omega.view());
(self.hs - 4.0 * area.sqrt()).abs()
}
pub fn to_spec1d(&self) -> Spectrum1D {
Spectrum1D::new(self.omega.to_owned(), self.energy())
}
pub fn to_spec2d(&self, spreading: &Spreading) -> Spectrum2D {
Spectrum2D::from_spec1d(&self.to_spec1d(), spreading)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default() {
let bretschneider = Bretschneider::default();
assert_eq!(bretschneider.hs, 1.0);
assert_eq!(bretschneider.tp, 10.0);
}
#[test]
fn test_new() {
let hs = 1.5;
let tp = 18.0;
let spec = Bretschneider::new(hs, tp);
assert_eq!(spec.hs, hs);
assert_eq!(spec.tp, tp);
}
#[test]
fn test_energy() {
let omega = Array1::linspace(0.1, PI, 100);
let hs = 1.0;
let tp = 10.0;
let energy = energy(omega.view(), hs, tp);
assert_eq!(energy.len(), omega.len());
}
#[test]
fn test_set() {
let hs = 1.5;
let mut spec = Bretschneider::default();
spec.set_hs(hs);
assert_eq!(spec.hs, hs);
let tp = 18.0;
spec.set_tp(tp);
assert_eq!(spec.tp, tp);
let hs = 2.0;
spec.set_hs(hs);
assert_eq!(spec.hs, hs);
}
#[test]
fn test_bretschneider() {
let omega = Array1::linspace(0.1, PI, 100);
let hs = 1.0;
let tp = 10.0;
let mut spec = Bretschneider::new(hs, tp);
let energy = spec.set_omega(omega).energy();
assert_eq!(energy.len(), 100);
}
}