use ndarray::Array1;
use crate::prelude::*;
use crate::waves::common::SpectralCommon;
const N_FREQ: usize = 256;
pub struct Phillips1958 {
pub alpha: f64,
pub omega: Array1<f64>,
}
pub struct Phillips {
pub u: f64,
pub alpha: f64,
pub omega: Array1<f64>,
}
pub fn energy(omega: &f64, alpha: f64) -> f64 {
alpha * GRAVITY.powi(2) * omega.powi(-5)
}
impl Default for Phillips1958 {
fn default() -> Self {
Phillips1958 {
alpha: 0.0081,
omega: Array1::<f64>::linspace(0.1, PI, N_FREQ),
}
}
}
impl Phillips1958 {
pub fn new() -> Self {
Phillips1958 {
..Default::default()
}
}
}
impl SpectralCommon for Phillips1958 {
fn hs(&self) -> Result<f64, String> {
Err("hs is left undefined for the spectral tail".to_string())
}
fn tp(&self) -> Result<f64, String> {
Err("tp is left undefined for the spectral tail".to_string())
}
fn omega(&self) -> &Array1<f64> {
&self.omega
}
fn energy(&self) -> Array1<f64> {
self.omega.iter().map(|w| energy(w, self.alpha)).collect()
}
}
impl Default for Phillips {
fn default() -> Self {
Phillips {
u: 10.0,
alpha: 0.0081,
omega: Array1::<f64>::linspace(0.1, PI, N_FREQ),
}
}
}
impl SpectralCommon for Phillips {
fn hs(&self) -> Result<f64, String> {
Ok(2. * self.alpha.sqrt() * GRAVITY / self.wp()?.powi(2))
}
fn tp(&self) -> Result<f64, String> {
Ok(TWO_PI / self.wp()?)
}
fn wp(&self) -> Result<f64, String> {
Ok(GRAVITY / self.u)
}
fn omega(&self) -> &Array1<f64> {
&self.omega
}
fn energy(&self) -> Array1<f64> {
let wp = self.wp().unwrap_or(0.0);
self.omega
.iter()
.map(|w| match w {
w if w <= &wp => 0.0,
_ => energy(w, self.alpha),
})
.collect()
}
}
impl Phillips {
pub fn new(u: f64) -> Self {
Phillips {
u,
..Default::default()
}
}
pub fn m_n(&self, n: usize) -> f64 {
self.alpha
* GRAVITY.powi(2)
* (TWO_PI).powi(-4)
* self.fp().unwrap_or(0.0).powi((n as i32) - 4)
/ (4. - n as f64)
}
#[allow(non_snake_case)]
pub fn M_n(&self, n: usize) -> f64 {
self.alpha
* GRAVITY.powi(2)
* (1. / TWO_PI).powi(n as i32)
* self.wp().unwrap_or(0.0).powi((n as i32) - 4)
/ (4. - n as f64)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_phillips_energy() {
let phillips = Phillips1958::new();
let energy = phillips.energy();
assert_eq!(phillips.alpha, 0.0081);
assert_eq!(phillips.omega.len(), N_FREQ);
assert_eq!(energy.len(), N_FREQ);
}
#[test]
fn test_raises() {
let phillips = Phillips1958::new();
assert!(phillips.hs().is_err());
assert!(phillips.tp().is_err());
}
}