From d2740177b1abe4ab2f5ca2693dd53ae307865024 Mon Sep 17 00:00:00 2001 From: Anton Reinhard Date: Tue, 13 Aug 2024 11:18:12 +0200 Subject: [PATCH 01/10] Remove current multiplicity implementation --- src/interfaces/particles/spin_pol.jl | 12 ------------ test/particle_properties.jl | 10 ---------- 2 files changed, 22 deletions(-) diff --git a/src/interfaces/particles/spin_pol.jl b/src/interfaces/particles/spin_pol.jl index 9695405..94b4fbf 100644 --- a/src/interfaces/particles/spin_pol.jl +++ b/src/interfaces/particles/spin_pol.jl @@ -177,15 +177,3 @@ y-polarized struct PolarizationY <: AbstractDefinitePolarization end const PolY = PolarizationY Base.show(io::IO, ::PolY) = print(io, "y-polarized") - -""" - multiplicity(spin_or_pol) - -Return the number of spins or polarizations respresented by `spin_or_pol`, e.g. `multiplicity(SpinUp()) == 1`, but `multiplicity(AllSpin()) = 2`. - -""" -function multiplicity end -multiplicity(::AbstractDefinitePolarization) = 1 -multiplicity(::AbstractDefiniteSpin) = 1 -multiplicity(::AbstractIndefinitePolarization) = 2 -multiplicity(::AbstractIndefiniteSpin) = 2 diff --git a/test/particle_properties.jl b/test/particle_properties.jl index 74a84c8..5565e8c 100644 --- a/test/particle_properties.jl +++ b/test/particle_properties.jl @@ -24,14 +24,4 @@ test_broadcast(x::AbstractSpinOrPolarization) = x end @testset "multiplicity of spins or pols" begin - @testset "single" begin - @testset "$spin_or_pol" for spin_or_pol in (SpinUp(), SpinDown(), PolX(), PolY()) - @test multiplicity(spin_or_pol) == 1 - end - end - @testset "multiple" begin - @testset "$spin_or_pol" for spin_or_pol in (AllSpin(), AllPol()) - @test multiplicity(spin_or_pol) == 2 - end - end end From 7c856df69891476f0bfc537d2931df10b9686b2d Mon Sep 17 00:00:00 2001 From: Anton Reinhard Date: Tue, 13 Aug 2024 11:42:45 +0200 Subject: [PATCH 02/10] Move process impl files --- src/QEDbase.jl | 4 +- src/implementations/process/momenta.jl | 25 ++++++++++ .../{process.jl => process/particles.jl} | 50 ------------------- src/implementations/process/spin_pols.jl | 37 ++++++++++++++ 4 files changed, 65 insertions(+), 51 deletions(-) create mode 100644 src/implementations/process/momenta.jl rename src/implementations/{process.jl => process/particles.jl} (56%) create mode 100644 src/implementations/process/spin_pols.jl diff --git a/src/QEDbase.jl b/src/QEDbase.jl index 7c3235f..14c4bf5 100644 --- a/src/QEDbase.jl +++ b/src/QEDbase.jl @@ -110,7 +110,9 @@ include("interfaces/particle_stateful.jl") include("interfaces/process.jl") include("interfaces/phase_space_point.jl") -include("implementations/process.jl") +include("implementations/process/momenta.jl") +include("implementations/process/particles.jl") +include("implementations/process/spin_pols.jl") include("implementations/cross_section/diff_probability.jl") include("implementations/cross_section/diff_cross_section.jl") diff --git a/src/implementations/process/momenta.jl b/src/implementations/process/momenta.jl new file mode 100644 index 0000000..9de4a09 --- /dev/null +++ b/src/implementations/process/momenta.jl @@ -0,0 +1,25 @@ +""" + _generate_momenta( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::NTuple{N,T}, + out_phase_space::NTuple{M,T}, + ) where {N,M,T<:Real} + +Return four-momenta for incoming and outgoing particles for given coordinate based phase-space points. +""" +function _generate_momenta( + proc::AbstractProcessDefinition, + model::AbstractModelDefinition, + phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::NTuple{N,T}, + out_phase_space::NTuple{M,T}, +) where {N,M,T<:Real} + in_momenta = _generate_incoming_momenta(proc, model, phase_space_def, in_phase_space) + out_momenta = _generate_outgoing_momenta( + proc, model, phase_space_def, in_phase_space, out_phase_space + ) + + return in_momenta, out_momenta +end diff --git a/src/implementations/process.jl b/src/implementations/process/particles.jl similarity index 56% rename from src/implementations/process.jl rename to src/implementations/process/particles.jl index 627cb1f..7b77d6b 100644 --- a/src/implementations/process.jl +++ b/src/implementations/process/particles.jl @@ -57,53 +57,3 @@ Return the number of particles of the given particle's direction and species in ) return number_particles(proc_def, particle_direction(ps), particle_species(ps)) end - -# default implementation -function incoming_spin_pols(proc_def::AbstractProcessDefinition) - return ntuple( - x -> is_fermion(incoming_particles(proc_def)[x]) ? AllSpin() : AllPolarization(), - number_incoming_particles(proc_def), - ) -end - -# default implementation -function outgoing_spin_pols(proc_def::AbstractProcessDefinition) - return ntuple( - x -> is_fermion(outgoing_particles(proc_def)[x]) ? AllSpin() : AllPolarization(), - number_outgoing_particles(proc_def), - ) -end - -""" - spin_pols(proc_def::AbstractProcessDefinition, dir::ParticleDirection) - -Return the tuple of spins and polarizations for the process in the given direction. Dispatches to [`incoming_spin_pols`](@ref) or [`outgoing_spin_pols`](@ref). -""" -spin_pols(proc_def::AbstractProcessDefinition, dir::Incoming) = incoming_spin_pols(proc_def) -spin_pols(proc_def::AbstractProcessDefinition, dir::Outgoing) = outgoing_spin_pols(proc_def) - -""" - _generate_momenta( - proc::AbstractProcessDefinition, - model::AbstractModelDefinition, - phase_space_def::AbstractPhasespaceDefinition, - in_phase_space::NTuple{N,T}, - out_phase_space::NTuple{M,T}, - ) where {N,M,T<:Real} - -Return four-momenta for incoming and outgoing particles for given coordinate based phase-space points. -""" -function _generate_momenta( - proc::AbstractProcessDefinition, - model::AbstractModelDefinition, - phase_space_def::AbstractPhasespaceDefinition, - in_phase_space::NTuple{N,T}, - out_phase_space::NTuple{M,T}, -) where {N,M,T<:Real} - in_momenta = _generate_incoming_momenta(proc, model, phase_space_def, in_phase_space) - out_momenta = _generate_outgoing_momenta( - proc, model, phase_space_def, in_phase_space, out_phase_space - ) - - return in_momenta, out_momenta -end diff --git a/src/implementations/process/spin_pols.jl b/src/implementations/process/spin_pols.jl new file mode 100644 index 0000000..923786c --- /dev/null +++ b/src/implementations/process/spin_pols.jl @@ -0,0 +1,37 @@ + +# default implementation +function incoming_spin_pols(proc_def::AbstractProcessDefinition) + return ntuple( + x -> is_fermion(incoming_particles(proc_def)[x]) ? AllSpin() : AllPolarization(), + number_incoming_particles(proc_def), + ) +end + +# default implementation +function outgoing_spin_pols(proc_def::AbstractProcessDefinition) + return ntuple( + x -> is_fermion(outgoing_particles(proc_def)[x]) ? AllSpin() : AllPolarization(), + number_outgoing_particles(proc_def), + ) +end + +""" + spin_pols(proc_def::AbstractProcessDefinition, dir::ParticleDirection) + +Return the tuple of spins and polarizations for the process in the given direction. Dispatches to [`incoming_spin_pols`](@ref) or [`outgoing_spin_pols`](@ref). +""" +spin_pols(proc_def::AbstractProcessDefinition, dir::Incoming) = incoming_spin_pols(proc_def) +spin_pols(proc_def::AbstractProcessDefinition, dir::Outgoing) = outgoing_spin_pols(proc_def) + +""" + multiplicity(proc::AbstractProcessDefinition) + +Return the number of spin and polarization combinations represented by `proc` total. This depends on the specific [`AbstractSpinOrPolarization`](@ref)s returned by [`spin_pols`](@ref) for `proc`. +For example, a default Compton process with four indefinite spins/polarizations has a multiplicity of 2^4 = 16. A Compton process with many incoming photons that have synced polarizations +will still have a multiplicity of 16. + +See also: [`SyncedPolarization`](@ref), [`SyncedSpin`](@ref) +""" +function multiplicity(proc::AbstractProcessDefinition) + # TODO +end From 1c922836ce9a3b37d86f03b93daf5cf9313251b9 Mon Sep 17 00:00:00 2001 From: Anton Reinhard Date: Tue, 13 Aug 2024 13:25:39 +0200 Subject: [PATCH 03/10] Add SyncedPolarization and SyncedSpin types --- src/QEDbase.jl | 3 ++- src/implementations/process/spin_pols.jl | 1 - src/interfaces/particles/spin_pol.jl | 32 ++++++++++++++++++++++++ test/particle_properties.jl | 12 ++++++--- 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/QEDbase.jl b/src/QEDbase.jl index 14c4bf5..6650f2a 100644 --- a/src/QEDbase.jl +++ b/src/QEDbase.jl @@ -45,7 +45,7 @@ export AbstractDefinitePolarization, AbstractIndefinitePolarization export PolarizationX, PolX, PolarizationY, PolY, AllPolarization, AllPol export AbstractDefiniteSpin, AbstractIndefiniteSpin export SpinUp, SpinDown, AllSpin -export multiplicity +export SyncedSpin, SyncedPolarization # probabilities export differential_probability, unsafe_differential_probability @@ -63,6 +63,7 @@ export AbstractProcessDefinition, incoming_particles, outgoing_particles export number_incoming_particles, number_outgoing_particles export particles, number_particles export incoming_spin_pols, outgoing_spin_pols, spin_pols +export multiplicity # Abstract phase space definition interface export AbstractCoordinateSystem, AbstractFrameOfReference, AbstractPhasespaceDefinition diff --git a/src/implementations/process/spin_pols.jl b/src/implementations/process/spin_pols.jl index 923786c..99fc17f 100644 --- a/src/implementations/process/spin_pols.jl +++ b/src/implementations/process/spin_pols.jl @@ -33,5 +33,4 @@ will still have a multiplicity of 16. See also: [`SyncedPolarization`](@ref), [`SyncedSpin`](@ref) """ function multiplicity(proc::AbstractProcessDefinition) - # TODO end diff --git a/src/interfaces/particles/spin_pol.jl b/src/interfaces/particles/spin_pol.jl index 94b4fbf..fed06bd 100644 --- a/src/interfaces/particles/spin_pol.jl +++ b/src/interfaces/particles/spin_pol.jl @@ -177,3 +177,35 @@ y-polarized struct PolarizationY <: AbstractDefinitePolarization end const PolY = PolarizationY Base.show(io::IO, ::PolY) = print(io, "y-polarized") + +""" + SyncedPolarization{N::Int} <: AbstractIndefinitePolarization + +An indefinite polarization type, indicating that multiple particles have a synced polarization. +Two polarizations are considered synced when they have the same value for `N`. This means that +the resulting multiplicity will be 2 total for all particles with the same `SyncedPolarization`. + +See also: [`multiplicity`](@ref) +""" +struct SyncedPolarization{N} <: AbstractIndefinitePolarization + function SyncedPolarization{N}() where {N} + @assert N isa Int "N must be of type Int" + return new{N}() + end +end + +""" + SyncedSpin{N::Int} <: AbstractIndefiniteSpin + +An indefinite spin type, indicating that multiple particles have a synced spin. +Two spins are considered synced when they have the same value for `N`. This means that +the resulting multiplicity will be 2 total for all particles with the same `SyncedSpin`. + +See also: [`multiplicity`](@ref) +""" +struct SyncedSpin{N} <: AbstractIndefiniteSpin + function SyncedSpin{N}() where {N} + @assert N isa Int "N must be of type Int" + return new{N}() + end +end diff --git a/test/particle_properties.jl b/test/particle_properties.jl index 5565e8c..6e06745 100644 --- a/test/particle_properties.jl +++ b/test/particle_properties.jl @@ -16,12 +16,16 @@ test_broadcast(x::AbstractSpinOrPolarization) = x @testset "spins and polarization" begin @testset "$spin_or_pol" for spin_or_pol in ( - SpinUp(), SpinDown(), AllSpin(), PolX(), PolY(), AllPol() + SpinUp(), + SpinDown(), + AllSpin(), + PolX(), + PolY(), + AllPol(), + SyncedSpin{1}(), + SyncedPolarization{1}(), ) @test test_broadcast.(spin_or_pol) == spin_or_pol end end end - -@testset "multiplicity of spins or pols" begin -end From d95e0803e2fb5cec894e12853ea87561529e1083 Mon Sep 17 00:00:00 2001 From: Anton Reinhard Date: Tue, 13 Aug 2024 14:13:42 +0200 Subject: [PATCH 04/10] Add process multiplicity --- src/implementations/process/spin_pols.jl | 72 ++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/implementations/process/spin_pols.jl b/src/implementations/process/spin_pols.jl index 99fc17f..edaecc4 100644 --- a/src/implementations/process/spin_pols.jl +++ b/src/implementations/process/spin_pols.jl @@ -23,6 +23,73 @@ Return the tuple of spins and polarizations for the process in the given directi spin_pols(proc_def::AbstractProcessDefinition, dir::Incoming) = incoming_spin_pols(proc_def) spin_pols(proc_def::AbstractProcessDefinition, dir::Outgoing) = outgoing_spin_pols(proc_def) +@inline _multiplicity(::AbstractDefinitePolarization) = 1 +@inline _multiplicity(::AbstractDefiniteSpin) = 1 +@inline _multiplicity(::AllSpin) = 2 +@inline _multiplicity(::AllPol) = 2 + +@inline _multiplicity(::SyncedPolarization{N}, seen_spin_pols::Tuple{}) where {N} = 2 +@inline _multiplicity(::SyncedSpin{N}, seen_spin_pols::Tuple{}) where {N} = 2 + +@inline function _multiplicity( + sp::SyncedPolarization{N}, seen_pols::Tuple{Int,Vararg{Int}} +) where {N} + if seen_pols[1] == N + return 1 + else + return _multiplicity(sp, seen_pols[2:end]) + end +end + +@inline function _multiplicity( + ss::SyncedSpin{N}, seen_spins::Tuple{Int,Vararg{Int}} +) where {N} + if seen_spins[1] == N + return 1 + else + return _multiplicity(ss, seen_spins[2:end]) + end +end + +# multiplicity of the empty spin_pol set is 1 +@inline _multiplicity(::Tuple{}, _, _) = 1 + +# recursion for abstract spins or pols that are not synced +@inline function _multiplicity( + spin_pols::Tuple{AbstractSpin,Vararg{AbstractSpinOrPolarization}}, + seen_spins::NTuple{S,Int}, + seen_pols::NTuple{P,Int}, +) where {S,P} + return _multiplicity(spin_pols[1]) * + _multiplicity(spin_pols[2:end], seen_spins, seen_pols) +end +@inline function _multiplicity( + spin_pols::Tuple{AbstractPolarization,Vararg{AbstractSpinOrPolarization}}, + seen_spins::NTuple{S,Int}, + seen_pols::NTuple{P,Int}, +) where {S,P} + return _multiplicity(spin_pols[1]) * + _multiplicity(spin_pols[2:end], seen_spins, seen_pols) +end + +# recursion for synced spins or pols +@inline function _multiplicity( + spin_pols::Tuple{SyncedPolarization{N},Vararg{AbstractSpinOrPolarization}}, + seen_spins::NTuple{S,Int}, + seen_pols::NTuple{P,Int}, +) where {N,S,P} + return _multiplicity(spin_pols[1], seen_pols) * + _multiplicity(spin_pols[2:end], seen_spins, (seen_pols..., N)) +end +@inline function _multiplicity( + spin_pols::Tuple{SyncedSpin{N},Vararg{AbstractSpinOrPolarization}}, + seen_spins::NTuple{S,Int}, + seen_pols::NTuple{P,Int}, +) where {N,S,P} + return _multiplicity(spin_pols[1], seen_spins) * + _multiplicity(spin_pols[2:end], (seen_spins..., N), seen_pols) +end + """ multiplicity(proc::AbstractProcessDefinition) @@ -33,4 +100,9 @@ will still have a multiplicity of 16. See also: [`SyncedPolarization`](@ref), [`SyncedSpin`](@ref) """ function multiplicity(proc::AbstractProcessDefinition) + return _multiplicity( + (incoming_spin_pols(proc)..., outgoing_spin_pols(proc)...), + NTuple{0,Int}(), + NTuple{0,Int}(), + ) end From 37717b4d7c88d51209214ea9d57b162ef4eee2dc Mon Sep 17 00:00:00 2001 From: Anton Reinhard Date: Tue, 13 Aug 2024 15:08:11 +0200 Subject: [PATCH 05/10] Add some (somewhat) fuzzy and some specific testing for multiplicity --- src/implementations/process/spin_pols.jl | 3 ++ src/interfaces/particles/spin_pol.jl | 6 +++ test/interfaces/process.jl | 64 ++++++++++++++++++++++++ test/particle_properties.jl | 3 ++ test/test_implementation/test_process.jl | 18 +++++++ 5 files changed, 94 insertions(+) diff --git a/src/implementations/process/spin_pols.jl b/src/implementations/process/spin_pols.jl index edaecc4..35c21c3 100644 --- a/src/implementations/process/spin_pols.jl +++ b/src/implementations/process/spin_pols.jl @@ -97,6 +97,9 @@ Return the number of spin and polarization combinations represented by `proc` to For example, a default Compton process with four indefinite spins/polarizations has a multiplicity of 2^4 = 16. A Compton process with many incoming photons that have synced polarizations will still have a multiplicity of 16. +!!! note Performance + As long as [`incoming_spin_pols`](@ref) and [`outgoing_spin_pols`](@ref) can be evaluated at compile time, this function is completely compiled away. + See also: [`SyncedPolarization`](@ref), [`SyncedSpin`](@ref) """ function multiplicity(proc::AbstractProcessDefinition) diff --git a/src/interfaces/particles/spin_pol.jl b/src/interfaces/particles/spin_pol.jl index fed06bd..3392bcf 100644 --- a/src/interfaces/particles/spin_pol.jl +++ b/src/interfaces/particles/spin_pol.jl @@ -185,6 +185,9 @@ An indefinite polarization type, indicating that multiple particles have a synce Two polarizations are considered synced when they have the same value for `N`. This means that the resulting multiplicity will be 2 total for all particles with the same `SyncedPolarization`. +Having a single `SyncedPolarization{N}` in a process is legal. In this case, it behaves just +like an [`AllPol`](@ref) would. + See also: [`multiplicity`](@ref) """ struct SyncedPolarization{N} <: AbstractIndefinitePolarization @@ -201,6 +204,9 @@ An indefinite spin type, indicating that multiple particles have a synced spin. Two spins are considered synced when they have the same value for `N`. This means that the resulting multiplicity will be 2 total for all particles with the same `SyncedSpin`. +Having a single `SyncedSpin{N}` in a process is legal. In this case, it behaves just +like an [`AllSpin`](@ref) would. + See also: [`multiplicity`](@ref) """ struct SyncedSpin{N} <: AbstractIndefiniteSpin diff --git a/test/interfaces/process.jl b/test/interfaces/process.jl index a09608e..df9154e 100644 --- a/test/interfaces/process.jl +++ b/test/interfaces/process.jl @@ -111,6 +111,70 @@ include("../test_implementation/TestImplementation.jl") end end + @testset "process multiplicity" begin + boson = TestImplementation.TestParticleBoson() + fermion = TestImplementation.TestParticleFermion() + + _mult(::AbstractDefinitePolarization) = 1 + _mult(::AbstractDefiniteSpin) = 1 + _mult(::AbstractIndefinitePolarization) = 2 + _mult(::AbstractIndefiniteSpin) = 2 + + # test all possible combinations for fermion+boson->fermion+boson processes, without synced + spins = (SpinUp(), SpinDown(), AllSpin()) + pols = (PolX(), PolY(), AllPol()) + for (p1, s1, p2, s2) in Iterators.product(pols, spins, pols, spins) + @test multiplicity( + TestImplementation.TestProcessSP( + (boson, fermion), (boson, fermion), (p1, s1), (p2, s2) + ), + ) == prod(_mult.((p1, s1, p2, s2))) + end + + # some special cases for synced spins and pols testing + for i in 1:4 + # i synced bosons + @test multiplicity( + TestImplementation.TestProcessSP( + (ntuple(_ -> boson, i)..., fermion), + (boson, fermion), + (ntuple(_ -> SyncedPolarization{1}(), i)..., AllSpin()), + (AllPol(), AllSpin()), + ), + ) == 16 + + @test multiplicity( + TestImplementation.TestProcessSP( + (boson, fermion), + (ntuple(_ -> boson, i)..., fermion), + (AllPol(), SpinDown()), + (ntuple(_ -> SyncedPolarization{1}(), i)..., AllSpin()), + ), + ) == 8 + + for j in 1:4 + # ... with j synced fermions + @test multiplicity( + TestImplementation.TestProcessSP( + (ntuple(_ -> boson, i)..., fermion), + (boson, ntuple(_ -> fermion, j)), + (ntuple(_ -> SyncedPolarization{1}(), i)..., SpinDown()), + (PolX(), ntuple(_ -> SyncedSpin{1}(), j)...), + ), + ) == 4 + end + end + + @test multiplicity( + TestImplementation.TestProcessSP( + (ntuple(_ -> boson, 2)..., fermion), + (ntuple(_ -> boson, 2)..., fermion), + (ntuple(_ -> SyncedPolarization{1}(), 2)..., SpinUp()), + (ntuple(_ -> SyncedPolarization{2}(), 2)..., AllSpin()), + ), + ) == 8 + end + @testset "incident flux" begin test_incident_flux = QEDbase._incident_flux( InPhaseSpacePoint(TESTPROC, TESTMODEL, TESTPSDEF, IN_PS) diff --git a/test/particle_properties.jl b/test/particle_properties.jl index 6e06745..9c355fd 100644 --- a/test/particle_properties.jl +++ b/test/particle_properties.jl @@ -28,4 +28,7 @@ test_broadcast(x::AbstractSpinOrPolarization) = x @test test_broadcast.(spin_or_pol) == spin_or_pol end end + + @test_throws AssertionError SyncedSpin{5.5}() + @test_throws AssertionError SyncedPolarization{:sym}() end diff --git a/test/test_implementation/test_process.jl b/test/test_implementation/test_process.jl index 8a31dce..4f5d623 100644 --- a/test/test_implementation/test_process.jl +++ b/test/test_implementation/test_process.jl @@ -22,6 +22,24 @@ end QEDbase.incoming_particles(proc::TestProcess) = proc.incoming_particles QEDbase.outgoing_particles(proc::TestProcess) = proc.outgoing_particles +""" + TestProcessSP + +Process for testing with settable spin and polarization. +""" +struct TestProcessSP{IP<:Tuple,OP<:Tuple,IN_SP<:Tuple,OUT_SP<:Tuple} <: + AbstractProcessDefinition + incoming_particles::IP + outgoing_particles::OP + incoming_spin_pols::IN_SP + outgoing_spin_pols::OUT_SP +end + +QEDbase.incoming_particles(proc::TestProcessSP) = proc.incoming_particles +QEDbase.outgoing_particles(proc::TestProcessSP) = proc.outgoing_particles +QEDbase.incoming_spin_pols(proc::TestProcessSP) = proc.incoming_spin_pols +QEDbase.outgoing_spin_pols(proc::TestProcessSP) = proc.outgoing_spin_pols + struct TestProcess_FAIL{IP<:Tuple,OP<:Tuple} <: AbstractProcessDefinition incoming_particles::IP outgoing_particles::OP From 4c03cc3ba7370abb33a0d94ed241fc51683aec22 Mon Sep 17 00:00:00 2001 From: Anton Reinhard Date: Tue, 13 Aug 2024 15:21:23 +0200 Subject: [PATCH 06/10] Fix docs --- src/interfaces/particles/spin_pol.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interfaces/particles/spin_pol.jl b/src/interfaces/particles/spin_pol.jl index 3392bcf..8f1e68e 100644 --- a/src/interfaces/particles/spin_pol.jl +++ b/src/interfaces/particles/spin_pol.jl @@ -186,7 +186,7 @@ Two polarizations are considered synced when they have the same value for `N`. T the resulting multiplicity will be 2 total for all particles with the same `SyncedPolarization`. Having a single `SyncedPolarization{N}` in a process is legal. In this case, it behaves just -like an [`AllPol`](@ref) would. +like an [`AllPolarization`](@ref) would. See also: [`multiplicity`](@ref) """ From 73c8518938996c2b5e8a26a1410bd241258d0fb4 Mon Sep 17 00:00:00 2001 From: Anton Reinhard Date: Tue, 13 Aug 2024 15:54:27 +0200 Subject: [PATCH 07/10] Add incoming and outgoing variants of multiplicity --- src/QEDbase.jl | 2 +- src/implementations/process/spin_pols.jl | 35 +++++- src/interfaces/process.jl | 11 +- test/interfaces/process.jl | 136 ++++++++++++----------- 4 files changed, 117 insertions(+), 67 deletions(-) diff --git a/src/QEDbase.jl b/src/QEDbase.jl index 6650f2a..e66e4f6 100644 --- a/src/QEDbase.jl +++ b/src/QEDbase.jl @@ -63,7 +63,7 @@ export AbstractProcessDefinition, incoming_particles, outgoing_particles export number_incoming_particles, number_outgoing_particles export particles, number_particles export incoming_spin_pols, outgoing_spin_pols, spin_pols -export multiplicity +export multiplicity, incoming_multiplicity, outgoing_multiplicity # Abstract phase space definition interface export AbstractCoordinateSystem, AbstractFrameOfReference, AbstractPhasespaceDefinition diff --git a/src/implementations/process/spin_pols.jl b/src/implementations/process/spin_pols.jl index 35c21c3..a4e50cd 100644 --- a/src/implementations/process/spin_pols.jl +++ b/src/implementations/process/spin_pols.jl @@ -100,7 +100,10 @@ will still have a multiplicity of 16. !!! note Performance As long as [`incoming_spin_pols`](@ref) and [`outgoing_spin_pols`](@ref) can be evaluated at compile time, this function is completely compiled away. -See also: [`SyncedPolarization`](@ref), [`SyncedSpin`](@ref) +!!! note Incoming and Outgoing Spins/Polarizations + Note that the total multiplicity is not necessarily the incoming and outgoing multiplicities multiplied. This is the case when incoming and outgoing particles are synced with one another. + +See also: [`SyncedPolarization`](@ref), [`SyncedSpin`](@ref), [`incoming_multiplicity`](@ref), [`outgoing_multiplicity`](@ref) """ function multiplicity(proc::AbstractProcessDefinition) return _multiplicity( @@ -109,3 +112,33 @@ function multiplicity(proc::AbstractProcessDefinition) NTuple{0,Int}(), ) end + +""" + incoming_multiplicity(proc::AbstractProcessDefinition) + +Return the number of spin and polarization combinations represented by `proc`s incoming particles. This function only considers the incoming particles' spins and polarizations, returned by +[`incoming_spin_pols`](@ref) for `proc`. + +!!! note Incoming and Outgoing Spins/Polarizations + Note that the total multiplicity is not necessarily the incoming and outgoing multiplicities multiplied. For the total process multiplicity, see [`multiplicity`](@ref). + +See also: [`SyncedPolarization`](@ref), [`SyncedSpin`](@ref), [`multiplicity`](@ref), [`outgoing_multiplicity`](@ref) +""" +function incoming_multiplicity(proc::AbstractProcessDefinition) + return _multiplicity(incoming_spin_pols(proc), NTuple{0,Int}(), NTuple{0,Int}()) +end + +""" + outgoing_multiplicity(proc::AbstractProcessDefinition) + +Return the number of spin and polarization combinations represented by `proc`s outgoing particles. This function only considers the outgoing particles' spins and polarizations, returned by +[`outgoing_spin_pols`](@ref) for `proc`. + +!!! note Incoming and Outgoing Spins/Polarizations + Note that the total multiplicity is not necessarily the incoming and outgoing multiplicities multiplied. For the total process multiplicity, see [`multiplicity`](@ref). + +See also: [`SyncedPolarization`](@ref), [`SyncedSpin`](@ref), [`multiplicity`](@ref), [`incoming_multiplicity`](@ref) +""" +function outgoing_multiplicity(proc::AbstractProcessDefinition) + return _multiplicity(outgoing_spin_pols(proc), NTuple{0,Int}(), NTuple{0,Int}()) +end diff --git a/src/interfaces/process.jl b/src/interfaces/process.jl index a504d83..69a8c3f 100644 --- a/src/interfaces/process.jl +++ b/src/interfaces/process.jl @@ -28,6 +28,16 @@ outgoing_spin_pols(proc_def::AbstractProcessDefinition) can be overloaded. They must return a tuple of [`AbstractSpinOrPolarization`], where the order must match the order of the process' particles. A default implementation is provided which assumes [`AllSpin`](@ref) for every [`is_fermion`](@ref) particle and [`AllPolarization`](@ref) for every [`is_boson`](@ref) particle. +On top of these spin and polarization functions, the following functions are automatically defined: + +```Julia +multiplicity(proc_def::AbstractProcessDefinition) +incoming_multiplicity(proc_def::AbstractProcessDefinition) +outgoing_multiplicity(proc_def::AbstractProcessDefinition) +``` + +Which return the number of spin and polarization combinations that should be considered for the process. For more detail, refer to the functions' documentations. + Furthermore, to calculate scattering probabilities and differential cross sections, the following interface functions need to be implemented for every combination of `CustomProcess<:AbstractProcessDefinition`, `CustomModel<:AbstractModelDefinition`, and `CustomPhasespaceDefinition<:AbstractPhasespaceDefinition`. @@ -52,7 +62,6 @@ Optional is the implementation of ``` to enable the calculation of total probabilities and cross sections. - """ abstract type AbstractProcessDefinition end diff --git a/test/interfaces/process.jl b/test/interfaces/process.jl index df9154e..afec0db 100644 --- a/test/interfaces/process.jl +++ b/test/interfaces/process.jl @@ -111,70 +111,6 @@ include("../test_implementation/TestImplementation.jl") end end - @testset "process multiplicity" begin - boson = TestImplementation.TestParticleBoson() - fermion = TestImplementation.TestParticleFermion() - - _mult(::AbstractDefinitePolarization) = 1 - _mult(::AbstractDefiniteSpin) = 1 - _mult(::AbstractIndefinitePolarization) = 2 - _mult(::AbstractIndefiniteSpin) = 2 - - # test all possible combinations for fermion+boson->fermion+boson processes, without synced - spins = (SpinUp(), SpinDown(), AllSpin()) - pols = (PolX(), PolY(), AllPol()) - for (p1, s1, p2, s2) in Iterators.product(pols, spins, pols, spins) - @test multiplicity( - TestImplementation.TestProcessSP( - (boson, fermion), (boson, fermion), (p1, s1), (p2, s2) - ), - ) == prod(_mult.((p1, s1, p2, s2))) - end - - # some special cases for synced spins and pols testing - for i in 1:4 - # i synced bosons - @test multiplicity( - TestImplementation.TestProcessSP( - (ntuple(_ -> boson, i)..., fermion), - (boson, fermion), - (ntuple(_ -> SyncedPolarization{1}(), i)..., AllSpin()), - (AllPol(), AllSpin()), - ), - ) == 16 - - @test multiplicity( - TestImplementation.TestProcessSP( - (boson, fermion), - (ntuple(_ -> boson, i)..., fermion), - (AllPol(), SpinDown()), - (ntuple(_ -> SyncedPolarization{1}(), i)..., AllSpin()), - ), - ) == 8 - - for j in 1:4 - # ... with j synced fermions - @test multiplicity( - TestImplementation.TestProcessSP( - (ntuple(_ -> boson, i)..., fermion), - (boson, ntuple(_ -> fermion, j)), - (ntuple(_ -> SyncedPolarization{1}(), i)..., SpinDown()), - (PolX(), ntuple(_ -> SyncedSpin{1}(), j)...), - ), - ) == 4 - end - end - - @test multiplicity( - TestImplementation.TestProcessSP( - (ntuple(_ -> boson, 2)..., fermion), - (ntuple(_ -> boson, 2)..., fermion), - (ntuple(_ -> SyncedPolarization{1}(), 2)..., SpinUp()), - (ntuple(_ -> SyncedPolarization{2}(), 2)..., AllSpin()), - ), - ) == 8 - end - @testset "incident flux" begin test_incident_flux = QEDbase._incident_flux( InPhaseSpacePoint(TESTPROC, TESTMODEL, TESTPSDEF, IN_PS) @@ -268,3 +204,75 @@ include("../test_implementation/TestImplementation.jl") InPhaseSpacePoint(TESTPROC, TESTMODEL, TESTPSDEF, ps_in_coords) end end + +@testset "Process Multiplicity" begin + boson = TestImplementation.TestParticleBoson() + fermion = TestImplementation.TestParticleFermion() + + _mult(::AbstractDefinitePolarization) = 1 + _mult(::AbstractDefiniteSpin) = 1 + _mult(::AbstractIndefinitePolarization) = 2 + _mult(::AbstractIndefiniteSpin) = 2 + + @testset "no synced spins/pols" begin # test all possible combinations for fermion+boson->fermion+boson processes, without synced + spins = (SpinUp(), SpinDown(), AllSpin()) + pols = (PolX(), PolY(), AllPol()) + for (p1, s1, p2, s2) in Iterators.product(pols, spins, pols, spins) + proc = TestImplementation.TestProcessSP( + (boson, fermion), (boson, fermion), (p1, s1), (p2, s2) + ) + @test multiplicity(proc) == prod(_mult.((p1, s1, p2, s2))) + @test incoming_multiplicity(proc) == prod(_mult.((p1, s1))) + @test outgoing_multiplicity(proc) == prod(_mult.((p2, s2))) + end + end + + # some special cases for synced spins and pols testing + for i in 1:4 + # i synced bosons + proc = TestImplementation.TestProcessSP( + (ntuple(_ -> boson, i)..., fermion), + (boson, fermion), + (ntuple(_ -> SyncedPolarization{1}(), i)..., AllSpin()), + (AllPol(), AllSpin()), + ) + @test multiplicity(proc) == 16 + @test incoming_multiplicity(proc) == 4 + @test outgoing_multiplicity(proc) == 4 + + proc = TestImplementation.TestProcessSP( + (boson, fermion), + (ntuple(_ -> boson, i)..., fermion), + (AllPol(), SpinDown()), + (ntuple(_ -> SyncedPolarization{1}(), i)..., AllSpin()), + ) + @test multiplicity(proc) == 8 + @test incoming_multiplicity(proc) == 2 + @test outgoing_multiplicity(proc) == 4 + + for j in 1:4 + # ... with j synced fermions + proc = TestImplementation.TestProcessSP( + (ntuple(_ -> boson, i)..., fermion), + (boson, ntuple(_ -> fermion, j)), + (ntuple(_ -> SyncedPolarization{1}(), i)..., SpinDown()), + (PolX(), ntuple(_ -> SyncedSpin{1}(), j)...), + ) + @test multiplicity(proc) == 4 + @test incoming_multiplicity(proc) == 2 + @test outgoing_multiplicity(proc) == 2 + end + end + + @testset "multiple differing synced polarizations" begin + proc = TestImplementation.TestProcessSP( + (ntuple(_ -> boson, 2)..., fermion), + (ntuple(_ -> boson, 2)..., fermion), + (ntuple(_ -> SyncedPolarization{1}(), 2)..., SpinUp()), + (ntuple(_ -> SyncedPolarization{2}(), 2)..., AllSpin()), + ) + @test multiplicity(proc) == 8 + @test incoming_multiplicity(proc) == 2 + @test outgoing_multiplicity(proc) == 4 + end +end From 9bf3ffaad4a92be613d66480c3ef26437c3ced38 Mon Sep 17 00:00:00 2001 From: Anton Reinhard Date: Tue, 13 Aug 2024 16:13:38 +0200 Subject: [PATCH 08/10] Add test case where syncs happen across in/out CI_INTG_PKG_URL_QEDprocesses: https://github.com/AntonReinhard/QEDprocesses.jl#dff825b70b027c7251eda6ed20389b75cb78377d --- test/interfaces/process.jl | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/interfaces/process.jl b/test/interfaces/process.jl index afec0db..127766f 100644 --- a/test/interfaces/process.jl +++ b/test/interfaces/process.jl @@ -275,4 +275,16 @@ end @test incoming_multiplicity(proc) == 2 @test outgoing_multiplicity(proc) == 4 end + + @testset "synced polarization across in and out particles" begin + proc = TestImplementation.TestProcessSP( + (ntuple(_ -> boson, 2)..., fermion), + (ntuple(_ -> boson, 2)..., fermion), + (ntuple(i -> SyncedPolarization{i}(), 2)..., SpinUp()), + (ntuple(i -> SyncedPolarization{i}(), 2)..., SpinDown()), + ) + @test multiplicity(proc) == 4 + @test incoming_multiplicity(proc) == 4 + @test outgoing_multiplicity(proc) == 4 + end end From d0ddb73ff6ed72a691a6229635d16fbd6e947819 Mon Sep 17 00:00:00 2001 From: AntonReinhard Date: Wed, 14 Aug 2024 11:24:38 +0200 Subject: [PATCH 09/10] Make SyncedSpin/Pol constructors prettier --- src/interfaces/particles/spin_pol.jl | 6 ++---- test/interfaces/process.jl | 16 ++++++++-------- test/particle_properties.jl | 7 ++----- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/interfaces/particles/spin_pol.jl b/src/interfaces/particles/spin_pol.jl index 8f1e68e..0e31f49 100644 --- a/src/interfaces/particles/spin_pol.jl +++ b/src/interfaces/particles/spin_pol.jl @@ -191,8 +191,7 @@ like an [`AllPolarization`](@ref) would. See also: [`multiplicity`](@ref) """ struct SyncedPolarization{N} <: AbstractIndefinitePolarization - function SyncedPolarization{N}() where {N} - @assert N isa Int "N must be of type Int" + function SyncedPolarization(N::Int) return new{N}() end end @@ -210,8 +209,7 @@ like an [`AllSpin`](@ref) would. See also: [`multiplicity`](@ref) """ struct SyncedSpin{N} <: AbstractIndefiniteSpin - function SyncedSpin{N}() where {N} - @assert N isa Int "N must be of type Int" + function SyncedSpin(N::Int) return new{N}() end end diff --git a/test/interfaces/process.jl b/test/interfaces/process.jl index 127766f..a234d65 100644 --- a/test/interfaces/process.jl +++ b/test/interfaces/process.jl @@ -233,7 +233,7 @@ end proc = TestImplementation.TestProcessSP( (ntuple(_ -> boson, i)..., fermion), (boson, fermion), - (ntuple(_ -> SyncedPolarization{1}(), i)..., AllSpin()), + (ntuple(_ -> SyncedPolarization(1), i)..., AllSpin()), (AllPol(), AllSpin()), ) @test multiplicity(proc) == 16 @@ -244,7 +244,7 @@ end (boson, fermion), (ntuple(_ -> boson, i)..., fermion), (AllPol(), SpinDown()), - (ntuple(_ -> SyncedPolarization{1}(), i)..., AllSpin()), + (ntuple(_ -> SyncedPolarization(1), i)..., AllSpin()), ) @test multiplicity(proc) == 8 @test incoming_multiplicity(proc) == 2 @@ -255,8 +255,8 @@ end proc = TestImplementation.TestProcessSP( (ntuple(_ -> boson, i)..., fermion), (boson, ntuple(_ -> fermion, j)), - (ntuple(_ -> SyncedPolarization{1}(), i)..., SpinDown()), - (PolX(), ntuple(_ -> SyncedSpin{1}(), j)...), + (ntuple(_ -> SyncedPolarization(1), i)..., SpinDown()), + (PolX(), ntuple(_ -> SyncedSpin(1), j)...), ) @test multiplicity(proc) == 4 @test incoming_multiplicity(proc) == 2 @@ -268,8 +268,8 @@ end proc = TestImplementation.TestProcessSP( (ntuple(_ -> boson, 2)..., fermion), (ntuple(_ -> boson, 2)..., fermion), - (ntuple(_ -> SyncedPolarization{1}(), 2)..., SpinUp()), - (ntuple(_ -> SyncedPolarization{2}(), 2)..., AllSpin()), + (ntuple(_ -> SyncedPolarization(1), 2)..., SpinUp()), + (ntuple(_ -> SyncedPolarization(2), 2)..., AllSpin()), ) @test multiplicity(proc) == 8 @test incoming_multiplicity(proc) == 2 @@ -280,8 +280,8 @@ end proc = TestImplementation.TestProcessSP( (ntuple(_ -> boson, 2)..., fermion), (ntuple(_ -> boson, 2)..., fermion), - (ntuple(i -> SyncedPolarization{i}(), 2)..., SpinUp()), - (ntuple(i -> SyncedPolarization{i}(), 2)..., SpinDown()), + (ntuple(i -> SyncedPolarization(i), 2)..., SpinUp()), + (ntuple(i -> SyncedPolarization(i), 2)..., SpinDown()), ) @test multiplicity(proc) == 4 @test incoming_multiplicity(proc) == 4 diff --git a/test/particle_properties.jl b/test/particle_properties.jl index 9c355fd..45952c9 100644 --- a/test/particle_properties.jl +++ b/test/particle_properties.jl @@ -22,13 +22,10 @@ test_broadcast(x::AbstractSpinOrPolarization) = x PolX(), PolY(), AllPol(), - SyncedSpin{1}(), - SyncedPolarization{1}(), + SyncedSpin(1), + SyncedPolarization(1), ) @test test_broadcast.(spin_or_pol) == spin_or_pol end end - - @test_throws AssertionError SyncedSpin{5.5}() - @test_throws AssertionError SyncedPolarization{:sym}() end From 2dfae741f84342394e96cc8eacdb2c9fbee4f009 Mon Sep 17 00:00:00 2001 From: AntonReinhard Date: Wed, 14 Aug 2024 11:35:17 +0200 Subject: [PATCH 10/10] Add performance note to process interface docs CI_INTG_PKG_URL_QEDprocesses: https://github.com/AntonReinhard/QEDprocesses.jl#1287aecf85d577ffa460739ccfa1a5c290c7b3a2 --- src/interfaces/process.jl | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/interfaces/process.jl b/src/interfaces/process.jl index 69a8c3f..efdb3ba 100644 --- a/src/interfaces/process.jl +++ b/src/interfaces/process.jl @@ -28,6 +28,9 @@ outgoing_spin_pols(proc_def::AbstractProcessDefinition) can be overloaded. They must return a tuple of [`AbstractSpinOrPolarization`], where the order must match the order of the process' particles. A default implementation is provided which assumes [`AllSpin`](@ref) for every [`is_fermion`](@ref) particle and [`AllPolarization`](@ref) for every [`is_boson`](@ref) particle. +!!! note Performance + It is very beneficial for the performance of derived functions if these functions return compile-time-known values. + On top of these spin and polarization functions, the following functions are automatically defined: ```Julia @@ -74,6 +77,9 @@ Broadcast.broadcastable(proc::AbstractProcessDefinition) = Ref(proc) Interface function for scattering processes. Return a tuple of the incoming particles for the given process definition. This function needs to be given to implement the scattering process interface. +!!! note Performance + It is very beneficial for the performance of derived functions if this function returns compile-time-known values. + See also: [`AbstractParticleType`](@ref) """ function incoming_particles end @@ -84,6 +90,9 @@ function incoming_particles end Interface function for scattering processes. Return the tuple of outgoing particles for the given process definition. This function needs to be given to implement the scattering process interface. +!!! note Performance + It is very beneficial for the performance of derived functions if this function returns compile-time-known values. + See also: [`AbstractParticleType`](@ref) """ function outgoing_particles end @@ -94,6 +103,9 @@ function outgoing_particles end Interface function for scattering processes. Return the tuple of spins or polarizations for the given process definition. The order must be the same as the particles returned from [`incoming_particles`](@ref). A default implementation is provided, returning [`AllSpin`](@ref) for every [`is_fermion`](@ref) and [`AllPolarization`](@ref) for every [`is_boson`](@ref). +!!! note Performance + It is very beneficial for the performance of derived functions if this function returns compile-time-known values. + See also: [`AbstractSpinOrPolarization`](@ref) """ function incoming_spin_pols end @@ -104,6 +116,9 @@ function incoming_spin_pols end Interface function for scattering processes. Return the tuple of spins or polarizations for the given process definition. The order must be the same as the particles returned from [`outgoing_particles`](@ref). A default implementation is provided, returning [`AllSpin`](@ref) for every [`is_fermion`](@ref) and [`AllPolarization`](@ref) for every [`is_boson`](@ref). +!!! note Performance + It is very beneficial for the performance of derived functions if this function returns compile-time-known values. + See also: [`AbstractSpinOrPolarization`](@ref) """ function outgoing_spin_pols end