kinematics

kinematics

Classes and functions for relativistic four-momentum kinematics.

class HelicityAdapter(transitions: ReactionInfo | Iterable[Topology | StateTransition])[source]

Bases: object

Converter for four-momenta to kinematic variable data.

The create_expressions method forms the bridge between four-momentum data for the decay you are studying and the kinematic variables that are in the HelicityModel. These are invariant mass (see get_invariant_mass_label()) and the \(\theta\) and \(\phi\) helicity angles (see get_helicity_angle_label()).

register_transition(transition: StateTransition) None[source]
register_topology(topology: Topology) None[source]
property registered_topologies: frozenset[Topology]
permutate_registered_topologies() None[source]

Register outgoing edge permutations of all registered_topologies.

See Extend kinematic variables.

create_expressions(generate_wigner_angles: bool = False) dict[str, Expr][source]
create_four_momentum_symbols(topology: Topology) FourMomenta[source]

Create a set of array-symbols for a Topology.

>>> from qrules.topology import create_isobar_topologies
>>> topologies = create_isobar_topologies(3)
>>> create_four_momentum_symbols(topologies[0])
{0: p0, 1: p1, 2: p2}
FourMomenta

A mapping of state IDs to their corresponding FourMomentumSymbol.

It’s best to create a dict of FourMomenta with create_four_momentum_symbols().

alias of Dict[int, FourMomentumSymbol]

FourMomentumSymbol

Array-Symbol that represents an array of four-momenta.

The array is assumed to be of shape \(n\times 4\) with \(n\) the number of events. The four-momenta are assumed to be in the order \(\left(E,\vec{p}\right)\). See also Energy, FourMomentumX, FourMomentumY, and FourMomentumZ.

class Energy(momentum: Basic, **hints)[source]

Bases: UnevaluatedExpression

Represents the energy-component of a FourMomentumSymbol.

\(E\left(p\right)=p\left[:, 0\right]\)

class FourMomentumX(momentum: Basic, **hints)[source]

Bases: UnevaluatedExpression

Component \(x\) of a FourMomentumSymbol.

\({p}_x=p\left[:, 1\right]\)

class FourMomentumY(momentum: Basic, **hints)[source]

Bases: UnevaluatedExpression

Component \(y\) of a FourMomentumSymbol.

\({p}_y=p\left[:, 2\right]\)

class FourMomentumZ(momentum: Basic, **hints)[source]

Bases: UnevaluatedExpression

Component \(z\) of a FourMomentumSymbol.

\({p}_z=p\left[:, 3\right]\)

class ThreeMomentum(momentum: Basic, **hints)[source]

Bases: UnevaluatedExpression, NumPyPrintable

Spatial components of a FourMomentumSymbol.

\(\vec{p}=p\left[:, 1:\right]\)

p[:, 1:]
class EuclideanNorm(vector: Basic, **hints)[source]

Bases: UnevaluatedExpression, NumPyPrintable

Take the euclidean norm of an array over axis 1.

\(\left|v\right|=\sqrt{\left|v\right|^{2}}\)

from numpy import sqrt, sum

numpy.sqrt(sum(v**2, axis=1))
class EuclideanNormSquared(vector: Basic, **hints)[source]

Bases: UnevaluatedExpression

Take the squared euclidean norm of an array over axis 1.

three_momentum_norm(momentum: Basic) EuclideanNorm[source]
class InvariantMass(momentum: Basic, **hints)[source]

Bases: UnevaluatedExpression

Invariant mass of a FourMomentumSymbol.

(1)\[ \begin{eqnarray} m_{p} & = & \sqrt[\mathrm{c}]{E\left(p\right)^{2} - \left|\vec{p}\right|^{2}} \end{eqnarray}\]
class Phi(momentum: Basic, **hints)[source]

Bases: UnevaluatedExpression

Azimuthal angle \(\phi\) of a FourMomentumSymbol.

(2)\[ \begin{eqnarray} \phi\left(p\right) & = & \operatorname{atan_{2}}{\left({p}_y,{p}_x \right)} \end{eqnarray}\]
class Theta(momentum: Basic, **hints)[source]

Bases: UnevaluatedExpression

Polar (elevation) angle \(\theta\) of a FourMomentumSymbol.

(3)\[ \begin{eqnarray} \theta\left(p\right) & = & \operatorname{acos}{\left(\frac{{p}_z}{\left|\vec{p}\right|} \right)} \end{eqnarray}\]
class NegativeMomentum(momentum: Basic, **hints)[source]

Bases: UnevaluatedExpression

Invert the spatial components of a FourMomentumSymbol.

class MinkowskiMetric(momentum: Basic, **hints)[source]

