use crate::PhysicsError;
use crate::kernels::dynamics::quantities::Length;
use crate::kernels::photonics::quantities::{RayAngle, Wavelength};
use deep_causality_num::{FromPrimitive, RealField};
pub fn single_slit_irradiance_kernel<R>(
i0: R,
slit_width: Length<R>,
theta: RayAngle<R>,
wavelength: Wavelength<R>,
) -> Result<R, PhysicsError>
where
R: RealField + FromPrimitive,
{
if i0 < R::zero() {
return Err(PhysicsError::PhysicalInvariantBroken(
"Irradiance i0 cannot be negative".into(),
));
}
let a = slit_width.value();
let lambda = wavelength.value();
let angle = theta.value();
if lambda == R::zero() {
return Err(PhysicsError::Singularity("Wavelength is zero".into()));
}
let beta = (R::pi() * a * angle.sin()) / lambda;
let eps = R::epsilon().sqrt();
if beta.abs() < eps {
return Ok(i0);
}
let sinc = beta.sin() / beta;
let i = i0 * sinc * sinc;
Ok(i)
}
pub fn grating_equation_kernel<R>(
pitch: Length<R>,
order: i32,
incidence: RayAngle<R>,
wavelength: Wavelength<R>,
) -> Result<RayAngle<R>, PhysicsError>
where
R: RealField + FromPrimitive,
{
let d = pitch.value();
let m = R::from_f64(order as f64)
.ok_or_else(|| PhysicsError::NumericalInstability("R::from_f64(order)".into()))?;
let lambda = wavelength.value();
let theta_i = incidence.value();
if d <= R::zero() {
return Err(PhysicsError::PhysicalInvariantBroken(
"Grating pitch must be positive".into(),
));
}
let sin_theta_m = (m * lambda / d) + theta_i.sin();
if sin_theta_m.abs() > R::one() {
return Err(PhysicsError::PhysicalInvariantBroken(
"Diffraction order does not exist for this configuration".into(),
));
}
let theta_m = sin_theta_m.asin();
RayAngle::<R>::new(theta_m)
}