use crate::kernels::nuclear::quantities::FourMomentum;
use deep_causality_num::{FromPrimitive, RealField};
use super::kinematics::{LightconeEndpoint, StringSegment};
#[derive(Debug, Clone)]
pub struct LundString<R: RealField> {
segment: StringSegment<R>,
z_used_quark: R,
z_used_antiquark: R,
}
impl<R: RealField + FromPrimitive> LundString<R> {
pub fn new(quark: FourMomentum<R>, antiquark: FourMomentum<R>) -> Self {
Self {
segment: StringSegment::from_endpoints(&quark, &antiquark),
z_used_quark: R::zero(),
z_used_antiquark: R::zero(),
}
}
pub fn invariant_mass(&self) -> R {
self.segment.invariant_mass()
}
pub fn can_fragment(&self, min_mass: R) -> bool {
self.invariant_mass() > min_mass
}
pub fn w_plus(&self) -> R {
self.segment.w_plus() * (R::one() - self.z_used_quark)
}
pub fn w_minus(&self) -> R {
self.segment.w_minus() * (R::one() - self.z_used_antiquark)
}
pub fn take_from_quark(&mut self, z: R, pt_x: R, pt_y: R, mass: R) -> FourMomentum<R> {
let two = R::from_f64(2.0).expect("R::from_f64(2.0) failed");
let eps = R::from_f64(1e-10).expect("R::from_f64(1e-10) failed");
let w_plus = self.w_plus();
let hadron_p_plus = z * w_plus;
let mt_sq = mass * mass + pt_x * pt_x + pt_y * pt_y;
let denom = if hadron_p_plus > eps {
hadron_p_plus
} else {
eps
};
let hadron_p_minus = mt_sq / denom;
self.z_used_quark += z * (R::one() - self.z_used_quark);
let w_minus = self.segment.w_minus();
if w_minus > eps {
self.z_used_antiquark += hadron_p_minus / w_minus;
}
let e = (hadron_p_plus + hadron_p_minus) / two;
let pz = (hadron_p_plus - hadron_p_minus) / two;
FourMomentum::<R>::new(e, pt_x, pt_y, pz)
}
pub fn take_from_antiquark(&mut self, z: R, pt_x: R, pt_y: R, mass: R) -> FourMomentum<R> {
let two = R::from_f64(2.0).expect("R::from_f64(2.0) failed");
let eps = R::from_f64(1e-10).expect("R::from_f64(1e-10) failed");
let w_minus = self.w_minus();
let hadron_p_minus = z * w_minus;
let mt_sq = mass * mass + pt_x * pt_x + pt_y * pt_y;
let denom = if hadron_p_minus > eps {
hadron_p_minus
} else {
eps
};
let hadron_p_plus = mt_sq / denom;
self.z_used_antiquark += z * (R::one() - self.z_used_antiquark);
let w_plus = self.segment.w_plus();
if w_plus > eps {
self.z_used_quark += hadron_p_plus / w_plus;
}
let e = (hadron_p_plus + hadron_p_minus) / two;
let pz = (hadron_p_plus - hadron_p_minus) / two;
FourMomentum::<R>::new(e, pt_x, pt_y, pz)
}
#[allow(dead_code)]
pub fn quark_endpoint(&self) -> &LightconeEndpoint<R> {
&self.segment.quark
}
#[allow(dead_code)]
pub fn antiquark_endpoint(&self) -> &LightconeEndpoint<R> {
&self.segment.antiquark
}
pub fn final_hadron(&self, _mass: R) -> FourMomentum<R> {
let two = R::from_f64(2.0).expect("R::from_f64(2.0) failed");
let p_plus = self.w_plus();
let p_minus = self.w_minus();
let e = (p_plus + p_minus) / two;
let pz = (p_plus - p_minus) / two;
FourMomentum::<R>::new(e, R::zero(), R::zero(), pz)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lund_string_creation() {
let q = FourMomentum::<f64>::new(50.0, 0.0, 0.0, 50.0);
let qbar = FourMomentum::<f64>::new(50.0, 0.0, 0.0, -50.0);
let string: LundString<f64> = LundString::new(q, qbar);
assert!(string.invariant_mass() > 99.0);
assert!(string.can_fragment(10.0));
}
#[test]
fn test_take_from_quark() {
let q = FourMomentum::<f64>::new(50.0, 0.0, 0.0, 50.0);
let qbar = FourMomentum::<f64>::new(50.0, 0.0, 0.0, -50.0);
let mut string: LundString<f64> = LundString::new(q, qbar);
let hadron = string.take_from_quark(0.3, 0.0, 0.0, 0.14);
assert!(hadron.e() > 0.0);
assert!(hadron.pz() > 0.0);
}
}