Bases: NumPyPrintable

Minkowski metric \(\eta = (1, -1, -1, -1)\).

class BoostZMatrix(beta: Basic, n_events: Expr | None = None, **kwargs)[source]

Bases: UnevaluatedExpression

Represents a Lorentz boost matrix in the \(z\)-direction.

Parameters
  • beta – Velocity in the \(z\)-direction, \(\beta=p_z/E\).

  • n_events – Number of events \(n\) for this matrix array of shape \(n\times4\times4\). Defaults to the len of beta.

This boost operates on a FourMomentumSymbol and looks like:

(4)\[\begin{split}\boldsymbol{B_z}\left(\beta\right) = \left[\begin{matrix}\frac{1}{\sqrt[\mathrm{c}]{1 - \beta^{2}}} & 0 & 0 & - \frac{\beta}{\sqrt[\mathrm{c}]{1 - \beta^{2}}}\\0 & 1 & 0 & 0\\0 & 0 & 1 & 0\\- \frac{\beta}{\sqrt[\mathrm{c}]{1 - \beta^{2}}} & 0 & 0 & \frac{1}{\sqrt[\mathrm{c}]{1 - \beta^{2}}}\end{matrix}\right]\end{split}\]

In TensorWaves, this class is expressed in a computational backend and it should operate on four-momentum arrays of rank-2. As such, this boost matrix becomes a rank-3 matrix. When using NumPy as backend, the computation looks as follows:

from numpy import array, ones, sqrt, zeros

def _lambdifygenerated(b):
    x0 = 1/numpy.sqrt(1 - b**2)
    x1 = len(b)
    return (array(
            [
                [x0, zeros(x1), zeros(x1), -b*x0],
                [zeros(x1), ones(x1), zeros(x1), zeros(x1)],
                [zeros(x1), zeros(x1), ones(x1), zeros(x1)],
                [-b*x0, zeros(x1), zeros(x1), x0],
            ]
        ).transpose((2, 0, 1)))

Note that this code was generated with sympy.lambdify with cse=True. The repetition of numpy.ones() is still bothersome, but these sub-nodes is also extracted by sympy.cse if the expression is nested further down in an expression tree, for instance when boosting a FourMomentumSymbol \(p\) in the \(z\)-direction:

(5)\[\boldsymbol{B_z}\left(\beta\right) \boldsymbol{R_y}\left(\theta\right) \boldsymbol{R_z}\left(\phi\right) p\]

which in numpy code becomes:

from numpy import array, cos, einsum, ones, sin, sqrt, zeros

def _lambdifygenerated(beta, p, phi, theta):
    x0 = 1/numpy.sqrt(1 - beta**2)
    x1 = len(p)
    x2 = ones(x1)
    x3 = zeros(x1)
    return (einsum("...ij,...jk,...kl,...l->...i", array(
            [
                [x0, x3, x3, -beta*x0],
                [x3, x2, x3, x3],
                [x3, x3, x2, x3],
                [-beta*x0, x3, x3, x0],
            ]
        ).transpose((2, 0, 1)), array(
            [
                [x2, x3, x3, x3],
                [x3, numpy.cos(theta), x3, numpy.sin(theta)],
                [x3, x3, x2, x3],
                [x3, -numpy.sin(theta), x3, numpy.cos(theta)],
            ]
        ).transpose((2, 0, 1)), array(
            [
                [x2, x3, x3, x3],
                [x3, numpy.cos(phi), -numpy.sin(phi), x3],
                [x3, numpy.sin(phi), numpy.cos(phi), x3],
                [x3, x3, x3, x2],
            ]
        ).transpose((2, 0, 1)), p))
class BoostMatrix(momentum: Basic, **kwargs)[source]

Bases: UnevaluatedExpression

Compute a rank-3 Lorentz boost matrix from a FourMomentumSymbol.

This boost operates on a FourMomentumSymbol and looks like:

