use crate::PhysicsError;
use crate::kernels::fluids::quantities::{
AccelerationVector, Density, KinematicViscosity, Pressure, Velocity3, VelocityGradient,
ViscousStress, VorticityVector,
};
use deep_causality_num::{FromPrimitive, RealField};
pub fn convective_acceleration_kernel<R>(
u: &Velocity3<R>,
grad_u: &VelocityGradient<R>,
) -> AccelerationVector<R>
where
R: RealField,
{
let u_raw = u.value();
let g = grad_u.value();
AccelerationVector::new_unchecked([
u_raw[0] * g[0][0] + u_raw[1] * g[0][1] + u_raw[2] * g[0][2],
u_raw[0] * g[1][0] + u_raw[1] * g[1][1] + u_raw[2] * g[1][2],
u_raw[0] * g[2][0] + u_raw[1] * g[2][1] + u_raw[2] * g[2][2],
])
}
pub fn viscous_diffusion_kernel<R>(
nu: &KinematicViscosity<R>,
laplacian_u: &[R; 3],
) -> AccelerationVector<R>
where
R: RealField,
{
let v = nu.value();
AccelerationVector::new_unchecked([v * laplacian_u[0], v * laplacian_u[1], v * laplacian_u[2]])
}
pub fn pressure_gradient_force_kernel<R>(
rho: &Density<R>,
grad_p: &[R; 3],
) -> Result<AccelerationVector<R>, PhysicsError>
where
R: RealField,
{
let r = rho.value();
if r == R::zero() {
return Err(PhysicsError::PhysicalInvariantBroken(
"pressure_gradient_force_kernel: density is zero".into(),
));
}
let inv_rho = R::one() / r;
Ok(AccelerationVector::new_unchecked([
-inv_rho * grad_p[0],
-inv_rho * grad_p[1],
-inv_rho * grad_p[2],
]))
}
pub fn continuity_rhs_kernel<R>(
rho: &Density<R>,
u: &Velocity3<R>,
grad_rho: &[R; 3],
div_u: R,
) -> R
where
R: RealField,
{
let r = rho.value();
let u_raw = u.value();
let u_dot_grad_rho = u_raw[0] * grad_rho[0] + u_raw[1] * grad_rho[1] + u_raw[2] * grad_rho[2];
-(u_dot_grad_rho + r * div_u)
}
pub fn vorticity_transport_kernel<R>(
omega: &VorticityVector<R>,
u: &Velocity3<R>,
grad_u: &VelocityGradient<R>,
grad_omega: &[[R; 3]; 3],
laplacian_omega: &[R; 3],
nu: &KinematicViscosity<R>,
) -> AccelerationVector<R>
where
R: RealField,
{
let w = omega.value();
let u_raw = u.value();
let gu = grad_u.value();
let v = nu.value();
let adv = [
u_raw[0] * grad_omega[0][0] + u_raw[1] * grad_omega[0][1] + u_raw[2] * grad_omega[0][2],
u_raw[0] * grad_omega[1][0] + u_raw[1] * grad_omega[1][1] + u_raw[2] * grad_omega[1][2],
u_raw[0] * grad_omega[2][0] + u_raw[1] * grad_omega[2][1] + u_raw[2] * grad_omega[2][2],
];
let stretch = [
w[0] * gu[0][0] + w[1] * gu[0][1] + w[2] * gu[0][2],
w[0] * gu[1][0] + w[1] * gu[1][1] + w[2] * gu[1][2],
w[0] * gu[2][0] + w[1] * gu[2][1] + w[2] * gu[2][2],
];
AccelerationVector::new_unchecked([
-adv[0] + stretch[0] + v * laplacian_omega[0],
-adv[1] + stretch[1] + v * laplacian_omega[1],
-adv[2] + stretch[2] + v * laplacian_omega[2],
])
}
pub fn scalar_advection_diffusion_kernel<R>(
u: &Velocity3<R>,
grad_phi: &[R; 3],
laplacian_phi: R,
diffusivity: R,
source: R,
) -> R
where
R: RealField,
{
let u_raw = u.value();
let advection = u_raw[0] * grad_phi[0] + u_raw[1] * grad_phi[1] + u_raw[2] * grad_phi[2];
-advection + diffusivity * laplacian_phi + source
}
pub fn kinetic_energy_density_kernel<R>(
rho: &Density<R>,
u: &Velocity3<R>,
) -> Result<R, PhysicsError>
where
R: RealField + FromPrimitive,
{
let half = R::from_f64(0.5)
.ok_or_else(|| PhysicsError::NumericalInstability("R::from_f64(0.5) failed".into()))?;
let u_raw = u.value();
let speed_sq = u_raw[0] * u_raw[0] + u_raw[1] * u_raw[1] + u_raw[2] * u_raw[2];
Ok(rho.value() * half * speed_sq)
}
pub fn viscous_dissipation_rate_kernel<R>(tau: &ViscousStress<R>, grad_u: &VelocityGradient<R>) -> R
where
R: RealField,
{
let t = tau.value();
let g = grad_u.value();
t[0][0] * g[0][0]
+ t[0][1] * g[0][1]
+ t[0][2] * g[0][2]
+ t[1][0] * g[1][0]
+ t[1][1] * g[1][1]
+ t[1][2] * g[1][2]
+ t[2][0] * g[2][0]
+ t[2][1] * g[2][1]
+ t[2][2] * g[2][2]
}
pub fn pressure_work_kernel<R>(p: &Pressure<R>, div_u: R) -> R
where
R: RealField,
{
p.value() * div_u
}