use crate::PhysicsError;
use crate::kernels::dynamics::quantities::Length;
use crate::kernels::photonics::quantities::{AbcdMatrix, ComplexBeamParameter, Wavelength};
use deep_causality_num::{Complex, DivisionAlgebra, RealField};
pub fn gaussian_q_propagation_kernel<R>(
q_in: ComplexBeamParameter<R>,
matrix: &AbcdMatrix<R>,
) -> Result<ComplexBeamParameter<R>, PhysicsError>
where
R: RealField + Default,
{
let m = matrix.inner();
if m.shape() != [2, 2] {
return Err(PhysicsError::DimensionMismatch(
"ABCD matrix must be 2x2".into(),
));
}
let d = m.data();
let a = d[0];
let b = d[1];
let c = d[2];
let dd = d[3];
let q = q_in.value();
let num = q * a + Complex::new(b, R::zero());
let den = q * c + Complex::new(dd, R::zero());
if den.norm_sqr() == R::zero() {
return Err(PhysicsError::Singularity(
"Gaussian beam propagation singularity (denominator zero)".into(),
));
}
let q_out = num / den;
if q_out.im <= R::zero() {
return Err(PhysicsError::PhysicalInvariantBroken(
"Resulting Gaussian q-parameter has non-positive imaginary part".into(),
));
}
ComplexBeamParameter::new(q_out)
}
pub fn beam_spot_size_kernel<R>(
q: ComplexBeamParameter<R>,
wavelength: Wavelength<R>,
) -> Result<Length<R>, PhysicsError>
where
R: RealField,
{
let q_val = q.value();
let lambda = wavelength.value();
if q_val.norm_sqr() == R::zero() {
return Err(PhysicsError::Singularity("q parameter is zero".into()));
}
let inv_q = Complex::new(R::one(), R::zero()) / q_val;
let im_inv_q = inv_q.im;
if im_inv_q >= R::zero() {
return Err(PhysicsError::PhysicalInvariantBroken(
"Invalid q parameter for spot size extraction: Im(1/q) >= 0".into(),
));
}
let pi = R::pi();
let w_sq = -lambda / (pi * im_inv_q);
let w = w_sq.sqrt();
Length::new(w)
}