use crate::kernels::photonics::quantities::{AbcdMatrix, OpticalPower, RayAngle, RayHeight};
use crate::{IndexOfRefraction, PhysicsError};
use deep_causality_num::RealField;
use deep_causality_tensor::{CausalTensor, Tensor};
pub fn ray_transfer_kernel<R>(
matrix: &AbcdMatrix<R>,
height: RayHeight<R>,
angle: RayAngle<R>,
) -> Result<(RayHeight<R>, RayAngle<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 y_in = height.value();
let theta_in = angle.value();
let input_vec = CausalTensor::new(vec![y_in, theta_in], vec![2, 1])?;
let output_vec = m.matmul(&input_vec)?;
let y_out = output_vec.data()[0];
let theta_out = output_vec.data()[1];
Ok((RayHeight::new(y_out)?, RayAngle::new(theta_out)?))
}
pub fn snells_law_kernel<R>(
n1: IndexOfRefraction<R>,
n2: IndexOfRefraction<R>,
theta1: RayAngle<R>,
) -> Result<RayAngle<R>, PhysicsError>
where
R: RealField,
{
let n1_val = n1.value();
let n2_val = n2.value();
let theta1_val = theta1.value();
let sin_theta2 = (n1_val / n2_val) * theta1_val.sin();
if sin_theta2.abs() > R::one() {
return Err(PhysicsError::PhysicalInvariantBroken(
"Total Internal Reflection: sin(theta2) > 1".into(),
));
}
let theta2 = sin_theta2.asin();
RayAngle::new(theta2)
}
pub fn lens_maker_kernel<R>(
n: IndexOfRefraction<R>,
r1: R,
r2: R,
) -> Result<OpticalPower<R>, PhysicsError>
where
R: RealField,
{
let n_val = n.value();
if r1 == R::zero() || r2 == R::zero() {
return Err(PhysicsError::Singularity(
"Radius of curvature cannot be zero".into(),
));
}
let power = (n_val - R::one()) * ((R::one() / r1) - (R::one() / r2));
OpticalPower::new(power)
}