use laddu_physics::{
math::{WignerDMatrix, clebsch_gordan as physics_clebsch_gordan},
vectors::{Vec3, Vec4},
};
use pyo3::{prelude::*, types::PyAny};
use super::{
error::to_py_err,
expr::{PyExpr, extract_expr},
quantum::{extract_projection, extract_spin},
};
#[pyclass(name = "Vec3", module = "laddu", frozen, skip_from_py_object)]
#[derive(Clone)]
pub struct PyVec3 {
pub(crate) inner: Vec3,
}
#[pymethods]
impl PyVec3 {
#[new]
#[pyo3(signature = (
x: "Expr | int | float",
y: "Expr | int | float",
z: "Expr | int | float"
))]
fn new(x: &Bound<'_, PyAny>, y: &Bound<'_, PyAny>, z: &Bound<'_, PyAny>) -> PyResult<Self> {
Ok(Self {
inner: Vec3::new(extract_expr(x)?, extract_expr(y)?, extract_expr(z)?),
})
}
#[staticmethod]
fn zero() -> Self {
Self {
inner: Vec3::zero(),
}
}
#[staticmethod]
fn event(prefix: &str) -> Self {
Self {
inner: Vec3::event(prefix),
}
}
#[staticmethod]
fn x_axis() -> Self {
Self { inner: Vec3::x() }
}
#[staticmethod]
fn x() -> Self {
Self::x_axis()
}
#[staticmethod]
fn y_axis() -> Self {
Self { inner: Vec3::y() }
}
#[staticmethod]
fn y() -> Self {
Self::y_axis()
}
#[staticmethod]
fn z_axis() -> Self {
Self { inner: Vec3::z() }
}
#[staticmethod]
fn z() -> Self {
Self::z_axis()
}
fn cross(&self, other: &Self) -> Self {
Self {
inner: self.inner.cross(&other.inner),
}
}
fn dot(&self, other: &Self) -> PyExpr {
self.inner.dot(&other.inner).into()
}
fn __matmul__(&self, other: &Self) -> PyExpr {
self.dot(other)
}
fn px(&self) -> PyExpr {
self.inner.px().into()
}
fn py(&self) -> PyExpr {
self.inner.py().into()
}
fn pz(&self) -> PyExpr {
self.inner.pz().into()
}
fn mag2(&self) -> PyExpr {
self.inner.mag2().into()
}
fn mag(&self) -> PyExpr {
self.inner.mag().into()
}
fn costheta(&self) -> PyExpr {
self.inner.costheta().into()
}
fn phi(&self) -> PyExpr {
self.inner.phi().into()
}
fn unit(&self) -> Self {
Self {
inner: self.inner.unit(),
}
}
#[pyo3(signature = (mass: "Expr | int | float"))]
fn with_mass(&self, mass: &Bound<'_, PyAny>) -> PyResult<PyVec4> {
Ok(PyVec4 {
inner: self.inner.with_mass(extract_expr(mass)?),
})
}
#[pyo3(signature = (energy: "Expr | int | float"))]
fn with_energy(&self, energy: &Bound<'_, PyAny>) -> PyResult<PyVec4> {
Ok(PyVec4 {
inner: self.inner.with_energy(extract_expr(energy)?),
})
}
fn as_expr(&self) -> PyExpr {
self.inner.as_expr().into()
}
fn __add__(&self, other: &Self) -> Self {
Self {
inner: &self.inner + &other.inner,
}
}
fn __sub__(&self, other: &Self) -> Self {
Self {
inner: &self.inner - &other.inner,
}
}
fn __neg__(&self) -> Self {
Self {
inner: -&self.inner,
}
}
fn __mul__(&self, scalar: &Bound<'_, PyAny>) -> PyResult<Self> {
let scalar = extract_expr(scalar)?;
Ok(Self {
inner: &self.inner * &scalar,
})
}
fn __rmul__(&self, scalar: &Bound<'_, PyAny>) -> PyResult<Self> {
self.__mul__(scalar)
}
fn __truediv__(&self, scalar: &Bound<'_, PyAny>) -> PyResult<Self> {
let scalar = extract_expr(scalar)?;
Ok(Self {
inner: &self.inner / &scalar,
})
}
}
#[pyclass(name = "Vec4", module = "laddu", frozen, skip_from_py_object)]
#[derive(Clone)]
pub struct PyVec4 {
pub(crate) inner: Vec4,
}
#[pymethods]
impl PyVec4 {
#[new]
#[pyo3(signature = (
e: "Expr | int | float",
px: "Expr | int | float",
py: "Expr | int | float",
pz: "Expr | int | float"
))]
fn new(
e: &Bound<'_, PyAny>,
px: &Bound<'_, PyAny>,
py: &Bound<'_, PyAny>,
pz: &Bound<'_, PyAny>,
) -> PyResult<Self> {
Ok(Self {
inner: Vec4::new(
extract_expr(e)?,
extract_expr(px)?,
extract_expr(py)?,
extract_expr(pz)?,
),
})
}
#[staticmethod]
fn event(prefix: &str) -> Self {
Self {
inner: Vec4::event(prefix),
}
}
fn px(&self) -> PyExpr {
self.inner.px().into()
}
fn py(&self) -> PyExpr {
self.inner.py().into()
}
fn pz(&self) -> PyExpr {
self.inner.pz().into()
}
fn e(&self) -> PyExpr {
self.inner.e().into()
}
fn momentum(&self) -> PyVec3 {
PyVec3 {
inner: self.inner.momentum(),
}
}
fn vec3(&self) -> PyVec3 {
PyVec3 {
inner: self.inner.vec3(),
}
}
fn beta(&self) -> PyVec3 {
PyVec3 {
inner: self.inner.beta(),
}
}
fn gamma(&self) -> PyExpr {
self.inner.gamma().into()
}
fn m2(&self) -> PyExpr {
self.inner.m2().into()
}
fn mass(&self) -> PyExpr {
self.inner.m().into()
}
fn m(&self) -> PyExpr {
self.mass()
}
fn mag2(&self) -> PyExpr {
self.inner.mag2().into()
}
fn mag(&self) -> PyExpr {
self.inner.mag().into()
}
fn dot(&self, other: &Self) -> PyExpr {
self.inner.dot(&other.inner).into()
}
fn __matmul__(&self, other: &Self) -> PyExpr {
self.dot(other)
}
fn boost(&self, beta: &PyVec3) -> Self {
Self {
inner: self.inner.boost(&beta.inner),
}
}
fn as_expr(&self) -> PyExpr {
self.inner.as_expr().into()
}
fn __add__(&self, other: &Self) -> Self {
Self {
inner: &self.inner + &other.inner,
}
}
fn __sub__(&self, other: &Self) -> Self {
Self {
inner: &self.inner - &other.inner,
}
}
fn __neg__(&self) -> Self {
Self {
inner: -&self.inner,
}
}
}
#[pyfunction]
#[pyo3(signature = (
j1: "J | S | L | int | float",
m1: "M | int | float",
j2: "J | S | L | int | float",
m2: "M | int | float",
j: "J | S | L | int | float",
m: "M | int | float"
))]
pub fn clebsch_gordan(
j1: &Bound<'_, PyAny>,
m1: &Bound<'_, PyAny>,
j2: &Bound<'_, PyAny>,
m2: &Bound<'_, PyAny>,
j: &Bound<'_, PyAny>,
m: &Bound<'_, PyAny>,
) -> PyResult<f64> {
Ok(physics_clebsch_gordan(
extract_spin(j1)?,
extract_projection(m1)?,
extract_spin(j2)?,
extract_projection(m2)?,
extract_spin(j)?,
extract_projection(m)?,
))
}
#[pyclass(name = "WignerD", module = "laddu", frozen, skip_from_py_object)]
pub struct PyWignerD {
inner: WignerDMatrix,
}
#[pymethods]
impl PyWignerD {
#[new]
#[pyo3(signature = (
j: "J | S | L | int | float",
m_prime: "M | int | float",
m: "M | int | float"
))]
fn new(
j: &Bound<'_, PyAny>,
m_prime: &Bound<'_, PyAny>,
m: &Bound<'_, PyAny>,
) -> PyResult<Self> {
Ok(Self {
inner: WignerDMatrix::new(
extract_spin(j)?,
extract_projection(m_prime)?,
extract_projection(m)?,
)
.map_err(to_py_err)?,
})
}
#[pyo3(signature = (beta: "Expr | int | float"))]
fn d(&self, beta: &Bound<'_, PyAny>) -> PyResult<PyExpr> {
Ok(self.inner.d(extract_expr(beta)?).into())
}
#[allow(non_snake_case)]
#[pyo3(signature = (
alpha: "Expr | int | float",
beta: "Expr | int | float",
gamma: "Expr | int | float | None" = None
))]
fn D(
&self,
alpha: &Bound<'_, PyAny>,
beta: &Bound<'_, PyAny>,
gamma: Option<&Bound<'_, PyAny>>,
) -> PyResult<PyExpr> {
Ok(self
.inner
.D(
extract_expr(alpha)?,
extract_expr(beta)?,
gamma
.map(extract_expr)
.transpose()?
.unwrap_or_else(|| 0.0.into()),
)
.into())
}
}