use crate::error::{SpecialError, SpecialResult};
use crate::spheroidal::cf_helpers::{
angular_function, flammer_eigenvalue, radial_function, SphericalBesselKind, SpheroidalParity,
DEFAULT_D_LEN,
};
#[allow(dead_code)]
pub fn pro_cv(m: i32, n: i32, c: f64) -> SpecialResult<f64> {
if m < 0 || n < m {
return Err(SpecialError::DomainError(
"Parameters must satisfy m ≥ 0 and n ≥ m".to_string(),
));
}
if n > 1000 {
return Err(SpecialError::DomainError(
"Parameter n is too large (> 1000), may cause numerical instability".to_string(),
));
}
if c.abs() > 1000.0 {
return Err(SpecialError::DomainError(
"Parameter c is too large (|c| > 1000), may cause numerical instability".to_string(),
));
}
if c.is_nan() {
return Ok(f64::NAN);
}
if c.is_infinite() {
let n_f = n as f64;
return Ok(-c.powi(2) / 4.0 + (2.0 * n_f + 1.0) * c.abs());
}
if c == 0.0 {
return Ok(n as f64 * (n as f64 + 1.0));
}
flammer_eigenvalue(SpheroidalParity::Prolate, m, n, c.abs(), DEFAULT_D_LEN)
}
#[allow(dead_code)]
pub fn pro_cv_seq(m: i32, n: i32, c: f64) -> SpecialResult<Vec<f64>> {
if m < 0 || n < m {
return Err(SpecialError::DomainError(
"Parameters must satisfy m ≥ 0 and n ≥ m".to_string(),
));
}
if n - m > 199 {
return Err(SpecialError::DomainError(
"Difference between n and m is too large (max 199)".to_string(),
));
}
if c.is_nan() {
return Ok(vec![f64::NAN; (n - m + 1) as usize]);
}
let mut result = Vec::with_capacity((n - m + 1) as usize);
for degree in m..=n {
result.push(pro_cv(m, degree, c)?);
}
Ok(result)
}
#[allow(dead_code)]
pub fn pro_ang1(m: i32, n: i32, c: f64, x: f64) -> SpecialResult<(f64, f64)> {
if m < 0 || n < m {
return Err(SpecialError::DomainError(
"Parameters must satisfy m ≥ 0 and n ≥ m".to_string(),
));
}
if !(-1.0..=1.0).contains(&x) {
return Err(SpecialError::DomainError(
"Angular coordinate x must be in range [-1, 1]".to_string(),
));
}
if c.is_nan() || x.is_nan() {
return Ok((f64::NAN, f64::NAN));
}
angular_function(SpheroidalParity::Prolate, m, n, c.abs(), x)
}
#[allow(dead_code)]
pub fn pro_rad1(m: i32, n: i32, c: f64, x: f64) -> SpecialResult<(f64, f64)> {
if m < 0 || n < m {
return Err(SpecialError::DomainError(
"Parameters must satisfy m ≥ 0 and n ≥ m".to_string(),
));
}
if x < 1.0 {
return Err(SpecialError::DomainError(
"Radial coordinate x must be ≥ 1.0".to_string(),
));
}
if c.is_nan() || x.is_nan() {
return Ok((f64::NAN, f64::NAN));
}
if c == 0.0 {
let p_mn = crate::orthogonal::legendre_assoc(n as usize, m, x);
let h = 1.0e-8_f64;
let p_plus = crate::orthogonal::legendre_assoc(n as usize, m, x + h);
let p_minus = crate::orthogonal::legendre_assoc(n as usize, m, x - h);
let p_prime = (p_plus - p_minus) / (2.0 * h);
return Ok((p_mn, p_prime));
}
radial_function(
SpheroidalParity::Prolate,
SphericalBesselKind::First,
m,
n,
c.abs(),
x,
)
}
#[allow(dead_code)]
pub fn pro_rad2(m: i32, n: i32, c: f64, x: f64) -> SpecialResult<(f64, f64)> {
if m < 0 || n < m {
return Err(SpecialError::DomainError(
"Parameters must satisfy m ≥ 0 and n ≥ m".to_string(),
));
}
if x < 1.0 {
return Err(SpecialError::DomainError(
"Radial coordinate x must be ≥ 1.0".to_string(),
));
}
if c.is_nan() || x.is_nan() {
return Ok((f64::NAN, f64::NAN));
}
if c == 0.0 {
return crate::spheroidal::helpers::legendre_associated_second_kind(n, m, x);
}
radial_function(
SpheroidalParity::Prolate,
SphericalBesselKind::Second,
m,
n,
c.abs(),
x,
)
}