Relativistic Two-Body Decay Kinematics#
This tutorial uses physicskit.particle.kinematics and
physicskit.particle.decays to build a two-body decay in a parent
particle’s rest frame, boost it into a moving (“lab”) frame, and check
two of the most basic relativistic-kinematics invariants: invariant mass
and rapidity additivity.
Decaying a parent particle at rest#
two_body_decay() builds both daughters’
four-momenta for a parent of mass M decaying to daughters of mass
m1, m2, emitted at a chosen angle:
import numpy as np
from physicskit.particle.kinematics import boost, boost_to_com, invariant_mass, rapidity
from physicskit.particle.decays import two_body_decay
M, m1, m2 = 1.0, 0.3, 0.2
p1, p2 = two_body_decay(M, m1, m2, cos_theta=0.6, phi=0.4)
print(p1) # FourVector(E=0.525, px=0.3175, py=0.1342, pz=0.2585)
print(p2) # FourVector(E=0.475, px=-0.3175, py=-0.1342, pz=-0.2585)
The two daughters are exactly back-to-back in the parent’s rest frame
(p1.p_vec + p2.p_vec is the zero vector), and reassembling their
four-momenta with invariant_mass()
recovers the parent mass exactly:
print(invariant_mass([p1, p2])) # 1.0
Boosting into a moving frame#
Physically, a real parent particle is rarely at rest – it was itself
produced moving, e.g. in a beam or a previous decay.
boost() moves any four-vector into
a frame where the parent travels at velocity beta along a chosen
axis. Applying the same boost to both daughters is exactly what
“boosting the whole decay into the lab frame” means:
beta_lab = 0.6
p1_lab = boost(p1, beta_lab, axis="z")
p2_lab = boost(p2, beta_lab, axis="z")
print(p1_lab) # FourVector(E=0.8501, px=0.3175, py=0.1342, pz=0.7169)
print(p2_lab) # FourVector(E=0.3999, px=-0.3175, py=-0.1342, pz=0.03312)
Invariant mass is, true to its name, exactly invariant – reconstructing it from the boosted daughters still gives the parent mass:
print(invariant_mass([p1_lab, p2_lab])) # 1.0 (to floating-point precision)
This is precisely the technique real particle-physics experiments use to discover unstable particles they cannot detect directly: measure the momenta of two decay products, and look for a peak in their reconstructed invariant mass at the parent’s mass.
Rapidity is additive under a boost#
Unlike ordinary velocity, rapidity \(y=\tfrac12\ln[(E+p_z)/(E-p_z)]\) adds linearly under a further boost along the same axis – a boost by \(\beta\) shifts every particle’s rapidity by exactly \(\operatorname{artanh}\beta\), regardless of its own momentum. That makes rapidity the natural variable for comparing particles produced in different reference frames:
y_rest = rapidity(p1)
y_lab = rapidity(p1_lab)
print(y_lab - y_rest) # 0.6931...
print(np.arctanh(beta_lab)) # 0.6931... -- an exact match
As a final consistency check,
boost_to_com() recovers the
boost velocity of the daughters’ own center-of-momentum frame relative
to the lab – exactly the beta_lab we applied:
print(boost_to_com([p1_lab, p2_lab])) # [0. 0. 0.6]