pub mod coupling;
pub mod feynman;
pub mod propagator;
pub mod vacuum;
use serde::{Deserialize, Serialize};
use tracing::warn;
use crate::error::{MimamsaError, ensure_finite, require_all_finite};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum FieldType {
Scalar,
Fermion,
GaugeBoson,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum GaugeChoice {
Feynman,
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct FourMomentum {
pub e: f64,
pub px: f64,
pub py: f64,
pub pz: f64,
}
const MAX_MOMENTUM_COMPONENT: f64 = 1.34e154;
impl FourMomentum {
pub fn new(e: f64, px: f64, py: f64, pz: f64) -> Result<Self, MimamsaError> {
require_all_finite(&[e, px, py, pz], "FourMomentum::new")?;
for &c in &[e, px, py, pz] {
if c.abs() > MAX_MOMENTUM_COMPONENT {
warn!(e, px, py, pz, "FourMomentum component magnitude too large");
return Err(MimamsaError::Computation(
"FourMomentum component magnitude too large".to_string(),
));
}
}
Ok(Self { e, px, py, pz })
}
#[inline]
pub fn invariant_mass_sq(&self) -> Result<f64, MimamsaError> {
ensure_finite(
self.e * self.e - self.px * self.px - self.py * self.py - self.pz * self.pz,
"FourMomentum::invariant_mass_sq",
)
}
#[inline]
pub fn spatial_magnitude(&self) -> Result<f64, MimamsaError> {
ensure_finite(
(self.px * self.px + self.py * self.py + self.pz * self.pz).sqrt(),
"FourMomentum::spatial_magnitude",
)
}
#[inline]
pub fn add(&self, other: &Self) -> Result<Self, MimamsaError> {
Self::new(
self.e + other.e,
self.px + other.px,
self.py + other.py,
self.pz + other.pz,
)
}
#[inline]
pub fn sub(&self, other: &Self) -> Result<Self, MimamsaError> {
Self::new(
self.e - other.e,
self.px - other.px,
self.py - other.py,
self.pz - other.pz,
)
}
#[inline]
pub fn dot(&self, other: &Self) -> Result<f64, MimamsaError> {
ensure_finite(
self.e * other.e - self.px * other.px - self.py * other.py - self.pz * other.pz,
"FourMomentum::dot",
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_four_momentum_on_shell_massless() {
let p = FourMomentum::new(10.0, 10.0, 0.0, 0.0).unwrap();
let m2 = p.invariant_mass_sq().unwrap();
assert!(m2.abs() < 1e-10);
}
#[test]
fn test_four_momentum_on_shell_massive() {
let m = crate::constants::M_ELECTRON_GEV;
let p = FourMomentum::new(m, 0.0, 0.0, 0.0).unwrap();
let m2 = p.invariant_mass_sq().unwrap();
assert!((m2 - m * m).abs() < 1e-20);
}
#[test]
fn test_four_momentum_addition() {
let p1 = FourMomentum::new(5.0, 3.0, 0.0, 0.0).unwrap();
let p2 = FourMomentum::new(5.0, -3.0, 0.0, 0.0).unwrap();
let total = p1.add(&p2).unwrap();
assert!((total.e - 10.0).abs() < 1e-12);
assert!(total.px.abs() < 1e-12);
}
#[test]
fn test_four_momentum_dot_product() {
let p = FourMomentum::new(5.0, 3.0, 0.0, 4.0).unwrap();
let pp = p.dot(&p).unwrap();
assert!(pp.abs() < 1e-10);
}
#[test]
fn test_four_momentum_overflow_rejected() {
assert!(FourMomentum::new(f64::MAX, 0.0, 0.0, 0.0).is_err());
}
#[test]
fn test_four_momentum_nan_rejected() {
assert!(FourMomentum::new(f64::NAN, 0.0, 0.0, 0.0).is_err());
}
#[test]
fn test_field_type_serde() {
let ft = FieldType::Scalar;
let json = serde_json::to_string(&ft).unwrap();
let back: FieldType = serde_json::from_str(&json).unwrap();
assert_eq!(ft, back);
}
}