diff --git a/src/QEDcore.jl b/src/QEDcore.jl index af51154..ef81690 100644 --- a/src/QEDcore.jl +++ b/src/QEDcore.jl @@ -13,18 +13,10 @@ export BiSpinor, AdjointBiSpinor, DiracMatrix export gamma, GAMMA, DiracGammaRepresentation, slashed # particle types -export AbstractParticleSpinor export FermionLike, Fermion, AntiFermion, MajoranaFermion export BosonLike, Boson, AntiBoson, MajoranaBoson export Electron, Positron, Photon -# particle spinors -export BASE_PARTICLE_SPINOR, BASE_ANTIPARTICLE_SPINOR -export IncomingFermionSpinor, - OutgoingFermionSpinor, IncomingAntiFermionSpinor, OutgoingAntiFermionSpinor -export SpinorU, SpinorUbar, SpinorV, SpinorVbar -export @valid_spinor_input - # particle base states export base_state @@ -58,6 +50,5 @@ include("algebraic_objects/gamma_matrices.jl") include("particles/particle_types.jl") include("particles/propagators.jl") include("particles/states.jl") -include("particles/spinors.jl") end diff --git a/src/particles/particle_types.jl b/src/particles/particle_types.jl index 97917df..ecd0a9c 100644 --- a/src/particles/particle_types.jl +++ b/src/particles/particle_types.jl @@ -1,17 +1,10 @@ ############### -# The particle types +# The particle types # # In this file, we define the types of particles, their states and directions, and -# implement the abstact particle interface accordingly. +# implement the abstact particle interface accordingly. ############### -""" - AbstractParticleSpinor - -TBW -""" -abstract type AbstractParticleSpinor end - """ Abstract base types for particle species that act like fermions in the sense of particle statistics. @@ -24,10 +17,10 @@ QEDbase.is_fermion(::FermionLike) = true """ Abstract base type for fermions as distinct from [`AntiFermion`](@ref)s. - + !!! note "particle interface" All subtypes of `Fermion` have - ```julia + ```julia is_fermion(::Fermion) = true is_particle(::Fermion) = true is_anti_particle(::Fermion) = false @@ -44,8 +37,8 @@ QEDbase.is_anti_particle(::Fermion) = false Abstract base type for anti-fermions as distinct from its particle counterpart `Fermion`. !!! note "particle interface" - All subtypes of `AntiFermion` have - ```julia + All subtypes of `AntiFermion` have + ```julia is_fermion(::AntiFermion) = true is_particle(::AntiFermion) = false is_anti_particle(::AntiFermion) = true @@ -61,13 +54,13 @@ QEDbase.is_anti_particle(::AntiFermion) = true Abstract base type for majorana-fermions, i.e. fermions which are their own anti-particles. !!! note "particle interface" - All subtypes of `MajoranaFermion` have - ```julia + All subtypes of `MajoranaFermion` have + ```julia is_fermion(::MajoranaFermion) = true is_particle(::MajoranaFermion) = true is_anti_particle(::MajoranaFermion) = true ``` - + """ abstract type MajoranaFermion <: FermionLike end @@ -76,7 +69,7 @@ QEDbase.is_particle(::MajoranaFermion) = true QEDbase.is_anti_particle(::MajoranaFermion) = true """ -Concrete type for *electrons* as a particle species. Mostly used for dispatch. +Concrete type for *electrons* as a particle species. Mostly used for dispatch. ```jldoctest julia> using QEDcore @@ -99,7 +92,7 @@ QEDbase.charge(::Electron) = -1.0 Base.show(io::IO, ::Electron) = print(io, "electron") """ -Concrete type for *positrons* as a particle species. Mostly used for dispatch. +Concrete type for *positrons* as a particle species. Mostly used for dispatch. ```jldoctest julia> using QEDcore @@ -122,8 +115,8 @@ QEDbase.charge(::Positron) = 1.0 Base.show(io::IO, ::Positron) = print(io, "positron") """ -Abstract base types for particle species that act like bosons in the sense of particle statistics. - +Abstract base types for particle species that act like bosons in the sense of particle statistics. + !!! note "particle interface" Every concrete subtype of `BosonLike` has `is_boson(::BosonLike) = true`. """ @@ -133,10 +126,10 @@ QEDbase.is_boson(::BosonLike) = true """ Abstract base type for bosons as distinct from its anti-particle counterpart [`AntiBoson`](@ref). - + !!! note "particle interface" All subtypes of `Boson` have - ```julia + ```julia is_boson(::Boson) = true is_particle(::Boson) = true is_anti_particle(::Boson) = false @@ -148,10 +141,10 @@ QEDbase.is_anti_particle(::Boson) = false """ Abstract base type for anti-bosons as distinct from its particle counterpart [`Boson`](@ref). - + !!! note "particle interface" All subtypes of `AntiBoson` have - ```julia + ```julia is_boson(::AntiBoson) = true is_particle(::AntiBoson) = false is_anti_particle(::AntiBoson) = true @@ -165,8 +158,8 @@ QEDbase.is_anti_particle(::AntiBoson) = true Abstract base type for majorana-bosons, i.e. bosons which are their own anti-particles. !!! note "particle interface" - All subtypes of `MajoranaBoson` have - ```julia + All subtypes of `MajoranaBoson` have + ```julia is_boson(::MajoranaBoson) = true is_particle(::MajoranaBoson) = true is_anti_particle(::MajoranaBoson) = true @@ -177,7 +170,7 @@ QEDbase.is_particle(::MajoranaBoson) = true QEDbase.is_anti_particle(::MajoranaBoson) = true """ -Concrete type for the *photons* as a particle species. Mostly used for dispatch. +Concrete type for the *photons* as a particle species. Mostly used for dispatch. ```jldoctest julia> using QEDcore diff --git a/src/particles/spinors.jl b/src/particles/spinors.jl deleted file mode 100644 index ab9ddbb..0000000 --- a/src/particles/spinors.jl +++ /dev/null @@ -1,121 +0,0 @@ -const SPINOR_VALIDITY_CHECK = Ref(true) - -macro valid_spinor_input(ex) - return quote - SPINOR_VALIDITY_CHECK.x = false - local val = $(esc(ex)) - SPINOR_VALIDITY_CHECK.x = true - val - end -end - -const BASE_PARTICLE_SPINOR_UP = BiSpinor(1.0, 0.0, 0.0, 0.0) -const BASE_PARTICLE_SPINOR_DOWN = BiSpinor(0.0, 1.0, 0.0, 0.0) -const BASE_PARTICLE_SPINOR = [BASE_PARTICLE_SPINOR_UP, BASE_PARTICLE_SPINOR_DOWN] -const BASE_ANTIPARTICLE_SPINOR_UP = BiSpinor(0.0, 0.0, 1.0, 0.0) -const BASE_ANTIPARTICLE_SPINOR_DOWN = BiSpinor(0.0, 0.0, 0.0, 1.0) -const BASE_ANTIPARTICLE_SPINOR = [ - BASE_ANTIPARTICLE_SPINOR_UP, BASE_ANTIPARTICLE_SPINOR_DOWN -] - -@inline function _check_spinor_input( - mom::T, mass::Float64 -) where {T<:AbstractLorentzVector{TE}} where {TE<:Real} - if SPINOR_VALIDITY_CHECK[] && !isonshell(mom, mass) - throw( - SpinorConstructionError( - "P^2 = $(getMass2(mom)) needs to be equal to mass^2=$(mass^2)" - ), - ) - end -end - -# -# fermion spinors -# - -function _build_particle_booster( - mom::T, mass::Float64 -) where {T<:AbstractLorentzVector{TE}} where {TE<:Real} - _check_spinor_input(mom, mass) - return (slashed(mom) + mass * one(DiracMatrix)) / (sqrt(abs(mom.t) + mass)) -end - -struct IncomingFermionSpinor <: AbstractParticleSpinor - booster::DiracMatrix -end - -function IncomingFermionSpinor( - mom::T, mass::Float64 -) where {T<:AbstractLorentzVector{TE}} where {TE<:Real} - return IncomingFermionSpinor(_build_particle_booster(mom, mass)) -end - -function (SP::IncomingFermionSpinor)(spin::Int64) - return SP.booster * BASE_PARTICLE_SPINOR[spin] -end - -const SpinorU = IncomingFermionSpinor - -struct OutgoingFermionSpinor <: AbstractParticleSpinor - booster::DiracMatrix -end - -function OutgoingFermionSpinor( - mom::T, mass::Float64 -) where {T<:AbstractLorentzVector{TE}} where {TE<:Real} - return OutgoingFermionSpinor(_build_particle_booster(mom, mass)) -end - -function (SP::OutgoingFermionSpinor)(spin::Int64) - return AdjointBiSpinor(SP.booster * BASE_PARTICLE_SPINOR[spin]) * GAMMA[1] -end - -const SpinorUbar = OutgoingFermionSpinor - -# -# Anti fermion spinors -# - -function _build_antiparticle_booster( - mom::T, mass::Float64 -) where {T<:AbstractLorentzVector{TE}} where {TE<:Real} - _check_spinor_input(mom, mass) - return (mass * one(DiracMatrix) - slashed(mom)) / (sqrt(abs(mom.t) + mass)) -end - -struct OutgoingAntiFermionSpinor <: AbstractParticleSpinor - booster::DiracMatrix -end - -function OutgoingAntiFermionSpinor( - mom::T, mass::Float64 -) where {T<:AbstractLorentzVector{TE}} where {TE<:Real} - return OutgoingAntiFermionSpinor(_build_antiparticle_booster(mom, mass)) -end - -function (SP::OutgoingAntiFermionSpinor)(spin::Int64) - return SP.booster * BASE_ANTIPARTICLE_SPINOR[spin] -end - -const SpinorV = OutgoingAntiFermionSpinor - -struct IncomingAntiFermionSpinor <: AbstractParticleSpinor - booster::DiracMatrix -end - -function IncomingAntiFermionSpinor( - mom::T, mass::Float64 -) where {T<:AbstractLorentzVector{TE}} where {TE<:Real} - return IncomingAntiFermionSpinor(_build_antiparticle_booster(mom, mass)) -end - -function (SP::IncomingAntiFermionSpinor)(spin::Int64) - return AdjointBiSpinor(SP.booster * BASE_ANTIPARTICLE_SPINOR[spin]) * GAMMA[1] -end - -const SpinorVbar = IncomingAntiFermionSpinor - -function Base.getindex(SP::T, idx) where {T<:AbstractParticleSpinor} - return idx in (1, 2) ? SP(idx) : throw(BoundsError()) -end diff --git a/test/particles/spinors.jl b/test/particles/spinors.jl deleted file mode 100644 index 7d424c7..0000000 --- a/test/particles/spinors.jl +++ /dev/null @@ -1,88 +0,0 @@ -using QEDcore -using Random - -const ATOL = 1e-15 - -const SPINS = (1, 2) - -@testset "particle spinors" for LorentzVectorType in [SFourMomentum, MFourMomentum] - rng = MersenneTwister(1234) - x, y, z = rand(rng, 3) - mass = rand(rng) - P = LorentzVectorType(sqrt(x^2 + y^2 + z^2 + mass^2), x, y, z) - - U = SpinorU(P, mass) - Ubar = SpinorUbar(P, mass) - V = SpinorV(P, mass) - Vbar = SpinorVbar(P, mass) - - @testset "construction" begin - @test U isa IncomingFermionSpinor - @test Ubar isa OutgoingFermionSpinor - @test V isa OutgoingAntiFermionSpinor - @test Vbar isa IncomingAntiFermionSpinor - - for spin in SPINS - @test isapprox(U[spin], U.booster * BASE_PARTICLE_SPINOR[spin]) - @test isapprox(V[spin], V.booster * BASE_ANTIPARTICLE_SPINOR[spin]) - - @test isapprox(Ubar[spin], AdjointBiSpinor(U[spin]) * GAMMA[1]) - @test isapprox(Vbar[spin], AdjointBiSpinor(V[spin]) * GAMMA[1]) - end - end # construction - - @testset "normatlisation" begin - for s1 in SPINS - for s2 in SPINS - @test isapprox(Ubar[s1] * U[s2], 2 * mass * (s1 == s2)) - @test isapprox(Vbar[s1] * V[s2], -2 * mass * (s1 == s2)) - @test isapprox(Ubar[s1] * V[s2], 0.0) - @test isapprox(Vbar[s1] * U[s2], 0.0) - end - end - end # normatlisation - - @testset "completeness" begin - sumU = zero(DiracMatrix) - sumV = zero(DiracMatrix) - for spin in SPINS - sumU += U(spin) * Ubar(spin) - sumV += V(spin) * Vbar(spin) - end - - @test isapprox(sumU, (slashed(P) + mass * one(DiracMatrix))) - @test isapprox(sumV, (slashed(P) - mass * one(DiracMatrix))) - end # completeness - - @testset "diracs equation" begin - for spin in SPINS - @test isapprox( - (slashed(P) - mass * one(DiracMatrix)) * U[spin], zero(BiSpinor), atol=ATOL - ) - @test isapprox( - (slashed(P) + mass * one(DiracMatrix)) * V[spin], zero(BiSpinor), atol=ATOL - ) - @test isapprox( - Ubar[spin] * (slashed(P) - mass * one(DiracMatrix)), - zero(AdjointBiSpinor), - atol=ATOL, - ) - @test isapprox( - Vbar[spin] * (slashed(P) + mass * one(DiracMatrix)), - zero(AdjointBiSpinor), - atol=ATOL, - ) - end - end #diracs equation - - @testset "sandwich" begin - for s1 in SPINS - for s2 in SPINS - @test isapprox( - LorentzVectorType(Ubar[s1] * (GAMMA * U[s2])) * (s1 == s2), - 2 * P * (s1 == s2), - ) - end - end - end #sandwich -end # particle spinors diff --git a/test/particles/states.jl b/test/particles/states.jl index 36dd488..6c9eb48 100644 --- a/test/particles/states.jl +++ b/test/particles/states.jl @@ -4,15 +4,8 @@ using Random include("../utils.jl") -FERMION_STATES_GROUNDTRUTH_FACTORY = Dict( - (Incoming, Electron) => IncomingFermionSpinor, - (Outgoing, Electron) => OutgoingFermionSpinor, - (Incoming, Positron) => IncomingAntiFermionSpinor, - (Outgoing, Positron) => OutgoingAntiFermionSpinor, -) - RNG = MersenneTwister(708583836976) -ATOL = eps() +ATOL = 1e-15 RTOL = 0.0 PHOTON_ENERGIES = (0.0, rand(RNG), rand(RNG) * 10) COS_THETAS = (-1.0, -rand(RNG), 0.0, rand(RNG), 1.0) @@ -48,21 +41,77 @@ test_broadcast(x::AbstractSpinOrPolarization) = x Iterators.product((Electron, Positron), (Incoming, Outgoing)) mom = SFourMomentum(sqrt(mass(p()) + X^2 + Y^2 + Z^2), X, Y, Z) particle_mass = mass(p()) - groundtruth_states = FERMION_STATES_GROUNDTRUTH_FACTORY[(d, p)](mom, particle_mass) - groundtruth_tuple = SVector(groundtruth_states(1), groundtruth_states(2)) - @test base_state(p(), d(), mom, AllSpin()) == groundtruth_tuple - @test base_state(p(), d(), mom, SpinUp()) == groundtruth_tuple[1] - @test base_state(p(), d(), mom, SpinDown()) == groundtruth_tuple[2] - - @test QEDbase._as_svec(base_state(p(), d(), mom, AllSpin())) isa SVector - @test QEDbase._as_svec(base_state(p(), d(), mom, SpinUp())) isa SVector - @test QEDbase._as_svec(base_state(p(), d(), mom, SpinDown())) isa SVector - - @test QEDbase._as_svec(base_state(p(), d(), mom, AllSpin())) == groundtruth_tuple - @test QEDbase._as_svec(base_state(p(), d(), mom, SpinUp()))[1] == - groundtruth_tuple[1] - @test QEDbase._as_svec(base_state(p(), d(), mom, SpinDown()))[1] == - groundtruth_tuple[2] + + @testset "tooling" begin + @test QEDbase._as_svec(base_state(p(), d(), mom, AllSpin())) isa SVector + @test QEDbase._as_svec(base_state(p(), d(), mom, SpinUp())) isa SVector + @test QEDbase._as_svec(base_state(p(), d(), mom, SpinDown())) isa SVector + end + end + @testset "spinor properties" begin + x, y, z = rand(RNG, 3) + m = mass(Electron()) + P = SFourMomentum(sqrt(x^2 + y^2 + z^2 + m^2), x, y, z) + + U = base_state(Electron(), Incoming(), P, AllSpin()) + Ubar = base_state(Electron(), Outgoing(), P, AllSpin()) + V = base_state(Positron(), Outgoing(), P, AllSpin()) + Vbar = base_state(Positron(), Incoming(), P, AllSpin()) + + @testset "normatlisation" begin + for s1 in (1, 2) + for s2 in (1, 2) + @test isapprox(Ubar[s1] * U[s2], 2 * m * (s1 == s2)) + @test isapprox(Vbar[s1] * V[s2], -2 * m * (s1 == s2)) + @test isapprox(Ubar[s1] * V[s2], 0.0) + @test isapprox(Vbar[s1] * U[s2], 0.0) + end + end + end # normatlisation + + @testset "completeness" begin + sumU = zero(DiracMatrix) + sumV = zero(DiracMatrix) + for spin in (1, 2) + sumU += U[spin] * Ubar[spin] + sumV += V[spin] * Vbar[spin] + end + + @test isapprox(sumU, (slashed(P) + m * one(DiracMatrix))) + @test isapprox(sumV, (slashed(P) - m * one(DiracMatrix))) + end # completeness + + @testset "diracs equation" begin + for spin in (1, 2) + @test isapprox( + (slashed(P) - m * one(DiracMatrix)) * U[spin], zero(BiSpinor), atol=ATOL + ) + @test isapprox( + (slashed(P) + m * one(DiracMatrix)) * V[spin], zero(BiSpinor), atol=ATOL + ) + @test isapprox( + Ubar[spin] * (slashed(P) - m * one(DiracMatrix)), + zero(AdjointBiSpinor), + atol=ATOL, + ) + @test isapprox( + Vbar[spin] * (slashed(P) + m * one(DiracMatrix)), + zero(AdjointBiSpinor), + atol=ATOL, + ) + end + end #diracs equation + + @testset "sandwich" begin + for s1 in (1, 2) + for s2 in (1, 2) + @test isapprox( + SFourMomentum(Ubar[s1] * (GAMMA * U[s2])) * (s1 == s2), + 2 * P * (s1 == s2), + ) + end + end + end #sandwich end end diff --git a/test/runtests.jl b/test/runtests.jl index 48f361a..47d20c0 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -33,10 +33,6 @@ begin include("particles/states.jl") end - @time @safetestset "particle spinors" begin - include("particles/spinors.jl") - end - @time @safetestset "particle base states" begin include("particles/states.jl") end