use crate::{Frequency, Mass, MomentOfInertia, PhysicsError};
use deep_causality_multivector::{CausalMultiVector, MultiVector};
use deep_causality_num::RealField;
#[derive(Debug, Clone, PartialEq)]
pub struct PhysicalVector<R: RealField>(pub CausalMultiVector<R>);
impl<R: RealField> Default for PhysicalVector<R> {
fn default() -> Self {
Self(
CausalMultiVector::new(
vec![R::zero()],
deep_causality_multivector::Metric::Euclidean(0),
)
.unwrap(),
)
}
}
impl<R: RealField> PhysicalVector<R> {
pub fn new(val: CausalMultiVector<R>) -> Self {
Self(val)
}
pub fn inner(&self) -> &CausalMultiVector<R> {
&self.0
}
pub fn into_inner(self) -> CausalMultiVector<R> {
self.0
}
}
pub fn kinetic_energy_kernel<R>(
mass: Mass<R>,
velocity: &CausalMultiVector<R>,
) -> Result<R, PhysicsError>
where
R: deep_causality_num::RealField + deep_causality_num::FromPrimitive,
{
let v_sq = velocity.squared_magnitude();
if !v_sq.is_finite() {
return Err(PhysicsError::NumericalInstability(
"Velocity squared magnitude is not finite".into(),
));
}
let neg_eps = R::from_f64(-1e-12)
.ok_or_else(|| PhysicsError::NumericalInstability("R::from_f64(-1e-12)".into()))?;
if v_sq < neg_eps {
return Err(PhysicsError::PhysicalInvariantBroken(
"Negative squared speed in kinetic energy calculation".into(),
));
}
let v_sq_clamped = if v_sq < R::zero() { R::zero() } else { v_sq };
let half = R::from_f64(0.5)
.ok_or_else(|| PhysicsError::NumericalInstability("R::from_f64(0.5)".into()))?;
let e = half * mass.value() * v_sq_clamped;
Ok(e)
}
pub fn rotational_kinetic_energy_kernel<R>(
inertia: MomentOfInertia<R>,
omega: Frequency<R>,
) -> Result<R, PhysicsError>
where
R: deep_causality_num::RealField + deep_causality_num::FromPrimitive,
{
let w = omega.value();
let half = R::from_f64(0.5)
.ok_or_else(|| PhysicsError::NumericalInstability("R::from_f64(0.5)".into()))?;
let e = half * inertia.value() * w * w;
Ok(e)
}
pub fn torque_kernel<R>(
radius: &CausalMultiVector<R>,
force: &CausalMultiVector<R>,
) -> Result<PhysicalVector<R>, PhysicsError>
where
R: RealField,
{
if radius.metric() != force.metric() {
return Err(PhysicsError::DimensionMismatch(format!(
"Metric mismatch: {:?} != {:?}",
radius.metric(),
force.metric()
)));
}
let t = radius.outer_product(force);
Ok(PhysicalVector(t))
}
pub fn angular_momentum_kernel<R>(
radius: &CausalMultiVector<R>,
momentum: &CausalMultiVector<R>,
) -> Result<PhysicalVector<R>, PhysicsError>
where
R: RealField,
{
if radius.metric() != momentum.metric() {
return Err(PhysicsError::DimensionMismatch(format!(
"Metric mismatch: {:?} != {:?}",
radius.metric(),
momentum.metric()
)));
}
let l = radius.outer_product(momentum);
Ok(PhysicalVector(l))
}