(6)\[\begin{split}\boldsymbol{B}\left(p\right) = \left[\begin{matrix}\frac{1}{\sqrt{1 - \frac{\left|\vec{p}\right|^{2}}{E\left(p\right)^{2}}}} & - \frac{{p}_x}{\sqrt{1 - \frac{\left|\vec{p}\right|^{2}}{E\left(p\right)^{2}}} E\left(p\right)} & - \frac{{p}_y}{\sqrt{1 - \frac{\left|\vec{p}\right|^{2}}{E\left(p\right)^{2}}} E\left(p\right)} & - \frac{{p}_z}{\sqrt{1 - \frac{\left|\vec{p}\right|^{2}}{E\left(p\right)^{2}}} E\left(p\right)}\\- \frac{{p}_x}{\sqrt{1 - \frac{\left|\vec{p}\right|^{2}}{E\left(p\right)^{2}}} E\left(p\right)} & \frac{\left(-1 + \frac{1}{\sqrt{1 - \frac{\left|\vec{p}\right|^{2}}{E\left(p\right)^{2}}}}\right) {p}_x^{2}}{\left|\vec{p}\right|^{2}} + 1 & \frac{\left(-1 + \frac{1}{\sqrt{1 - \frac{\left|\vec{p}\right|^{2}}{E\left(p\right)^{2}}}}\right) {p}_x {p}_y}{\left|\vec{p}\right|^{2}} & \frac{\left(-1 + \frac{1}{\sqrt{1 - \frac{\left|\vec{p}\right|^{2}}{E\left(p\right)^{2}}}}\right) {p}_x {p}_z}{\left|\vec{p}\right|^{2}}\\- \frac{{p}_y}{\sqrt{1 - \frac{\left|\vec{p}\right|^{2}}{E\left(p\right)^{2}}} E\left(p\right)} & \frac{\left(-1 + \frac{1}{\sqrt{1 - \frac{\left|\vec{p}\right|^{2}}{E\left(p\right)^{2}}}}\right) {p}_x {p}_y}{\left|\vec{p}\right|^{2}} & \frac{\left(-1 + \frac{1}{\sqrt{1 - \frac{\left|\vec{p}\right|^{2}}{E\left(p\right)^{2}}}}\right) {p}_y^{2}}{\left|\vec{p}\right|^{2}} + 1 & \frac{\left(-1 + \frac{1}{\sqrt{1 - \frac{\left|\vec{p}\right|^{2}}{E\left(p\right)^{2}}}}\right) {p}_y {p}_z}{\left|\vec{p}\right|^{2}}\\- \frac{{p}_z}{\sqrt{1 - \frac{\left|\vec{p}\right|^{2}}{E\left(p\right)^{2}}} E\left(p\right)} & \frac{\left(-1 + \frac{1}{\sqrt{1 - \frac{\left|\vec{p}\right|^{2}}{E\left(p\right)^{2}}}}\right) {p}_x {p}_z}{\left|\vec{p}\right|^{2}} & \frac{\left(-1 + \frac{1}{\sqrt{1 - \frac{\left|\vec{p}\right|^{2}}{E\left(p\right)^{2}}}}\right) {p}_y {p}_z}{\left|\vec{p}\right|^{2}} & \frac{\left(-1 + \frac{1}{\sqrt{1 - \frac{\left|\vec{p}\right|^{2}}{E\left(p\right)^{2}}}}\right) {p}_z^{2}}{\left|\vec{p}\right|^{2}} + 1\end{matrix}\right]\end{split}\]

In TensorWaves, this class is expressed in a computational backend and it should operate on four-momentum arrays of rank-2. As such, this boost matrix becomes a rank-3 matrix. When using NumPy as backend, the computation looks as follows:

from numpy import sqrt, sum

def _lambdifygenerated(p):
    x0 = p
    x1 = x0[:, 0]
    x2 = sum(x0[:, 1:]**2, axis=1)
    x3 = 1/numpy.sqrt(1 - x2/x1**2)
    x4 = x0[:, 1]
    x5 = x3/x1
    x6 = x0[:, 2]
    x7 = x0[:, 3]
    x8 = (x3 - 1)/x2
    x9 = x4*x8
    return (array(
            [
                [x3, -x4*x5, -x5*x6, -x5*x7],
                [-x4*x5, x4**2*x8 + 1, x6*x9, x7*x9],
                [-x5*x6, x6*x9, x6**2*x8 + 1, x6*x7*x8],
                [-x5*x7, x7*x9, x6*x7*x8, x7**2*x8 + 1],
            ]
        ).transpose((2, 0, 1)))
class RotationYMatrix(angle: Basic, n_events: Expr | None = None, **hints)[source]

Bases: UnevaluatedExpression

Rotation matrix around the \(y\)-axis for a FourMomentumSymbol.

Parameters
  • angle – Angle with which to rotate, see e.g. Phi and Theta.

  • n_events – Number of events \(n\) for this matrix array of shape \(n\times4\times4\). Defaults to the len of angle.

The matrix for a rotation over angle \(\alpha\) around the \(y\)-axis operating on FourMomentumSymbol looks like:

(7)\[\begin{split}\boldsymbol{R_y}\left(\alpha\right) = \left[\begin{matrix}1 & 0 & 0 & 0\\0 & \cos{\left(\alpha \right)} & 0 & \sin{\left(\alpha \right)}\\0 & 0 & 1 & 0\\0 & - \sin{\left(\alpha \right)} & 0 & \cos{\left(\alpha \right)}\end{matrix}\right]\end{split}\]

