use once_cell::sync::Lazy;
use std::sync::{Arc, RwLock};
use crate::eop::eop_provider::EarthOrientationProvider;
use crate::eop::eop_types::{EOPExtrapolation, EOPType};
use crate::eop::static_provider::StaticEOPProvider;
use crate::utils::BraheError;
#[cfg(test)]
use serial_test::serial;
static GLOBAL_EOP: Lazy<Arc<RwLock<Box<dyn EarthOrientationProvider + Sync + Send>>>> =
Lazy::new(|| Arc::new(RwLock::new(Box::new(StaticEOPProvider::new()))));
pub fn set_global_eop_provider<T: EarthOrientationProvider + Sync + Send + 'static>(provider: T) {
*GLOBAL_EOP.write().unwrap() = Box::new(provider);
}
pub fn get_global_ut1_utc(mjd: f64) -> Result<f64, BraheError> {
GLOBAL_EOP.read().unwrap().get_ut1_utc(mjd)
}
pub fn get_global_pm(mjd: f64) -> Result<(f64, f64), BraheError> {
GLOBAL_EOP.read().unwrap().get_pm(mjd)
}
pub fn get_global_dxdy(mjd: f64) -> Result<(f64, f64), BraheError> {
GLOBAL_EOP.read().unwrap().get_dxdy(mjd)
}
pub fn get_global_lod(mjd: f64) -> Result<f64, BraheError> {
GLOBAL_EOP.read().unwrap().get_lod(mjd)
}
#[allow(non_snake_case)]
pub fn get_global_eop(mjd: f64) -> Result<(f64, f64, f64, f64, f64, f64), BraheError> {
GLOBAL_EOP.read().unwrap().get_eop(mjd)
}
pub fn get_global_eop_initialization() -> bool {
GLOBAL_EOP.read().unwrap().is_initialized()
}
pub fn get_global_eop_len() -> usize {
GLOBAL_EOP.read().unwrap().len()
}
pub fn get_global_eop_type() -> EOPType {
GLOBAL_EOP.read().unwrap().eop_type()
}
pub fn get_global_eop_extrapolation() -> EOPExtrapolation {
GLOBAL_EOP.read().unwrap().extrapolation()
}
pub fn get_global_eop_interpolation() -> bool {
GLOBAL_EOP.read().unwrap().interpolation()
}
pub fn get_global_eop_mjd_min() -> f64 {
GLOBAL_EOP.read().unwrap().mjd_min()
}
pub fn get_global_eop_mjd_max() -> f64 {
GLOBAL_EOP.read().unwrap().mjd_max()
}
pub fn get_global_eop_mjd_last_lod() -> f64 {
GLOBAL_EOP.read().unwrap().mjd_last_lod()
}
pub fn get_global_eop_mjd_last_dxdy() -> f64 {
GLOBAL_EOP.read().unwrap().mjd_last_dxdy()
}
pub fn initialize_eop() -> Result<(), BraheError> {
use crate::eop::caching_provider::CachingEOPProvider;
let provider = CachingEOPProvider::new(
None, EOPType::StandardBulletinA,
7 * 86400, false, true, EOPExtrapolation::Hold,
)?;
set_global_eop_provider(provider);
Ok(())
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
#[serial]
mod tests {
use super::*;
use crate::constants::AS2RAD;
use crate::eop::file_provider::FileEOPProvider;
use crate::eop::static_provider::StaticEOPProvider;
use std::env;
use std::path::Path;
use approx::assert_abs_diff_eq;
fn setup_test_global_eop(eop_interpolation: bool, eop_extrapolation: EOPExtrapolation) {
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let filepath = Path::new(&manifest_dir)
.join("test_assets")
.join("finals.all.iau2000.txt");
let eop = FileEOPProvider::from_file(&filepath, eop_interpolation, eop_extrapolation)
.expect("Failed to load EOP file for tests");
assert!(eop.is_initialized());
set_global_eop_provider(eop);
}
fn clear_test_global_eop() {
set_global_eop_provider(StaticEOPProvider::new());
}
#[test]
#[serial]
fn test_set_global_eop_from_zero() {
clear_test_global_eop();
assert!(!get_global_eop_initialization());
let eop = StaticEOPProvider::from_zero();
set_global_eop_provider(eop);
assert!(get_global_eop_initialization());
assert_eq!(get_global_eop_len(), 1);
assert_eq!(get_global_eop_mjd_min(), 0.0);
assert_eq!(get_global_eop_mjd_max(), f64::MAX);
assert_eq!(get_global_eop_type(), EOPType::Static);
assert_eq!(get_global_eop_extrapolation(), EOPExtrapolation::Hold);
assert!(!get_global_eop_interpolation());
assert_eq!(get_global_ut1_utc(59950.0).unwrap(), 0.0);
assert_eq!(get_global_pm(59950.0).unwrap().0, 0.0);
assert_eq!(get_global_pm(59950.0).unwrap().1, 0.0);
assert_eq!(get_global_dxdy(59950.0).unwrap().0, 0.0);
assert_eq!(get_global_dxdy(59950.0).unwrap().1, 0.0);
assert_eq!(get_global_lod(59950.0).unwrap(), 0.0);
}
#[test]
#[serial]
fn test_set_global_eop_from_static_values() {
clear_test_global_eop();
assert!(!get_global_eop_initialization());
let eop = StaticEOPProvider::from_values((0.001, 0.002, 0.003, 0.004, 0.005, 0.006));
set_global_eop_provider(eop);
assert!(get_global_eop_initialization());
assert_eq!(get_global_eop_len(), 1);
assert_eq!(get_global_eop_mjd_min(), 0.0);
assert_eq!(get_global_eop_mjd_max(), f64::MAX);
assert_eq!(get_global_eop_type(), EOPType::Static);
assert_eq!(get_global_eop_extrapolation(), EOPExtrapolation::Hold);
assert!(!get_global_eop_interpolation());
assert_eq!(get_global_ut1_utc(59950.0).unwrap(), 0.003);
assert_eq!(get_global_pm(59950.0).unwrap().0, 0.001);
assert_eq!(get_global_pm(59950.0).unwrap().1, 0.002);
assert_eq!(get_global_dxdy(59950.0).unwrap().0, 0.004);
assert_eq!(get_global_dxdy(59950.0).unwrap().1, 0.005);
assert_eq!(get_global_lod(59950.0).unwrap(), 0.006);
}
#[test]
#[serial]
fn test_set_global_eop_from_c04_file() {
clear_test_global_eop();
assert!(!get_global_eop_initialization());
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let filepath = Path::new(&manifest_dir)
.join("test_assets")
.join("EOP_20_C04_one_file_1962-now.txt");
let eop = FileEOPProvider::from_file(&filepath, true, EOPExtrapolation::Hold).unwrap();
set_global_eop_provider(eop);
assert!(get_global_eop_initialization());
assert_eq!(get_global_eop_len(), 22605);
assert_eq!(get_global_eop_mjd_min(), 37665.0);
assert_eq!(get_global_eop_mjd_max(), 60269.0);
assert_eq!(get_global_eop_type(), EOPType::C04);
assert_eq!(get_global_eop_extrapolation(), EOPExtrapolation::Hold);
assert!(get_global_eop_interpolation());
}
#[test]
#[serial]
fn test_set_global_eop_from_default_c04() {
clear_test_global_eop();
assert!(!get_global_eop_initialization());
let eop = FileEOPProvider::from_default_file(EOPType::C04, false, EOPExtrapolation::Zero)
.unwrap();
set_global_eop_provider(eop);
assert!(get_global_eop_initialization());
assert!(get_global_eop_len() >= 22619);
assert_eq!(get_global_eop_mjd_min(), 37665.0);
assert!(get_global_eop_mjd_max() >= 60269.0);
assert_eq!(get_global_eop_type(), EOPType::C04);
assert_eq!(get_global_eop_extrapolation(), EOPExtrapolation::Zero);
assert!(!get_global_eop_interpolation());
}
#[test]
#[serial]
fn test_set_global_eop_from_standard_file() {
clear_test_global_eop();
assert!(!get_global_eop_initialization());
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let filepath = Path::new(&manifest_dir)
.join("test_assets")
.join("finals.all.iau2000.txt");
let eop = FileEOPProvider::from_file(&filepath, true, EOPExtrapolation::Hold).unwrap();
set_global_eop_provider(eop);
assert!(get_global_eop_initialization());
assert_eq!(get_global_eop_len(), 18989);
assert_eq!(get_global_eop_mjd_min(), 41684.0);
assert_eq!(get_global_eop_mjd_max(), 60672.0);
assert_eq!(get_global_eop_type(), EOPType::StandardBulletinA);
assert_eq!(get_global_eop_extrapolation(), EOPExtrapolation::Hold);
assert!(get_global_eop_interpolation());
}
#[test]
#[serial]
fn test_set_global_eop_from_default_standard() {
clear_test_global_eop();
assert!(!get_global_eop_initialization());
let eop = FileEOPProvider::from_default_file(
EOPType::StandardBulletinA,
false,
EOPExtrapolation::Zero,
)
.unwrap();
set_global_eop_provider(eop);
assert!(get_global_eop_initialization());
assert!(get_global_eop_len() >= 18996);
assert_eq!(get_global_eop_mjd_min(), 41684.0);
assert!(get_global_eop_mjd_max() >= 60672.0);
assert_eq!(get_global_eop_type(), EOPType::StandardBulletinA);
assert_eq!(get_global_eop_extrapolation(), EOPExtrapolation::Zero);
assert!(!get_global_eop_interpolation());
}
#[test]
#[serial]
fn test_get_global_ut1_utc() {
clear_test_global_eop();
setup_test_global_eop(true, EOPExtrapolation::Hold);
assert!(get_global_eop_initialization());
let ut1_utc = get_global_ut1_utc(59569.0).unwrap();
assert_eq!(ut1_utc, -0.1079939);
let ut1_utc = get_global_ut1_utc(59569.5).unwrap();
assert_eq!(ut1_utc, (-0.1079939 + -0.1075984) / 2.0);
let ut1_utc = get_global_ut1_utc(99999.0).unwrap();
assert_eq!(ut1_utc, 0.0420038);
setup_test_global_eop(true, EOPExtrapolation::Zero);
let ut1_utc = get_global_ut1_utc(99999.0).unwrap();
assert_eq!(ut1_utc, 0.0);
}
#[test]
#[serial]
fn test_get_global_pm_xy() {
clear_test_global_eop();
setup_test_global_eop(true, EOPExtrapolation::Hold);
assert!(get_global_eop_initialization());
let (pm_x, pm_y) = get_global_pm(59569.0).unwrap();
assert_eq!(pm_x, 0.075382 * AS2RAD);
assert_eq!(pm_y, 0.263451 * AS2RAD);
let (pm_x, pm_y) = get_global_pm(59569.5).unwrap();
assert_eq!(pm_x, (0.075382 * AS2RAD + 0.073157 * AS2RAD) / 2.0);
assert_eq!(pm_y, (0.263451 * AS2RAD + 0.264273 * AS2RAD) / 2.0);
let (pm_x, pm_y) = get_global_pm(99999.0).unwrap();
assert_eq!(pm_x, 0.173369 * AS2RAD);
assert_eq!(pm_y, 0.266914 * AS2RAD);
setup_test_global_eop(true, EOPExtrapolation::Zero);
let (pm_x, pm_y) = get_global_pm(99999.0).unwrap();
assert_eq!(pm_x, 0.0);
assert_eq!(pm_y, 0.0);
}
#[test]
#[serial]
#[allow(non_snake_case)]
fn test_get_global_dxdy() {
clear_test_global_eop();
setup_test_global_eop(true, EOPExtrapolation::Hold);
assert!(get_global_eop_initialization());
let (dX, dY) = get_global_dxdy(59569.0).unwrap();
assert_eq!(dX, 0.265 * 1.0e-3 * AS2RAD);
assert_eq!(dY, -0.067 * 1.0e-3 * AS2RAD);
let (dX, dY) = get_global_dxdy(59569.5).unwrap();
assert_eq!(dX, (0.265 * AS2RAD + 0.268 * AS2RAD) * 1.0e-3 / 2.0);
assert_abs_diff_eq!(
dY,
(-0.067 * AS2RAD + -0.067 * AS2RAD) * 1.0e-3 / 2.0,
epsilon = f64::EPSILON
);
let (dX, dY) = get_global_dxdy(99999.0).unwrap();
assert_eq!(dX, 0.006 * 1.0e-3 * AS2RAD);
assert_eq!(dY, -0.118 * 1.0e-3 * AS2RAD);
setup_test_global_eop(true, EOPExtrapolation::Zero);
let (dX, dY) = get_global_dxdy(99999.0).unwrap();
assert_eq!(dX, 0.0);
assert_eq!(dY, 0.0);
}
#[test]
#[serial]
fn test_get_global_lod() {
clear_test_global_eop();
setup_test_global_eop(true, EOPExtrapolation::Hold);
assert!(get_global_eop_initialization());
let lod = get_global_lod(59569.0).unwrap();
assert_eq!(lod, -0.3999 * 1.0e-3);
let lod = get_global_lod(59569.5).unwrap();
assert_eq!(lod, (-0.3999 + -0.3604) * 1.0e-3 / 2.0);
let lod = get_global_lod(99999.0).unwrap();
assert_eq!(lod, 0.7706 * 1.0e-3);
setup_test_global_eop(true, EOPExtrapolation::Zero);
let lod = get_global_lod(99999.0).unwrap();
assert_eq!(lod, 0.0);
}
#[test]
#[serial]
fn test_get_global_eop_initialization() {
clear_test_global_eop();
setup_test_global_eop(true, EOPExtrapolation::Hold);
assert!(get_global_eop_initialization());
}
#[test]
#[serial]
fn test_get_global_eop_len() {
clear_test_global_eop();
setup_test_global_eop(true, EOPExtrapolation::Hold);
assert!(get_global_eop_initialization());
assert_eq!(get_global_eop_len(), 18989);
}
#[test]
#[serial]
fn test_get_global_eop_type() {
clear_test_global_eop();
setup_test_global_eop(true, EOPExtrapolation::Hold);
assert!(get_global_eop_initialization());
assert_eq!(get_global_eop_type(), EOPType::StandardBulletinA);
}
#[test]
#[serial]
fn test_get_global_eop_extrapolation() {
clear_test_global_eop();
setup_test_global_eop(true, EOPExtrapolation::Hold);
assert!(get_global_eop_initialization());
assert_eq!(get_global_eop_extrapolation(), EOPExtrapolation::Hold);
}
#[test]
#[serial]
fn test_get_global_eop_interpolation() {
clear_test_global_eop();
setup_test_global_eop(true, EOPExtrapolation::Hold);
assert!(get_global_eop_initialization());
assert!(get_global_eop_interpolation());
}
#[test]
#[serial]
fn test_get_global_eop_mjd_min() {
clear_test_global_eop();
setup_test_global_eop(true, EOPExtrapolation::Hold);
assert!(get_global_eop_initialization());
assert_eq!(get_global_eop_mjd_min(), 41684.0);
}
#[test]
#[serial]
fn test_get_global_eop_mjd_max() {
clear_test_global_eop();
setup_test_global_eop(true, EOPExtrapolation::Hold);
assert!(get_global_eop_initialization());
assert_eq!(get_global_eop_mjd_max(), 60672.0);
}
#[test]
#[serial]
fn test_get_global_eop_mjd_last_lod() {
clear_test_global_eop();
setup_test_global_eop(true, EOPExtrapolation::Hold);
assert!(get_global_eop_initialization());
assert_eq!(get_global_eop_mjd_last_lod(), 60298.0);
}
#[test]
#[serial]
fn test_get_global_eop_mjd_last_dxdy() {
clear_test_global_eop();
setup_test_global_eop(true, EOPExtrapolation::Hold);
assert!(get_global_eop_initialization());
assert_eq!(get_global_eop_mjd_last_dxdy(), 60373.0);
}
#[test]
#[serial]
#[cfg_attr(not(feature = "ci"), ignore)]
fn test_initialize_eop() {
clear_test_global_eop();
assert!(!get_global_eop_initialization());
initialize_eop().unwrap();
assert!(get_global_eop_initialization());
assert_eq!(get_global_eop_type(), EOPType::StandardBulletinA);
assert_eq!(get_global_eop_extrapolation(), EOPExtrapolation::Hold);
assert!(get_global_eop_interpolation());
assert!(get_global_eop_len() > 0);
let mjd = 60000.0;
let ut1_utc = get_global_ut1_utc(mjd).unwrap();
assert!(ut1_utc.is_finite());
let (pm_x, pm_y) = get_global_pm(mjd).unwrap();
assert!(pm_x.is_finite());
assert!(pm_y.is_finite());
}
}