use crate::error::RobustError;
use crate::rho::RhoFunction;
use std::f64::consts::PI;
#[derive(Debug, Clone, Copy)]
pub struct Andrews {
c: f64,
}
impl Andrews {
pub fn new(c: f64) -> Result<Self, RobustError> {
if c.is_finite() && c > 0.0 {
Ok(Self { c })
} else {
Err(RobustError::InvalidTuning { value: c })
}
}
}
impl Default for Andrews {
fn default() -> Self {
Self { c: 1.339 }
}
}
impl RhoFunction for Andrews {
fn rho(&self, r: f64) -> f64 {
let c2 = self.c * self.c;
if r.abs() <= self.c * PI {
c2 * (1.0 - (r / self.c).cos())
} else {
2.0 * c2
}
}
fn psi(&self, r: f64) -> f64 {
if r.abs() <= self.c * PI {
self.c * (r / self.c).sin()
} else {
0.0
}
}
fn weight(&self, r: f64) -> f64 {
if r == 0.0 {
1.0 } else if r.abs() <= self.c * PI {
self.c * (r / self.c).sin() / r
} else {
0.0
}
}
fn psi_prime(&self, r: f64) -> f64 {
if r.abs() <= self.c * PI {
(r / self.c).cos()
} else {
0.0
}
}
fn tuning(&self) -> f64 {
self.c
}
fn is_redescending(&self) -> bool {
true
}
fn rho_sup(&self) -> Option<f64> {
Some(2.0 * self.c * self.c)
}
}