#![allow(clippy::excessive_precision)]
use super::consts::{M_PI_2, MACHEP};
pub fn ellpj(u: f64, m: f64) -> (f64, f64, f64, f64) {
if !(0.0..=1.0).contains(&m) || m.is_nan() {
(f64::NAN, f64::NAN, f64::NAN, f64::NAN)
} else if m < 1.0e-9 {
let t = u.sin();
let b = u.cos();
let ai = 0.25 * m * (u - t * b);
(
t - ai * b,
b + ai * t,
1.0 - 0.5 * m * t * t,
u - ai
)
} else if m >= 0.9999999999 {
let mut ai = 0.25 * (1.0 - m);
let b = u.cosh();
let t = u.tanh();
let phi = 1.0 / b;
let twon = b * u.sinh();
let sn = t + ai * (twon - u) / (b * b);
let ph = 2.0 * u.exp().atan() - M_PI_2 + ai * (twon - u) / b;
ai *= t * phi;
let cn = phi - ai * (twon - u);
let dn = phi + ai * (twon + u);
(sn, cn, dn, ph)
} else {
let mut a: [f64; 9] = [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
let mut b = (1.0 - m).sqrt();
let mut c: [f64; 9] = [m.sqrt(), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
let mut twon = 1.0;
let mut i = 0;
while (c[i] / a[i]).abs() > MACHEP {
if i > 7 {
break;
}
let ai = a[i];
i += 1;
c[i] = (ai - b) / 2.0;
let t = (ai * b).sqrt();
a[i] = (ai + b) / 2.0;
b = t;
twon *= 2.0;
}
let mut phi = twon * a[i] * u;
while i >= 1 {
let t = c[i] * phi.sin() / a[i];
b = phi;
phi = (t.asin() + phi) / 2.0;
i -= 1;
}
let sn = phi.sin();
let t = phi.cos();
let cn = t;
let dnfac = (phi - b).cos();
let dn = if dnfac.abs() < 0.1 {
(1.0 - m*sn*sn).sqrt()
}
else {
t / dnfac
};
let ph = phi;
(sn, cn, dn, ph)
}
}
#[cfg(test)]
mod ellpj_tests {
use super::*;
fn tuple_is_nan(t: (f64, f64, f64, f64)) -> bool {
t.0.is_nan() && t.1.is_nan() && t.2.is_nan() && t.3.is_nan()
}
#[test]
fn ellpj_trivials() {
assert_eq!(tuple_is_nan(ellpj(0.0, -f64::INFINITY)), true);
assert_eq!(tuple_is_nan(ellpj(0.0, -1e20)), true);
assert_eq!(tuple_is_nan(ellpj(0.0, -1.0)), true);
assert_eq!(tuple_is_nan(ellpj(0.0, -1e-20)), true);
assert_eq!(tuple_is_nan(ellpj(0.0, 1.0 + 1e-15)), true);
assert_eq!(tuple_is_nan(ellpj(0.0, 2.0)), true);
assert_eq!(tuple_is_nan(ellpj(0.0, 1e20)), true);
assert_eq!(tuple_is_nan(ellpj(0.0, f64::INFINITY)), true);
assert_eq!(tuple_is_nan(ellpj(0.0, f64::NAN)), true);
}
#[test]
fn ellpj_m_small() {
assert_eq!(ellpj(0.0, 1e-9 - 1e-20), (0.0, 1.0, 1.0, 0.0));
assert_eq!(ellpj(0.0, 5e-10), (0.0, 1.0, 1.0, 0.0));
assert_eq!(ellpj(0.0, 1e-10), (0.0, 1.0, 1.0, 0.0));
assert_eq!(ellpj(0.0, 1e-20), (0.0, 1.0, 1.0, 0.0));
assert_eq!(ellpj(M_PI_2, 1e-9 - 1e-20), (1.0, 3.926991429271371e-10, 0.9999999995, 1.5707963264021976));
assert_eq!(ellpj(M_PI_2, 5e-10), (1.0, 1.9634960208170204e-10, 0.99999999975, 1.570796326598547));
assert_eq!(ellpj(M_PI_2, 1e-10), (1.0, 3.926996940221238e-11, 0.99999999995, 1.5707963267556266));
assert_eq!(ellpj(M_PI_2, 1e-20), (1.0, 6.123626694818465e-17, 1.0, 1.5707963267948966));
assert_eq!(ellpj(-M_PI_2, 1e-9 - 1e-20), (-1.0, 3.926991429271371e-10, 0.9999999995, -1.5707963264021976));
assert_eq!(ellpj(-M_PI_2, 5e-10), (-1.0, 1.9634960208170204e-10, 0.99999999975, -1.570796326598547));
assert_eq!(ellpj(-M_PI_2, 1e-10), (-1.0, 3.926996940221238e-11, 0.99999999995, -1.5707963267556266));
assert_eq!(ellpj(-M_PI_2, 1e-20), (-1.0, 6.123626694818465e-17, 1.0, -1.5707963267948966));
assert_eq!(ellpj(1000.0, 1e-9 - 1e-20), (0.8268794000026128, 0.5623792829144593, 0.9999999996581351, 999.9999997501162));
assert_eq!(ellpj(1000.0, 5e-10), (0.8268794702673077, 0.5623791796025811, 0.9999999998290675, 999.9999998750582));
assert_eq!(ellpj(1000.0, 1e-10), (0.8268795264790636, 0.5623790969530785, 0.9999999999658135, 999.9999999750116));
assert_eq!(ellpj(1000.0, 1e-20), (0.8268795405320025, 0.5623790762907029, 1.0, 1000.0));
}
#[test]
fn ellpj_m_large() {
assert_eq!(ellpj(0.0, 0.9999999999), (0.0, 1.0, 1.0, 0.0));
assert_eq!(ellpj(0.0, 0.99999999995), (0.0, 1.0, 1.0, 0.0));
assert_eq!(ellpj(0.0, 0.9999999999999999), (0.0, 1.0, 1.0, 0.0));
assert_eq!(ellpj(M_PI_2, 0.9999999999), (0.9171523356839659, 0.39853681529997453, 0.3985368154055066, 1.1608753910106864));
assert_eq!(ellpj(M_PI_2, 0.99999999995), (0.9171523356756202, 0.3985368153191806, 0.3985368153719467, 1.1608753909897453));
assert_eq!(ellpj(M_PI_2, 0.9999999999999999), (0.9171523356672744, 0.39853681533838664, 0.39853681533838675, 1.1608753909688043));
assert_eq!(ellpj(-M_PI_2, 0.9999999999), (-0.9171523356839659, 0.39853681529997453, 0.3985368154055066, -1.1608753910106864));
assert_eq!(ellpj(-M_PI_2, 0.99999999995), (-0.9171523356756202, 0.3985368153191806, 0.3985368153719467, -1.1608753909897453));
assert_eq!(ellpj(-M_PI_2, 0.9999999999999999), (-0.9171523356672744, 0.39853681533838664, 0.39853681533838675, -1.1608753909688043));
assert_eq!(ellpj(10.0, 0.9999999999), (0.9999999959026927, 9.052452851700366e-05, 9.107519020403078e-05, 1.5707058022662561));
assert_eq!(ellpj(10.0, 0.99999999995), (0.9999999958901927, 9.066219392741045e-05, 9.093752477092401e-05, 1.5707056646008453));
assert_eq!(ellpj(10.0, 0.9999999999999999), (0.9999999958776927, 9.079985903213866e-05, 9.07998596434959e-05, 1.57070552693574));
assert_eq!(ellpj(-10.0, 0.9999999999), (-0.9999999959026927, 9.052452851700366e-05, 9.107519020403078e-05, -1.570705802266256));
assert_eq!(ellpj(-10.0, 0.99999999995), (-0.9999999958901927, 9.066219392741045e-05, 9.093752477092401e-05, -1.570705664600845));
assert_eq!(ellpj(-10.0, 0.9999999999999999), (-0.9999999958776927, 9.079985903213866e-05, 9.07998596434959e-05, -1.5707055269357397));
}
#[test]
fn ellpj_nominal() {
assert_eq!(ellpj(0.0, 1e-9), (0.0, 1.0, 1.0, 0.0));
assert_eq!(ellpj(0.0, 0.1), (0.0, 1.0, 1.0, 0.0));
assert_eq!(ellpj(0.0, 0.5), (0.0, 1.0, 1.0, 0.0));
assert_eq!(ellpj(0.0, 0.9), (0.0, 1.0, 1.0, 0.0));
assert_eq!(ellpj(0.0, 0.9999999998), (0.0, 1.0, 1.0, 0.0));
assert_eq!(ellpj(M_PI_2, 1e-9), (1.0, 3.926992677185533e-10, 0.9999999995, 1.5707963264021974));
assert_eq!(ellpj(M_PI_2, 0.1), (0.9992196178831643, 0.03949880045549695, 0.9487655218881756, 1.5312872484118731));
assert_eq!(ellpj(M_PI_2, 0.5), (0.9797395592908522, 0.20027579973767845, 0.7211485269903025, 1.3691569109849622));
assert_eq!(ellpj(M_PI_2, 0.9), (0.9330319394105544, 0.3597935519708204, 0.4653023318615559, 1.2027497085690817));
assert_eq!(ellpj(M_PI_2, 0.9999999998), (0.9171523357006574, 0.39853681526156237, 0.39853681547262654, 1.1608753910525684));
assert_eq!(ellpj(-M_PI_2, 1e-9), (-1.0, 3.926992677185533e-10, 0.9999999995, -1.5707963264021974));
assert_eq!(ellpj(-M_PI_2, 0.1), (-0.9992196178831643, 0.03949880045549695, 0.9487655218881756, -1.5312872484118731));
assert_eq!(ellpj(-M_PI_2, 0.5), (-0.9797395592908522, 0.20027579973767845, 0.7211485269903025, -1.3691569109849622));
assert_eq!(ellpj(-M_PI_2, 0.9), (-0.9330319394105544, 0.3597935519708204, 0.4653023318615559, -1.2027497085690817));
assert_eq!(ellpj(-M_PI_2, 0.9999999998), (-0.9171523357006574, 0.39853681526156237, 0.39853681547262654, -1.1608753910525684));
assert_eq!(ellpj(10.0, 1e-9), (-0.5440211088874444, -0.8390715303744225, 0.9999999998520201, 9.999999997614118));
assert_eq!(ellpj(10.0, 0.1), (-0.3191099739995604, -0.9477176924031755, 0.9948954128195586, 9.74956817373828));
assert_eq!(ellpj(10.0, 0.5), (0.8588125059527789, -0.5122900346669922, 0.7944938890951594, 8.39183082303414));
assert_eq!(ellpj(10.0, 0.9), (-0.3030609695105877, 0.9529711689024504, 0.9577779721226483, 5.9752822590846275));
assert_eq!(ellpj(10.0, 0.9999999998), (0.9999999959275412, 9.024919769607522e-05, 9.1350521069685e-05, 1.570706077597078));
assert_eq!(ellpj(-10.0, 1e-9), (0.5440211088874444, -0.8390715303744225, 0.9999999998520201, -9.999999997614118));
assert_eq!(ellpj(-10.0, 0.1), (0.3191099739995604, -0.9477176924031755, 0.9948954128195586, -9.74956817373828));
assert_eq!(ellpj(-10.0, 0.5), (-0.8588125059527789, -0.5122900346669922, 0.7944938890951594, -8.39183082303414));
assert_eq!(ellpj(-10.0, 0.9), (0.3030609695105877, 0.9529711689024504, 0.9577779721226483, -5.9752822590846275));
assert_eq!(ellpj(-10.0, 0.9999999998), (-0.9999999959275412, 9.024919769607522e-05, 9.1350521069685e-05, -1.570706077597078));
}
}