Skip to content

Commit

Permalink
Refactoring of differential cross section functionality (#38)
Browse files Browse the repository at this point in the history
# Problem statement 

The current implementation only allows implementing
`differential_cross_section` directly for given processes. Furthermore,
the interface does not allow the implementation of different phase-space
coordinate systems, e.g. to model $d\sigma/dE$ **and**
$d\sigma/d\cos\theta$ for the same process.

# Suggested solution

## Advanced process interface
I suggest to disassemble the differential cross-sections interface into
a more flexible interface:

```mermaid
flowchart TD
  _differential_cross_section --> _differential_probability
  _differential_cross_section --> _incident_flux*
  _differential_probability --> _avg_matrix_element_square
  _differential_probability --> _phase_space_factor*
  _differential_probability -.-> _is_in_phasespace*
  _avg_matrix_element_square --> _matrix_element*
  _avg_matrix_element_square --> _avg_normalization*
```
where the functions with the asterisk give the new interface for the
calculation of differential cross-sections:

* `_matrix_element`: the matrix element of the process
* `_phase_space_factor`: the value of the pre-differential factor of the
phase-space measure
* `_is_in_phasespace`: checks if a given input is physical, see below
* `_incident_flux`: the incident particle flux, used to normalize the
probability
* `_avg_normalization`: normalization for averaging of squared matrix
elements

The underscore of those functions implies, that they are not exported,
and no input validation check is performed. For the functions
`_differential_cross_section` and `_differential_probability` there are
versions `differential_cross_section` and `differential_probability`,
where input validation is performed.

## Phase space definition
To attack the original problem using different coordinate systems for
the same process, this PR adds a simple system for coordinate systems
and frames of reference. Those are propagated through a composite type:

```Julia
PhasespaceDefinition{
    CS<:AbstractCoordinateSystem,
    F<: AbstractFrameOfReference
}
```
Currently, the given example implementations are very limited, but this
deserves an interface in the future. A dedicated issue will be opened
during the review process of this PR (see todos below).

## Phase space check

**Not included** in the input validation is the check if given incoming
and outgoing phase-spaces are physical, i.e. if all momenta are on-shell
and fulfill some sort of energy-momentum conservation. Therefore, I
suggest to add another interface function

```Julia
_is_in_phasespace(
    in_ps_def::AbstractPhasespaceDefinition,
    in_ps::AbstractVector{T},
    out_ps_def::AbstractPhasespaceDefinition,
    out_ps::AbstractVector{T},
) where {T<:QEDbase.AbstractFourMomentum}
``` 

which returns `true` if the input is physical, and `false` otherwise.
Consequently, there are unsafe versions of cross-sections and
probabilities, which don't perform the check given by the function
above, and safe versions, which return null if the condition given by
`_is_in_phasespace` is not met.

# Final remarks
To conclude, the different versions of cross-section and probability
functions, derived from the interface above, are

```Julia
_unsafe_differential_cross_section # without input validation, without phase-space check
_differential_cross_section        # without input validation, with phase-space check
unsafe_differential_cross_section  # with input validation, without phase-space check
differential_cross_section         # with input validation, with phase-space check

_unsafe_differential_probability   # without input validation, without phase-space check
_differential_probability          # without input validation, with phase-space check
unsafe_differential_probability    # with input validation, without phase-space check
differential_probability           # with input validation, with phase-space check
```

where only the functions without an underscore are exported, for all of
those functions, there are implementations for all combinations of
vectors and matrices for the incoming and outgoing phase space.

## Todos:
- [x] write tests for `(_(unsafe_))probability`
- [x] make total cross-section an interface function
- [x] make energy-momentum check for *safe implementations* an interface
function
- [ ] Write a gist about the broadcasted implementations
- [x] rename `_[unsafe_]probability` to
`_[unsafe]differential_probability`
- [x] cleanup in Project.toml
- [x] open issue on `PhasespaceDefinition`

---------

Co-authored-by: Uwe Hernandez Acosta <u.hernandez@hzdr.de>
Co-authored-by: Tom Jungnickel <140055258+tjungni@users.noreply.github.com>
  • Loading branch information
3 people authored Mar 7, 2024
1 parent 152f71e commit f703634
Show file tree
Hide file tree
Showing 18 changed files with 1,616 additions and 375 deletions.
2 changes: 0 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ authors = ["Uwe Hernandez Acosta <u.hernandez@hzdr.de>", "Simeon Ehrig", "Klaus
version = "0.1.0"

[deps]
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
QEDbase = "10e22c08-3ccb-4172-bfcf-7d7aa3d04d93"

[compat]
DocStringExtensions = "0.9"
QEDbase = "0.1"
julia = "1.6"
18 changes: 16 additions & 2 deletions src/QEDprocesses.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@ export AbstractModelDefinition, fundamental_interaction_type
export AbstractProcessDefinition, incoming_particles, outgoing_particles
export in_phasespace_dimension, out_phasespace_dimension
export number_incoming_particles, number_outgoing_particles
export differential_cross_section, total_cross_section

# 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

# Abstract setup interface
export AbstractComputationSetup, InvalidInputError, compute
Expand All @@ -16,12 +23,19 @@ export AbstractProcessSetup, scattering_process, physical_model
# propagator
export propagator

using DocStringExtensions
# phase space
export AbstractCoordinateSystem, SphericalCoordinateSystem
export AbstractFrameOfReference, CenterOfMomentumFrame, ElectronRestFrame
export AbstractPhasespaceDefinition, PhasespaceDefinition

using QEDbase

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("probabilities.jl")
include("cross_sections.jl")
end
304 changes: 304 additions & 0 deletions src/cross_sections.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
########################
# differential cross sections and probabilities.
#
# 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
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<:QEDbase.AbstractFourMomentum}
I = 1 / (4 * _incident_flux(proc, model, in_phase_space))

return I * _unsafe_differential_probability(
proc,
model,
in_phase_space_def,
in_phase_space,
out_phase_space_def,
out_phase_space,
)
end

# differential cross sections without energy momentum conservation check
# single in phase space point/ several out phase space points
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::AbstractMatrix{T},
) where {T<:QEDbase.AbstractFourMomentum}
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(
proc,
model,
in_phase_space_def,
in_phase_space,
out_phase_space_def,
view(out_phase_space, :, i),
)
end
return res
end

