mod integration;
mod van_rhijn;
mod vertical_profile;
mod vertical_profile_io;
pub use van_rhijn::VanRhijnConfig;
pub use vertical_profile::{
AirglowWavelengthApplicability, ValidatedZenithDomain, VerticalEmissionProfile,
VerticalEmissionProfileDefinition, VerticalEmissionProfileError, VerticalProfileNormalization,
VERTICAL_EMISSION_PROFILE_SCHEMA_VERSION,
};
use crate::error::Result;
use crate::units::ScaleFactors;
use integration::VERTICAL_PROFILE_INTEGRATOR_VERSION;
use siderust::coordinates::centers::Geodetic;
use siderust::coordinates::frames::{EquatorialMeanJ2000, ECEF};
use siderust::coordinates::spherical::Direction as SphericalDirection;
use siderust::event::horizontal::star_horizontal;
use siderust::qtty::{Degrees, Kilometers, Nanometers};
use tempoch::{Time, JD, TT, UTC};
use van_rhijn::VAN_RHIJN_IMPLEMENTATION_VERSION;
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum AirglowGeometryModel {
VanRhijn(VanRhijnConfig),
VerticalProfile(VerticalEmissionProfile),
}
impl AirglowGeometryModel {
pub(crate) fn geometry_factor(
&self,
observer: Geodetic<ECEF>,
zenith: Degrees,
) -> Result<ScaleFactors> {
match self {
Self::VanRhijn(config) => config.geometry_factor(zenith),
Self::VerticalProfile(profile) => profile.geometry_factor(observer, zenith),
}
}
pub const fn model_id(&self) -> &'static str {
match self {
Self::VanRhijn(_) => "van_rhijn",
Self::VerticalProfile(_) => "vertical_profile",
}
}
pub(crate) fn metadata(&self) -> AirglowGeometryMetadata {
match self {
Self::VanRhijn(config) => AirglowGeometryMetadata {
model: self.model_id(),
implementation_version: VAN_RHIJN_IMPLEMENTATION_VERSION,
emission_height_km: Some(config.emission_height_km()),
profile_id: None,
profile_schema_version: None,
checksum_sha256: None,
normalization: None,
altitude_min_km: None,
altitude_max_km: None,
wavelength_min_nm: None,
wavelength_max_nm: None,
wavelength_band: None,
assumptions: "geometrically thin, horizontally uniform emitting shell; historical NSB baseline".into(),
provenance: "Van Rhijn (1921) analytic shell factor implemented by Siderust 0.11.0".into(),
license: None,
validated_zenith: config.validated_zenith_domain(),
},
Self::VerticalProfile(profile) => {
let wavelength = profile.wavelength_applicability();
AirglowGeometryMetadata {
model: self.model_id(),
implementation_version: VERTICAL_PROFILE_INTEGRATOR_VERSION,
emission_height_km: None,
profile_id: Some(profile.profile_id().to_string()),
profile_schema_version: Some(profile.schema_version()),
checksum_sha256: Some(profile.checksum_sha256().to_string()),
normalization: Some(profile.normalization().as_str()),
altitude_min_km: profile.altitude_km().first().copied(),
altitude_max_km: profile.altitude_km().last().copied(),
wavelength_min_nm: Some(wavelength.min),
wavelength_max_nm: Some(wavelength.max),
wavelength_band: Some(wavelength.band.clone()),
assumptions: profile.assumptions().to_string(),
provenance: profile.provenance().to_string(),
license: Some(profile.license().to_string()),
validated_zenith: profile.validated_zenith_domain(),
}
}
}
}
}
impl Default for AirglowGeometryModel {
fn default() -> Self {
Self::VanRhijn(VanRhijnConfig::default())
}
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct AirglowGeometryMetadata {
pub model: &'static str,
pub implementation_version: &'static str,
pub emission_height_km: Option<Kilometers>,
pub profile_id: Option<String>,
pub profile_schema_version: Option<u32>,
pub checksum_sha256: Option<String>,
pub normalization: Option<&'static str>,
pub altitude_min_km: Option<Kilometers>,
pub altitude_max_km: Option<Kilometers>,
pub wavelength_min_nm: Option<Nanometers>,
pub wavelength_max_nm: Option<Nanometers>,
pub wavelength_band: Option<String>,
pub assumptions: String,
pub provenance: String,
pub license: Option<String>,
pub validated_zenith: ValidatedZenithDomain,
}
pub(crate) fn target_altitude(
time: Time<UTC>,
location: Geodetic<ECEF>,
target: SphericalDirection<EquatorialMeanJ2000>,
) -> Degrees {
let jd = time.to::<TT>().to::<JD>();
star_horizontal(target.ra(), target.dec(), &location, jd).alt()
}