use std::f64::consts::PI;
pub(crate) const PIT2: f64 = 2.0 * PI;
pub(crate) const PID2: f64 = PI / 2.0;
pub(crate) const C: f64 = 2.997925e5;
pub(crate) const LOGTEN: f64 = core::f64::consts::LN_10;
pub const EARTH_RADIUS: f64 = 6370.0;
#[non_exhaustive]
#[derive(
serde::Serialize, serde::Deserialize, Clone, Copy, Debug, Default, PartialEq, Eq, Hash,
)]
pub enum ElectronDensityModel {
#[default]
Chapman,
Elect1,
Linear,
QuasiParabolic,
VarChapman,
DualChapman,
}
#[non_exhaustive]
#[derive(
serde::Serialize, serde::Deserialize, Clone, Copy, Debug, Default, PartialEq, Eq, Hash,
)]
pub enum MagneticFieldModel {
#[default]
Dipole,
Constant,
Cubic,
Igrf14,
}
#[non_exhaustive]
#[derive(
serde::Serialize, serde::Deserialize, Clone, Copy, Debug, Default, PartialEq, Eq, Hash,
)]
pub enum CollisionModel {
#[default]
DoubleExponential,
Constant,
SingleExponential,
}
#[non_exhaustive]
#[derive(
serde::Serialize, serde::Deserialize, Clone, Copy, Debug, Default, PartialEq, Eq, Hash,
)]
pub enum RefractiveIndexModel {
#[default]
Full,
NoFieldNoCollisions,
NoFieldWithCollisions,
WithFieldNoCollisions,
}
#[non_exhaustive]
#[derive(
serde::Serialize, serde::Deserialize, Clone, Copy, Debug, Default, PartialEq, Eq, Hash,
)]
pub enum PerturbationModel {
#[default]
None,
Torus,
Trough,
Shock,
Bulge,
Exponential,
}
#[non_exhaustive]
#[derive(
serde::Serialize, serde::Deserialize, Clone, Copy, Debug, Default, PartialEq, Eq, Hash,
)]
pub enum RayMode {
#[default]
Extraordinary,
Ordinary,
}
impl RayMode {
pub fn to_sign(self) -> f64 {
match self {
RayMode::Extraordinary => -1.0,
RayMode::Ordinary => 1.0,
}
}
}
#[non_exhaustive]
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, derive_builder::Builder)]
#[builder(default, setter(into))]
pub struct ModelParams {
pub earth_r: f64,
pub ed_model: ElectronDensityModel,
pub mag_model: MagneticFieldModel,
pub col_model: CollisionModel,
pub rindex_model: RefractiveIndexModel,
pub pert_model: PerturbationModel,
pub fc: f64,
pub hm: f64,
pub sh: f64,
pub alpha: f64,
pub ed_a: f64,
pub ed_b: f64,
pub ed_c: f64,
pub ed_e: f64,
pub ym: f64,
pub fc2: f64,
pub hm2: f64,
pub sh2: f64,
pub chi: f64,
pub fh: f64,
pub dip: f64,
pub epoch_year: f64,
pub nu1: f64,
pub h1: f64,
pub a1: f64,
pub nu2: f64,
pub h2: f64,
pub a2: f64,
pub p1: f64,
pub p2: f64,
pub p3: f64,
pub p4: f64,
pub p5: f64,
pub p6: f64,
pub p7: f64,
pub p8: f64,
pub p9: f64,
}
impl ModelParams {
pub fn builder() -> ModelParamsBuilder {
ModelParamsBuilder::default()
}
pub fn validate(&self) -> Result<(), String> {
if self.earth_r <= 0.0 {
return Err(format!("earth_r must be positive, got {}", self.earth_r));
}
if self.fc < 0.0 {
return Err(format!("fc (foF2) must be non-negative, got {}", self.fc));
}
if self.hm < 0.0 {
return Err(format!("hm (hmF2) must be non-negative, got {}", self.hm));
}
if self.sh < 0.0 {
return Err(format!("sh (scale height) must be non-negative, got {}", self.sh));
}
if self.fh < 0.0 {
return Err(format!("fh (gyrofrequency) must be non-negative, got {}", self.fh));
}
Ok(())
}
}
impl Default for ModelParams {
fn default() -> Self {
Self {
earth_r: EARTH_RADIUS,
ed_model: ElectronDensityModel::default(),
mag_model: MagneticFieldModel::default(),
col_model: CollisionModel::default(),
rindex_model: RefractiveIndexModel::default(),
pert_model: PerturbationModel::default(),
fc: 10.0,
hm: 250.0,
sh: 100.0,
alpha: 0.5,
ed_a: 0.0,
ed_b: 0.0,
ed_c: 0.0,
ed_e: 0.0,
ym: 100.0,
fc2: 0.0,
hm2: 0.0,
sh2: 0.0,
chi: 3.0,
fh: 0.8,
dip: 0.0,
epoch_year: 2025.0,
nu1: 1_050_000.0,
h1: 100.0,
a1: 0.148,
nu2: 30.0,
h2: 140.0,
a2: 0.0183,
p1: 0.0,
p2: 0.0,
p3: 0.0,
p4: 0.0,
p5: 0.0,
p6: 0.0,
p7: 0.0,
p8: 0.0,
p9: 0.0,
}
}
}