use crate::site::{atmosphere::rayleigh_optical_depth_local_pressure, AtmosphericConditions};
use crate::units::angular::{Degrees, Radian};
use crate::units::dimensionless::{OpticalDepths, Transmittance, Transmittances};
use crate::units::radiometry::WattsPerSquareMeterSteradianNanometer;
use crate::units::{
MagnitudesPerAirmass, Quantity, ScaleFactors, WattPerSquareMeterSteradianMicrometer,
};
use siderust::atmosphere::{airmass, Young1994};
use siderust::qtty::Nanometers;
#[cfg_attr(
feature = "python",
pyo3::pyclass(
eq,
frozen,
rename_all = "SCREAMING_SNAKE_CASE",
module = "nsb",
from_py_object
)
)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum ZodiacalExtinction {
None,
#[default]
Noll2012Approx,
}
impl ZodiacalExtinction {
pub const fn as_str(self) -> &'static str {
match self {
Self::None => "none",
Self::Noll2012Approx => "noll-2012-approximation",
}
}
pub(crate) fn transmission_for_spectral_radiance(
&self,
reference_500: WattsPerSquareMeterSteradianNanometer,
wavelength: Nanometers,
zenith: Degrees,
) -> Transmittances {
match self {
Self::None => Transmittances::new(1.0),
Self::Noll2012Approx => noll2012_transmission(reference_500, wavelength, zenith),
}
}
}
fn noll2012_transmission(
reference_500: WattsPerSquareMeterSteradianNanometer,
wavelength: Nanometers,
zenith: Degrees,
) -> Transmittances {
if reference_500.value() == 0.0 {
return Transmittances::new(1.0);
}
const NOLL_BRIGHTNESS_UNIT: Quantity<WattPerSquareMeterSteradianMicrometer> =
Quantity::new(1.0e-8);
let normalized_brightness =
reference_500.to::<WattPerSquareMeterSteradianMicrometer>() / NOLL_BRIGHTNESS_UNIT;
let dex = normalized_brightness.log10();
let fext_m = if dex <= 2.255 {
1.309 * dex - 2.598
} else {
0.468 * dex - 0.702
};
let fext_r = if dex <= 2.244 {
1.407 * dex - 2.692
} else {
0.527 * dex - 0.715
};
let wavelength_ratio = ScaleFactors::new(wavelength / Nanometers::new(1000.0));
let kaer = if wavelength < Nanometers::new(400.0) {
MagnitudesPerAirmass::new(0.05)
} else {
MagnitudesPerAirmass::new(0.013 * wavelength_ratio.powf(ScaleFactors::new(-1.38)).value())
};
let tau_m = OpticalDepths::new(0.4 * std::f64::consts::LN_10 * kaer.value());
let tau_r =
rayleigh_optical_depth_local_pressure(wavelength, AtmosphericConditions::paranal_average());
let am = airmass::<Young1994>(zenith.to::<Radian>());
let tau_eff = (tau_r * fext_r + tau_m * fext_m) * am.value();
(-tau_eff).exp().to::<Transmittance>()
}