Skip to content

Commit

Permalink
Add tests for generic process
Browse files Browse the repository at this point in the history
  • Loading branch information
AntonReinhard committed Aug 21, 2024
1 parent 1bb3c49 commit 3f67b0f
Show file tree
Hide file tree
Showing 5 changed files with 348 additions and 11 deletions.
98 changes: 88 additions & 10 deletions src/processes/generic_process/process.jl
Original file line number Diff line number Diff line change
@@ -1,37 +1,84 @@
mutable struct GenericQEDProcess{INT,OUTT,INSP,OUTSP} <: AbstractProcessDefinition where {
INT<:Tuple,OUTT<:Tuple,INSP<:Tuple,OUTSP<:Tuple
}
"""
GenericQEDProcess <: AbstractProcessDefinition
An implementation of the `AbstractProcessDefinition` interface for a generic particle process in QED
with any number of incoming and outgoing particles, and any combination of spins or polarizations for the particles set.
The [`isphysical`](@ref) function can be used to check whether the process is possible in QED.
!!! note
The computation of cross sections and probabilities is currently unimplemented.
"""
struct GenericQEDProcess{INT,OUTT,INSP,OUTSP} <:
AbstractProcessDefinition where {INT<:Tuple,OUTT<:Tuple,INSP<:Tuple,OUTSP<:Tuple}
incoming_particles::INT
outgoing_particles::OUTT

incoming_spins_pols::INSP
outgoing_spins_pols::OUTSP
incoming_spin_pols::INSP
outgoing_spin_pols::OUTSP

matrix_element_squared::Function
"""
GenericQEDProcess(
in_particles::Tuple{AbstractParticleType},
out_particles::Tuple{AbstractParticleType},
in_sp::Tuple{AbstractSpinOrPolarization},
out_sp::Tuple{AbstractSpinOrPolarization}
)
Constructor for a GenericQEDProcess with the given incoming and outgoing particles and their respective spins and pols.
The constructor asserts that the particles are compatible with their respective spins and polarizations. If the assertion fails, an
`InvalidInputError` is thrown.
"""
function GenericQEDProcess(
in_particles::INT, out_particles::OUTT, in_sp::INSP, out_sp::OUTSP
in_particles::INT, out_particles::OUTT, in_spin_pols::INSP, out_spin_pols::OUTSP
) where {INT<:Tuple,OUTT<:Tuple,INSP<:Tuple,OUTSP<:Tuple}
_assert_particle_type_tuple(in_particles)
_assert_particle_type_tuple(out_particles)

_assert_spin_pol_particle_compatability(in_particles, in_spin_pols)
_assert_spin_pol_particle_compatability(out_particles, out_spin_pols)

return new{INT,OUTT,INSP,OUTSP}(
in_particles, out_particles, in_sp, out_sp, _ -> error("unimplemented")
in_particles, out_particles, in_spin_pols, out_spin_pols
)
end
end

"""
GenericQEDProcess(in_particles::Tuple{AbstractParticleType}, out_particles::Tuple{AbstractParticleType})
Constructor for a GenericQEDProcess, setting `AllPol` and `AllSpin` for every boson and fermion, respectively.
"""
function GenericQEDProcess(
in_particles::INT, out_particles::OUTT
) where {INT<:Tuple,OUTT<:Tuple}
# this will be called again by the default constructor, but it produces a nicer warning here
# than the following spin/pol generation failing because is_fermion or is_boson isn't defined on not allowed types
_assert_particle_type_tuple(in_particles)
_assert_particle_type_tuple(out_particles)

in_spin_pols = ntuple(
x -> is_fermion(in_particles[x]) ? AllSpin() : AllPolarization(),
length(in_particles),
)
out_spin_pols = ntuple(
x -> is_fermion(out_particles[x]) ? AllSpin() : AllPolarization(),
length(out_particles),
)
return GenericQEDProcess(in_particles, out_particles, in_spin_pols, out_spin_pols)
end

function QEDbase.incoming_particles(proc::GenericQEDProcess)
return proc.incoming_particles
end
function QEDbase.outgoing_particles(proc::GenericQEDProcess)
return proc.outgoing_particles
end
function QEDbase.incoming_spin_pols(proc::GenericQEDProcess)
return proc.incoming_spins_pols
return proc.incoming_spin_pols
end
function QEDbase.outgoing_spin_pols(proc::GenericQEDProcess)
return proc.outgoing_spins_pols
return proc.outgoing_spin_pols
end

