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]

See Also#