use crate::erfa::*;
use crate::time::julian_date;
use chrono::{TimeZone, Utc};
#[test]
fn test_precession_matrix() {
let matrix = precession_matrix(2451545.0, 0.0);
assert!((matrix[0][0] - 1.0).abs() < 1e-10);
assert!((matrix[1][1] - 1.0).abs() < 1e-10);
assert!((matrix[2][2] - 1.0).abs() < 1e-10);
assert!(matrix[0][1].abs() < 1e-6);
assert!(matrix[0][2].abs() < 1e-6);
assert!(matrix[1][0].abs() < 1e-6);
}
#[test]
fn test_bias_precession_nutation_matrix() {
let matrix = bias_precession_nutation_matrix(2451545.0, 0.0);
assert!((matrix[0][0] - 1.0).abs() < 1e-6);
assert!((matrix[1][1] - 1.0).abs() < 1e-6);
assert!((matrix[2][2] - 1.0).abs() < 1e-6);
}
#[test]
fn test_greenwich_mean_sidereal_time() {
let dt = Utc.with_ymd_and_hms(1987, 4, 10, 0, 0, 0).unwrap();
let jd = julian_date(dt);
let gmst_rad = greenwich_mean_sidereal_time(jd, 0.0, crate::time_scales::utc_to_tt_jd(jd), 0.0);
let gmst_hours = gmst_rad * 12.0 / std::f64::consts::PI;
let gmst_normalized = if gmst_hours < 0.0 { gmst_hours + 24.0 } else { gmst_hours % 24.0 };
assert!((gmst_normalized - 13.18).abs() < 0.1);
}
#[test]
fn test_greenwich_apparent_sidereal_time() {
let dt = Utc.with_ymd_and_hms(2024, 1, 1, 0, 0, 0).unwrap();
let jd = julian_date(dt);
let gast_rad = greenwich_apparent_sidereal_time(jd, 0.0, crate::time_scales::utc_to_tt_jd(jd), 0.0);
let gmst_rad = greenwich_mean_sidereal_time(jd, 0.0, crate::time_scales::utc_to_tt_jd(jd), 0.0);
let diff_rad = (gast_rad - gmst_rad).abs();
let diff_arcsec = diff_rad * 206264.806;
assert!(diff_arcsec < 20.0, "Equation of equinoxes too large: {} arcsec", diff_arcsec);
}
#[test]
fn test_earth_rotation_angle() {
let jd = 2451545.0;
let era_rad = earth_rotation_angle(jd, 0.0);
assert!((0.0..2.0 * std::f64::consts::PI).contains(&era_rad));
}
#[test]
fn test_icrs_to_cirs() {
let ra_icrs = 100.0_f64.to_radians();
let dec_icrs = 25.0_f64.to_radians();
let jd = 2451545.0;
let result = icrs_to_cirs(ra_icrs, dec_icrs, 0.0, 0.0, 0.0, 0.0, jd, 0.0);
assert!(result.is_ok());
let (ra_cirs, dec_cirs, _eo) = result.unwrap();
assert!((ra_cirs - ra_icrs).abs() < 0.001); assert!((dec_cirs - dec_icrs).abs() < 0.001);
}
#[test]
fn test_icrs_to_observed_basic() {
let ra_icrs = 0.0_f64.to_radians();
let dec_icrs = 0.0_f64.to_radians();
let dt = Utc.with_ymd_and_hms(2024, 1, 1, 0, 0, 0).unwrap();
let jd = julian_date(dt);
let result = icrs_to_observed(
ra_icrs, dec_icrs,
0.0, 0.0, 0.0, 0.0, jd, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1013.25, 15.0, 0.5, 0.55, );
assert!(result.is_ok());
let (az, zd, _ha, _dec, _ra, _eo) = result.unwrap();
assert!((0.0..=2.0 * std::f64::consts::PI).contains(&az));
assert!((0.0..=std::f64::consts::PI).contains(&zd));
}
#[test]
fn test_cirs_to_observed_basic() {
let ri = 0.0_f64.to_radians();
let di = 0.0_f64.to_radians();
let dt = Utc.with_ymd_and_hms(2024, 1, 1, 0, 0, 0).unwrap();
let jd = julian_date(dt);
let result = cirs_to_observed(
ri, di,
jd, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1013.25, 15.0, 0.5, 0.55, );
assert!(result.is_ok());
let (az, zd, _ha, _dec, _ra, _eo) = result.unwrap();
assert!((0.0..=2.0 * std::f64::consts::PI).contains(&az));
assert!((0.0..=std::f64::consts::PI).contains(&zd));
}
#[test]
fn test_icrs_to_observed_with_proper_motion() {
let ra_icrs = 279.23473479_f64.to_radians(); let dec_icrs = 38.78368896_f64.to_radians();
let pr = 200.94 * std::f64::consts::PI / (180.0 * 3600.0 * 1000.0);
let pd = 286.23 * std::f64::consts::PI / (180.0 * 3600.0 * 1000.0);
let dt = Utc.with_ymd_and_hms(2024, 1, 1, 0, 0, 0).unwrap();
let jd = julian_date(dt);
let result = icrs_to_observed(
ra_icrs, dec_icrs,
pr, pd, 0.130, 0.0, jd, 0.0,
0.0,
0.0, 0.0, 0.0,
0.0, 0.0,
0.0, 0.0, 0.0, 0.55, );
assert!(result.is_ok());
}
#[test]
fn test_icrs_to_observed_high_latitude() {
let ra_icrs = 0.0_f64.to_radians();
let dec_icrs = 80.0_f64.to_radians();
let dt = Utc.with_ymd_and_hms(2024, 6, 21, 12, 0, 0).unwrap();
let jd = julian_date(dt);
let result = icrs_to_observed(
ra_icrs, dec_icrs,
0.0, 0.0, 0.0, 0.0,
jd, 0.0,
0.0,
0.0, 70.0_f64.to_radians(), 0.0, 0.0, 0.0,
1013.25, -20.0, 0.3, 0.55, );
assert!(result.is_ok());
}
#[test]
fn test_precession_matrix_orthogonal() {
let matrix = precession_matrix(2460000.0, 0.0);
let mut product = [[0.0; 3]; 3];
for (i, row) in product.iter_mut().enumerate() {
for (j, cell) in row.iter_mut().enumerate() {
for matrix_row in &matrix {
*cell += matrix_row[i] * matrix_row[j];
}
}
}
for (i, row) in product.iter().enumerate() {
for (j, &cell) in row.iter().enumerate() {
let expected = if i == j { 1.0 } else { 0.0 };
assert!((cell - expected).abs() < 1e-10,
"Matrix not orthogonal at [{},{}]: {}", i, j, product[i][j]);
}
}
}
#[test]
fn test_bias_precession_nutation_matrix_determinant() {
let matrix = bias_precession_nutation_matrix(2460000.0, 0.0);
let det = matrix[0][0] * (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1])
- matrix[0][1] * (matrix[1][0] * matrix[2][2] - matrix[1][2] * matrix[2][0])
+ matrix[0][2] * (matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0]);
assert!((det - 1.0).abs() < 1e-10, "Determinant = {}, expected 1", det);
}
#[test]
fn test_friendly_function_names() {
let jd = 2451545.0;
let gmst = greenwich_mean_sidereal_time(jd, 0.0, jd, 0.0);
assert!(!gmst.is_nan());
let gast = greenwich_apparent_sidereal_time(jd, 0.0, jd, 0.0);
assert!(!gast.is_nan());
let era = earth_rotation_angle(jd, 0.0);
assert!(!era.is_nan());
let matrix = bias_precession_nutation_matrix(jd, 0.0);
assert_eq!(matrix.len(), 3);
assert_eq!(matrix[0].len(), 3);
}