diff --git a/src/QEDprocesses.jl b/src/QEDprocesses.jl index 6d6ddb3..3bb38ef 100644 --- a/src/QEDprocesses.jl +++ b/src/QEDprocesses.jl @@ -5,13 +5,16 @@ export AbstractModelDefinition, fundamental_interaction_type # Abstract process interface export AbstractProcessDefinition, incoming_particles, outgoing_particles -export in_phasespace_dimension, out_phasespace_dimension export number_incoming_particles, number_outgoing_particles # probabilities export differential_probability, unsafe_differential_probability export total_probability +# probabilities +export differential_probability, unsafe_differential_probability +export total_probability + # differential cross section export differential_cross_section, unsafe_differential_cross_section export total_cross_section @@ -34,8 +37,9 @@ include("utils.jl") include("interfaces/model_interface.jl") include("interfaces/process_interface.jl") include("interfaces/setup_interface.jl") -include("propagators.jl") include("phase_spaces.jl") +include("momentum_generation.jl") +include("propagators.jl") include("probabilities.jl") include("cross_sections.jl") end diff --git a/src/cross_sections.jl b/src/cross_sections.jl index 7a3c947..7f0925f 100644 --- a/src/cross_sections.jl +++ b/src/cross_sections.jl @@ -1,18 +1,17 @@ ######################## -# differential cross sections and probabilities. +# differential and total cross sections. # # This file contains default implementations for differential and total cross # sections based on the scattering process interface ######################## ############ -# # differential cross sections -# ############ # differential cross sections without energy momentum conservation check # single in phase space point/ single out phase space point +# based on four-momenta function _unsafe_differential_cross_section( proc::AbstractProcessDefinition, model::AbstractModelDefinition, @@ -33,6 +32,30 @@ function _unsafe_differential_cross_section( ) end +# differential cross sections without energy momentum conservation check +# single in phase space point/ single out phase space point +# based on coordinates +function _unsafe_differential_cross_section( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVector{T}, + out_phase_space_def::AbstractPhasespaceDefinition, + out_phase_space::AbstractVector{T}, +) where {T<:Real} + in_momenta, out_momenta = _generate_momenta( + proc, + model, + in_phase_space_def, + in_phase_space, + out_phase_space_def, + out_phase_space, + ) + return _unsafe_differential_cross_section( + proc, model, in_phase_space_def, in_momenta, out_phase_space_def, out_momenta + ) +end + # differential cross sections without energy momentum conservation check # single in phase space point/ several out phase space points function _unsafe_differential_cross_section( @@ -42,7 +65,7 @@ function _unsafe_differential_cross_section( in_phase_space::AbstractVector{T}, out_phase_space_def::AbstractPhasespaceDefinition, out_phase_space::AbstractMatrix{T}, -) where {T<:QEDbase.AbstractFourMomentum} +) where {T<:AbstractPhasespaceElement} res = Vector{eltype(T)}(undef, size(out_phase_space, 2)) for i in 1:size(out_phase_space, 2) res[i] = _unsafe_differential_cross_section( @@ -66,7 +89,7 @@ function _unsafe_differential_cross_section( in_phase_space::AbstractMatrix{T}, out_phase_space_def::AbstractPhasespaceDefinition, out_phase_space::AbstractVecOrMat{T}, -) where {T<:QEDbase.AbstractFourMomentum} +) where {T<:AbstractPhasespaceElement} res = Matrix{eltype(T)}(undef, size(in_phase_space, 2), size(out_phase_space, 2)) for i in 1:size(in_phase_space, 2) res[i, :] .= _unsafe_differential_cross_section( @@ -92,7 +115,7 @@ end out_phase_space::AbstractVecOrMat{T}, ) where {T<:QEDbase.AbstractFourMomentum} -Return the differential cross section without checking if the given phase space(s) are physical. +Return the differential cross section evaluated at the four-momenta without checking if the given phase space(s) are physical. """ function unsafe_differential_cross_section( proc::AbstractProcessDefinition, @@ -102,17 +125,41 @@ function unsafe_differential_cross_section( out_phase_space_def::AbstractPhasespaceDefinition, out_phase_space::AbstractVecOrMat{T}, ) where {T<:QEDbase.AbstractFourMomentum} - size(in_phase_space, 1) == number_incoming_particles(proc) || throw( - DimensionMismatch( - "The number of incoming particles <$(number_incoming_particles(proc))> is inconsistent with input size <$(size(in_phase_space,1))>", - ), - ) + _check_in_phase_space_dimension(proc, model, in_phase_space) + _check_out_phase_space_dimension(proc, model, out_phase_space) - size(out_phase_space, 1) == number_outgoing_particles(proc) || throw( - DimensionMismatch( - "The number of outgoing particles <$(number_outgoing_particles(proc))> is inconsistent with input size <$(size(out_phase_space,1))>", - ), + return _unsafe_differential_cross_section( + proc, + model, + in_phase_space_def, + in_phase_space, + out_phase_space_def, + out_phase_space, ) +end + +""" + unsafe_differential_cross_section( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVecOrMat{T}, + out_phase_space_def::AbstractPhasespaceDefinition, + out_phase_space::AbstractVecOrMat{T}, +) where {T<:Real} + +Return the differential cross section evaluated at the coordinates without checking if the given phase space(s) are physical. +""" +function unsafe_differential_cross_section( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVecOrMat{T}, + out_phase_space_def::AbstractPhasespaceDefinition, + out_phase_space::AbstractVecOrMat{T}, +) where {T<:Real} + _check_in_phase_space_dimension(proc, model, in_phase_space) + _check_out_phase_space_dimension(proc, model, out_phase_space) return _unsafe_differential_cross_section( proc, @@ -157,6 +204,27 @@ end # differential cross sections with energy momentum conservation check # single in phase space point/ several out phase space points +function _differential_cross_section( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVector{T}, + out_phase_space_def::AbstractPhasespaceDefinition, + out_phase_space::AbstractVector{T}, +)::Float64 where {T<:Real} + in_momenta, out_momenta = _generate_momenta( + proc, + model, + in_phase_space_def, + in_phase_space, + out_phase_space_def, + out_phase_space, + ) + return _differential_cross_section( + proc, model, in_phase_space_def, in_momenta, out_phase_space_def, out_momenta + ) +end + function _differential_cross_section( proc::AbstractProcessDefinition, model::AbstractModelDefinition, @@ -164,7 +232,7 @@ function _differential_cross_section( in_phase_space::AbstractVector{T}, out_phase_space_def::AbstractPhasespaceDefinition, out_phase_space::AbstractMatrix{T}, -) where {T<:QEDbase.AbstractFourMomentum} +) where {T<:AbstractPhasespaceElement} res = Vector{eltype(T)}(undef, size(out_phase_space, 2)) for i in 1:size(out_phase_space, 2) res[i] = _differential_cross_section( @@ -188,7 +256,7 @@ function _differential_cross_section( in_phase_space::AbstractMatrix{T}, out_phase_space_def::AbstractPhasespaceDefinition, out_phase_space::AbstractVecOrMat{T}, -) where {T<:QEDbase.AbstractFourMomentum} +) where {T<:AbstractPhasespaceElement} res = Matrix{eltype(T)}(undef, size(in_phase_space, 2), size(out_phase_space, 2)) for i in 1:size(in_phase_space, 2) res[i, :] .= _differential_cross_section( @@ -213,7 +281,7 @@ end out_phase_space::AbstractVecOrMat{T}, ) where {T<:QEDbase.AbstractFourMomentum} -If the given phase spaces are physical, return differential cross section. Zero otherwise +If the given phase spaces are physical, return differential cross section evaluated at the four-momenta. Zero otherwise. """ function differential_cross_section( @@ -224,17 +292,41 @@ function differential_cross_section( out_phase_space_def::AbstractPhasespaceDefinition, out_phase_space::AbstractVecOrMat{T}, ) where {T<:QEDbase.AbstractFourMomentum} - size(in_phase_space, 1) == number_incoming_particles(proc) || throw( - DimensionMismatch( - "The number of incoming particles <$(number_incoming_particles(proc))> is inconsistent with input size <$(size(in_phase_space,1))>", - ), - ) + _check_in_phase_space_dimension(proc, model, in_phase_space) + _check_out_phase_space_dimension(proc, model, out_phase_space) - size(out_phase_space, 1) == number_outgoing_particles(proc) || throw( - DimensionMismatch( - "The number of outgoing particles <$(number_outgoing_particles(proc))> is inconsistent with input size <$(size(out_phase_space,1))>", - ), + return _differential_cross_section( + proc, + model, + in_phase_space_def, + in_phase_space, + out_phase_space_def, + out_phase_space, ) +end + +""" + differential_cross_section( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVecOrMat{T}, + out_phase_space_def::AbstractPhasespaceDefinition, + out_phase_space::AbstractVecOrMat{T}, +) where {T<:Real} + +If the given phase spaces are physical, return differential cross section evaluated at the coordinates. Zero otherwise. +""" +function differential_cross_section( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVecOrMat{T}, + out_phase_space_def::AbstractPhasespaceDefinition, + out_phase_space::AbstractVecOrMat{T}, +) where {T<:Real} + _check_in_phase_space_dimension(proc, model, in_phase_space) + _check_out_phase_space_dimension(proc, model, out_phase_space) return _differential_cross_section( proc, @@ -251,6 +343,7 @@ end ############ # total cross section on single phase space point +# based on four-momenta function _total_cross_section( proc::AbstractProcessDefinition, model::AbstractModelDefinition, @@ -262,13 +355,25 @@ function _total_cross_section( return I * _total_probability(proc, model, in_phase_space_def, in_phase_space) end +# total cross section on single phase space point +# based on coordinates +function _total_cross_section( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVector{T}, +) where {T<:Real} + in_momenta = _generate_incoming_momenta(proc, model, in_phase_space_def, in_phase_space) + return _total_cross_section(proc, model, in_phase_space_def, in_momenta) +end + # total cross section on several phase space points function _total_cross_section( proc::AbstractProcessDefinition, model::AbstractModelDefinition, in_phase_space_def::AbstractPhasespaceDefinition, in_phase_space::AbstractMatrix{T}, -) where {T<:QEDbase.AbstractFourMomentum} +) where {T<:AbstractPhasespaceElement} res = Vector{eltype(T)}(undef, size(in_phase_space, 2)) for i in 1:size(in_phase_space, 2) res[i] = _total_cross_section( @@ -286,7 +391,7 @@ end in_phase_space::AbstractVecOrMat{T}, ) where {T<:QEDbase.AbstractFourMomentum} -Return the total cross section for a given combination of scattering process and compute model. +Return the total cross section for a given combination of scattering process and compute model, evaluated at the particle momenta. """ function total_cross_section( proc::AbstractProcessDefinition, @@ -294,11 +399,28 @@ function total_cross_section( in_phase_space_def::AbstractPhasespaceDefinition, in_phase_space::AbstractVecOrMat{T}, ) where {T<:QEDbase.AbstractFourMomentum} - size(in_phase_space, 1) == number_incoming_particles(proc) || throw( - DimensionMismatch( - "The number of incoming particles <$(number_incoming_particles(proc))> is inconsistent with input size <$(size(in_phase_space,1))>", - ), - ) + _check_in_phase_space_dimension(proc, model, in_phase_space) + + return _total_cross_section(proc, model, in_phase_space_def, in_phase_space) +end + +""" + total_cross_section( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVecOrMat{T}, + ) where {T<:Real} + +Return the total cross section for a given combination of scattering process and compute model, evaluated at the coordinates. +""" +function total_cross_section( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVecOrMat{T}, +) where {T<:Real} + _check_in_phase_space_dimension(proc, model, in_phase_space) return _total_cross_section(proc, model, in_phase_space_def, in_phase_space) end diff --git a/src/interfaces/process_interface.jl b/src/interfaces/process_interface.jl index 4e721be..15fc2f2 100644 --- a/src/interfaces/process_interface.jl +++ b/src/interfaces/process_interface.jl @@ -141,9 +141,9 @@ function _averaging_norm end proc::AbstractProcessDefinition, model::AbstractModelDefinition, in_ps_def::InPhasespaceDefinition, - in_phase_space::AbstractVector{T} + in_ps::AbstractVector{T} out_ps_def::OutPhasespaceDefinition, - out_phase_space::AbstractVector{T} + out_ps::AbstractVector{T} ) where {T<:QEDbase.AbstractFourMomentum} Interface function, which returns `true`, if the combination of the given incoming and outgoing phase space @@ -200,6 +200,24 @@ Return the number of outgoing particles of a given process. return length(outgoing_particles(proc_def)) end +""" + in_phase_space_dimension( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + ) +TBW +""" +function in_phase_space_dimension end + +""" + out_phase_space_dimension( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + ) +TBW +""" +function out_phase_space_dimension end + """ _total_probability( proc::AbstractProcessDefinition, diff --git a/src/momentum_generation.jl b/src/momentum_generation.jl new file mode 100644 index 0000000..c6e3014 --- /dev/null +++ b/src/momentum_generation.jl @@ -0,0 +1,58 @@ +##### +# Generation of four-momenta from coordinates +# +# This file contains the interface and functionality to compute momenta from +# given coordinates. +##### + +""" + _generate_incoming_momenta + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVector{T}, + ) where {T<:Real} + +Interface function to generate the four-momenta of the incoming particles from coordinates for a given phase-space definition. +""" +function _generate_incoming_momenta end + +""" + _generate_outgoing_momenta + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + out_phase_space_def::AbstractPhasespaceDefinition, + out_phase_space::AbstractVector{T}, + ) where {T<:Real} + +Interface function to generate the four-momenta of the outgoing particles from coordinates for a given phase-space definition. +""" +function _generate_outgoing_momenta end + +""" + _generate_momenta( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVector{T}, + out_phase_space_def::AbstractPhasespaceDefinition, + out_phase_space::AbstractVector{T}, +) where {T<:Real} + +Return four-momenta for incoming and outgoing particles for given coordinate based phase-space points. +""" +function _generate_momenta( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVector{T}, + out_phase_space_def::AbstractPhasespaceDefinition, + out_phase_space::AbstractVector{T}, +) where {T<:Real} + in_momenta = _generate_incoming_momenta(proc, model, in_phase_space_def, in_phase_space) + out_momenta = _generate_outgoing_momenta( + proc, model, out_phase_space_def, out_phase_space + ) + + return in_momenta, out_momenta +end diff --git a/src/phase_spaces.jl b/src/phase_spaces.jl index ba2f64a..d35fe36 100644 --- a/src/phase_spaces.jl +++ b/src/phase_spaces.jl @@ -3,6 +3,8 @@ # # This file contains a collection of types and functions to handle phase spaces # for scattering processes. +# +# TODO: ship to interfaces! ##################### abstract type AbstractCoordinateSystem end @@ -13,8 +15,71 @@ struct CenterOfMomentumFrame <: AbstractFrameOfReference end struct ElectronRestFrame <: AbstractFrameOfReference end abstract type AbstractPhasespaceDefinition end + +""" + + PhasespaceDefinition(coord_sys::AbstractCoordinateSystem, frame::AbstractFrameOfReference) + +Convenient type to dispatch on coordiante systems and frames of reference. +""" struct PhasespaceDefinition{CS<:AbstractCoordinateSystem,F<:AbstractFrameOfReference} <: AbstractPhasespaceDefinition coord_sys::CS frame::F end + +# abstract type for generic phase spaces +# +# Currently, elements can be either four-momenta, or real numbers, +# i.e. coordinates. +AbstractPhasespaceElement = Union{QEDbase.AbstractFourMomentum,Real} + +# utility functions + +@inline function _check_in_phase_space_dimension( + proc::AbstractProcessDefinition, + ::AbstractModelDefinition, + in_phase_space::AbstractVecOrMat{T}, +) where {T<:QEDbase.AbstractFourMomentum} + return size(in_phase_space, 1) == number_incoming_particles(proc) || throw( + DimensionMismatch( + "The number of incoming particles <$(number_incoming_particles(proc))> is inconsistent with input size <$(size(in_phase_space,1))>", + ), + ) +end + +@inline function _check_out_phase_space_dimension( + proc::AbstractProcessDefinition, + ::AbstractModelDefinition, + out_phase_space::AbstractVecOrMat{T}, +) where {T<:QEDbase.AbstractFourMomentum} + return size(out_phase_space, 1) == number_outgoing_particles(proc) || throw( + DimensionMismatch( + "The number of outgoing particles <$(number_outgoing_particles(proc))> is inconsistent with input size <$(size(out_phase_space,1))>", + ), + ) +end + +@inline function _check_in_phase_space_dimension( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space::AbstractVecOrMat{T}, +) where {T<:Real} + return size(in_phase_space, 1) == in_phase_space_dimension(proc, model) || throw( + DimensionMismatch( + "The dimension of the in-phase-space <$(in_phase_space_dimension(proc,model))> is inconsistent with input size <$(size(in_phase_space,1))>", + ), + ) +end + +@inline function _check_out_phase_space_dimension( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + out_phase_space::AbstractVecOrMat{T}, +) where {T<:Real} + return size(out_phase_space, 1) == out_phase_space_dimension(proc, model) || throw( + DimensionMismatch( + "The dimension of the out-phase-space <$(out_phase_space_dimension(proc,model))> is inconsistent with input size <$(size(out_phase_space,1))>", + ), + ) +end diff --git a/src/probabilities.jl b/src/probabilities.jl index 798a0bc..97e3fb2 100644 --- a/src/probabilities.jl +++ b/src/probabilities.jl @@ -8,6 +8,7 @@ # differential probability without energy momentum conservation check # single in phase space points/ single out phase space point +# based on four-momenta function _unsafe_differential_probability( proc::AbstractProcessDefinition, model::AbstractModelDefinition, @@ -34,6 +35,29 @@ function _unsafe_differential_probability( return normalization * sum(matrix_elements_sq) * ps_fac end +# differential probability without energy momentum conservation check +# based on coordinates +function _unsafe_differential_probability( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVector{T}, + out_phase_space_def::AbstractPhasespaceDefinition, + out_phase_space::AbstractVector{T}, +) where {T<:Real} + in_momenta, out_momenta = _generate_momenta( + proc, + model, + in_phase_space_def, + in_phase_space, + out_phase_space_def, + out_phase_space, + ) + return _unsafe_differential_probability( + proc, model, in_phase_space_def, in_momenta, out_phase_space_def, out_momenta + ) +end + # differential probability without energy momentum conservation check # single in phase space points/ several out phase space point function _unsafe_differential_probability( @@ -43,7 +67,7 @@ function _unsafe_differential_probability( in_phase_space::AbstractVector{T}, out_phase_space_def::AbstractPhasespaceDefinition, out_phase_space::AbstractMatrix{T}, -) where {T<:QEDbase.AbstractFourMomentum} +) where {T<:AbstractPhasespaceElement} res = Vector{eltype(T)}(undef, size(out_phase_space, 2)) for i in 1:size(out_phase_space, 2) res[i] = _unsafe_differential_probability( @@ -67,7 +91,7 @@ function _unsafe_differential_probability( in_phase_space::AbstractMatrix{T}, out_phase_space_def::AbstractPhasespaceDefinition, out_phase_space::AbstractVecOrMat{T}, -) where {T<:QEDbase.AbstractFourMomentum} +) where {T<:AbstractPhasespaceElement} res = Matrix{eltype(T)}(undef, size(in_phase_space, 2), size(out_phase_space, 2)) for i in 1:size(in_phase_space, 2) res[i, :] .= _unsafe_differential_probability( @@ -92,7 +116,7 @@ end out_phase_space::AbstractVecOrMat{T}, ) where {T<:QEDbase.AbstractFourMomentum} -Return differential probability without checking if the given phase space(s) are physical. +Return differential probability evaluated at the four-momenta without checking if the given phase space(s) are physical. """ function unsafe_differential_probability( proc::AbstractProcessDefinition, @@ -102,17 +126,41 @@ function unsafe_differential_probability( out_phase_space_def::AbstractPhasespaceDefinition, out_phase_space::AbstractVecOrMat{T}, ) where {T<:QEDbase.AbstractFourMomentum} - size(in_phase_space, 1) == number_incoming_particles(proc) || throw( - DimensionMismatch( - "The number of incoming particles <$(number_incoming_particles(proc))> is inconsistent with input size <$(size(in_phase_space,1))>", - ), - ) + _check_in_phase_space_dimension(proc, model, in_phase_space) + _check_out_phase_space_dimension(proc, model, out_phase_space) - size(out_phase_space, 1) == number_outgoing_particles(proc) || throw( - DimensionMismatch( - "The number of outgoing particles <$(number_outgoing_particles(proc))> is inconsistent with input size <$(size(out_phase_space,1))>", - ), + return _unsafe_differential_probability( + proc, + model, + in_phase_space_def, + in_phase_space, + out_phase_space_def, + out_phase_space, ) +end + +""" + unsafe_differential_probability( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVecOrMat{T}, + out_phase_space_def::AbstractPhasespaceDefinition, + out_phase_space::AbstractVecOrMat{T}, + ) where {T<:Real} + +Return differential probability evaluated at the coordinates without checking if the given phase space(s) are physical. +""" +function unsafe_differential_probability( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVecOrMat{T}, + out_phase_space_def::AbstractPhasespaceDefinition, + out_phase_space::AbstractVecOrMat{T}, +) where {T<:Real} + _check_in_phase_space_dimension(proc, model, in_phase_space) + _check_out_phase_space_dimension(proc, model, out_phase_space) return _unsafe_differential_probability( proc, @@ -125,7 +173,8 @@ function unsafe_differential_probability( end # differential probability with energy momentum conservation check -# one in phase space points/ one out phase space point +# one in phase space point/ one out phase space point +# based on four-momenta function _differential_probability( proc::AbstractProcessDefinition, model::AbstractModelDefinition, @@ -155,6 +204,30 @@ function _differential_probability( ) end +# differential probability with energy momentum conservation check +# one in phase space point/ one out phase space point +# based on coordinates +function _differential_probability( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVector{T}, + out_phase_space_def::AbstractPhasespaceDefinition, + out_phase_space::AbstractVector{T}, +) where {T<:Real} + in_momenta, out_momenta = _generate_momenta( + proc, + model, + in_phase_space_def, + in_phase_space, + out_phase_space_def, + out_phase_space, + ) + return _differential_probability( + proc, model, in_phase_space_def, in_momenta, out_phase_space_def, out_momenta + ) +end + # differential probability with energy momentum conservation check # one in phase space points/ several out phase space point function _differential_probability( @@ -164,7 +237,7 @@ function _differential_probability( in_phase_space::AbstractVector{T}, out_phase_space_def::AbstractPhasespaceDefinition, out_phase_space::AbstractMatrix{T}, -) where {T<:QEDbase.AbstractFourMomentum} +) where {T<:AbstractPhasespaceElement} res = Vector{eltype(T)}(undef, size(out_phase_space, 2)) for i in 1:size(out_phase_space, 2) res[i] = _differential_probability( @@ -188,7 +261,7 @@ function _differential_probability( in_phase_space::AbstractMatrix{T}, out_phase_space_def::AbstractPhasespaceDefinition, out_phase_space::AbstractVecOrMat{T}, -) where {T<:QEDbase.AbstractFourMomentum} +) where {T<:AbstractPhasespaceElement} res = Matrix{eltype(T)}(undef, size(in_phase_space, 2), size(out_phase_space, 2)) for i in 1:size(in_phase_space, 2) res[i, :] .= _differential_probability( @@ -213,7 +286,7 @@ end out_phase_space::AbstractVecOrMat{T}, ) where {T<:QEDbase.AbstractFourMomentum} -Return the differential cross section if the given phase spaces are physical, and zero otherwise. +If the given phase spaces are physical, return differential probability evaluated at the four-momenta. Zero otherwise. """ function differential_probability( proc::AbstractProcessDefinition, @@ -223,17 +296,41 @@ function differential_probability( out_phase_space_def::AbstractPhasespaceDefinition, out_phase_space::AbstractVecOrMat{T}, ) where {T<:QEDbase.AbstractFourMomentum} - size(in_phase_space, 1) == number_incoming_particles(proc) || throw( - DimensionMismatch( - "The number of incoming particles <$(number_incoming_particles(proc))> is inconsistent with input size <$(size(in_phase_space,1))>", - ), - ) + _check_in_phase_space_dimension(proc, model, in_phase_space) + _check_out_phase_space_dimension(proc, model, out_phase_space) - size(out_phase_space, 1) == number_outgoing_particles(proc) || throw( - DimensionMismatch( - "The number of outgoing particles <$(number_outgoing_particles(proc))> is inconsistent with input size <$(size(out_phase_space,1))>", - ), + return _differential_probability( + proc, + model, + in_phase_space_def, + in_phase_space, + out_phase_space_def, + out_phase_space, ) +end + +""" + differential_probability( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVecOrMat{T}, + out_phase_space_def::AbstractPhasespaceDefinition, + out_phase_space::AbstractVecOrMat{T}, +) where {T<:Real} + +If the given phase spaces are physical, return differential probability evaluated at the coordinates. Zero otherwise. +""" +function differential_probability( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVecOrMat{T}, + out_phase_space_def::AbstractPhasespaceDefinition, + out_phase_space::AbstractVecOrMat{T}, +) where {T<:Real} + _check_in_phase_space_dimension(proc, model, in_phase_space) + _check_out_phase_space_dimension(proc, model, out_phase_space) return _differential_probability( proc, @@ -249,13 +346,25 @@ end # Total probability ########### -# total probability on several phase space point +# total probability on a phase space point +# based on coordinates +function _total_probability( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVector{T}, +) where {T<:Real} + in_momenta = _generate_incoming_momenta(proc, model, in_phase_space_def, in_phase_space) + return _total_probability(proc, model, in_phase_space_def, in_momenta) +end + +# total probability on several phase space points function _total_probability( proc::AbstractProcessDefinition, model::AbstractModelDefinition, in_phase_space_def::AbstractPhasespaceDefinition, in_phase_space::AbstractMatrix{T}, -) where {T<:QEDbase.AbstractFourMomentum} +) where {T<:AbstractPhasespaceElement} res = Vector{eltype(T)}(undef, size(in_phase_space, 2)) for i in 1:size(in_phase_space, 2) res[i] = _total_probability( @@ -273,7 +382,7 @@ end in_phase_space::AbstractMatrix{T}, ) where {T<:QEDbase.AbstractFourMomentum} -Return the total probability of a given model and process combination. +Return the total probability of a given model and process combination, evaluated at the particle momenta. """ function total_probability( proc::AbstractProcessDefinition, @@ -281,11 +390,28 @@ function total_probability( in_phase_space_def::AbstractPhasespaceDefinition, in_phase_space::AbstractVecOrMat{T}, ) where {T<:QEDbase.AbstractFourMomentum} - size(in_phase_space, 1) == number_incoming_particles(proc) || throw( - DimensionMismatch( - "The number of incoming particles <$(number_incoming_particles(proc))> is inconsistent with input size <$(size(in_phase_space,1))>", - ), - ) + _check_in_phase_space_dimension(proc, model, in_phase_space) + + return _total_probability(proc, model, in_phase_space_def, in_phase_space) +end + +""" + total_probability( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractMatrix{T}, + ) where {T<:Real} + +Return the total probability of a given model and process combination, evaluated at the coordinates. +""" +function total_probability( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVecOrMat{T}, +) where {T<:Real} + _check_in_phase_space_dimension(proc, model, in_phase_space) return _total_probability(proc, model, in_phase_space_def, in_phase_space) end diff --git a/test/cross_sections.jl b/test/cross_sections.jl index 3da0744..ed1811e 100644 --- a/test/cross_sections.jl +++ b/test/cross_sections.jl @@ -127,117 +127,210 @@ TESTPSDEF = TestImplementation.TestPhasespaceDef() @test_throws DimensionMismatch unsafe_differential_cross_section( TESTPROC, TESTMODEL, TESTPSDEF, P_IN, TESTPSDEF, P_OUT ) + + COORDS_IN = TestImplementation.flat_components(P_IN) + COORDS_OUT = TestImplementation.flat_components(P_OUT) + @test_throws DimensionMismatch unsafe_differential_cross_section( + TESTPROC, TESTMODEL, TESTPSDEF, COORDS_IN, TESTPSDEF, COORDS_OUT + ) end end end - end - @testset "safe" begin - @testset "compute" begin - for (P_IN, P_OUT) in p_combs_valid - diffCS = differential_cross_section( - TESTPROC, TESTMODEL, TESTPSDEF, P_IN, TESTPSDEF, P_OUT - ) - groundtruth = TestImplementation._groundtruth_safe_diffCS( - TESTPROC, P_IN, P_OUT - ) - @test isapprox(diffCS, groundtruth, atol=ATOL, rtol=RTOL) - end - end - @testset "invalid input" begin - for (P_IN, P_OUT) in p_combs - - # filter out all valid combinations - if !((P_IN, P_OUT) in p_combs_valid) - @test_throws DimensionMismatch differential_cross_section( + @testset "safe" begin + @testset "compute" begin + for (P_IN, P_OUT) in p_combs_valid + diffCS_on_moms = differential_cross_section( TESTPROC, TESTMODEL, TESTPSDEF, P_IN, TESTPSDEF, P_OUT ) + COORDS_IN = TestImplementation.flat_components(P_IN) + COORDS_OUT = TestImplementation.flat_components(P_OUT) + diffCS_on_coords = differential_cross_section( + TESTPROC, TESTMODEL, TESTPSDEF, COORDS_IN, TESTPSDEF, COORDS_OUT + ) + groundtruth = TestImplementation._groundtruth_safe_diffCS( + TESTPROC, P_IN, P_OUT + ) + @test isapprox(diffCS_on_moms, groundtruth, atol=ATOL, rtol=RTOL) + @test isapprox(diffCS_on_coords, groundtruth, atol=ATOL, rtol=RTOL) end end - end - end - @testset "total cross section" begin - @testset "compute" begin - for P_IN in (p_in_phys, p_in_set_phys) - groundtruth = TestImplementation._groundtruth_total_cross_section(P_IN) - totCS_on_moms = total_cross_section( - TESTPROC, TESTMODEL, TESTPSDEF, P_IN - ) - @test isapprox(totCS_on_moms, groundtruth, atol=ATOL, rtol=RTOL) + + @testset "invalid input" begin + for (P_IN, P_OUT) in p_combs + + # filter out all valid combinations + if !((P_IN, P_OUT) in p_combs_valid) + @test_throws DimensionMismatch differential_cross_section( + TESTPROC, TESTMODEL, TESTPSDEF, P_IN, TESTPSDEF, P_OUT + ) + + COORDS_IN = TestImplementation.flat_components(P_IN) + COORDS_OUT = TestImplementation.flat_components(P_OUT) + @test_throws DimensionMismatch differential_cross_section( + TESTPROC, + TESTMODEL, + TESTPSDEF, + COORDS_IN, + TESTPSDEF, + COORDS_OUT, + ) + end + end end end - @testset "invalid input" begin - for P_IN in (p_in_phys_invalid, p_in_set_phys_invalid) - @test_throws DimensionMismatch total_cross_section( - TESTPROC, TESTMODEL, TESTPSDEF, P_IN - ) + + @testset "total cross section" begin + @testset "compute" begin + for P_IN in (p_in_phys, p_in_set_phys) + groundtruth = TestImplementation._groundtruth_total_cross_section( + P_IN + ) + totCS_on_moms = total_cross_section( + TESTPROC, TESTMODEL, TESTPSDEF, P_IN + ) + + COORDS_IN = TestImplementation.flat_components(P_IN) + totCS_on_coords = total_cross_section( + TESTPROC, TESTMODEL, TESTPSDEF, COORDS_IN + ) + + @test isapprox(totCS_on_moms, groundtruth, atol=ATOL, rtol=RTOL) + @test isapprox(totCS_on_coords, groundtruth, atol=ATOL, rtol=RTOL) + end end - end - end - end + @testset "invalid input" begin + for P_IN in (p_in_phys_invalid, p_in_set_phys_invalid) + @test_throws DimensionMismatch total_cross_section( + TESTPROC, TESTMODEL, TESTPSDEF, P_IN + ) - @testset "differential probability" begin - @testset "unsafe compute" begin - for (P_IN, P_OUT) in p_combs_phys - prob = unsafe_differential_probability( - TESTPROC, TESTMODEL, TESTPSDEF, P_IN, TESTPSDEF, P_OUT - ) - groundtruth = TestImplementation._groundtruth_unsafe_probability( - TESTPROC, P_IN, P_OUT - ) - @test isapprox(prob, groundtruth, atol=ATOL, rtol=RTOL) + COORDS_IN = TestImplementation.flat_components(P_IN) + @test_throws DimensionMismatch total_cross_section( + TESTPROC, TESTMODEL, TESTPSDEF, COORDS_IN + ) + end + end end end - @testset "unsafe invalid input" begin - for (P_IN, P_OUT) in p_combs + @testset "differential probability" begin + @testset "unsafe" begin + @testset "compute" begin + for (P_IN, P_OUT) in p_combs_phys + prob_on_moms = unsafe_differential_probability( + TESTPROC, TESTMODEL, TESTPSDEF, P_IN, TESTPSDEF, P_OUT + ) + COORDS_IN = TestImplementation.flat_components(P_IN) + COORDS_OUT = TestImplementation.flat_components(P_OUT) + prob_on_coords = unsafe_differential_probability( + TESTPROC, TESTMODEL, TESTPSDEF, COORDS_IN, TESTPSDEF, COORDS_OUT + ) + groundtruth = TestImplementation._groundtruth_unsafe_probability( + TESTPROC, P_IN, P_OUT + ) + @test isapprox(prob_on_moms, groundtruth, atol=ATOL, rtol=RTOL) + @test isapprox(prob_on_coords, groundtruth, atol=ATOL, rtol=RTOL) + end + end - # filter out all valid combinations - if !((P_IN, P_OUT) in p_combs_valid) - @test_throws DimensionMismatch unsafe_differential_probability( - TESTPROC, TESTMODEL, TESTPSDEF, P_IN, TESTPSDEF, P_OUT - ) + @testset "invalid input" begin + for (P_IN, P_OUT) in p_combs + + # filter out all valid combinations + if !((P_IN, P_OUT) in p_combs_valid) + @test_throws DimensionMismatch unsafe_differential_probability( + TESTPROC, TESTMODEL, TESTPSDEF, P_IN, TESTPSDEF, P_OUT + ) + + COORDS_IN = TestImplementation.flat_components(P_IN) + COORDS_OUT = TestImplementation.flat_components(P_OUT) + @test_throws DimensionMismatch unsafe_differential_probability( + TESTPROC, + TESTMODEL, + TESTPSDEF, + COORDS_IN, + TESTPSDEF, + COORDS_OUT, + ) + end + end end end - end - @testset "safe compute" begin - for (P_IN, P_OUT) in p_combs_valid - prob = differential_probability( - TESTPROC, TESTMODEL, TESTPSDEF, P_IN, TESTPSDEF, P_OUT - ) - groundtruth = TestImplementation._groundtruth_safe_probability( - TESTPROC, P_IN, P_OUT - ) - @test isapprox(prob, groundtruth, atol=ATOL, rtol=RTOL) - end - end + @testset "safe" begin + @testset "compute" begin + for (P_IN, P_OUT) in p_combs_valid + prob_on_moms = differential_probability( + TESTPROC, TESTMODEL, TESTPSDEF, P_IN, TESTPSDEF, P_OUT + ) - @testset "safe invalid input" begin - for (P_IN, P_OUT) in p_combs + COORDS_IN = TestImplementation.flat_components(P_IN) + COORDS_OUT = TestImplementation.flat_components(P_OUT) + prob_on_coords = differential_probability( + TESTPROC, TESTMODEL, TESTPSDEF, COORDS_IN, TESTPSDEF, COORDS_OUT + ) + groundtruth = TestImplementation._groundtruth_safe_probability( + TESTPROC, P_IN, P_OUT + ) + @test isapprox(prob_on_moms, groundtruth, atol=ATOL, rtol=RTOL) + @test isapprox(prob_on_coords, groundtruth, atol=ATOL, rtol=RTOL) + end + end - # filter out all valid combinations - if !((P_IN, P_OUT) in p_combs_valid) - @test_throws DimensionMismatch differential_probability( - TESTPROC, TESTMODEL, TESTPSDEF, P_IN, TESTPSDEF, P_OUT - ) + @testset "invalid input" begin + for (P_IN, P_OUT) in p_combs + + # filter out all valid combinations + if !((P_IN, P_OUT) in p_combs_valid) + @test_throws DimensionMismatch differential_probability( + TESTPROC, TESTMODEL, TESTPSDEF, P_IN, TESTPSDEF, P_OUT + ) + + COORDS_IN = TestImplementation.flat_components(P_IN) + COORDS_OUT = TestImplementation.flat_components(P_OUT) + @test_throws DimensionMismatch differential_probability( + TESTPROC, + TESTMODEL, + TESTPSDEF, + COORDS_IN, + TESTPSDEF, + COORDS_OUT, + ) + end + end end end - end - @testset "total probability" begin - @testset "compute" begin - for P_IN in (p_in_phys, p_in_set_phys) - groundtruth = TestImplementation._groundtruth_total_probability(P_IN) - totCS_on_moms = total_probability(TESTPROC, TESTMODEL, TESTPSDEF, P_IN) + @testset "total probability" begin + @testset "compute" begin + for P_IN in (p_in_phys, p_in_set_phys) + groundtruth = TestImplementation._groundtruth_total_probability( + P_IN + ) + totCS_on_moms = total_probability( + TESTPROC, TESTMODEL, TESTPSDEF, P_IN + ) - @test isapprox(totCS_on_moms, groundtruth, atol=ATOL, rtol=RTOL) + COORDS_IN = TestImplementation.flat_components(P_IN) + totCS_on_coords = total_probability( + TESTPROC, TESTMODEL, TESTPSDEF, COORDS_IN + ) + + @test isapprox(totCS_on_moms, groundtruth, atol=ATOL, rtol=RTOL) + @test isapprox(totCS_on_coords, groundtruth, atol=ATOL, rtol=RTOL) + end end - end - @testset "invalid input" begin - for P_IN in (p_in_phys_invalid, p_in_set_phys_invalid) - @test_throws DimensionMismatch total_probability( - TESTPROC, TESTMODEL, TESTPSDEF, P_IN - ) + @testset "invalid input" begin + for P_IN in (p_in_phys_invalid, p_in_set_phys_invalid) + @test_throws DimensionMismatch total_probability( + TESTPROC, TESTMODEL, TESTPSDEF, P_IN + ) + + COORDS_IN = TestImplementation.flat_components(P_IN) + @test_throws DimensionMismatch total_probability( + TESTPROC, TESTMODEL, TESTPSDEF, COORDS_IN + ) + end end end end diff --git a/test/interfaces/process_interface.jl b/test/interfaces/process_interface.jl index 69135fd..35b4865 100644 --- a/test/interfaces/process_interface.jl +++ b/test/interfaces/process_interface.jl @@ -84,6 +84,19 @@ include("../test_implementation/TestImplementation.jl") end end + @testset "is in phasespace" begin + @test QEDprocesses._is_in_phasespace( + TESTPROC, TESTMODEL, TESTPSDEF, IN_PS, TESTPSDEF, OUT_PS + ) + + IN_PS_unphysical = deepcopy(IN_PS) + IN_PS_unphysical[1] = SFourMomentum(zeros(4)) + + @test !QEDprocesses._is_in_phasespace( + TESTPROC, TESTMODEL, TESTPSDEF, IN_PS_unphysical, TESTPSDEF, OUT_PS + ) + end + @testset "is in phasespace" begin @test QEDprocesses._is_in_phasespace( TESTPROC, TESTMODEL, TESTPSDEF, IN_PS, TESTPSDEF, OUT_PS diff --git a/test/test_implementation/groundtruths.jl b/test/test_implementation/groundtruths.jl index 22421cc..78731ba 100644 --- a/test/test_implementation/groundtruths.jl +++ b/test/test_implementation/groundtruths.jl @@ -63,6 +63,10 @@ function _groundtruth_phase_space_factor(in_ps, out_ps) return 1 / (prod(en_in) * prod(en_out)) end +function _groundtruth_generate_momenta(ps_coords) + moms = _furl_moms(ps_coords) + return moms +end """ _groundtruth_unsafe_probability(proc, in_ps, out_ps) diff --git a/test/test_implementation/test_process.jl b/test/test_implementation/test_process.jl index 239e354..9c56d37 100644 --- a/test/test_implementation/test_process.jl +++ b/test/test_implementation/test_process.jl @@ -37,6 +37,13 @@ function TestProcess_FAIL(rng::AbstractRNG, N_in::Int, N_out::Int) return TestProcess_FAIL(in_particles, out_particles) end +function QEDprocesses.in_phase_space_dimension(proc::TestProcess, ::TestModel) + return number_incoming_particles(proc) * 4 +end +function QEDprocesses.out_phase_space_dimension(proc::TestProcess, ::TestModel) + return number_outgoing_particles(proc) * 4 +end + # dummy phase space definition + failing phase space definition struct TestPhasespaceDef <: AbstractPhasespaceDefinition end struct TestPhasespaceDef_FAIL <: AbstractPhasespaceDefinition end @@ -81,6 +88,24 @@ function QEDprocesses._phase_space_factor( return _groundtruth_phase_space_factor(in_ps, out_ps) end +function QEDprocesses._generate_incoming_momenta( + proc::TestProcess, + model::TestModel, + in_phase_space_def::TestPhasespaceDef, + in_phase_space::AbstractVector{T}, +) where {T<:Real} + return _groundtruth_generate_momenta(in_phase_space) +end + +function QEDprocesses._generate_outgoing_momenta( + proc::TestProcess, + model::TestModel, + out_phase_space_def::TestPhasespaceDef, + out_phase_space::AbstractVector{T}, +) where {T<:Real} + return _groundtruth_generate_momenta(out_phase_space) +end + function QEDprocesses._total_probability( proc::TestProcess, model::TestModel, diff --git a/test/test_implementation/utils.jl b/test/test_implementation/utils.jl index b4d4f9d..8720970 100644 --- a/test/test_implementation/utils.jl +++ b/test/test_implementation/utils.jl @@ -3,3 +3,37 @@ _any_fail(x...) = true _any_fail(::TestProcess, ::TestModel) = false _any_fail(::TestProcess, ::TestModel, ::TestPhasespaceDef, ::TestPhasespaceDef) = false + +# unrolls all elements of a list of four-momenta into vector of coordinates +function _unroll_moms(ps_moms::AbstractVector{T}) where {T<:QEDbase.AbstractFourMomentum} + return collect(Iterators.flatten(ps_moms)) +end + +function _unroll_moms(ps_moms::AbstractMatrix{T}) where {T<:QEDbase.AbstractFourMomentum} + res = Matrix{eltype(T)}(undef, size(ps_moms, 1) * 4, size(ps_moms, 2)) + for i in 1:size(ps_moms, 2) + res[:, i] .= _unroll_moms(view(ps_moms, :, i)) + end + return res +end + +flat_components(moms) = _unroll_moms(moms) + +# collect components of four-momenta from a vector of coordinates +function __furl_moms(ps_coords::AbstractVector{T}) where {T<:Real} + return SFourMomentum.(eachcol(reshape(ps_coords, 4, :))) +end + +function _furl_moms(ps_coords::AbstractVector{T}) where {T<:Real} + @assert length(ps_coords) % 4 == 0 + return __furl_moms(ps_coords) +end + +function _furl_moms(ps_coords::AbstractMatrix{T}) where {T<:Real} + @assert size(ps_coords, 1) % 4 == 0 + res = Matrix{SFourMomentum}(undef, Int(size(ps_coords, 1)//4), size(ps_coords, 2)) + for i in 1:size(ps_coords, 2) + res[:, i] .= __furl_moms(view(ps_coords, :, i)) + end + return res +end