From e84809cea7f9ecf3cbac9c6145999650dc6243e9 Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Thu, 16 May 2024 14:39:09 +0200 Subject: [PATCH] perturbative Compton (#40) This PR adds one photon Compton scattering described in perturbative QED. This includes the following variants * diff. probability and cross section on momenta * diff. probability and cross section on coordinates (electron restframe and spherical coordinates) All implementations are done for arbitrary combinations of spins and polarizations. ## Todos - [x] discuss where the spins/polarizations are stored: proc or phase space point (be aware of dispatch) - [x] add total cross section - [x] add unit test for total cross section - [x] add unit tests for phase space point input --------- Co-authored-by: Uwe Hernandez Acosta Co-authored-by: Tom Jungnickel <140055258+tjungni@users.noreply.github.com> Co-authored-by: Anton Reinhard --- Project.toml | 1 + src/QEDprocesses.jl | 19 ++ src/constants.jl | 7 + src/models/models.jl | 2 + src/models/perturbative_qed.jl | 23 +++ src/patch_QEDbase.jl | 8 +- .../one_photon_compton/one_photon_compton.jl | 11 ++ .../perturbative/cross_section.jl | 173 ++++++++++++++++++ .../perturbative/kinematics.jl | 54 ++++++ .../perturbative/total_probability.jl | 20 ++ src/processes/one_photon_compton/process.jl | 61 ++++++ src/propagators.jl | 4 +- test/Project.toml | 1 + .../one_photon_compton/groundtruths.jl | 26 +++ .../one_photon_compton/perturbative.jl | 118 ++++++++++++ test/processes/one_photon_compton/process.jl | 56 ++++++ test/processes/run_process_test.jl | 8 + test/runtests.jl | 4 + 18 files changed, 592 insertions(+), 4 deletions(-) create mode 100644 src/constants.jl create mode 100644 src/models/models.jl create mode 100644 src/models/perturbative_qed.jl create mode 100644 src/processes/one_photon_compton/one_photon_compton.jl create mode 100644 src/processes/one_photon_compton/perturbative/cross_section.jl create mode 100644 src/processes/one_photon_compton/perturbative/kinematics.jl create mode 100644 src/processes/one_photon_compton/perturbative/total_probability.jl create mode 100644 src/processes/one_photon_compton/process.jl create mode 100644 test/processes/one_photon_compton/groundtruths.jl create mode 100644 test/processes/one_photon_compton/perturbative.jl create mode 100644 test/processes/one_photon_compton/process.jl create mode 100644 test/processes/run_process_test.jl diff --git a/Project.toml b/Project.toml index 1a4e0dc..e1da762 100644 --- a/Project.toml +++ b/Project.toml @@ -5,6 +5,7 @@ version = "0.1.0" [deps] QEDbase = "10e22c08-3ccb-4172-bfcf-7d7aa3d04d93" +QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" [compat] diff --git a/src/QEDprocesses.jl b/src/QEDprocesses.jl index 134d68b..d571b0f 100644 --- a/src/QEDprocesses.jl +++ b/src/QEDprocesses.jl @@ -1,5 +1,9 @@ module QEDprocesses +# constants +export ALPHA, + ALPHA_SQUARE, ELEMENTARY_CHARGE, ELEMENTARY_CHARGE_SQUARE, ELECTRONMASS, ONE_OVER_FOURPI + # Abstract model interface export AbstractModelDefinition, fundamental_interaction_type @@ -34,16 +38,31 @@ export ParticleStateful, PhaseSpacePoint export spin, polarization, particle_direction, particle_species, momentum, getindex export generate_phase_space +# specific compute models +export PerturbativeQED + +# specific scattering processes +export Compton, omega_prime + using QEDbase +using StaticArrays +using QuadGK +include("constants.jl") include("utils.jl") + include("interfaces/model_interface.jl") include("interfaces/process_interface.jl") include("interfaces/setup_interface.jl") + include("phase_spaces.jl") include("momentum_generation.jl") include("propagators.jl") include("probabilities.jl") include("cross_sections.jl") + +include("models/models.jl") +include("processes/one_photon_compton/one_photon_compton.jl") + include("patch_QEDbase.jl") end diff --git a/src/constants.jl b/src/constants.jl new file mode 100644 index 0000000..b4b2498 --- /dev/null +++ b/src/constants.jl @@ -0,0 +1,7 @@ + +const ALPHA = inv(137.035999074) +const ALPHA_SQUARE = ALPHA^2 +const ELEMENTARY_CHARGE = sqrt(4 * pi * ALPHA) +const ELEMENTARY_CHARGE_SQUARE = 4 * pi * ALPHA +const ELECTRONMASS = 0.510998928e6 # eV +const ONE_OVER_FOURPI = 1 / (4 * pi) diff --git a/src/models/models.jl b/src/models/models.jl new file mode 100644 index 0000000..f08ce00 --- /dev/null +++ b/src/models/models.jl @@ -0,0 +1,2 @@ + +include("perturbative_qed.jl") diff --git a/src/models/perturbative_qed.jl b/src/models/perturbative_qed.jl new file mode 100644 index 0000000..33bad1f --- /dev/null +++ b/src/models/perturbative_qed.jl @@ -0,0 +1,23 @@ + +struct PerturbativeQED <: AbstractModelDefinition end + +fundamental_interaction_type(::PerturbativeQED) = :electromagnetic + +""" + in_phase_space_dimension(proc::AbstractProcessDefinition, ::PerturbativeQED) + + +Return the number of degrees of freedom to determine the incoming phase space for processes in PerturbativeQED. + +!!! note "Convention" + + The current implementation only supports the case where two of the incoming particles collide head-on. + +""" +function in_phase_space_dimension(proc::AbstractProcessDefinition, ::PerturbativeQED) + return 3 * number_incoming_particles(proc) - 4 - 1 +end + +function out_phase_space_dimension(proc::AbstractProcessDefinition, ::PerturbativeQED) + return 3 * number_outgoing_particles(proc) - 4 +end diff --git a/src/patch_QEDbase.jl b/src/patch_QEDbase.jl index fac3ee5..740ced7 100644 --- a/src/patch_QEDbase.jl +++ b/src/patch_QEDbase.jl @@ -2,10 +2,16 @@ # Patches for `QEDbase.jl` # remove if this went into `QEDbase.jl` # -# fix will be provided here: https://github.com/QEDjl-project/QEDbase.jl/pull/62 ############# +# fix: https://github.com/QEDjl-project/QEDbase.jl/pull/62 Broadcast.broadcastable(dir::Incoming) = Ref(dir) Broadcast.broadcastable(dir::Outgoing) = Ref(dir) Broadcast.broadcastable(part::AbstractParticleType) = Ref(part) Broadcast.broadcastable(spin_or_pol::AbstractSpinOrPolarization) = Ref(spin_or_pol) + +# fix: https://github.com/QEDjl-project/QEDbase.jl/pull/63 +number_of_spin_pol(::AbstractDefinitePolarization) = 1 +number_of_spin_pol(::AbstractDefiniteSpin) = 1 +number_of_spin_pol(::AbstractIndefinitePolarization) = 2 +number_of_spin_pol(::AbstractIndefiniteSpin) = 2 diff --git a/src/processes/one_photon_compton/one_photon_compton.jl b/src/processes/one_photon_compton/one_photon_compton.jl new file mode 100644 index 0000000..922fc8d --- /dev/null +++ b/src/processes/one_photon_compton/one_photon_compton.jl @@ -0,0 +1,11 @@ +################# +# The one-photon Compton process +# +# This file contains the implementation of the abstract process setup for +# Compton +################## + +include("process.jl") +include("perturbative/kinematics.jl") +include("perturbative/cross_section.jl") +include("perturbative/total_probability.jl") diff --git a/src/processes/one_photon_compton/perturbative/cross_section.jl b/src/processes/one_photon_compton/perturbative/cross_section.jl new file mode 100644 index 0000000..4330433 --- /dev/null +++ b/src/processes/one_photon_compton/perturbative/cross_section.jl @@ -0,0 +1,173 @@ +##### +# Perturbative one-photon Compton scattering +# Implementation of the cross section interface +##### + +function _incident_flux( + proc::Compton, model::PerturbativeQED, in_ps::AbstractVector{T} +) where {T<:QEDbase.AbstractFourMomentum} + return @inbounds in_ps[1] * in_ps[2] +end + +function _matrix_element( + proc::Compton, + model::PerturbativeQED, + in_ps::AbstractVector{T}, + out_ps::AbstractVector{T}, +) where {T<:QEDbase.AbstractFourMomentum} + return _pert_compton_matrix_element(proc, in_ps, out_ps) +end + +""" + +!!! note "Convention" + + We average over the initial spins and pols, and sum over final. +""" +function _averaging_norm(proc::Compton) + normalizations = number_of_spin_pol.(_in_spin_and_pol(proc)) + return inv(prod(normalizations)) +end + +function _all_onshell( + proc::Compton, in_ps::AbstractVector{T}, out_ps::AbstractVector{T} +) where {T<:QEDbase.AbstractFourMomentum} + sq_in_moms = getMass2.(in_ps) + sq_out_moms = getMass2.(out_ps) + sq_in_masses = mass.(incoming_particles(proc)) .^ 2 + sq_out_masses = mass.(outgoing_particles(proc)) .^ 2 + return isapprox(sq_in_moms, SVector(sq_in_masses)) && + isapprox(sq_out_moms, SVector(sq_out_masses)) +end + +function _is_in_phasespace( + proc::Compton, + model::PerturbativeQED, + in_ps_def::AbstractPhasespaceDefinition, + in_ps::AbstractVector{T}, + out_ps::AbstractVector{T}, +) where {T<:QEDbase.AbstractFourMomentum} + return (isapprox(sum(in_ps), sum(out_ps))) ? _all_onshell(proc, in_ps, out_ps) : false +end + +@inline function _phase_space_factor( + proc::Compton, + model::PerturbativeQED, + in_ps_def::AbstractPhasespaceDefinition, + in_ps::AbstractVector{T}, + out_ps::AbstractVector{T}, +) where {T<:QEDbase.AbstractFourMomentum} + return _pert_compton_ps_fac(in_ps_def, in_ps[2], out_ps[2]) +end + +####### +# Matrix elements +####### + +@inline function _pert_compton_matrix_element( + proc::Compton, in_ps::AbstractVector{T}, out_ps::AbstractVector{T} +) where {T<:QEDbase.AbstractFourMomentum} + in_electron_mom = in_ps[1] + in_photon_mom = in_ps[2] + out_electron_mom = out_ps[1] + out_photon_mom = out_ps[2] + + in_electron_state = base_state(Electron(), Incoming(), in_electron_mom, proc.in_spin) + in_photon_state = base_state(Photon(), Incoming(), in_photon_mom, proc.in_pol) + + out_electron_state = base_state(Electron(), Outgoing(), out_electron_mom, proc.out_spin) + + out_photon_state = base_state(Photon(), Outgoing(), out_photon_mom, proc.out_pol) + return _pert_compton_matrix_element( + in_electron_mom, + in_electron_state, + in_photon_mom, + in_photon_state, + out_electron_mom, + out_electron_state, + out_photon_mom, + out_photon_state, + ) +end + +function _pert_compton_matrix_element( + in_electron_mom::T, + in_electron_state, + in_photon_mom::T, + in_photon_state, + out_electron_mom::T, + out_electron_state, + out_photon_mom::T, + out_photon_state, +) where {T<:QEDbase.AbstractFourMomentum} + base_states_comb = Iterators.product( + QEDbase._as_svec(in_electron_state), + QEDbase._as_svec(in_photon_state), + QEDbase._as_svec(out_electron_state), + QEDbase._as_svec(out_photon_state), + ) + + matrix_elements = Vector{ComplexF64}() + sizehint!(matrix_elements, length(base_states_comb)) + for (in_el, in_ph, out_el, out_ph) in base_states_comb + push!( + matrix_elements, + _pert_compton_matrix_element_single( + in_electron_mom, + in_el, + in_photon_mom, + in_ph, + out_electron_mom, + out_el, + out_photon_mom, + out_ph, + ), + ) + end + + return matrix_elements +end + +function _pert_compton_matrix_element_single( + in_electron_mom::T, + in_electron_state::BiSpinor, + in_photon_mom::T, + in_photon_state::SLorentzVector, + out_electron_mom::T, + out_electron_state::AdjointBiSpinor, + out_photon_mom::T, + out_photon_state::SLorentzVector, +) where {T<:QEDbase.AbstractFourMomentum} + in_ph_slashed = slashed(in_photon_state) + out_ph_slashed = slashed(out_photon_state) + + prop1 = _fermion_propagator(in_photon_mom + in_electron_mom, mass(Electron())) + prop2 = _fermion_propagator(in_electron_mom - out_photon_mom, mass(Electron())) + + # TODO: fermion propagator is not yet in QEDbase + diagram_1 = + out_electron_state * + (out_ph_slashed * (prop1 * (in_ph_slashed * in_electron_state))) + diagram_2 = + out_electron_state * + (in_ph_slashed * (prop2 * (out_ph_slashed * in_electron_state))) + + result = diagram_1 + diagram_2 + + # TODO: find (preferably unitful) global provider for physical constants + # elementary charge + return ELEMENTARY_CHARGE_SQUARE * result +end + +####### +# Phase space factors +####### + +function _pert_compton_ps_fac( + in_ps_def::PhasespaceDefinition{inCS,ElectronRestFrame}, in_photon_mom, out_photon_mom +) where {inCS} + # TODO + omega = getE(in_photon_mom) + omega_prime = getE(out_photon_mom) + return omega_prime^2 / (16 * pi^2 * omega * mass(Electron())) +end diff --git a/src/processes/one_photon_compton/perturbative/kinematics.jl b/src/processes/one_photon_compton/perturbative/kinematics.jl new file mode 100644 index 0000000..75fa0fb --- /dev/null +++ b/src/processes/one_photon_compton/perturbative/kinematics.jl @@ -0,0 +1,54 @@ +@inline function _pert_omega_prime(omega, cth; mass=1.0) + return omega / (1 + omega / mass * (1 - cth)) +end + +function generate_momenta( + proc::Compton, + model::PerturbativeQED, + in_ps_def::PhasespaceDefinition{SphericalCoordinateSystem,ElectronRestFrame}, + in_ps::AbstractVector{T}, + out_ps::AbstractVector{T}, +) where {T<:Real} + return _generate_momenta(proc, model, in_ps_def, in_ps, out_ps) +end + +function _generate_incoming_momenta( + proc::Compton, + model::PerturbativeQED, + in_ps_def::PhasespaceDefinition{SphericalCoordinateSystem,ElectronRestFrame}, + in_ps::AbstractVector{T}, +) where {T<:Real} + om = in_ps[1] + + P = SFourMomentum(one(om), zero(om), zero(om), zero(om)) + K = SFourMomentum(om, zero(om), zero(om), om) + + return [P, K] +end + +function _generate_momenta( + proc::Compton, + model::PerturbativeQED, + in_ps_def::PhasespaceDefinition{SphericalCoordinateSystem,ElectronRestFrame}, + in_ps::AbstractVector{T}, + out_ps::AbstractVector{T}, +) where {T<:Real} + omega = in_ps[1] + cth = out_ps[1] + phi = out_ps[2] + P, K, Pp, Kp = _generate_momenta_elab_sph(omega, cth, phi) # TODO: do this coord and frame dependent + in_moms = SVector(P, K) + out_moms = SVector(Pp, Kp) + return in_moms, out_moms +end + +function _generate_momenta_elab_sph(om, cth, phi, m=1.0) + P = SFourMomentum(m, zero(m), zero(m), zero(m)) + K = SFourMomentum(om, zero(om), zero(om), om) + omp = _pert_omega_prime(om, cth) + sth = sqrt(1 - cth^2) + sphi, cphi = sincos(phi) + Kp = SFourMomentum(omp, omp * sth * cphi, omp * sth * sphi, omp * cth) + Pp = P + K - Kp + return P, K, Pp, Kp +end diff --git a/src/processes/one_photon_compton/perturbative/total_probability.jl b/src/processes/one_photon_compton/perturbative/total_probability.jl new file mode 100644 index 0000000..4ec00ed --- /dev/null +++ b/src/processes/one_photon_compton/perturbative/total_probability.jl @@ -0,0 +1,20 @@ + +function _total_probability( + proc::Compton, + model::PerturbativeQED, + in_phase_space_def::AbstractPhasespaceDefinition, + in_phase_space::AbstractVector{T}, +) where {T<:QEDbase.AbstractFourMomentum} + omega = getE(in_phase_space[2]) + + function func(x) + return _unsafe_differential_probability( + proc, model, in_phase_space_def, [omega], [x, 0.0] + ) + end + + tot_prob, _ = quadgk(func, -1, 1; rtol=sqrt(eps(omega))) + + tot_prob *= 2 * pi # phi integration is trivial + return tot_prob +end diff --git a/src/processes/one_photon_compton/process.jl b/src/processes/one_photon_compton/process.jl new file mode 100644 index 0000000..87e6f4f --- /dev/null +++ b/src/processes/one_photon_compton/process.jl @@ -0,0 +1,61 @@ +""" + + Compton( + in_spin [= AllSpin()] + in_pol [= AllPol()] + out_spin [= AllSpin()] + out_pol [= AllPol()] + ) + +""" +struct Compton{InElectronSpin,InPhotonPol,OutElectronSpin,OutPhotonPol} <: + AbstractProcessDefinition where { + InElectronSpin<:AbstractSpin, + InPhotonPol<:AbstractPolarization, + OutElectronSpin<:AbstractSpin, + OutPhotonPol<:AbstractPolarization, +} + in_spin::InElectronSpin + in_pol::InPhotonPol + + out_spin::OutElectronSpin + out_pol::OutPhotonPol +end + +function Compton() + return Compton(AllSpin(), AllPol(), AllSpin(), AllPol()) +end + +Compton(in_pol::AbstractPolarization) = Compton(AllSpin(), in_pol, AllSpin(), AllPol()) +function Compton(in_pol::AbstractPolarization, out_pol::AbstractPolarization) + return Compton(AllSpin(), in_pol, AllSpin(), out_pol) +end + +_polarizations(proc::Compton) = (proc.in_pol, proc.out_pol) +_spins(proc::Compton) = (proc.in_spin, proc.out_spin) +_in_spin_and_pol(proc::Compton) = (proc.in_spin, proc.in_pol) +_out_spin_and_pol(proc::Compton) = (proc.out_spin, proc.out_pol) + +function QEDprocesses.incoming_particles(::Compton) + return (Electron(), Photon()) +end + +function QEDprocesses.outgoing_particles(::Compton) + return (Electron(), Photon()) +end + +function _spin_or_pol(process::Compton, ::Electron, ::Incoming) + return process.in_spin +end + +function _spin_or_pol(process::Compton, ::Electron, ::Outgoing) + return process.out_spin +end + +function _spin_or_pol(process::Compton, ::Photon, ::Incoming) + return process.in_pol +end + +function _spin_or_pol(process::Compton, ::Photon, ::Outgoing) + return process.out_pol +end diff --git a/src/propagators.jl b/src/propagators.jl index ab52549..3eb375d 100644 --- a/src/propagators.jl +++ b/src/propagators.jl @@ -7,9 +7,7 @@ """ -```julia -propagator(particle::AbstractParticleType, mom::QEDbase.AbstractFourMomentum, [mass::Real]) -``` + propagator(particle::AbstractParticleType, mom::QEDbase.AbstractFourMomentum, [mass::Real]) Return the propagator of a particle for a given four-momentum. If `mass` is passed, the respective propagator for massive particles is used, if not, it is assumed the particle passed in is massless. diff --git a/test/Project.toml b/test/Project.toml index 6ab0525..b85fbd2 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,5 +1,6 @@ [deps] QEDbase = "10e22c08-3ccb-4172-bfcf-7d7aa3d04d93" +QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" diff --git a/test/processes/one_photon_compton/groundtruths.jl b/test/processes/one_photon_compton/groundtruths.jl new file mode 100644 index 0000000..3505733 --- /dev/null +++ b/test/processes/one_photon_compton/groundtruths.jl @@ -0,0 +1,26 @@ + +""" +Klein-Nishina: differential cross section + +source: Peskin, Schroeder. "Quantum field theory." (1995). eq: 5.91 +note: we compute d sigma/ d Omega, and *not* d sigma/ d cos theta (the difference is a factor 2 pi) + +""" +function _groundtruth_pert_compton_diffCS_spinsum_polsum(om, cth, mass) + prefac = ALPHA_SQUARE / 2 + omp = QEDprocesses._pert_omega_prime(om, cth) + sth_sq = 1 - cth^2 + return prefac * (omp / om)^2 * (omp / om + om / omp - sth_sq) +end + +function _groundtruth_pert_compton_diffCS_spinsum_xpol(omega, ctheta, phi, mass) + om_prime = QEDprocesses._pert_omega_prime(omega, ctheta) + om_prime_over_om = om_prime / omega + return 0.5 * ALPHA_SQUARE / mass^2 * + om_prime_over_om^2 * + (om_prime_over_om + 1.0 / om_prime_over_om - 2 * (1 - ctheta^2) * cos(phi)^2) +end + +function _groundtruth_pert_compton_diffCS_spinsum_ypol(omega, ctheta, phi, mass) + return _groundtruth_pert_compton_diffCS_spinsum_xpol(omega, ctheta, phi + pi / 2, mass) +end diff --git a/test/processes/one_photon_compton/perturbative.jl b/test/processes/one_photon_compton/perturbative.jl new file mode 100644 index 0000000..9d28869 --- /dev/null +++ b/test/processes/one_photon_compton/perturbative.jl @@ -0,0 +1,118 @@ + +using QEDbase +using QEDprocesses +using Random +using StaticArrays +using QuadGK + +const RNG = MersenneTwister(77697185) +const ATOL = eps() +const RTOL = sqrt(eps()) + +include("groundtruths.jl") + +const MODEL = PerturbativeQED() +const PS_DEF = PhasespaceDefinition(SphericalCoordinateSystem(), ElectronRestFrame()) +const OMEGAS = (1e-6 * rand(RNG), 1e-3 * rand(RNG), rand(RNG), 1e3 * rand(RNG)) + +const COS_THETAS = [-1.0, 2 * rand(RNG) - 1, 0.0, 1.0] +const PHIS = [0, 2 * pi, rand(RNG) * 2 * pi] + +@testset "perturbative kinematics" begin + PROC = Compton() + @testset "momentum generation" begin + @testset "$om, $cth, $phi" for (om, cth, phi) in + Iterators.product(OMEGAS, COS_THETAS, PHIS) + IN_COORDS = [om] + OUT_COORDS = [cth, phi] + IN_PS, OUT_PS = QEDprocesses._generate_momenta( + PROC, MODEL, PS_DEF, IN_COORDS, OUT_COORDS + ) + in_mom_square = getMass2.(IN_PS) + out_mom_square = getMass2.(OUT_PS) + in_masses = mass.(incoming_particles(PROC)) .^ 2 + out_masses = mass.(outgoing_particles(PROC)) .^ 2 + @test isapprox(in_mom_square, SVector(in_masses)) + @test isapprox(out_mom_square, SVector(out_masses)) + end + end +end + +@testset "perturbative" begin + @testset "$omega" for omega in OMEGAS + @testset "differential cross section" begin + @testset "spin and pol summed" begin + PROC = Compton() + + @testset "$cos_theta $phi" for (cos_theta, phi) in + Iterators.product(COS_THETAS, PHIS) + IN_COORDS = [omega] + OUT_COORDS = [cos_theta, phi] + groundtruth = _groundtruth_pert_compton_diffCS_spinsum_polsum( + omega, cos_theta, 1.0 + ) + test_val = unsafe_differential_cross_section( + PROC, MODEL, PS_DEF, IN_COORDS, OUT_COORDS + ) + @test isapprox(test_val, groundtruth, atol=ATOL, rtol=RTOL) + end + end + + @testset "x-pol and spin summed" begin + PROC = Compton(PolX()) + + @testset "$cos_theta $phi" for (cos_theta, phi) in + Iterators.product(COS_THETAS, PHIS) + IN_COORDS = [omega] + OUT_COORDS = [cos_theta, phi] + groundtruth = _groundtruth_pert_compton_diffCS_spinsum_xpol( + omega, cos_theta, phi, 1.0 + ) + test_val = unsafe_differential_cross_section( + PROC, MODEL, PS_DEF, IN_COORDS, OUT_COORDS + ) + @test isapprox(test_val, groundtruth, atol=ATOL, rtol=RTOL) + end + end + + @testset "y-pol and spin summed" begin + PROC = Compton(PolY()) + + @testset "$cos_theta $phi" for (cos_theta, phi) in + Iterators.product(COS_THETAS, PHIS) + IN_COORDS = [omega] + OUT_COORDS = [cos_theta, phi] + groundtruth = _groundtruth_pert_compton_diffCS_spinsum_ypol( + omega, cos_theta, phi, 1.0 + ) + test_val = unsafe_differential_cross_section( + PROC, MODEL, PS_DEF, IN_COORDS, OUT_COORDS + ) + @test isapprox(test_val, groundtruth, atol=ATOL, rtol=RTOL) + end + end + end + @testset "total cross section" begin + @testset "spin and pol summed" begin + PROC = Compton() + # Klein-Nishina: total cross section + function klein_nishina_total_cross_section(in_ps) + function func(x) + return unsafe_differential_cross_section( + Compton(), PerturbativeQED(), PS_DEF, in_ps, [x, 0.0] + ) + end + res, err = quadgk(func, -1, 1) + + # note: mul by 2pi instead of the phi-integration + return 2 * pi * res + end + + IN_COORDS = [omega] + groundtruth = klein_nishina_total_cross_section(IN_COORDS) + test_val = @inferred total_cross_section(PROC, MODEL, PS_DEF, IN_COORDS) + @test isapprox(test_val, groundtruth, atol=ATOL, rtol=RTOL) + end + end + end +end diff --git a/test/processes/one_photon_compton/process.jl b/test/processes/one_photon_compton/process.jl new file mode 100644 index 0000000..00c4169 --- /dev/null +++ b/test/processes/one_photon_compton/process.jl @@ -0,0 +1,56 @@ +using QEDprocesses +using Random +using QEDbase + +POLS = [PolX(), PolY(), AllPol()] +SPINS = [SpinUp(), SpinDown(), AllSpin()] +POL_AND_SPIN_COMBINATIONS = Iterators.product(SPINS, POLS, SPINS, POLS) +POL_COMBINATIONS = Iterators.product(POLS, POLS) + +@testset "constructor" begin + @testset "default" begin + proc = Compton() + @test QEDprocesses._spin_or_pol(proc, Photon(), Incoming()) == AllPol() + @test QEDprocesses._spin_or_pol(proc, Electron(), Incoming()) == AllSpin() + @test QEDprocesses._spin_or_pol(proc, Photon(), Outgoing()) == AllPol() + @test QEDprocesses._spin_or_pol(proc, Electron(), Outgoing()) == AllSpin() + end + + @testset "in_pol" begin + @testset "$pol" for pol in POLS + proc = Compton(pol) + @test QEDprocesses._spin_or_pol(proc, Electron(), Incoming()) == AllSpin() + @test QEDprocesses._spin_or_pol(proc, Photon(), Incoming()) == pol + @test QEDprocesses._spin_or_pol(proc, Electron(), Outgoing()) == AllSpin() + @test QEDprocesses._spin_or_pol(proc, Photon(), Outgoing()) == AllPol() + end + end + + @testset "in_pol+out_pol" begin + @testset "$in_pol, $out_pol" for (in_pol, out_pol) in POL_COMBINATIONS + proc = Compton(in_pol, out_pol) + @test QEDprocesses._spin_or_pol(proc, Electron(), Incoming()) == AllSpin() + @test QEDprocesses._spin_or_pol(proc, Photon(), Incoming()) == in_pol + @test QEDprocesses._spin_or_pol(proc, Electron(), Outgoing()) == AllSpin() + @test QEDprocesses._spin_or_pol(proc, Photon(), Outgoing()) == out_pol + end + 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 = Compton(in_spin, in_pol, out_spin, out_pol) + @test QEDprocesses._spin_or_pol(proc, Electron(), Incoming()) == in_spin + @test QEDprocesses._spin_or_pol(proc, Photon(), Incoming()) == in_pol + @test QEDprocesses._spin_or_pol(proc, Electron(), Outgoing()) == out_spin + @test QEDprocesses._spin_or_pol(proc, Photon(), Outgoing()) == out_pol + end + end +end +@testset "particle content" begin + proc = Compton() + @test incoming_particles(proc) == (Electron(), Photon()) + @test outgoing_particles(proc) == (Electron(), Photon()) + @test number_incoming_particles(proc) == 2 + @test number_outgoing_particles(proc) == 2 +end diff --git a/test/processes/run_process_test.jl b/test/processes/run_process_test.jl new file mode 100644 index 0000000..509b379 --- /dev/null +++ b/test/processes/run_process_test.jl @@ -0,0 +1,8 @@ + +@time @safetestset "general one photon compton" begin + include("one_photon_compton/process.jl") +end + +@time @safetestset "perturbative one photon compton" begin + include("one_photon_compton/perturbative.jl") +end diff --git a/test/runtests.jl b/test/runtests.jl index 9510013..9ecc6ee 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -21,7 +21,11 @@ begin @time @safetestset "cross section & probability" begin include("cross_sections.jl") end + @time @safetestset "phase spaces" begin include("phase_spaces.jl") end + + # scattering processes + include("processes/run_process_test.jl") end