From a8326f23daeaa56ee53ea11ed31e3a71e36b9597 Mon Sep 17 00:00:00 2001 From: Klaus Steiniger Date: Fri, 22 Nov 2024 12:00:40 +0100 Subject: [PATCH 1/6] start implementation of phase integrals --- src/interfaces/background_field_interface.jl | 34 ++++++++++++++++++++ src/phase_integrals/first_integral.jl | 25 ++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 src/phase_integrals/first_integral.jl diff --git a/src/interfaces/background_field_interface.jl b/src/interfaces/background_field_interface.jl index c526757..95e2b8c 100644 --- a/src/interfaces/background_field_interface.jl +++ b/src/interfaces/background_field_interface.jl @@ -200,3 +200,37 @@ function generic_spectrum( # TODO: maybe use broadcasting here return map(x -> generic_spectrum(field, pol, x), photon_number_parameter) end + +# phase integrals B_i(l) +# +# TODO: Up to now, all of this is just copy paste and needs to be adapted to phase integrals +""" + + phase_integral_1(field::AbstractPulsedPlaneWaveField, pol::AbstractDefinitePolarization, p_in::, p_out::, pnum) + +Return the first phase integral of the given field, for the given phase space point `p_in, p_out` and a given photon number parameter `pnum`. + +!!! note "Convention" + + The first phase integral is defined as: + + ```math + \\begin{align*} + B_0(l, p, p^\\prime)& = \\int \\mathrm{d}\\varphi \\exp[\\imath l \\varphi + \\imath G(\\varphi)] \\\\ + \\end{align*} + ``` + where ``G(\\varphi,p, p^\\prime)`` is the [`phase function`](@ref), ``(p,p^\\prime)`` the given phase space point, and ``l`` the photon number parameter. +""" +function phase_integral_1 end + +# integrand shared by all phase integrals +@inline function _shared_integrand( + field::AbstractPulsedPlaneWaveField, + pol::AbstractPolarization, + p_in::T, + p_out::T, + phi::T, + pnum::T +) where {T<:Real} + return exp(1im*(pnum*phi + _phase_function(field, pol, p_in, p_out, phi))) +end diff --git a/src/phase_integrals/first_integral.jl b/src/phase_integrals/first_integral.jl new file mode 100644 index 0000000..be338c0 --- /dev/null +++ b/src/phase_integrals/first_integral.jl @@ -0,0 +1,25 @@ +###################### +# First phase integral +###################### + +# Does it need to be the same T for all arguments? +function phase_integral_1( + field::AbstractPulsedPlaneWaveField, + pol::AbstractPolarization, + p_in::T, + p_out::T, + pnum::T +) where {T<:Real} + return quadgk(t -> , endpoints(domain(field))...)[1] +end + +function phase_integral_1( + field::AbstractPulsedPlaneWaveField, + p_in::T, + p_out::T, + photon_number_parameter::AbstractVector{T} +) where {T<:Real} + # TODO: maybe use broadcasting here + return map(x -> generic_spectrum(field, p_in, p_out, x), photon_number_parameter) +end + From 9f4496dcde2a66f9e67fa89639c3f092632606c3 Mon Sep 17 00:00:00 2001 From: Klaus Steiniger Date: Fri, 22 Nov 2024 13:01:30 +0100 Subject: [PATCH 2/6] Phase Integrals: add interfaces --- src/QEDfields.jl | 3 + src/interfaces/background_field_interface.jl | 14 +--- src/phase_integrals/first_integral.jl | 3 +- src/phase_integrals/phase_integrals.jl | 67 ++++++++++++++++++++ src/phase_integrals/second_integral.jl | 26 ++++++++ src/phase_integrals/zeroth_integral.jl | 25 ++++++++ 6 files changed, 124 insertions(+), 14 deletions(-) create mode 100644 src/phase_integrals/phase_integrals.jl create mode 100644 src/phase_integrals/second_integral.jl create mode 100644 src/phase_integrals/zeroth_integral.jl diff --git a/src/QEDfields.jl b/src/QEDfields.jl index e9435e1..d0be196 100644 --- a/src/QEDfields.jl +++ b/src/QEDfields.jl @@ -13,9 +13,12 @@ export polarization_vector, oscillator export CosSquarePulse, GaussianPulse +export phase_integral_0, phase_integral_1, phase_integral_2 + include("interfaces/background_field_interface.jl") include("polarization.jl") include("pulses/cos_square.jl") include("pulses/gaussian.jl") +include("phase_integrals/phase_integrals.jl") end diff --git a/src/interfaces/background_field_interface.jl b/src/interfaces/background_field_interface.jl index 95e2b8c..6427b0e 100644 --- a/src/interfaces/background_field_interface.jl +++ b/src/interfaces/background_field_interface.jl @@ -216,21 +216,9 @@ Return the first phase integral of the given field, for the given phase space po ```math \\begin{align*} - B_0(l, p, p^\\prime)& = \\int \\mathrm{d}\\varphi \\exp[\\imath l \\varphi + \\imath G(\\varphi)] \\\\ + B_1(l, p, p^\\prime)& = \\int \\mathrm{d}\\varphi \\exp[\\imath l \\varphi + \\imath G(\\varphi)] \\\\ \\end{align*} ``` where ``G(\\varphi,p, p^\\prime)`` is the [`phase function`](@ref), ``(p,p^\\prime)`` the given phase space point, and ``l`` the photon number parameter. """ function phase_integral_1 end - -# integrand shared by all phase integrals -@inline function _shared_integrand( - field::AbstractPulsedPlaneWaveField, - pol::AbstractPolarization, - p_in::T, - p_out::T, - phi::T, - pnum::T -) where {T<:Real} - return exp(1im*(pnum*phi + _phase_function(field, pol, p_in, p_out, phi))) -end diff --git a/src/phase_integrals/first_integral.jl b/src/phase_integrals/first_integral.jl index be338c0..5b0bee1 100644 --- a/src/phase_integrals/first_integral.jl +++ b/src/phase_integrals/first_integral.jl @@ -15,11 +15,12 @@ end function phase_integral_1( field::AbstractPulsedPlaneWaveField, + pol::AbstractPolarization, p_in::T, p_out::T, photon_number_parameter::AbstractVector{T} ) where {T<:Real} # TODO: maybe use broadcasting here - return map(x -> generic_spectrum(field, p_in, p_out, x), photon_number_parameter) + return map(x -> phase_integral_1(field, pol, p_in, p_out, x), photon_number_parameter) end diff --git a/src/phase_integrals/phase_integrals.jl b/src/phase_integrals/phase_integrals.jl new file mode 100644 index 0000000..89d1332 --- /dev/null +++ b/src/phase_integrals/phase_integrals.jl @@ -0,0 +1,67 @@ +########################################### +# Definitions common to all phase integrals +########################################### + +# PPW field integral +@inline function _field_integral( + field::AbstractPulsedPlaneWaveField, + pol::AbstractPolarization, + phi::T +) where {T<:Real} + return +end + +# PPW field squared integral +@inline function _field_squared_integral( + field::AbstractPulsedPlaneWaveField, + pol::AbstractPolarization, + phi::T +) where {T<:Real} + return +end + +# kinematic vector factor alpha_1^mu appearing in Volkov phase +@inline function _kinematic_vector_phase_factor( + field::AbstractPulsedPlaneWaveField, + p_in::T, + p_out::T, +) where {T<:Real} + return +end + +# kinematic scalar factor alpha_2 appearing in Volkov phase +@inline function _kinematic_scalar_phase_factor( + field::AbstractPulsedPlaneWaveField, + p_in::T, + p_out::T, +) where {T<:Real} + return +end + +# non-linear Volkov phase +@inline function _phase_function( + field::AbstractPulsedPlaneWaveField, + pol::AbstractPolarization, + p_in::T, + p_out::T, + phi::T +) where {T<:Real} + return +end + +# integrand shared by all phase integrals +@inline function _shared_integrand( + field::AbstractPulsedPlaneWaveField, + pol::AbstractPolarization, + p_in::T, + p_out::T, + phi::T, + pnum::T +) where {T<:Real} + return exp(1im*(pnum*phi + _phase_function(field, pol, p_in, p_out, phi))) +end + + +include("zeroth_integral.jl") +include("first_integral.jl") +include("second_integral.jl") diff --git a/src/phase_integrals/second_integral.jl b/src/phase_integrals/second_integral.jl new file mode 100644 index 0000000..dde60ac --- /dev/null +++ b/src/phase_integrals/second_integral.jl @@ -0,0 +1,26 @@ +####################### +# Second phase integral +####################### + +# Does it need to be the same T for all arguments? +function phase_integral_2( + field::AbstractPulsedPlaneWaveField, + pol::AbstractPolarization, + p_in::T, + p_out::T, + pnum::T +) where {T<:Real} + return quadgk(t -> , endpoints(domain(field))...)[1] +end + +function phase_integral_2( + field::AbstractPulsedPlaneWaveField, + pol::AbstractPolarization, + p_in::T, + p_out::T, + photon_number_parameter::AbstractVector{T} +) where {T<:Real} + # TODO: maybe use broadcasting here + return map(x -> phase_integral_2(field, p_in, p_out, x), photon_number_parameter) +end + diff --git a/src/phase_integrals/zeroth_integral.jl b/src/phase_integrals/zeroth_integral.jl new file mode 100644 index 0000000..54c2092 --- /dev/null +++ b/src/phase_integrals/zeroth_integral.jl @@ -0,0 +1,25 @@ +####################### +# Zeroth phase integral +####################### + +# Does it need to be the same T for all arguments? +function phase_integral_0( + field::AbstractPulsedPlaneWaveField, + pol::AbstractPolarization, + p_in::T, + p_out::T, + pnum::T +) where {T<:Real} + return quadgk(t -> , endpoints(domain(field))...)[1] +end + +function phase_integral_0( + field::AbstractPulsedPlaneWaveField, + pol::AbstractPolarization, + p_in::T, + p_out::T, + photon_number_parameter::AbstractVector{T} +) where {T<:Real} + # TODO: maybe use broadcasting here + return map(x -> phase_integral_0(field, p_in, p_out, x), photon_number_parameter) +end From fbb898e0718df5ebb1d40d4c163178eefdbac98f Mon Sep 17 00:00:00 2001 From: Klaus Steiniger Date: Fri, 22 Nov 2024 14:01:56 +0100 Subject: [PATCH 3/6] Phase integrals: finish common implementations --- src/phase_integrals/phase_integrals.jl | 52 ++++++++++++++++---------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/src/phase_integrals/phase_integrals.jl b/src/phase_integrals/phase_integrals.jl index 89d1332..cda6748 100644 --- a/src/phase_integrals/phase_integrals.jl +++ b/src/phase_integrals/phase_integrals.jl @@ -2,62 +2,76 @@ # Definitions common to all phase integrals ########################################### -# PPW field integral +# from QEDprocesses.jl/src/constants.jl +# TODO: we might want to move the constants.jl file to QEDbase? See also TODO in QEDprocesses.jl/src/processes/one_photon_compton/perturbative/cross_section.jl +const ALPHA = inv(137.035999074) +const ELEMENTARY_CHARGE = sqrt(4 * pi * ALPHA) +const ELEMENTARY_CHARGE_SQUARE = 4 * pi * ALPHA + +# definite integral of PPW field +# TODO: Why does integration always start at 0? @inline function _field_integral( field::AbstractPulsedPlaneWaveField, pol::AbstractPolarization, phi::T ) where {T<:Real} - return + return quadgk(t -> amplitude(field, pol, t), 0.0, phi)[1] end -# PPW field squared integral +# definite integral of squared PPW field +# TODO: Why does integration always start at 0? @inline function _field_squared_integral( field::AbstractPulsedPlaneWaveField, pol::AbstractPolarization, phi::T ) where {T<:Real} - return + return quadgk(t -> amplitude(field, pol, t)^2, 0.0, phi)[1] end # kinematic vector factor alpha_1^mu appearing in Volkov phase +# TODO: Is `ELEMENTARY_CHARGE` actually related to the scattering particle or just a factor @inline function _kinematic_vector_phase_factor( field::AbstractPulsedPlaneWaveField, - p_in::T, - p_out::T, -) where {T<:Real} - return + p_in::MT, + p_out::MT, +) where {MT<:AbstractFourMomentum} + k_mu = momentum(field) + return ELEMENTARY_CHARGE*(p_out/(k_mu*p_out) - p_in/(k_mu*p_in)) end # kinematic scalar factor alpha_2 appearing in Volkov phase +# TODO: Is `ELEMENTARY_CHARGE` actually related to the scattering particle or just a factor @inline function _kinematic_scalar_phase_factor( field::AbstractPulsedPlaneWaveField, - p_in::T, - p_out::T, -) where {T<:Real} - return + p_in::MT, + p_out::MT, +) where {MT<:AbstractFourMomentum} + k_mu = momentum(field) + return ELEMENTARY_CHARGE_SQUARE * (1/(k_mu*p_in) - 1/(k_mu*p_out)) end # non-linear Volkov phase @inline function _phase_function( field::AbstractPulsedPlaneWaveField, pol::AbstractPolarization, - p_in::T, - p_out::T, + p_in::MT, + p_out::MT, phi::T -) where {T<:Real} - return +) where {MT<:AbstractFourMomentum, T<:Real} + first = _kinematic_vector_phase_factor(field, p_in, p_out) * _field_integral(field, pol, phi) + second = _kinematic_scalar_phase_factor(field, p_in, p_out) * _field_squared_integral(field, pol, phi) + return first+second end # integrand shared by all phase integrals @inline function _shared_integrand( field::AbstractPulsedPlaneWaveField, pol::AbstractPolarization, - p_in::T, - p_out::T, + p_in::MT, + p_out::MT, phi::T, pnum::T -) where {T<:Real} +) where {MT<:AbstractFourMomentum, T<:Real} return exp(1im*(pnum*phi + _phase_function(field, pol, p_in, p_out, phi))) end From 1177443f7dbc63d04e955b5019521052c9fa5f43 Mon Sep 17 00:00:00 2001 From: Klaus Steiniger Date: Fri, 3 Jan 2025 17:25:54 +0100 Subject: [PATCH 4/6] Phase Integrals: Add implementation for 2nd phase integrals + discussion notes + documentation --- src/interfaces/background_field_interface.jl | 22 +++++++++- src/phase_integrals/first_integral.jl | 2 +- src/phase_integrals/phase_integrals.jl | 38 +++++++++++++++++ src/phase_integrals/second_integral.jl | 2 +- src/phase_integrals/zeroth_integral.jl | 43 +++++++++++--------- 5 files changed, 83 insertions(+), 24 deletions(-) diff --git a/src/interfaces/background_field_interface.jl b/src/interfaces/background_field_interface.jl index 6427b0e..ea907e8 100644 --- a/src/interfaces/background_field_interface.jl +++ b/src/interfaces/background_field_interface.jl @@ -216,9 +216,27 @@ Return the first phase integral of the given field, for the given phase space po ```math \\begin{align*} - B_1(l, p, p^\\prime)& = \\int \\mathrm{d}\\varphi \\exp[\\imath l \\varphi + \\imath G(\\varphi)] \\\\ + B_1^\\mu(l, p, p^\\prime)& = \\int \\mathrm{d}\\varphi A^\\mu(\\varphi)\\exp[\\imath l \\varphi + \\imath G(\\varphi)] \\\\ \\end{align*} ``` - where ``G(\\varphi,p, p^\\prime)`` is the [`phase function`](@ref), ``(p,p^\\prime)`` the given phase space point, and ``l`` the photon number parameter. + where ``A^\\mu(\\varphi)`` is the background field, ``G(\\varphi,p, p^\\prime)`` is the [`phase function`](@ref), ``(p,p^\\prime)`` the given phase space point, and ``l`` the photon number parameter. """ function phase_integral_1 end + +""" + + phase_integral_2(field::AbstractPulsedPlaneWaveField, pol::AbstractDefinitePolarization, p_in::, p_out::, pnum) + +Return the second phase integral of the given field, for the given phase space point `p_in, p_out` and a given photon number parameter `pnum`. + +!!! note "Convention" + + The second phase integral is defined as: + + ```math + \\begin{align*} + B_2(l, p, p^\\prime)& = \\int \\mathrm{d}\\varphi A(\\varphi)^2 \\exp[\\imath l \\varphi + \\imath G(\\varphi)] \\\\ + \\end{align*} + ``` +""" +function phase_integral_2 end diff --git a/src/phase_integrals/first_integral.jl b/src/phase_integrals/first_integral.jl index 5b0bee1..d0dc824 100644 --- a/src/phase_integrals/first_integral.jl +++ b/src/phase_integrals/first_integral.jl @@ -10,7 +10,7 @@ function phase_integral_1( p_out::T, pnum::T ) where {T<:Real} - return quadgk(t -> , endpoints(domain(field))...)[1] + return quadgk(t -> amplitude(field, pol, t)*_shared_integrand(field, pol, p_in, p_out, t, pnum), endpoints(domain(field))...)[1] end function phase_integral_1( diff --git a/src/phase_integrals/phase_integrals.jl b/src/phase_integrals/phase_integrals.jl index cda6748..76c76c4 100644 --- a/src/phase_integrals/phase_integrals.jl +++ b/src/phase_integrals/phase_integrals.jl @@ -2,6 +2,25 @@ # Definitions common to all phase integrals ########################################### +# TODO: We need to talk about the handling of field polarization! +# Since some of the quantities required in phase integral computation are four-vectors, just as the bg-field itself, +# we need to return these as four-vectors, or their components. +# However, we do not even provide the field as a four-vector, yet. +# We just return its "amplitude", which is only the oscillator times the envelope, +# not even taking the correct maximum value a_0 of the field into account. (TODO!) +# +# I think both the polarization and the maximum value of the field should be a user defined quantity, +# but then these should also be members of the field struct, shouldn't they? +# Or are these separately set in the Process? +# +# All in all, I wonder how we should treat four-vectors in QEDfields. +# The problem of missing vectorial information appears here in _field_integral(), _kinematic_vector_phase_factor(), and phase_integral_1(). + +# TODO: The factors and integrals should not depend on the momenta of particles +# but on the Process and Phase Space Point (the latter of which holds the momenta) +# Question: Does the process hold a reference to the background field? +# If so, the explicit dependence on the background field should be removed to. + # from QEDprocesses.jl/src/constants.jl # TODO: we might want to move the constants.jl file to QEDbase? See also TODO in QEDprocesses.jl/src/processes/one_photon_compton/perturbative/cross_section.jl const ALPHA = inv(137.035999074) @@ -51,6 +70,25 @@ end end # non-linear Volkov phase +""" + + _phase_function(field::AbstractPulsedPlaneWaveField, pol::AbstractPolarization, p_in::, p_out::, phi::) + +Return the phase function (or non-linear Volkov phase), for the given phase space point `p_in, p_out` and a given phase value `phi`. + +!!! note "Convention" + + The non-linear Volkov phase is defined as: + + ```math + \\begin{align*} + G(\\varphi,p, p^\\prime)& = \\alpha_1^\\mu \\int\\limits_0^\\varphi \\mathrm{d}\\varphi^\\prime A_\\mu(\\varphi^\\prime) + + \\alpha_2 \\int\\limits_0^\\varphi \\mathrm{d}\\varphi^\\prime A^2(\\varphi^\\prime) \\\\ + \\end{align*} + ``` + where ``A^\\mu(\\varphi)`` is the background field, ``\\alpha_1^\\mu`` is the [`kinematic vector phase factor`](@ref), and ``\\alpha_2`` is the [`kinematic scalar phase factor`](@ref). + Both ``\\alpha_1^\\mu`` and ``\\alpha_2`` depend on the given phase space point ``(p,p^\\prime)`` and the field's reference momentum ``k^\\mu`` the photon number parameter. +""" @inline function _phase_function( field::AbstractPulsedPlaneWaveField, pol::AbstractPolarization, diff --git a/src/phase_integrals/second_integral.jl b/src/phase_integrals/second_integral.jl index dde60ac..9b304ad 100644 --- a/src/phase_integrals/second_integral.jl +++ b/src/phase_integrals/second_integral.jl @@ -10,7 +10,7 @@ function phase_integral_2( p_out::T, pnum::T ) where {T<:Real} - return quadgk(t -> , endpoints(domain(field))...)[1] + return quadgk(t -> amplitude(field, pol, t)^2 * _shared_integrand(field, pol, p_in, p_out, t, pnum), endpoints(domain(field))...)[1] end function phase_integral_2( diff --git a/src/phase_integrals/zeroth_integral.jl b/src/phase_integrals/zeroth_integral.jl index 54c2092..ba32cc2 100644 --- a/src/phase_integrals/zeroth_integral.jl +++ b/src/phase_integrals/zeroth_integral.jl @@ -2,24 +2,27 @@ # Zeroth phase integral ####################### -# Does it need to be the same T for all arguments? -function phase_integral_0( - field::AbstractPulsedPlaneWaveField, - pol::AbstractPolarization, - p_in::T, - p_out::T, - pnum::T -) where {T<:Real} - return quadgk(t -> , endpoints(domain(field))...)[1] -end +# Is actually diverging, therefore not implmented by now. +function phase_integral_0 end +# The expected signature would be +#phase_integral_0( +# field::AbstractPulsedPlaneWaveField, +# pol::AbstractPolarization, +# p_in::T, +# p_out::T, +# pnum::T +#) where {T<:Real} +# and the questions remains, whether T has to be the same for all arguments. -function phase_integral_0( - field::AbstractPulsedPlaneWaveField, - pol::AbstractPolarization, - p_in::T, - p_out::T, - photon_number_parameter::AbstractVector{T} -) where {T<:Real} - # TODO: maybe use broadcasting here - return map(x -> phase_integral_0(field, p_in, p_out, x), photon_number_parameter) -end + +# Implementation of above function for a vector of photon numbers +#function phase_integral_0( +# field::AbstractPulsedPlaneWaveField, +# pol::AbstractPolarization, +# p_in::T, +# p_out::T, +# photon_number_parameter::AbstractVector{T} +#) where {T<:Real} +# # TODO: maybe use broadcasting here +# return map(x -> phase_integral_0(field, pol, p_in, p_out, x), photon_number_parameter) +#end From 6d95340cbdc50d6ec5935588ba25ffe6257bdccb Mon Sep 17 00:00:00 2001 From: Klaus Steiniger Date: Fri, 24 Jan 2025 17:18:00 +0100 Subject: [PATCH 5/6] Refactor implementation according to vision for usage --- src/interfaces/background_field_interface.jl | 80 +++++--------------- src/interfaces/phase_integrals.jl | 75 ++++++++++++++++++ 2 files changed, 95 insertions(+), 60 deletions(-) create mode 100644 src/interfaces/phase_integrals.jl diff --git a/src/interfaces/background_field_interface.jl b/src/interfaces/background_field_interface.jl index ea907e8..b3e6a53 100644 --- a/src/interfaces/background_field_interface.jl +++ b/src/interfaces/background_field_interface.jl @@ -2,7 +2,7 @@ # The abstract background field interface # # In this file, the abstract interface for different types of background fields -# is defined. +# is defined. #################### """ Abstract base type for describing classical background fields. @@ -45,13 +45,13 @@ function reference_momentum end domain(::AbstractPulsedPlaneWaveField) -Interface function for [`AbstractPulsedPlaneWaveField`](@ref), which returns interval (as a `IntervalSets.Interval`) for the given background field. +Interface function for [`AbstractPulsedPlaneWaveField`](@ref), which returns interval (as a `IntervalSets.Interval`) for the given background field. """ function domain end """ - + pulse_length(::AbstractPulsedPlaneWaveField) Interface function for [`AbstractPulsedPlaneWaveField`](@ref), which returns a dimensionless representative number for the duration of the background field, @@ -68,18 +68,18 @@ Interface function for [`AbstractPulsedPlaneWaveField`](@ref), which returns the !!! note "Single point implementation" The interface function can be implemented for just one phase point as input. With that, evaluation on a vector of inputs is generically implemented by broadcasting. - However, if there is a better custom implementation for vectors in input values, consider implementing + However, if there is a better custom implementation for vectors in input values, consider implementing ```Julia - + _envelope(::AbstractPulsedPlaneWaveField, phi::AbstractVector{T<:Real}) ``` !!! note "unsafe implementation" - - This is the unsafe version of the phase envelope function, i.e. this should be implement without input checks like the domain check. - In the safe version [`envelope`](@ref), a domain check is performed, i.e. it returns the value of `_envelope` if the passed in `phi` - is in the `domain` of the field, and zero otherwise. + + This is the unsafe version of the phase envelope function, i.e. this should be implement without input checks like the domain check. + In the safe version [`envelope`](@ref), a domain check is performed, i.e. it returns the value of `_envelope` if the passed in `phi` + is in the `domain` of the field, and zero otherwise. """ function _envelope end @@ -87,16 +87,16 @@ function _envelope end function _envelope( field::AbstractPulsedPlaneWaveField, phi::AbstractVector{T} ) where {T<:Real} - # TODO: maybe use broadcasting here + # TODO: maybe use broadcasting here return map(x -> _envelope(field, x), phi) end """ - + envelope(pulsed_field::AbstractPulsedPlaneWaveField, phi::Real) - -Return the value of the phase envelope function (also referred to as pulse envelope or pulse shape) -for given `pulsed_field` and phase `phi`. Performs domain check on `phi` before calling [`_envelope`](@ref); + +Return the value of the phase envelope function (also referred to as pulse envelope or pulse shape) +for given `pulsed_field` and phase `phi`. Performs domain check on `phi` before calling [`_envelope`](@ref); returns zero if `phi` is not in the domain returned by `[domain](@ref)`. """ function envelope(field::AbstractPulsedPlaneWaveField, phi::Real) @@ -106,7 +106,7 @@ end function envelope( field::AbstractPulsedPlaneWaveField, phi::AbstractVector{T} ) where {T<:Real} - # TODO: maybe use broadcasting here + # TODO: maybe use broadcasting here return map(x -> envelope(field, x), phi) end @@ -123,7 +123,7 @@ function _amplitude( pol::AbstractDefinitePolarization, phi::AbstractVector{T}, ) where {T<:Real} - # TODO: maybe use broadcasting here + # TODO: maybe use broadcasting here return map(x -> _amplitude(field, pol, x), phi) end @@ -131,7 +131,7 @@ end amplitude(field::AbstractPulsedPlaneWaveField, pol::AbstractDefinitePolarization, phi) -Returns the value of the amplitude for a given polarization direction and phase variable `phi`. +Returns the value of the amplitude for a given polarization direction and phase variable `phi`. !!! note "Conventions" @@ -143,7 +143,7 @@ Returns the value of the amplitude for a given polarization direction and phase ``` !!! note "Safe implementation" - + In this function, a domain check is performed, i.e. if `phi` is in the domain of the field, the value of the amplitude is returned, and zero otherwise. """ @@ -158,7 +158,7 @@ function amplitude( pol::AbstractDefinitePolarization, phi::AbstractVector{T}, ) where {T<:Real} - # TODO: maybe use broadcasting here + # TODO: maybe use broadcasting here return map(x -> amplitude(field, pol, x), phi) end @@ -197,46 +197,6 @@ function generic_spectrum( pol::AbstractDefinitePolarization, photon_number_parameter::AbstractVector{T}, ) where {T<:Real} - # TODO: maybe use broadcasting here + # TODO: maybe use broadcasting here return map(x -> generic_spectrum(field, pol, x), photon_number_parameter) end - -# phase integrals B_i(l) -# -# TODO: Up to now, all of this is just copy paste and needs to be adapted to phase integrals -""" - - phase_integral_1(field::AbstractPulsedPlaneWaveField, pol::AbstractDefinitePolarization, p_in::, p_out::, pnum) - -Return the first phase integral of the given field, for the given phase space point `p_in, p_out` and a given photon number parameter `pnum`. - -!!! note "Convention" - - The first phase integral is defined as: - - ```math - \\begin{align*} - B_1^\\mu(l, p, p^\\prime)& = \\int \\mathrm{d}\\varphi A^\\mu(\\varphi)\\exp[\\imath l \\varphi + \\imath G(\\varphi)] \\\\ - \\end{align*} - ``` - where ``A^\\mu(\\varphi)`` is the background field, ``G(\\varphi,p, p^\\prime)`` is the [`phase function`](@ref), ``(p,p^\\prime)`` the given phase space point, and ``l`` the photon number parameter. -""" -function phase_integral_1 end - -""" - - phase_integral_2(field::AbstractPulsedPlaneWaveField, pol::AbstractDefinitePolarization, p_in::, p_out::, pnum) - -Return the second phase integral of the given field, for the given phase space point `p_in, p_out` and a given photon number parameter `pnum`. - -!!! note "Convention" - - The second phase integral is defined as: - - ```math - \\begin{align*} - B_2(l, p, p^\\prime)& = \\int \\mathrm{d}\\varphi A(\\varphi)^2 \\exp[\\imath l \\varphi + \\imath G(\\varphi)] \\\\ - \\end{align*} - ``` -""" -function phase_integral_2 end diff --git a/src/interfaces/phase_integrals.jl b/src/interfaces/phase_integrals.jl new file mode 100644 index 0000000..b0a0a73 --- /dev/null +++ b/src/interfaces/phase_integrals.jl @@ -0,0 +1,75 @@ +#################### +# The abstract phase integral interface +# +# In this file, the abstract interface for different copmutation methods of +# phase integrals is defined. +#################### +""" +Abstract base type for defining a method for phase integral computation. +""" +abstract type Method end + +""" +Analytic method for phase integral computation. + +Requires an existing implementation of analytic formulas for computing the +entities in the phase integrals. +""" +struct Analytic <: Method end + +""" +Fully numerical method for phase integral computation based on QuadGK. +""" +struct QuadGK <: Method end + +""" +Struct holding setup specific information to compute phase integrals. + +ToDo: We mix physical and numerical aspects in this class. +This does not seem ideal to me (Klaus). +""" +struct PhaseIntegral{P<:AbstractPulsedPlaneWaveField, M<:Method} + pulse::P + method::M +end + +# phase integrals B_i(l) +# +# TODO: Up to now, all of this is just copy paste and needs to be adapted to phase integrals +""" + + computeB1(ph_int_stp::PhaseIntegral, pol::AbstractPolarization, a0, pnum, alpha1x, alpha1y, alpha2) + +Return the first phase integral for the given setup `ph_Int_stp`, background field strength `a0`, photon number parameter `pnum`, components of the kinematic vector factor ``\\alpha_1^\\mu``, and kinematic scalar factor ``\\alpha_2``. + +!!! note "Convention" + + The first phase integral is defined as: + + ```math + \\begin{align*} + B_1^\\mu(l, p, p^\\prime)& = \\int \\mathrm{d}\\varphi A^\\mu(\\varphi)\\exp[\\imath l \\varphi + \\imath G(\\varphi)] \\\\ + \\end{align*} + ``` + where ``A^\\mu(\\varphi)`` is the background field, ``G(\\varphi,p, p^\\prime)`` is the [`phase function`](@ref), ``(p,p^\\prime)`` the given phase space point, and ``l`` the photon number parameter. +""" +function computeB1 end + +# TODO: REWORK THE FOLLOWING DOCUMENTATION +""" + + computeB2() + +Return the second phase integral. + +!!! note "Convention" + + The second phase integral is defined as: + + ```math + \\begin{align*} + B_2(l, p, p^\\prime)& = \\int \\mathrm{d}\\varphi A(\\varphi)^2 \\exp[\\imath l \\varphi + \\imath G(\\varphi)] \\\\ + \\end{align*} + ``` +""" +function computeB2 end From 4ecea3bbd70b92b924338a096e15e960e3c9ca2e Mon Sep 17 00:00:00 2001 From: Klaus Steiniger Date: Fri, 16 May 2025 01:40:09 +0200 Subject: [PATCH 6/6] Redesigning phase integral interface after offline discussion at Zebradiele --- src/interfaces/phase_integrals.jl | 76 ++++++++++++++++++++++++++---- test/interfaces/phase_integrals.jl | 9 ++++ test/runtests.jl | 3 ++ 3 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 test/interfaces/phase_integrals.jl diff --git a/src/interfaces/phase_integrals.jl b/src/interfaces/phase_integrals.jl index b0a0a73..9be585f 100644 --- a/src/interfaces/phase_integrals.jl +++ b/src/interfaces/phase_integrals.jl @@ -1,13 +1,13 @@ #################### # The abstract phase integral interface # -# In this file, the abstract interface for different copmutation methods of +# In this file, the abstract interface for different computation methods of # phase integrals is defined. #################### """ Abstract base type for defining a method for phase integral computation. """ -abstract type Method end +abstract type ComputeMethod end """ Analytic method for phase integral computation. @@ -15,12 +15,12 @@ Analytic method for phase integral computation. Requires an existing implementation of analytic formulas for computing the entities in the phase integrals. """ -struct Analytic <: Method end +struct Analytic <: ComputeMethod end """ -Fully numerical method for phase integral computation based on QuadGK. +Fully numerical method for phase integral computation. """ -struct QuadGK <: Method end +struct Numeric <: ComputeMethod end """ Struct holding setup specific information to compute phase integrals. @@ -28,11 +28,71 @@ Struct holding setup specific information to compute phase integrals. ToDo: We mix physical and numerical aspects in this class. This does not seem ideal to me (Klaus). """ -struct PhaseIntegral{P<:AbstractPulsedPlaneWaveField, M<:Method} - pulse::P - method::M +struct PhaseIntegral{F<:AbstractBackgroundField, C<:ComputeMethod} + bgfield::F + method::C + + function PhaseIntegral(bgfield::F, method::C) where {F<:AbstractBackgroundField, C<:ComputeMethod} + _assert_compatibility(bgfield, method) + new(bgfield, method) +end + + +""" + + _assert_compatibility(::AbstractBackgroundField, ::ComputeMethod) + +Interface function enforcing essential error check whether the respective functions exist that compute the phase integrals of the provided background field by the required method. +This function represents the default case stating that compute method and background field are not compatible. + +It must be specialized for compatible types as + _assert_compatibility(::CompatibleField, ::CompatibleComputeMethod) = nothing +""" +function _assert_compatibility(<:AbstractBackgroundField, <:ComputeMethod) + throw(ArgumentError("phase integral of provided background field cannot be computed with required method!")) +end + + +""" + + compute(pi::PhaseIntegral, vi::VertexInput) + +Interface function for [`PhaseIntegral`](@ref), which returns the result of the computation. + +Need to be specialized? I need to check on what the computation of phase integrals actually depends. +""" +function compute end + + +""" +Interface function returning background field. +All interface functions of background field, e.g. [`reference_momentum()`](@ref) can then be called on it. +""" +background_field(pi::PhaseIntegral) = pi.bgfield + + +""" +Composite type providing all (kinematic) information, required for dressed vertex computation and physe integral computation further down the line, via interface functions + +TODO: Should pnum become an explicit dependence of compute(pi, vi) in order to not construct a new VertexInput for every l, which is probably very slow. Because in the end we want to integrate the dressed vertex function Gamma^\mu over pnum. +""" +struct VertexInput{M<:QEDbase.AbstractFourMomentum,T<:Real} + pin::M + pout::M + pnum::T end + +""" +Interface functions of VertexInput +""" +in_momentum(vi::VertexInput) = vi.pin +out_momentum(vi::VertexInput) = vi.pout +photon_number_parameter(vi::VertexInput) = vi.pnum + + + +# TODO: The follwing is old stuff from 2024 and should be removed if not required in the implementation started in May 2025 # phase integrals B_i(l) # # TODO: Up to now, all of this is just copy paste and needs to be adapted to phase integrals diff --git a/test/interfaces/phase_integrals.jl b/test/interfaces/phase_integrals.jl new file mode 100644 index 0000000..efe4248 --- /dev/null +++ b/test/interfaces/phase_integrals.jl @@ -0,0 +1,9 @@ +using QEDbase: QEDbase +using QEDcore +using QEDfields +using Random + +RNG = MersenneTwister(137) +ATOL = 0.0 +RTOL = sqrt(eps()) + diff --git a/test/runtests.jl b/test/runtests.jl index 79e2139..798c922 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -11,6 +11,9 @@ using SafeTestsets include("interfaces/background_field_interface.jl") end +@time @safetestset "phase integrals" begin + include("interfaces/phase_integrals.jl") + @time @safetestset "polarization" begin include("polarization.jl") end