diff --git a/Project.toml b/Project.toml index b350c82..4c3c684 100644 --- a/Project.toml +++ b/Project.toml @@ -1,9 +1,6 @@ name = "QEDcore" uuid = "35dc0263-cb5f-4c33-a114-1d7f54ab753e" -authors = [ - "Uwe Hernandez Acosta ", - "Anton Reinhard ", -] +authors = ["Uwe Hernandez Acosta ", "Anton Reinhard"] version = "0.1.1" [deps] diff --git a/src/QEDcore.jl b/src/QEDcore.jl index ef81690..c73e9fd 100644 --- a/src/QEDcore.jl +++ b/src/QEDcore.jl @@ -6,6 +6,10 @@ export SLorentzVector, MLorentzVector # four momenta export SFourMomentum, MFourMomentum +# four momenta +export Boost +export BetaX, BetaY, BetaZ, BetaVector + # spinors export BiSpinor, AdjointBiSpinor, DiracMatrix @@ -34,6 +38,8 @@ using SimpleTraits @reexport using QEDbase +include("patch_QEDbase.jl") + include("algebraic_objects/dirac_tensors/types.jl") include("algebraic_objects/dirac_tensors/multiplication.jl") @@ -47,6 +53,14 @@ include("algebraic_objects/four_momentum.jl") include("algebraic_objects/lorentz_vector.jl") include("algebraic_objects/gamma_matrices.jl") +include("lorentz_boost/types.jl") +include("lorentz_boost/boost_parameter/boost_axis/types.jl") +include("lorentz_boost/boost_parameter/boost_axis/convert.jl") +include("lorentz_boost/boost_parameter/boost_axis/beta.jl") +include("lorentz_boost/boost_parameter/boost_vector/types.jl") +include("lorentz_boost/boost_parameter/boost_vector/beta.jl") +include("lorentz_boost/boost_parameter/boost_vector/utils.jl") + include("particles/particle_types.jl") include("particles/propagators.jl") include("particles/states.jl") diff --git a/src/lorentz_boost/boost_parameter/boost_axis/beta.jl b/src/lorentz_boost/boost_parameter/boost_axis/beta.jl new file mode 100644 index 0000000..b798000 --- /dev/null +++ b/src/lorentz_boost/boost_parameter/boost_axis/beta.jl @@ -0,0 +1,278 @@ + +########### +# Axis Beta +########### +""" + + AbstractAxisBeta{T} <: AbstractAxisBoostParameter{T} + +An abstract base type for the beta (velocity) parameter of type `T`, representing a Lorentz boost along a specific spatial axis. + +`AbstractAxisBeta{T}` extends `AbstractAxisBoostParameter{T}` and provides a general framework for defining beta parameters associated with individual Cartesian axes (x, y, z) in special relativity. The parameter `T` typically represents the numeric type (e.g., `Float64`, `Float32`) used for the beta value. + +### Usage + +Concrete subtypes of `AbstractAxisBeta{T}` define the beta parameters for Lorentz boosts along the x, y, and z axes: +- [`BetaX{T}`](@ref): Boost parameter for the x-axis. +- [`BetaY{T}`](@ref): Boost parameter for the y-axis. +- [`BetaZ{T}`](@ref): Boost parameter for the z-axis. + +These beta parameters are essential for performing axis-specific Lorentz boosts, which transform physical quantities such as four-momentum between different inertial frames. + +""" +abstract type AbstractAxisBeta{T} <: AbstractAxisBoostParameter{T} end + +Base.:-(beta::B) where {B<:AbstractAxisBeta} = B(-beta.param) + +_inv(beta::B) where {B<:AbstractAxisBeta} = B(-beta.param) + +@inline function _generic_axis_boost(en, comp, beta) + b2 = beta^2 + gamma = inv(sqrt(one(b2) - b2)) + + en_prime = gamma * (en - beta * comp) + comp_prime = gamma * (comp - beta * en) + + return (en_prime, comp_prime) +end + +""" + + BetaX(beta::T) where {T<:Real} + +Represents the beta parameter associated with a Lorentz boost along the x-axis, commonly denoted as ``\\beta_x``. + +The transformation for a boost along the x-axis is: + +```math +\\begin{pmatrix} +p_0\\\\ +p_1\\\\ +p_2\\\\ +p_3 +\\end{pmatrix} \\mapsto +\\begin{pmatrix} +\\gamma (p_0 - \\beta_x p_1)\\\\ +\\gamma (p_1 - \\beta_x p_0)\\\\ +p_2\\\\ +p_3 +\\end{pmatrix} +``` +where the kinematic factor is given as ``\\gamma = 1/\\sqrt{1-\\beta_x^2}``) + +## Example + +```jldoctest +julia> using QEDcore + +julia> beta_x = BetaX(0.5) +BetaX{Float64}(0.5) + +julia> boost = Boost(beta_x) +Boost{BetaX{Float64}}(BetaX{Float64}(0.5)) + +julia> p = SFourMomentum(4,3,2,1) +4-element SFourMomentum with indices SOneTo(4): + 4.0 + 3.0 + 2.0 + 1.0 + +julia> p_prime = boost(p) +4-element SFourMomentum with indices SOneTo(4): + 2.886751345948129 + 1.1547005383792517 + 2.0 + 1.0 + +julia> @assert isapprox(p*p,p_prime*p_prime) # Invariant mass is preserved +``` + +## External link + +* [Lorentz Boost on Wikipedia](https://en.wikipedia.org/wiki/Lorentz_transformation) +* [Kinematics in PDG review](https://pdg.lbl.gov/2024/reviews/rpp2024-rev-kinematics.pdf) + +""" +struct BetaX{T<:Real} <: AbstractAxisBeta{T} + param::T + function BetaX{T}(beta::T) where {T<:Real} + -one(beta) <= beta < one(beta) || + throw(InvalidInputError("beta parameter <$beta> must be between zero and one")) + return new{T}(beta) + end +end + +BetaX(beta::T) where {T<:Real} = BetaX{T}(beta) + +function _transform(boost_param::BetaX, p::M) where {M<:AbstractFourMomentum} + en = getE(p) + px = getX(p) + + en_prime, px_prime = _generic_axis_boost(en, px, boost_param.param) + return M(en_prime, px_prime, getY(p), getZ(p)) +end + +""" + + BetaY(beta::T) where {T<:Real} + +Represents the beta parameter associated with a Lorentz boost along the y-axis, commonly denoted as ``\\beta_y``. + +The transformation for a boost along the y-axis is: + +```math +\\begin{pmatrix} +p_0\\\\ +p_1\\\\ +p_2\\\\ +p_3 +\\end{pmatrix} \\mapsto +\\begin{pmatrix} +\\gamma (p_0 - \\beta_y p_2)\\\\ +p_1\\\\ +\\gamma (p_2 - \\beta_y p_0)\\\\ +p_3 +\\end{pmatrix} +``` +where the kinematic factor is given as ``\\gamma = 1/\\sqrt{1-\\beta_y^2}``) + +## Example + +```jldoctest +julia> using QEDcore + +julia> using Random + +julia> RNG = MersenneTwister(1234) +MersenneTwister(1234) + +julia> beta_y = BetaY(0.5) +BetaY{Float64}(0.5) + +julia> boost = Boost(beta_y) +Boost{BetaY{Float64}}(BetaY{Float64}(0.5)) + +julia> p = SFourMomentum(4,3,2,1) +4-element SFourMomentum with indices SOneTo(4): + 4.0 + 3.0 + 2.0 + 1.0 + +julia> p_prime = boost(p) +4-element SFourMomentum with indices SOneTo(4): + 3.4641016151377553 + 3.0 + 0.0 + 1.0 + +julia> @assert isapprox(p*p,p_prime*p_prime) # Invariant mass is preserved +``` + +## External link + +* [Lorentz Boost on Wikipedia](https://en.wikipedia.org/wiki/Lorentz_transformation) +* [Kinematics in PDG review](https://pdg.lbl.gov/2024/reviews/rpp2024-rev-kinematics.pdf) + +""" +struct BetaY{T<:Real} <: AbstractAxisBeta{T} + param::T + function BetaY{T}(beta::T) where {T<:Real} + -one(beta) <= beta < one(beta) || + throw(InvalidInputError("beta parameter <$beta> must be between zero and one")) + return new{T}(beta) + end +end + +BetaY(beta::T) where {T} = BetaY{T}(beta) + +function _transform(boost_param::BetaY, p::M) where {M<:AbstractFourMomentum} + en = getE(p) + py = getY(p) + + en_prime, py_prime = _generic_axis_boost(en, py, boost_param.param) + return M(en_prime, getX(p), py_prime, getZ(p)) +end + +""" + + BetaZ(beta::T) where {T<:Real} + +Represents the beta parameter associated with a Lorentz boost along the z-axis, commonly denoted as ``\\beta_z``. + +The transformation for a boost along the z-axis is: + +```math +\\begin{pmatrix} +p_0\\\\ +p_1\\\\ +p_2\\\\ +p_3 +\\end{pmatrix} \\mapsto +\\begin{pmatrix} +\\gamma (p_0 - \\beta_z p_3)\\\\ +p_1\\\\ +p_2\\\\ +\\gamma (p_3 - \\beta_z p_0)\\\\ +\\end{pmatrix} +``` +where the kinematic factor is given as ``\\gamma = 1/\\sqrt{1-\\beta_z^2}``) + +## Example + +```jldoctest +julia> using QEDcore + +julia> using Random + +julia> RNG = MersenneTwister(1234) +MersenneTwister(1234) + +julia> beta_z = BetaZ(0.5) +BetaZ{Float64}(0.5) + +julia> boost = Boost(beta_z) +Boost{BetaZ{Float64}}(BetaZ{Float64}(0.5)) + +julia> p = SFourMomentum(4,3,2,1) +4-element SFourMomentum with indices SOneTo(4): + 4.0 + 3.0 + 2.0 + 1.0 + +julia> p_prime = boost(p) +4-element SFourMomentum with indices SOneTo(4): + 4.041451884327381 + 3.0 + 2.0 + -1.1547005383792517 + +julia> @assert isapprox(p*p,p_prime*p_prime) # Invariant mass is preserved + +``` + +## External link + +* [Lorentz Boost on Wikipedia](https://en.wikipedia.org/wiki/Lorentz_transformation) +* [Kinematics in PDG review](https://pdg.lbl.gov/2024/reviews/rpp2024-rev-kinematics.pdf) + +""" +struct BetaZ{T<:Real} <: AbstractAxisBeta{T} + param::T + function BetaZ{T}(beta::T) where {T<:Real} + -one(beta) <= beta < one(beta) || + throw(InvalidInputError("beta parameter <$beta> must be between zero and one")) + return new{T}(beta) + end +end + +BetaZ(beta::T) where {T} = BetaZ{T}(beta) +function _transform(boost_param::BetaZ, p::M) where {M<:AbstractFourMomentum} + en = getE(p) + pz = getZ(p) + + en_prime, pz_prime = _generic_axis_boost(en, pz, boost_param.param) + return M(en_prime, getX(p), getY(p), pz_prime) +end diff --git a/src/lorentz_boost/boost_parameter/boost_axis/convert.jl b/src/lorentz_boost/boost_parameter/boost_axis/convert.jl new file mode 100644 index 0000000..94ffd77 --- /dev/null +++ b/src/lorentz_boost/boost_parameter/boost_axis/convert.jl @@ -0,0 +1,14 @@ + +function Base.convert( + ::Type{B}, param::Real +) where {T<:Real,B<:AbstractAxisBoostParameter{T}} + return B(T(param)) +end +function Base.convert( + ::Type{B1}, d::B2 +) where {T<:Real,B1<:AbstractAxisBoostParameter{T},B2<:AbstractAxisBoostParameter} + return B1(T(d.param)) +end +function Base.convert(::Type{B}, d::B) where {B<:AbstractAxisBoostParameter} + return d +end diff --git a/src/lorentz_boost/boost_parameter/boost_axis/types.jl b/src/lorentz_boost/boost_parameter/boost_axis/types.jl new file mode 100644 index 0000000..577d0e6 --- /dev/null +++ b/src/lorentz_boost/boost_parameter/boost_axis/types.jl @@ -0,0 +1,21 @@ +""" + AbstractAxisBoostParameter{T} + +An abstract base type representing a boost parameter of type `T`, associated with a specific axis in space (e.g., ``x``, ``y``, or ``z``). + +This type serves as a foundation for concrete boost parameter types that define Lorentz boosts along individual spatial directions. The parameter `T` typically represents the data type for the boost value (e.g., `Float64`, `Float32`). + +### Usage + +Subtypes of `AbstractAxisBoostParameter{T}` are used to define specific boost transformations along a given axis (such as [`BetaX`](@ref) for the x-axis). These types are essential in performing Lorentz boosts, which transform four-momentum vectors between different inertial reference frames. + +This abstract type is meant to be extended by concrete types to represent boosts along different Cartesian axes. + +""" +abstract type AbstractAxisBoostParameter{T} <: AbstractBoostParameter end + +function (::Type{BP})(boost_val::Real) where {T<:Real,BP<:AbstractAxisBoostParameter{T}} + return BP(T(boost_val)) +end + +Base.eltype(::AbstractAxisBoostParameter{T}) where {T} = T diff --git a/src/lorentz_boost/boost_parameter/boost_vector/beta.jl b/src/lorentz_boost/boost_parameter/boost_vector/beta.jl new file mode 100644 index 0000000..93b5d99 --- /dev/null +++ b/src/lorentz_boost/boost_parameter/boost_vector/beta.jl @@ -0,0 +1,122 @@ + +""" + + BetaVector(x::Real,y::Real,z::Real) + +Represents the spatial vector of velocity parameters (denoted as the "beta" vector) associated with motion in the three Cartesian directions, i.e., +``\\vec\\beta = (\\beta_x, \\beta_y, \\beta_z)``. These components correspond to the velocity of an object (in units of the speed of light) in each of the +``x``, ``y``, and ``z`` directions. + +The Lorentz boost along the direction of the beta vector ``\\vec\\beta`` transforms the four-momentum as follows: + +```math +\\begin{pmatrix} +p_0\\\\ +p_1\\\\ +p_2\\\\ +p_3 +\\end{pmatrix} \\mapsto +\\begin{pmatrix} + \\gamma (p_0 - \\vec\\beta \\vec p)\\\\ +p_1 + (\\frac{\\gamma - 1}{\\beta^2} \\vec\\beta\\vec p - \\gamma p_0) + \\beta_x\\\\ +p_2 + (\\frac{\\gamma - 1}{\\beta^2} \\vec\\beta\\vec p - \\gamma p_0) + \\beta_y\\\\ + p_3 + (\\frac{\\gamma - 1}{\\beta^2} \\vec\\beta\\vec p - \\gamma p_0) + \\beta_z\\\\ +\\end{pmatrix} +``` +where the kinematic factor is given as ``\\gamma = 1/\\sqrt{1-\\beta_x^2}``. + +## Example + +```jldoctest +julia> using QEDcore + +julia> beta_vec = BetaVector(0.2,0.3,0.1) +BetaVector{Float64}(0.2, 0.3, 0.1) + +julia> boost = Boost(beta_vec) +Boost{BetaVector{Float64}}(BetaVector{Float64}(0.2, 0.3, 0.1)) + +julia> p = SFourMomentum(4.0,3.0,2.0,1.0) +4-element SFourMomentum with indices SOneTo(4): + 4.0 + 3.0 + 2.0 + 1.0 + +julia> p_prime = boost(p) +4-element SFourMomentum with indices SOneTo(4): + 2.911484876492837 + 2.282803602436349 + 0.9242054036545237 + 0.6414018012181746 + +julia> @assert isapprox(p*p,p_prime*p_prime) # Invariant mass is preserved +``` + +## External link + +* [Lorentz Boost on Wikipedia](https://en.wikipedia.org/wiki/Lorentz_transformation) +* [Kinematics in PDG review](https://pdg.lbl.gov/2024/reviews/rpp2024-rev-kinematics.pdf) +* [`ROOT::Math:Boost` from ROOT](https://root.cern.ch/doc/master/classROOT_1_1Math_1_1Boost.html) + +""" +struct BetaVector{T<:Real} <: AbstractBoostVector + x::T + y::T + z::T + + function BetaVector(x::T, y::T, z::T) where {T} + b2 = x^2 + y^2 + z^2 + b2 <= 1 || throw( + InvalidInputError( + "wrong length of the beta vector ($x, $y, $z). Its length needs to be less or equal to one, but x^2 + y^2 + z^2 = $b2 is given.", + ), + ) + return new{T}(x, y, z) + end +end +BetaVector(x, y, z) = BetaVector(promote(x, y, z)...) + +Base.:-(b::BetaVector) = BetaVector(-b.x, -b.y, -b.z) + +@inline function _spatial_mul(p::AbstractFourMomentum, beta::BetaVector) + return p[2] * beta.x + p[3] * beta.y + p[4] * beta.z +end + +# assumption: beta vector components commute with four-momentum components +_spatial_mul(beta::BetaVector, p::AbstractFourMomentum) = _spatial_mul(p, beta) + +function _three_vector_square(beta_vec::BetaVector) + bx = beta_vec.x + by = beta_vec.y + bz = beta_vec.z + return bx^2 + by^2 + bz^2 +end + +@inline function _transform(beta_vec::BetaVector, p::M) where {M<:AbstractFourMomentum} + b2 = _three_vector_square(beta_vec) + if b2 == one(b2) + return p + end + gamma = inv(sqrt(one(b2) - b2)) + + en = getE(p) + px = getX(p) + py = getY(p) + pz = getZ(p) + bp = _spatial_mul(p, beta_vec) + gamma2 = (gamma - one(b2)) / b2 + fac = gamma2 * bp - gamma * en + px_prime = px + fac * beta_vec.x + py_prime = py + fac * beta_vec.y + pz_prime = pz + fac * beta_vec.z + en_prime = gamma * (en - bp) + + return M(en_prime, px_prime, py_prime, pz_prime) +end + +# inverse is just a boost with -beta +_inv(beta_vec::BetaVector) = BetaVector(-beta_vec.x, -beta_vec.y, -beta_vec.z) diff --git a/src/lorentz_boost/boost_parameter/boost_vector/types.jl b/src/lorentz_boost/boost_parameter/boost_vector/types.jl new file mode 100644 index 0000000..184f406 --- /dev/null +++ b/src/lorentz_boost/boost_parameter/boost_vector/types.jl @@ -0,0 +1,24 @@ +""" + AbstractBoostVector <: AbstractBoostParameter + +An abstract base type representing vector-like boost parameters, used to model Lorentz boosts +in any spatial dimension. + +`AbstractBoostVector` extends [`AbstractBoostParameter`](@ref) and provides the framework for +describing boosts that act in multiple spatial dimensions simultaneously, typically in +three-dimensional space. This type is designed to support vector representations of +velocities (in units of the speed of light) associated with Lorentz transformations in +special relativity. + +## Usage + +Concrete subtypes of `AbstractBoostVector` represent specific boost vectors that describe +the velocity components in each spatial dimension, such as [`BetaVector`](@ref). These boost +vectors are commonly used in transformations of four-vectors (e.g., four-momentum, +four-position) between different reference frames. + +For example: +- [`BetaVector{T}`](@ref): A concrete subtype representing a boost vector with velocity components ``\\beta_x``, ``\\beta_y``, and ``\\beta_z`` (in units of the speed of light). + +""" +abstract type AbstractBoostVector <: AbstractBoostParameter end diff --git a/src/lorentz_boost/boost_parameter/boost_vector/utils.jl b/src/lorentz_boost/boost_parameter/boost_vector/utils.jl new file mode 100644 index 0000000..fceebfe --- /dev/null +++ b/src/lorentz_boost/boost_parameter/boost_vector/utils.jl @@ -0,0 +1,13 @@ + +function Base.isapprox( + b1::BetaVector, + b2::BetaVector; + atol::Real=0.0, + rtol::Real=Base.rtoldefault(b1.x, b1.y, atol), + nans::Bool=false, + norm::Function=abs, +) + return isapprox(b1.x, b2.x; atol=atol, rtol=rtol, nans=nans, norm=norm) && + isapprox(b1.y, b2.y; atol=atol, rtol=rtol, nans=nans, norm=norm) && + isapprox(b1.z, b2.z; atol=atol, rtol=rtol, nans=nans, norm=norm) +end diff --git a/src/lorentz_boost/types.jl b/src/lorentz_boost/types.jl new file mode 100644 index 0000000..70a83f1 --- /dev/null +++ b/src/lorentz_boost/types.jl @@ -0,0 +1,94 @@ + +""" + + Boost{V<:AbstractBoostParameter} <: AbstractLorentzBoost + +A concrete type representing a Lorentz boost transformation, parameterized by a boost +parameter `V`. The boost parameter can be either axis-specific or vector-like, depending +on the subtype of [`AbstractBoostParameter`](@ref) used. The `Boost` type is used to perform +Lorentz boosts on four-vectors (such as four-momentum or four-position) between different +inertial frames in special relativity. + +## Fields +- `param::V`: A boost parameter of type `V`, which is a subtype of `AbstractBoostParameter`. + This parameter defines the velocity (as a fraction of the speed of light, ``\\beta``) + and the direction of the boost (e.g., along a single axis or in multiple directions). + +## Overview + +A Lorentz boost is a transformation that adjusts the time and spatial components of a +four-vector based on the relative velocity between two reference frames. The `Boost` +struct provides a general and flexible implementation of such a boost, where the type of +the boost parameter determines the direction and magnitude of the boost. + +Depending on the boost parameter `V`, the boost can be: +- **Axis-specific**: When `V` is an axis-specific boost parameter (e.g., `BetaX`), the + boost will be along that axis. +- **Vector-like**: When `V` is a vector of boost parameters (e.g., `BetaVector`), the + boost will have components in multiple spatial directions. + +## Example +To create a Lorentz boost along the x-axis using the `BetaX` boost parameter: + +```jldoctest example_boost_x +julia> using QEDcore + +julia> beta_x = BetaX(0.5) +BetaX{Float64}(0.5) + +julia> boost_x = Boost(beta_x) +Boost{BetaX{Float64}}(BetaX{Float64}(0.5)) +``` +To perform a Lorentz boost using the `boost_x` object, you can apply it to a four-vector, +such as four-momentum: + +```jldoctest example_boost_x +julia> p = SFourMomentum(4, 3, 2, 1) +4-element SFourMomentum with indices SOneTo(4): + 4.0 + 3.0 + 2.0 + 1.0 + +julia> p_prime = boost_x(p) # Perform the boost +4-element SFourMomentum with indices SOneTo(4): + 2.886751345948129 + 1.1547005383792517 + 2.0 + 1.0 + +julia> @assert isapprox(p*p, p_prime*p_prime) # The invariant mass is preserved +``` + +## Notes + +The `Boost` type provides a unified and flexible interface for applying Lorentz boosts, +with the boost parameter `V` determining the specific form of the transformation. +Lorentz boosts preserve the spacetime interval, meaning that applying the boost to a +four-vector will not change the invariant quantity. + +## See Also + +* [`AbstractBoostParameter`](@ref): Base type for specific kinds of boost parameters. +* [`BetaX`](@ref): Boost parameter for the x-axis. +* [`BetaY`](@ref): Boost parameter for the y-axis. +* [`BetaZ`](@ref): Boost parameter for the z-axis. +* [`BetaVector`](@ref): Vector of boost parameters for boosts in multiple spatial directions. +""" +struct Boost{T<:AbstractBoostParameter} <: AbstractLorentzBoost + param::T +end +boost_type(::Boost{T}) where {T} = T +Base.eltype(boost::Boost) = eltype(boost.param) + +# defaults +Boost(x::Real) = Boost(BetaX(x)) +Boost(x::Real, y::Real, z::Real) = Boost(BetaVector(x, y, z)) + +function _transform(boost::Boost, p::AbstractFourMomentum) + return _transform(boost.param, p) +end + +function Base.inv(boost::Boost) + return Boost(_inv(boost.param)) +end diff --git a/src/patch_QEDbase.jl b/src/patch_QEDbase.jl new file mode 100644 index 0000000..f88fc7c --- /dev/null +++ b/src/patch_QEDbase.jl @@ -0,0 +1,170 @@ +# This can be removed, if https://github.com/QEDjl-project/QEDbase.jl/pull/129 is merged +# and released. + +####### +# General coordinate transformations +####### + +""" + AbstractCoordinateTransformation + +Abstract base type for coordinate transformations supposed to be acting on four-momenta. +Every subtype of `trafo::AbstractCoordinateTransformation` should implement the following interface functions: + +* `QEDcore._transform(trafo,p)`: transforms `p` +* `Base.inv(trafo)`: returns the inverted transform + +## Example + +Implementing the interface by defining the interface functions: + +```jldoctest trafo_interface +julia> using QEDcore + +julia> struct TestTrafo{T} <: QEDcore.AbstractCoordinateTransformation + a::T + end + +julia> QEDcore._transform(trafo::TestTrafo,p) = trafo.a*p + +julia> Base.inv(trafo::TestTrafo) = TestTrafo(inv(trafo.a)) + +``` + +The `TestTrafo` can then be used to transform four-momenta: + +```jldoctest trafo_interface +julia> trafo = TestTrafo(2.0) +TestTrafo{Float64}(2.0) + +julia> p = SFourMomentum(4,3,2,1) +4-element SFourMomentum with indices SOneTo(4): + 4.0 + 3.0 + 2.0 + 1.0 + +julia> trafo(p) # multiply every component with 2.0 +4-element SFourMomentum with indices SOneTo(4): + 8.0 + 6.0 + 4.0 + 2.0 + +julia> inv(trafo)(p) # divide every component by 2.0 +4-element SFourMomentum with indices SOneTo(4): + 2.0 + 1.5 + 1.0 + 0.5 +``` +""" +abstract type AbstractCoordinateTransformation end +Base.broadcastable(trafo::AbstractCoordinateTransformation) = Ref(trafo) + +""" + _transform(trafo::AbstractCoordinateTransformation,p::AbstractFourMomentum) + +Interface function for the application of the transformation to the four-momentum `p`. Must return a four-momentum +of the same type as `p`. +""" +function _transform end + +# make the transform callable +@inline function (trafo::AbstractCoordinateTransformation)(p::AbstractFourMomentum) + return _transform(trafo, p) +end + +@inline function (trafo::AbstractCoordinateTransformation)( + psf::PSF +) where {PSF<:AbstractParticleStateful} + p_prime = _transform(trafo, momentum(psf)) + return PSF(p_prime) +end + +@inline function (trafo::AbstractCoordinateTransformation)( + psp::PSP +) where {PSP<:AbstractPhaseSpacePoint} + in_moms = momenta(psp, Incoming()) + out_moms = momenta(psp, Outgoing()) + in_moms_prime = _transform.(trafo, in_moms) + out_moms_prime = _transform.(trafo, out_moms) + + proc = process(psp) + mod = model(psp) + ps_def = phase_space_definition(psp) + return PhaseSpacePoint(proc, mod, ps_def, in_moms_prime, out_moms_prime) +end + +######### +# Abstract Lorentz Boosts +######### + +""" + + AbstractLorentzTransformation <: AbstractCoordinateTransformation + +An abstract base type representing Lorentz transformations, which are coordinate +transformations between inertial and reference frames in special relativity. + +`AbstractLorentzTransformation` extends `AbstractCoordinateTransformation` and provides +the foundational framework for all types of Lorentz transformations, including boosts. +These transformations preserve the Minkowski product of two four-vectors and are fundamental to +the description of relativistic physics, ensuring the laws of physics are the same in all +inertial frames. + +### Usage + +Subtypes of `AbstractLorentzTransformation` implement specific kinds of Lorentz transformations. +For example: +- [`Boost{T}`](@ref): A concrete implementation of Lorentz boosts with boost parameter `T` (see also [`AbstractBoostParameter`](@ref)). + +These subtypes perform transformations on four-vectors (such as [`SFourMomentum`](@ref)) between different inertial reference frames. +""" +abstract type AbstractLorentzTransformation <: AbstractCoordinateTransformation end + +""" + + AbstractLorentzBoost <: AbstractLorentzTransformation + +An abstract base type representing Lorentz boosts, a specific type of Lorentz transformation +associated with relative motion between inertial frames along one or more spatial directions. + +`AbstractLorentzBoost` extends `AbstractLorentzTransformation` and serves as the foundation +for all types of boost transformations in special relativity. Lorentz boosts describe how +four-vectors (such as [`SFourMomentum`](@ref)) change when transitioning between two reference frames moving at constant velocities (in units of the speed of light) relative to each other. + +For example: +- [`Boost{T}`](@ref): A concrete implementation of Lorentz boosts with boost parameter `T` (see also [`AbstractBoostParameter`](@ref)). + +""" +abstract type AbstractLorentzBoost <: AbstractLorentzTransformation end + +""" + + AbstractBoostParameter + +An abstract base type representing boost parameters used in Lorentz transformations, which +describe the relative motion between two inertial frames in special relativity. + +`AbstractBoostParameter` serves as the foundation for defining specific boost parameters +that control Lorentz boosts in different spatial directions. Boost parameters typically +represent the velocity of one reference frame relative to another, expressed as a fraction +of the speed of light (`\\beta`), and are essential for performing Lorentz transformations +on four-vectors (such as [`SFourMomentum`](@ref)). + +## Overview + +In the context of special relativity, a Lorentz boost is a transformation that changes the +time and spatial components of a four-vector based on the relative motion between two +inertial reference frames. For example, the boost parameter ``\\beta`` is dimensionless and represents +this velocity as a fraction of the speed of light. Depending on the frame's relative velocity, +different forms of boost parameters exist, such as those associated with a single axis or +a vector describing boosts in multiple spatial dimensions. + +The `AbstractBoostParameter` type is the parent type for all specific kinds of boost parameters, including: +- **Axis-specific Boost Parameters**: Such as [`BetaX`](@ref), which describes a boost along the x-axis. +- **Vector-like Boost Parameters**: Such as [`BetaVector`](@ref), which describes boosts with components in multiple spatial directions. + +""" +abstract type AbstractBoostParameter end diff --git a/test/lorentz_transform/lorentz_transform.jl b/test/lorentz_transform/lorentz_transform.jl new file mode 100644 index 0000000..3388295 --- /dev/null +++ b/test/lorentz_transform/lorentz_transform.jl @@ -0,0 +1,149 @@ +using QEDcore +using Random + +include("utils.jl") +include("../test_implementation/TestImplementation.jl") + +const RNG = MersenneTwister(12345) +const ATOL = 1e-15 + +const test_mom = rand(RNG, SFourMomentum) +const test_psf = ParticleStateful( + Incoming(), rand(RNG, TestImplementation.PARTICLE_SET), test_mom +) +const test_mass_square = test_mom * test_mom + +const TESTMODEL = TestImplementation.TestModel() +const TESTPSDEF = TestImplementation.TestPhasespaceDef() + +@testset "beta boost" begin + @testset "defaults" begin + xyz = rand(RNG, 3) + xyz = @. (2 * xyz - 1) / sqrt(3) + x, y, z = xyz + boost_x_default = Boost(x) + @test boost_x_default.param == BetaX(x) + + boost_vec_default = Boost(x, y, z) + @test boost_vec_default.param == BetaVector(x, y, z) + end + + @testset "$val_type" for val_type in (Float64, Float32) + @testset "axis beta" begin + @testset "$beta_param_type" for beta_param_type in (BetaX, BetaY, BetaZ) + test_beta_val = 2 * rand(RNG, val_type) - 1 + test_beta = beta_param_type(test_beta_val) + + @testset "element type" begin + @test eltype(test_beta) == val_type + end + + # test conversions + for comp_val_type in (Float64, Float32) + comp_beta = beta_param_type(comp_val_type(test_beta_val)) + + @testset "convert element" begin + test_beta_after = beta_param_type{comp_val_type}(test_beta_val) + @test test_beta_after == comp_beta + end + + @testset "convert type" begin + test_beta_after = convert(beta_param_type{comp_val_type}, test_beta) + @test test_beta_after == comp_beta + end + end + end + end + end + + @testset "$boost_param_type" for boost_param_type in (BetaVector, BetaX, BetaY, BetaZ) + test_param = _rand(RNG, boost_param_type) + boost = Boost(test_param) + + @testset "invariance" begin + test_mom_prime = boost(test_mom) + test_psf_prime = boost(test_psf) + @test isapprox(test_mom_prime * test_mom_prime, test_mass_square) + @test isapprox( + momentum(test_psf_prime) * momentum(test_psf_prime), test_mass_square + ) + end + + @testset "inversion" begin + inv_boost_direct = Boost(-test_param) + inv_boost = inv(boost) + + @test isapprox(inv_boost_direct(boost(test_mom)), test_mom) + @test isapprox(inv_boost(boost(test_mom)), test_mom) + end + + @testset "phase space point" begin + test_param = _rand(RNG, boost_param_type) + boost = Boost(test_param) + @testset "($N_INCOMING,$N_OUTGOING)" for (N_INCOMING, N_OUTGOING) in + Iterators.product( + (1, rand(RNG, 2:8)), (1, rand(RNG, 2:8)) + ) + INCOMING_PARTICLES = Tuple( + rand(RNG, TestImplementation.PARTICLE_SET, N_INCOMING) + ) + OUTGOING_PARTICLES = Tuple( + rand(RNG, TestImplementation.PARTICLE_SET, N_OUTGOING) + ) + + TESTPROC = TestImplementation.TestProcess( + INCOMING_PARTICLES, OUTGOING_PARTICLES + ) + IN_PS = TestImplementation._rand_momenta(RNG, N_INCOMING) + OUT_PS = TestImplementation._rand_momenta(RNG, N_OUTGOING) + PSP = PhaseSpacePoint(TESTPROC, TESTMODEL, TESTPSDEF, IN_PS, OUT_PS) + + PSP_prime = boost(PSP) + @test isapprox( + [getMass2.(momenta(PSP, Incoming()))...], + [getMass2.(momenta(PSP_prime, Incoming()))...], + ) + @test isapprox( + [getMass2.(momenta(PSP, Outgoing()))...], + [getMass2.(momenta(PSP_prime, Outgoing()))...], + ) + end + end + end + + @testset "recover axis boost" begin + test_beta_vec = _rand_beta(RNG, Float64) + boost = Boost(test_beta_vec) + + @testset "x boost" begin + rnd_beta = rand(RNG) + beta_x = BetaX(rnd_beta) + beta_vec_x = BetaVector(rnd_beta, 0.0, 0.0) + + boost_axis = Boost(beta_x) + boost_vec = Boost(beta_vec_x) + + @test isapprox(boost_axis(test_mom), boost_vec(test_mom)) + end + @testset "y boost" begin + rnd_beta = rand(RNG) + beta_y = BetaY(rnd_beta) + beta_vec_y = BetaVector(0.0, rnd_beta, 0.0) + + boost_axis = Boost(beta_y) + boost_vec = Boost(beta_vec_y) + + @test isapprox(boost_axis(test_mom), boost_vec(test_mom)) + end + @testset "z boost" begin + rnd_beta = rand(RNG) + beta_z = BetaZ(rnd_beta) + beta_vec_z = BetaVector(0.0, 0.0, rnd_beta) + + boost_axis = Boost(beta_z) + boost_vec = Boost(beta_vec_z) + + @test isapprox(boost_axis(test_mom), boost_vec(test_mom)) + end + end +end diff --git a/test/lorentz_transform/utils.jl b/test/lorentz_transform/utils.jl new file mode 100644 index 0000000..e609e98 --- /dev/null +++ b/test/lorentz_transform/utils.jl @@ -0,0 +1,19 @@ +""" +Return a random beta vector. +""" +function _rand_beta(rng::AbstractRNG, ::Type{T}=Float64) where {T<:Real} + beta_xyz = rand(rng, T, 3) + beta_xyz .*= 2 + beta_xyz .-= 1 + beta_xyz ./= sqrt(3) + return BetaVector(beta_xyz...) +end + +@inline _rand(rng::AbstractRNG, ::Type{BetaVector}, ::Type{T}=Float64) where {T<:Real} = + _rand_beta(rng, T) + +function _rand( + rng::AbstractRNG, ::Type{B}, ::Type{T}=Float64 +) where {B<:QEDcore.AbstractAxisBeta,T<:Real} + return B(2 * rand(rng, T) - one(T)) +end diff --git a/test/particles/states.jl b/test/particles/states.jl index 97ef0a0..5de2404 100644 --- a/test/particles/states.jl +++ b/test/particles/states.jl @@ -5,7 +5,7 @@ using Random include("../utils.jl") RNG = MersenneTwister(708583836976) -ATOL = 1e-15 +ATOL = 1e-14 RTOL = 0.0 PHOTON_ENERGIES = (0.0, rand(RNG), rand(RNG) * 10) COS_THETAS = (-1.0, -rand(RNG), 0.0, rand(RNG), 1.0) diff --git a/test/runtests.jl b/test/runtests.jl index 47d20c0..afef197 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3,6 +3,10 @@ using Test using SafeTestsets begin + @time @safetestset "Lorentz transform" begin + include("lorentz_transform/lorentz_transform.jl") + end + @time @safetestset "phase spaces" begin include("phase_spaces.jl") end