use crate::error::PhysicsError;
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct AmountOfSubstance<R: deep_causality_num::RealField>(R);
impl<R: deep_causality_num::RealField> Default for AmountOfSubstance<R> {
fn default() -> Self {
Self(R::zero())
}
}
impl<R: deep_causality_num::RealField> AmountOfSubstance<R> {
pub fn new(val: R) -> Result<Self, PhysicsError> {
if val < R::zero() {
return Err(PhysicsError::PhysicalInvariantBroken(
"Negative AmountOfSubstance".into(),
));
}
Ok(Self(val))
}
pub fn new_unchecked(val: R) -> Self {
Self(val)
}
pub fn value(&self) -> R {
self.0
}
}
impl<R: deep_causality_num::RealField + Into<f64>> From<AmountOfSubstance<R>> for f64 {
fn from(val: AmountOfSubstance<R>) -> Self {
val.0.into()
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct HalfLife<R: deep_causality_num::RealField>(R);
impl<R: deep_causality_num::RealField> Default for HalfLife<R> {
fn default() -> Self {
Self(R::epsilon())
}
}
impl<R: deep_causality_num::RealField> HalfLife<R> {
pub fn new(val: R) -> Result<Self, PhysicsError> {
if !val.is_finite() {
return Err(PhysicsError::PhysicalInvariantBroken(
"HalfLife must be finite".into(),
));
}
if val <= R::zero() {
return Err(PhysicsError::PhysicalInvariantBroken(
"HalfLife must be positive (zero implies infinite decay rate)".into(),
));
}
Ok(Self(val))
}
pub fn new_unchecked(val: R) -> Self {
Self(val)
}
pub fn value(&self) -> R {
self.0
}
}
impl<R: deep_causality_num::RealField + Into<f64>> From<HalfLife<R>> for f64 {
fn from(val: HalfLife<R>) -> Self {
val.0.into()
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Activity<R: deep_causality_num::RealField>(R);
impl<R: deep_causality_num::RealField> Default for Activity<R> {
fn default() -> Self {
Self(R::zero())
}
}
impl<R: deep_causality_num::RealField> Activity<R> {
pub fn new(val: R) -> Result<Self, PhysicsError> {
if val < R::zero() {
return Err(PhysicsError::PhysicalInvariantBroken(
"Negative Activity".into(),
));
}
Ok(Self(val))
}
pub fn new_unchecked(val: R) -> Self {
Self(val)
}
pub fn value(&self) -> R {
self.0
}
}
impl<R: deep_causality_num::RealField + Into<f64>> From<Activity<R>> for f64 {
fn from(val: Activity<R>) -> Self {
val.0.into()
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct EnergyDensity<R: deep_causality_num::RealField>(R);
impl<R: deep_causality_num::RealField> Default for EnergyDensity<R> {
fn default() -> Self {
Self(R::zero())
}
}
impl<R: deep_causality_num::RealField> EnergyDensity<R> {
pub fn new(val: R) -> Result<Self, PhysicsError> {
if val < R::zero() {
return Err(PhysicsError::PhysicalInvariantBroken(
"Negative EnergyDensity".into(),
));
}
Ok(Self(val))
}
pub fn new_unchecked(val: R) -> Self {
Self(val)
}
pub fn value(&self) -> R {
self.0
}
}
impl<R: deep_causality_num::RealField + Into<f64>> From<EnergyDensity<R>> for f64 {
fn from(val: EnergyDensity<R>) -> Self {
val.0.into()
}
}
use core::ops::{Add, Sub};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct FourMomentum<R: deep_causality_num::RealField> {
e: R,
px: R,
py: R,
pz: R,
}
impl<R: deep_causality_num::RealField> Default for FourMomentum<R> {
fn default() -> Self {
Self {
e: R::zero(),
px: R::zero(),
py: R::zero(),
pz: R::zero(),
}
}
}
impl<R: deep_causality_num::RealField> FourMomentum<R> {
pub const fn new(e: R, px: R, py: R, pz: R) -> Self {
Self { e, px, py, pz }
}
pub fn from_mass_and_momentum(mass: R, px: R, py: R, pz: R) -> Self {
let p_sq = px * px + py * py + pz * pz;
let e = (mass * mass + p_sq).sqrt();
Self { e, px, py, pz }
}
pub fn at_rest(mass: R) -> Self {
Self {
e: mass,
px: R::zero(),
py: R::zero(),
pz: R::zero(),
}
}
pub fn e(&self) -> R {
self.e
}
pub fn px(&self) -> R {
self.px
}
pub fn py(&self) -> R {
self.py
}
pub fn pz(&self) -> R {
self.pz
}
pub fn invariant_mass_squared(&self) -> R {
self.e * self.e - self.px * self.px - self.py * self.py - self.pz * self.pz
}
pub fn invariant_mass(&self) -> R {
let m_sq = self.invariant_mass_squared();
if m_sq > R::zero() {
m_sq.sqrt()
} else {
R::zero()
}
}
pub fn momentum_magnitude(&self) -> R {
(self.px * self.px + self.py * self.py + self.pz * self.pz).sqrt()
}
pub fn transverse_momentum(&self) -> R {
(self.px * self.px + self.py * self.py).sqrt()
}
pub fn transverse_mass(&self) -> R {
let m_sq = self.invariant_mass_squared();
let pt_sq = self.px * self.px + self.py * self.py;
(m_sq + pt_sq).sqrt()
}
pub fn lightcone_plus(&self) -> R {
self.e + self.pz
}
pub fn lightcone_minus(&self) -> R {
self.e - self.pz
}
pub fn phi(&self) -> R {
self.py.atan2(self.px)
}
}
impl<R: deep_causality_num::RealField + deep_causality_num::FromPrimitive> FourMomentum<R> {
pub fn rapidity(&self) -> R {
let denom = self.e - self.pz;
let eps = R::from_f64(1e-10).expect("R::from_f64(1e-10) failed");
if denom.abs() < eps {
return R::zero();
}
let half = R::from_f64(0.5).expect("R::from_f64(0.5) failed");
half * ((self.e + self.pz) / denom).ln()
}
pub fn pseudorapidity(&self) -> R {
let p = self.momentum_magnitude();
let eps = R::from_f64(1e-10).expect("R::from_f64(1e-10) failed");
if p.abs() < eps {
return R::zero();
}
let half = R::from_f64(0.5).expect("R::from_f64(0.5) failed");
half * ((p + self.pz) / (p - self.pz)).ln()
}
pub fn boost_z(&self, beta: R) -> Self {
let one = R::one();
let gamma = one / (one - beta * beta).sqrt();
let e_new = gamma * (self.e - beta * self.pz);
let pz_new = gamma * (self.pz - beta * self.e);
Self {
e: e_new,
px: self.px,
py: self.py,
pz: pz_new,
}
}
}
impl<R: deep_causality_num::RealField> Add for FourMomentum<R> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self {
e: self.e + rhs.e,
px: self.px + rhs.px,
py: self.py + rhs.py,
pz: self.pz + rhs.pz,
}
}
}
impl<R: deep_causality_num::RealField> Sub for FourMomentum<R> {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self {
e: self.e - rhs.e,
px: self.px - rhs.px,
py: self.py - rhs.py,
pz: self.pz - rhs.pz,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Hadron<R: deep_causality_num::RealField> {
pdg_id: i32,
momentum: FourMomentum<R>,
}
impl<R: deep_causality_num::RealField> Hadron<R> {
pub const fn new(pdg_id: i32, momentum: FourMomentum<R>) -> Self {
Self { pdg_id, momentum }
}
pub const fn pdg_id(&self) -> i32 {
self.pdg_id
}
pub fn momentum(&self) -> FourMomentum<R> {
self.momentum
}
pub fn mass(&self) -> R {
self.momentum.invariant_mass()
}
pub fn energy(&self) -> R {
self.momentum.e()
}
pub fn pt(&self) -> R {
self.momentum.transverse_momentum()
}
}
impl<R: deep_causality_num::RealField + deep_causality_num::FromPrimitive> Hadron<R> {
pub fn rapidity(&self) -> R {
self.momentum.rapidity()
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct LundParameters {
kappa: f64,
lund_a: f64,
lund_b: f64,
sigma_pt: f64,
strange_suppression: f64,
diquark_suppression: f64,
vector_meson_fraction: f64,
min_invariant_mass: f64,
}
impl Default for LundParameters {
fn default() -> Self {
Self {
kappa: 1.0, lund_a: 0.68, lund_b: 0.98, sigma_pt: 0.36, strange_suppression: 0.30, diquark_suppression: 0.10, vector_meson_fraction: 0.50, min_invariant_mass: 0.5, }
}
}
impl LundParameters {
#[allow(clippy::too_many_arguments)]
pub const fn new(
kappa: f64,
lund_a: f64,
lund_b: f64,
sigma_pt: f64,
strange_suppression: f64,
diquark_suppression: f64,
vector_meson_fraction: f64,
min_invariant_mass: f64,
) -> Self {
Self {
kappa,
lund_a,
lund_b,
sigma_pt,
strange_suppression,
diquark_suppression,
vector_meson_fraction,
min_invariant_mass,
}
}
pub const fn kappa(&self) -> f64 {
self.kappa
}
pub const fn lund_a(&self) -> f64 {
self.lund_a
}
pub const fn lund_b(&self) -> f64 {
self.lund_b
}
pub const fn sigma_pt(&self) -> f64 {
self.sigma_pt
}
pub const fn strange_suppression(&self) -> f64 {
self.strange_suppression
}
pub const fn diquark_suppression(&self) -> f64 {
self.diquark_suppression
}
pub const fn vector_meson_fraction(&self) -> f64 {
self.vector_meson_fraction
}
pub const fn min_invariant_mass(&self) -> f64 {
self.min_invariant_mass
}
}