Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Synced Spins and Polarizations #112

Merged
merged 10 commits into from
Aug 15, 2024
7 changes: 5 additions & 2 deletions src/QEDbase.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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, incoming_multiplicity, outgoing_multiplicity

# Abstract phase space definition interface
export AbstractCoordinateSystem, AbstractFrameOfReference, AbstractPhasespaceDefinition
Expand Down Expand Up @@ -110,7 +111,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")
Expand Down
25 changes: 25 additions & 0 deletions src/implementations/process/momenta.jl
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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
144 changes: 144 additions & 0 deletions src/implementations/process/spin_pols.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@

# 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)

@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)

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.

!!! 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.
szabo137 marked this conversation as resolved.
Show resolved Hide resolved

!!! 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(
(incoming_spin_pols(proc)..., outgoing_spin_pols(proc)...),
NTuple{0,Int}(),
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
40 changes: 33 additions & 7 deletions src/interfaces/particles/spin_pol.jl
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,39 @@ const PolY = PolarizationY
Base.show(io::IO, ::PolY) = print(io, "y-polarized")

"""
multiplicity(spin_or_pol)
SyncedPolarization{N::Int} <: AbstractIndefinitePolarization

Return the number of spins or polarizations respresented by `spin_or_pol`, e.g. `multiplicity(SpinUp()) == 1`, but `multiplicity(AllSpin()) = 2`.
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`.

Having a single `SyncedPolarization{N}` in a process is legal. In this case, it behaves just
like an [`AllPolarization`](@ref) would.

See also: [`multiplicity`](@ref)
"""
struct SyncedPolarization{N} <: AbstractIndefinitePolarization
function SyncedPolarization{N}() where {N}
szabo137 marked this conversation as resolved.
Show resolved Hide resolved
@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`.

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)
"""
function multiplicity end
multiplicity(::AbstractDefinitePolarization) = 1
multiplicity(::AbstractDefiniteSpin) = 1
multiplicity(::AbstractIndefinitePolarization) = 2
multiplicity(::AbstractIndefiniteSpin) = 2
struct SyncedSpin{N} <: AbstractIndefiniteSpin
function SyncedSpin{N}() where {N}
@assert N isa Int "N must be of type Int"
return new{N}()
end
end
11 changes: 10 additions & 1 deletion src/interfaces/process.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand All @@ -52,7 +62,6 @@ Optional is the implementation of

```
to enable the calculation of total probabilities and cross sections.

"""
abstract type AbstractProcessDefinition end

Expand Down
Loading
Loading