lorentz#
import ampform.kinematics.lorentz
Symbolic implementations for Lorentz vectors and boosts.
- 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}
- create_four_momentum_symbol(index: int) ArraySymbol [source]#
- FourMomenta#
A mapping of state IDs to their corresponding
FourMomentumSymbol
.It’s best to create a
dict
ofFourMomenta
withcreate_four_momentum_symbols()
.alias of
Dict
[int
,FourMomentumSymbol
]
- FourMomentumSymbol[source]#
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
, andFourMomentumZ
.
- class Energy(momentum, *args, evaluate: bool = False, **kwargs)[source]#
Bases:
Expr
Represents the energy-component of a
FourMomentumSymbol
.\(E\left(p\right)=p\left[:, 0\right]\)
- class FourMomentumX(momentum, *args, evaluate: bool = False, **kwargs)[source]#
Bases:
Expr
Component \(x\) of a
FourMomentumSymbol
.\({p}_x=p\left[:, 1\right]\)
- class FourMomentumY(momentum, *args, evaluate: bool = False, **kwargs)[source]#
Bases:
Expr
Component \(y\) of a
FourMomentumSymbol
.\({p}_y=p\left[:, 2\right]\)
- class FourMomentumZ(momentum, *args, evaluate: bool = False, **kwargs)[source]#
Bases:
Expr
Component \(z\) of a
FourMomentumSymbol
.\({p}_z=p\left[:, 3\right]\)
- class ThreeMomentum(momentum, *args, evaluate: bool = False, **kwargs)[source]#
Bases:
NumPyPrintable
Spatial components of a
FourMomentumSymbol
.\(\vec{p}=p\left[:, 1:\right]\)
p[:, 1:]
- class EuclideanNorm(vector, *args, evaluate: bool = False, **kwargs)[source]#
Bases:
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, *args, evaluate: bool = False, **kwargs)[source]#
Bases:
Expr
Take the squared euclidean norm of an array over axis 1.
- three_momentum_norm(momentum: Basic) EuclideanNorm [source]#
- class InvariantMass(momentum, *args, evaluate: bool = False, **kwargs)[source]#
Bases:
Expr
Invariant mass of a
FourMomentumSymbol
.(1)#\[\begin{split} \begin{array}{rcl} m_{p} &=& \sqrt[\mathrm{c}]{E\left(p\right)^{2} - \left|\vec{p}\right|^{2}} \\ \end{array}\end{split}\]
- class NegativeMomentum(momentum, *args, evaluate: bool = False, **kwargs)[source]#
Bases:
Expr
Invert the spatial components of a
FourMomentumSymbol
.
- class MinkowskiMetric(momentum, *args, evaluate: bool = False, **kwargs)[source]#
Bases:
NumPyPrintable
Minkowski metric \(\eta = (1, -1, -1, -1)\).
- class BoostZMatrix(beta, n_events, *args, evaluate: bool = False, **kwargs)[source]#
Bases:
Expr
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
ofbeta
.
This boost operates on a
FourMomentumSymbol
and looks like:(2)#\[\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
withcse=True
. The repetition ofnumpy.ones()
is still bothersome, but these sub-nodes is also extracted bysympy.cse
if the expression is nested further down in an expression tree, for instance when boosting aFourMomentumSymbol
\(p\) in the \(z\)-direction:(3)#\[\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, *args, evaluate: bool = False, **kwargs)[source]#
Bases:
Expr
Compute a rank-3 Lorentz boost matrix from a
FourMomentumSymbol
.This boost operates on a
FourMomentumSymbol
and looks like:(4)#\[\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, n_events, *args, evaluate: bool = False, **kwargs)[source]#
Bases:
Expr
Rotation matrix around the \(y\)-axis for a
FourMomentumSymbol
.- Parameters:
The matrix for a rotation over angle \(\alpha\) around the \(y\)-axis operating on
FourMomentumSymbol
looks like:(5)#\[\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, n_events, *args, evaluate: bool = False, **kwargs)[source]#
Bases:
Expr
Rotation matrix around the \(z\)-axis for a
FourMomentumSymbol
.- Parameters:
The matrix for a rotation over angle \(\alpha\) around the \(z\)-axis operating on
FourMomentumSymbol
looks like:(6)#\[\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 (3).
- class ArraySize(array, *args, evaluate: bool = False, **kwargs)[source]#
Bases:
NumPyPrintable
Symbolic expression for getting the size of a numerical array.
- 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
- compute_invariant_masses(four_momenta: FourMomenta, topology: Topology) dict[Symbol, Expr] [source]#
Compute the invariant masses for all final state combinations.
- get_invariant_mass_symbol(topology: Topology, state_id: int) Symbol [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 >>> from ampform._qrules import get_qrules_version >>> topologies = create_isobar_topologies(5) >>> topology = topologies[0 if get_qrules_version() < (0, 10) else 3] >>> get_invariant_mass_symbol(topology, 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_symbol(topologies[0], state_id=1) m_1