# differential cross sections without energy momentum conservation check
# several in phase space points/ one or several out phase space points
function _unsafe_differential_cross_section(
proc::AbstractProcessDefinition,
model::AbstractModelDefinition,
in_phase_space_def::AbstractPhasespaceDefinition,
in_phase_space::AbstractMatrix{T},
out_phase_space_def::AbstractPhasespaceDefinition,
out_phase_space::AbstractVecOrMat{T},
) where {T<:QEDbase.AbstractFourMomentum}
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(
proc,
model,
in_phase_space_def,
view(in_phase_space, :, i),
out_phase_space_def,
out_phase_space,
)
end
return res
end

"""
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<:QEDbase.AbstractFourMomentum}
Return the differential cross section 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<: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))>",
),
)

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

# differential cross sections with energy momentum conservation check
# single in phase space point/ single out phase space point
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},
) where {T<:QEDbase.AbstractFourMomentum}
if !_is_in_phasespace(
proc,
model,
in_phase_space_def,
in_phase_space,
out_phase_space_def,
out_phase_space,
)
return zero(eltype(T))
end

return _unsafe_differential_cross_section(
proc,
model,
in_phase_space_def,
in_phase_space,
out_phase_space_def,
out_phase_space,
)
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::AbstractMatrix{T},
) where {T<:QEDbase.AbstractFourMomentum}
res = Vector{eltype(T)}(undef, size(out_phase_space, 2))
for i in 1:size(out_phase_space, 2)
res[i] = _differential_cross_section(
proc,
model,
in_phase_space_def,
in_phase_space,
out_phase_space_def,
view(out_phase_space, :, i),
)
end
return res
end

# differential cross sections with energy momentum conservation check
# several in phase space points/ one or several out phase space points
function _differential_cross_section(
proc::AbstractProcessDefinition,
model::AbstractModelDefinition,
in_phase_space_def::AbstractPhasespaceDefinition,
in_phase_space::AbstractMatrix{T},
out_phase_space_def::AbstractPhasespaceDefinition,
out_phase_space::AbstractVecOrMat{T},
) where {T<:QEDbase.AbstractFourMomentum}
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(
proc,
model,
in_phase_space_def,
view(in_phase_space, :, i),
out_phase_space_def,
out_phase_space,
)
end
return res
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<:QEDbase.AbstractFourMomentum}
If the given phase spaces are physical, return differential cross section. 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<: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))>",
),
)

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

############
# Total cross sections
############

# total cross section on single phase space point
function _total_cross_section(
proc::AbstractProcessDefinition,
model::AbstractModelDefinition,
in_phase_space_def::AbstractPhasespaceDefinition,
in_phase_space::AbstractVector{T},
) where {T<:QEDbase.AbstractFourMomentum}
I = 1 / (4 * _incident_flux(proc, model, in_phase_space))

return I * _total_probability(proc, model, in_phase_space_def, in_phase_space)
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}
res = Vector{eltype(T)}(undef, size(in_phase_space, 2))
for i in 1:size(in_phase_space, 2)
res[i] = _total_cross_section(
proc, model, in_phase_space_def, view(in_phase_space, :, i)
)
end
return res
end

"""
total_cross_section(
proc::AbstractProcessDefinition,
model::AbstractModelDefinition,
in_phase_space_def::AbstractPhasespaceDefinition,
in_phase_space::AbstractVecOrMat{T},
) where {T<:QEDbase.AbstractFourMomentum}
Return the total cross section for a given combination of scattering process and compute model.
"""
function total_cross_section(
proc::AbstractProcessDefinition,
model::AbstractModelDefinition,
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))>",
),
)

return _total_cross_section(proc, model, in_phase_space_def, in_phase_space)
end
Loading

0 comments on commit f703634

Please sign in to comment.