See RotationZMatrix for the computational code.

class RotationZMatrix(angle: Basic, n_events: Expr | None = None, **hints)[source]

Bases: UnevaluatedExpression

Rotation matrix around the \(z\)-axis for a FourMomentumSymbol.

Parameters
  • angle – Angle with which to rotate, see e.g. Phi and Theta.

  • n_events – Number of events \(n\) for this matrix array of shape \(n\times4\times4\). Defaults to the len of angle.

The matrix for a rotation over angle \(\alpha\) around the \(z\)-axis operating on FourMomentumSymbol looks like:

(8)\[\begin{split}\boldsymbol{R_z}\left(\alpha\right) = \left[\begin{matrix}1 & 0 & 0 & 0\\0 & \cos{\left(\alpha \right)} & - \sin{\left(\alpha \right)} & 0\\0 & \sin{\left(\alpha \right)} & \cos{\left(\alpha \right)} & 0\\0 & 0 & 0 & 1\end{matrix}\right]\end{split}\]

In TensorWaves, this class is expressed in a computational backend and it should operate on four-momentum arrays of rank-2. As such, this boost matrix becomes a rank-3 matrix. When using NumPy as backend, the computation looks as follows:

from numpy import array, cos, ones, sin, zeros

def _lambdifygenerated(a):
    x0 = len(a)
    return (array(
            [
                [ones(x0), zeros(x0), zeros(x0), zeros(x0)],
                [zeros(x0), numpy.cos(a), -numpy.sin(a), zeros(x0)],
                [zeros(x0), numpy.sin(a), numpy.cos(a), zeros(x0)],
                [zeros(x0), zeros(x0), zeros(x0), ones(x0)],
            ]
        ).transpose((2, 0, 1)))

See also the note that comes with Equation (5).

compute_helicity_angles(four_momenta: Mapping[int, Expr], topology: Topology) dict[str, Expr][source]

Formulate expressions for all helicity angles in a topology.

Formulate expressions (Expr) for all helicity angles appearing in a given Topology. The expressions are given in terms of FourMomenta The expressions returned as values in a dict, where the keys are defined by get_helicity_angle_label().

Example

>>> from qrules.topology import create_isobar_topologies
>>> topologies = create_isobar_topologies(3)
>>> topology = topologies[0]
>>> four_momenta = create_four_momentum_symbols(topology)
>>> angles = compute_helicity_angles(four_momenta, topology)
>>> angles["theta_0"]
Theta(p1 + p2)
compute_invariant_masses(four_momenta: FourMomenta, topology: Topology) dict[str, Expr][source]

Compute the invariant masses for all final state combinations.

compute_wigner_angles(topology: Topology, momenta: FourMomenta, state_id: int) dict[str, Expr][source]

Create an Expr for each angle in a Wigner rotation.

Implementation of (B.2-4) in [1], with \(x'_z\) etc. taken from the result of compute_wigner_rotation_matrix().

compute_wigner_rotation_matrix(topology: Topology, momenta: FourMomenta, state_id: int) MatrixMultiplication[source]

Compute a Wigner rotation matrix.

Implementation of Eq. (36) in [1].

compute_boost_chain(topology: Topology, momenta: FourMomenta, state_id: int) list[BoostMatrix][source]
get_four_momentum_sum(topology: Topology, momenta: FourMomenta, state_id: int) ArraySum | FourMomentumSymbol[source]

Get the FourMomentumSymbol or sum of momenta for any edge ID.

If the edge ID is a final state ID, return its FourMomentumSymbol. If it’s an intermediate edge ID, return the sum of the momenta of the final states to which it decays.

>>> from qrules.topology import create_isobar_topologies
>>> topology = create_isobar_topologies(3)[0]
>>> momenta = create_four_momentum_symbols(topology)
>>> get_four_momentum_sum(topology, momenta, state_id=0)
p0
>>> get_four_momentum_sum(topology, momenta, state_id=3)
p1 + p2
get_invariant_mass_label(topology: Topology, state_id: int) str[source]

Generate an invariant mass label for a state (edge on a topology).

Example

In the case shown in Figure topologies[0], the invariant mass of state \(5\) is \(m_{034}\), because \(p_5=p_0+p_3+p_4\):

>>> from qrules.topology import create_isobar_topologies
>>> topologies = create_isobar_topologies(5)
>>> get_invariant_mass_label(topologies[0], state_id=5)
'm_034'

Naturally, the ‘invariant’ mass label for a final state is just the mass of the state itself:

>>> get_invariant_mass_label(topologies[0], state_id=1)
'm_1'