"""
Expand All @@ -47,3 +94,34 @@ function isphysical(proc::GenericQEDProcess)
number_particles(proc, Outgoing(), Electron())
) && number_particles(proc, Incoming()) + number_particles(proc, Outgoing()) >= 2
end

function Base.show(io::IO, proc::GenericQEDProcess)
print(io, "generic QED process \"")
for p in incoming_particles(proc)
print(io, _particle_to_letter(p))
end
print(io, " -> ")
for p in outgoing_particles(proc)
print(io, _particle_to_letter(p))
end
print(io, "\"")
return nothing
end

function Base.show(io::IO, ::MIME"text/plain", proc::GenericQEDProcess)
println(io, "generic QED process")
for dir in (Incoming(), Outgoing())
first = true
for (p, sp) in zip(particles(proc, dir), spin_pols(proc, dir))
if !first
print(io, ", ")
else
print(io, " $(dir): ")
first = false
end
print(io, "$(p) ($(sp))")
end
println(io)
end
return nothing
end
36 changes: 35 additions & 1 deletion src/processes/generic_process/utility.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,41 @@ end
function _assert_particle_type_tuple(t::Any)
throw(
InvalidInputError(
"invalid input, provide a tuple of AbstractParticleTypes to construct a QEDProcess",
"invalid input, provide a tuple of AbstractParticleTypes to construct a GenericQEDProcess",
),
)
end

_assert_spin_pol_particle_compatability(::Tuple{}, ::Tuple{}) = nothing
function _assert_spin_pol_particle_compatability(::Tuple{}, ::Tuple{Vararg})
throw(InvalidInputError("more spins/pols than particles given"))
end
function _assert_spin_pol_particle_compatability(::Tuple{Vararg}, ::Tuple{})
throw(InvalidInputError("more particles than spins/pols given"))
end

function _assert_spin_pol_particle_compatability(
particles::Tuple{AbstractParticleType,Vararg},
spin_pols::Tuple{AbstractSpinOrPolarization,Vararg},
)
if is_fermion(particles[1]) && !(spin_pols[1] isa AbstractSpin)
throw(
InvalidInputError(
"particle \"$(particles[1])\" is a fermion and should have a spin, but has \"$(spin_pols[1])\"",
),
)
end
if is_boson(particles[1]) && !(spin_pols[1] isa AbstractPolarization)
throw(
InvalidInputError(
"particle \"$(particles[1])\" is a boson and should have a polarization, but has \"$(spin_pols[1])\"",
),
)
end
return _assert_spin_pol_particle_compatability(particles[2:end], spin_pols[2:end])
end

# this should move to QEDbase as part of the interface, see https://github.com/QEDjl-project/QEDbase.jl/issues/114
_particle_to_letter(::Electron) = "e"
_particle_to_letter(::Positron) = "p"
_particle_to_letter(::Photon) = "k"
25 changes: 25 additions & 0 deletions test/processes/generic_process/groundtruths.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
POLS = [PolX(), PolY(), AllPol()]
SPINS = [SpinUp(), SpinDown(), AllSpin()]

function _groundtruth_is_physical(proc::GenericQEDProcess)
incoming_electrons = number_particles(proc, Incoming(), Electron())
incoming_positrons = number_particles(proc, Incoming(), Positron())
outgoing_electrons = number_particles(proc, Outgoing(), Electron())
outgoing_positrons = number_particles(proc, Outgoing(), Positron())

return incoming_electrons + outgoing_positrons ==
outgoing_electrons + incoming_positrons
end

function _groundtruth_spin_pols(particles)
return ntuple(
x -> is_fermion(particles[x]) ? AllSpin() : AllPolarization(), length(particles)
)
end

function _random_spin_pols(RNG, particles)
return ntuple(
x -> is_fermion(particles[x]) ? rand(RNG, SPINS) : rand(RNG, POLS),
length(particles),
)
end
197 changes: 197 additions & 0 deletions test/processes/generic_process/process.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
using QEDprocesses
using Random
using QEDcore

include("groundtruths.jl")

const RNG = MersenneTwister(77697185)

PARTICLES = [Electron(), Positron(), Photon()]
POLS = [PolX(), PolY(), AllPol()]
SPINS = [SpinUp(), SpinDown(), AllSpin()]
POL_AND_SPIN_COMBINATIONS = Iterators.product(SPINS, POLS, SPINS, POLS)
BUF = IOBuffer()

@testset "constructor" begin
@testset "default" begin
proc = GenericQEDProcess((Photon(), Electron()), (Photon(), Electron()))

@test QEDprocesses.spin_pols(proc, Incoming())[1] == AllPol()
@test QEDprocesses.spin_pols(proc, Incoming())[2] == AllSpin()
@test QEDprocesses.spin_pols(proc, Outgoing())[1] == AllPol()
@test QEDprocesses.spin_pols(proc, Outgoing())[2] == AllSpin()

print(BUF, proc)
@test String(take!(BUF)) == "generic QED process \"ke -> ke\""

show(BUF, MIME"text/plain"(), proc)
@test String(take!(BUF)) ==
"generic QED process\n incoming: photon ($(AllPol())), electron ($(AllSpin()))\n outgoing: photon ($(AllPol())), electron ($(AllSpin()))\n"

@test isphysical(proc)
end

@testset "all spins+pols" begin
@testset "$in_spin, $in_pol, $out_spin, $out_pol" for (
in_spin, in_pol, out_spin, out_pol
) in POL_AND_SPIN_COMBINATIONS
proc = GenericQEDProcess(
(Photon(), Electron()),
(Photon(), Electron()),
(in_pol, in_spin),
(out_pol, out_spin),
)

@test QEDprocesses.spin_pols(proc, Incoming())[1] == in_pol
@test QEDprocesses.spin_pols(proc, Incoming())[2] == in_spin
@test QEDprocesses.spin_pols(proc, Outgoing())[1] == out_pol
@test QEDprocesses.spin_pols(proc, Outgoing())[2] == out_spin

print(BUF, proc)
@test String(take!(BUF)) == "generic QED process \"ke -> ke\""

show(BUF, MIME"text/plain"(), proc)
@test String(take!(BUF)) ==
"generic QED process\n incoming: photon ($(in_pol)), electron ($(in_spin))\n outgoing: photon ($(out_pol)), electron ($(out_spin))\n"

@test isphysical(proc)
end
end

@testset "invalid types passed" begin
struct INVALID_PARTICLE end

@test_throws "invalid input, provide a tuple of AbstractParticleTypes to construct a GenericQEDProcess" GenericQEDProcess(
(INVALID_PARTICLE(), Electron()), (Photon(), Electron())
)
@test_throws InvalidInputError GenericQEDProcess(
(INVALID_PARTICLE(), Electron()), (Photon(), Electron())
)

@test_throws "invalid input, provide a tuple of AbstractParticleTypes to construct a GenericQEDProcess" GenericQEDProcess(
(Photon(), Electron()), (Photon(), INVALID_PARTICLE())
)
@test_throws InvalidInputError GenericQEDProcess(
(Photon(), Electron()), (Photon(), INVALID_PARTICLE())
)
end

@testset "incompatible spin/pols" begin
@test_throws InvalidInputError GenericQEDProcess(
(Electron(), Photon()),
(Electron(), Photon()),
(AllPol(), AllPol()),
(AllSpin(), AllPol()),
)
@test_throws "particle \"electron\" is a fermion and should have a spin, but has \"all polarizations\"" GenericQEDProcess(
(Electron(), Photon()),
(Electron(), Photon()),
(AllPol(), AllPol()),
(AllSpin(), AllPol()),
)

@test_throws InvalidInputError GenericQEDProcess(
(Electron(), Photon()),
(Electron(), Photon()),
(AllSpin(), AllSpin()),
(AllSpin(), AllPol()),
)
@test_throws "particle \"photon\" is a boson and should have a polarization, but has \"all spins\"" GenericQEDProcess(
(Electron(), Photon()),
(Electron(), Photon()),
(AllSpin(), AllSpin()),
(AllSpin(), AllPol()),
)
end

@testset "incompatible number of spins/pols" begin
IN_PARTICLES = Tuple(rand(RNG, PARTICLES, 2))
OUT_PARTICLES = Tuple(rand(RNG, PARTICLES, 2))
@testset "2 particles, 1 spin/pol" begin
@test_throws InvalidInputError GenericQEDProcess(
IN_PARTICLES,
OUT_PARTICLES,
_random_spin_pols(RNG, IN_PARTICLES)[1:1],
_random_spin_pols(RNG, OUT_PARTICLES),
)
@test_throws "more particles than spins/pols given" GenericQEDProcess(
IN_PARTICLES,
OUT_PARTICLES,
_random_spin_pols(RNG, IN_PARTICLES)[1:1],
_random_spin_pols(RNG, OUT_PARTICLES),
)

@test_throws InvalidInputError GenericQEDProcess(
IN_PARTICLES,
OUT_PARTICLES,
_random_spin_pols(RNG, IN_PARTICLES),
_random_spin_pols(RNG, OUT_PARTICLES)[1:1],
)
@test_throws "more particles than spins/pols given" GenericQEDProcess(
IN_PARTICLES,
OUT_PARTICLES,
_random_spin_pols(RNG, IN_PARTICLES),
_random_spin_pols(RNG, OUT_PARTICLES)[1:1],
)
end
@testset "2 particles, 3 spin/pols" begin
@test_throws InvalidInputError GenericQEDProcess(
IN_PARTICLES,
OUT_PARTICLES,
(_random_spin_pols(RNG, IN_PARTICLES)..., AllPol()),
_random_spin_pols(RNG, OUT_PARTICLES),
)
@test_throws "more spins/pols than particles given" GenericQEDProcess(
IN_PARTICLES,
OUT_PARTICLES,
(_random_spin_pols(RNG, IN_PARTICLES)..., AllSpin()),
_random_spin_pols(RNG, OUT_PARTICLES),
)

@test_throws InvalidInputError GenericQEDProcess(
IN_PARTICLES,
OUT_PARTICLES,
_random_spin_pols(RNG, IN_PARTICLES),
(_random_spin_pols(RNG, OUT_PARTICLES)..., AllPol()),
)
@test_throws "more spins/pols than particles given" GenericQEDProcess(
IN_PARTICLES,
OUT_PARTICLES,
_random_spin_pols(RNG, IN_PARTICLES),
(_random_spin_pols(RNG, OUT_PARTICLES)..., AllSpin()),
)
end
end
end

@testset "particle content" begin
@testset "$n -> $m processes" for (n, m) in Base.product((2, 4), (3, 5))
IN_PARTICLES = Tuple(rand(RNG, PARTICLES, n))
OUT_PARTICLES = Tuple(rand(RNG, PARTICLES, m))
proc = GenericQEDProcess(IN_PARTICLES, OUT_PARTICLES)
@testset "process $(proc)" begin
@test incoming_particles(proc) == IN_PARTICLES
@test outgoing_particles(proc) == OUT_PARTICLES
@test number_incoming_particles(proc) == n
@test number_outgoing_particles(proc) == m
@test incoming_spin_pols(proc) == _groundtruth_spin_pols(IN_PARTICLES)
@test outgoing_spin_pols(proc) == _groundtruth_spin_pols(OUT_PARTICLES)

@test isphysical(proc) == _groundtruth_is_physical(proc)
end

IN_SPIN_POLS = _random_spin_pols(RNG, IN_PARTICLES)
OUT_SPIN_POLS = _random_spin_pols(RNG, OUT_PARTICLES)
proc = GenericQEDProcess(IN_PARTICLES, OUT_PARTICLES, IN_SPIN_POLS, OUT_SPIN_POLS)
@testset "process $(proc) with set spins/pols" begin
@test incoming_particles(proc) == IN_PARTICLES
@test outgoing_particles(proc) == OUT_PARTICLES
@test number_incoming_particles(proc) == n
@test number_outgoing_particles(proc) == m
@test incoming_spin_pols(proc) == IN_SPIN_POLS
@test outgoing_spin_pols(proc) == OUT_SPIN_POLS

@test isphysical(proc) == _groundtruth_is_physical(proc)
end
end
end
Loading

0 comments on commit 3f67b0f

Please sign in to comment.