Compare commits
7 Commits
901944bd8b
...
92f534f6bf
Author | SHA1 | Date | |
---|---|---|---|
92f534f6bf | |||
55501c15c8 | |||
b5d92b729c | |||
6a9a7b41f1 | |||
a1581182ca | |||
1b4ba285c3 | |||
2921882fd4 |
@ -19,12 +19,17 @@ QEDprocesses = "46de9c38-1bb3-4547-a1ec-da24d767fdad"
|
||||
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
||||
Roots = "f2b01f46-fcfa-551c-844a-d8ac1e96c665"
|
||||
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
|
||||
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
|
||||
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
|
||||
oneAPI = "8f75cd03-7ff8-4ecb-9b8f-daf728133b1b"
|
||||
|
||||
[extras]
|
||||
CUDA_Runtime_jll = "76a88914-d11a-5bdc-97e0-2f5a05c973a2"
|
||||
QEDbase = "10e22c08-3ccb-4172-bfcf-7d7aa3d04d93"
|
||||
QEDcore = "35dc0263-cb5f-4c33-a114-1d7f54ab753e"
|
||||
QEDprocesses = "46de9c38-1bb3-4547-a1ec-da24d767fdad"
|
||||
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
|
||||
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
|
||||
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
|
||||
|
||||
[targets]
|
||||
test = ["Test"]
|
||||
test = ["SafeTestsets", "Test", "QEDbase", "QEDcore", "QEDprocesses"]
|
||||
|
@ -1,8 +1,10 @@
|
||||
using MetagraphOptimization
|
||||
using QEDbase
|
||||
using QEDcore
|
||||
using QEDprocesses
|
||||
using Random
|
||||
using UUIDs
|
||||
using CSV
|
||||
|
||||
RNG = Random.MersenneTwister(123)
|
||||
|
||||
@ -21,103 +23,79 @@ function mock_machine()
|
||||
)
|
||||
end
|
||||
|
||||
function congruent_input(processDescription::QEDProcessDescription, omega::Number)
|
||||
function congruent_input_momenta(processDescription::GenericQEDProcess, omega::Number)
|
||||
# generate an input sample for given e + nk -> e' + k' process, where the nk are equal
|
||||
massSum = 0
|
||||
inputMasses = Vector{Float64}()
|
||||
for (particle, n) in processDescription.inParticles
|
||||
for _ in 1:n
|
||||
massSum += mass(particle)
|
||||
push!(inputMasses, mass(particle))
|
||||
end
|
||||
for particle in incoming_particles(processDescription)
|
||||
massSum += mass(particle)
|
||||
push!(inputMasses, mass(particle))
|
||||
end
|
||||
outputMasses = Vector{Float64}()
|
||||
for (particle, n) in processDescription.outParticles
|
||||
for _ in 1:n
|
||||
massSum += mass(particle)
|
||||
push!(outputMasses, mass(particle))
|
||||
end
|
||||
for particle in outgoing_particles(processDescription)
|
||||
massSum += mass(particle)
|
||||
push!(outputMasses, mass(particle))
|
||||
end
|
||||
|
||||
initialMomenta = [
|
||||
i == 1 ? SFourMomentum(1, 0, 0, 0) : SFourMomentum(omega, 0, 0, omega) for
|
||||
i in 1:length(inputMasses)
|
||||
]
|
||||
initial_momenta =
|
||||
[i == 1 ? SFourMomentum(1, 0, 0, 0) : SFourMomentum(omega, 0, 0, omega) for i in 1:length(inputMasses)]
|
||||
|
||||
# add some extra random mass to allow for some momentum
|
||||
ss = sqrt(sum(initialMomenta) * sum(initialMomenta))
|
||||
ss = sqrt(sum(initial_momenta) * sum(initial_momenta))
|
||||
final_momenta = MetagraphOptimization.generate_physical_massive_moms(RNG, ss, outputMasses)
|
||||
|
||||
result = Vector{QEDProcessInput}()
|
||||
sizehint!(result, 16)
|
||||
|
||||
spin_pol_combinations = Iterators.product(
|
||||
[SpinUp, SpinDown], [SpinUp, SpinDown], [PolX, PolY], [PolX, PolY]
|
||||
)
|
||||
for (in_spin, out_spin, in_pol, out_pol) in spin_pol_combinations
|
||||
|
||||
# get the electron first, then the n photons
|
||||
particles = Vector{QEDParticle}()
|
||||
|
||||
for (particle, n) in processDescription.inParticles
|
||||
if particle <: FermionStateful
|
||||
mom = initialMomenta[1]
|
||||
push!(particles, particle(mom, in_spin()))
|
||||
elseif particle <: PhotonStateful
|
||||
for i in 1:n
|
||||
mom = initialMomenta[i + 1]
|
||||
push!(particles, particle(mom, in_pol()))
|
||||
end
|
||||
else
|
||||
@assert false
|
||||
end
|
||||
end
|
||||
|
||||
final_momenta = MetagraphOptimization.generate_physical_massive_moms(
|
||||
RNG, ss, outputMasses
|
||||
)
|
||||
index = 1
|
||||
for (particle, n) in processDescription.outParticles
|
||||
for _ in 1:n
|
||||
if particle <: FermionStateful
|
||||
push!(particles, particle(final_momenta[index], out_spin()))
|
||||
elseif particle <: PhotonStateful
|
||||
push!(particles, particle(final_momenta[index], out_pol()))
|
||||
end
|
||||
index += 1
|
||||
end
|
||||
end
|
||||
|
||||
inFerms = MetagraphOptimization._svector_from_type(
|
||||
processDescription, FermionStateful{Incoming,in_spin}, particles
|
||||
)
|
||||
outFerms = MetagraphOptimization._svector_from_type(
|
||||
processDescription, FermionStateful{Outgoing,out_spin}, particles
|
||||
)
|
||||
inAntiferms = MetagraphOptimization._svector_from_type(
|
||||
processDescription, AntiFermionStateful{Incoming,in_spin}, particles
|
||||
)
|
||||
outAntiferms = MetagraphOptimization._svector_from_type(
|
||||
processDescription, AntiFermionStateful{Outgoing,out_spin}, particles
|
||||
)
|
||||
inPhotons = MetagraphOptimization._svector_from_type(
|
||||
processDescription, PhotonStateful{Incoming,in_pol}, particles
|
||||
)
|
||||
outPhotons = MetagraphOptimization._svector_from_type(
|
||||
processDescription, PhotonStateful{Outgoing,out_pol}, particles
|
||||
)
|
||||
|
||||
processInput = QEDProcessInput(
|
||||
processDescription,
|
||||
inFerms,
|
||||
outFerms,
|
||||
inAntiferms,
|
||||
outAntiferms,
|
||||
inPhotons,
|
||||
outPhotons,
|
||||
)
|
||||
|
||||
push!(result, processInput)
|
||||
end
|
||||
|
||||
return result
|
||||
return (tuple(initial_momenta...), tuple(final_momenta...))
|
||||
end
|
||||
|
||||
function build_psp(processDescription::GenericQEDProcess, momenta)
|
||||
return PhaseSpacePoint(
|
||||
processDescription,
|
||||
PerturbativeQED(),
|
||||
PhasespaceDefinition(SphericalCoordinateSystem(), ElectronRestFrame()),
|
||||
momenta[1],
|
||||
momenta[2],
|
||||
)
|
||||
end
|
||||
|
||||
n = 1000000
|
||||
photons = 4
|
||||
omega = 2e-3
|
||||
|
||||
# n is the number of incoming photons
|
||||
# omega is the number
|
||||
|
||||
println("Generating $n inputs for $photons photons, omega=$omega...")
|
||||
|
||||
# temp process to generate momenta
|
||||
temp_process = parse_process("k"^photons * "e->ke", QEDModel(), PolX(), SpinUp(), PolX(), SpinUp())
|
||||
input_momenta = [congruent_input_momenta(temp_process, omega) for _ in 1:n]
|
||||
results = [0.0im for _ in 1:n]
|
||||
|
||||
for (in_pol, in_spin, out_pol, out_spin) in
|
||||
Iterators.product([PolX(), PolY()], [SpinUp(), SpinDown()], [PolX(), PolY()], [SpinUp(), SpinDown()])
|
||||
|
||||
print("Calculating for spin/pol config: $in_pol, $in_spin -> $out_pol, $out_spin... Preparing inputs... ")
|
||||
process = parse_process("k"^photons * "e->ke", QEDModel(), in_pol, in_spin, out_pol, out_spin)
|
||||
inputs = build_psp.(Ref(process), input_momenta)
|
||||
|
||||
print("Preparing graph... ")
|
||||
# prepare function
|
||||
graph = gen_graph(process)
|
||||
optimize_to_fixpoint!(ReductionOptimizer(), graph)
|
||||
print("Preparing function... ")
|
||||
func = get_compute_function(graph, process, mock_machine())
|
||||
|
||||
print("Calculating... ")
|
||||
for i in 1:n
|
||||
results[i] += func(inputs[i])^2
|
||||
end
|
||||
println("Done.")
|
||||
end
|
||||
|
||||
println("Writing results")
|
||||
open("$(photons)_congruent_photons_omega_$(omega).csv", "w") do f
|
||||
println(f, "out_photon_momentum;out_electron_momentum;result")
|
||||
for (momentum, result) in Iterators.zip(input_momenta, results)
|
||||
println(f, "$(momentum[2][1]);$(momentum[2][2]);$(result)")
|
||||
end
|
||||
end
|
||||
|
@ -413,7 +413,7 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Julia 1.10.2",
|
||||
"display_name": "Julia 1.10.4",
|
||||
"language": "julia",
|
||||
"name": "julia-1.10"
|
||||
},
|
||||
@ -421,7 +421,7 @@
|
||||
"file_extension": ".jl",
|
||||
"mimetype": "application/julia",
|
||||
"name": "julia",
|
||||
"version": "1.10.2"
|
||||
"version": "1.10.4"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
@ -66,8 +66,7 @@ export ComputeTaskABC_Sum
|
||||
|
||||
# QED model
|
||||
export FeynmanDiagram, FeynmanVertex, FeynmanTie, FeynmanParticle
|
||||
export PhotonStateful, FermionStateful, AntiFermionStateful
|
||||
export QEDParticle, QEDProcessDescription, QEDProcessInput, QEDModel
|
||||
export GenericQEDProcess, QEDModel
|
||||
export ComputeTaskQED_P
|
||||
export ComputeTaskQED_S1
|
||||
export ComputeTaskQED_S2
|
||||
@ -116,6 +115,8 @@ import Base.delete!
|
||||
import Base.insert!
|
||||
import Base.collect
|
||||
|
||||
include("QEDprocesses_patch.jl")
|
||||
|
||||
include("devices/interface.jl")
|
||||
include("task/type.jl")
|
||||
include("node/type.jl")
|
||||
@ -174,22 +175,26 @@ include("optimization/split.jl")
|
||||
include("models/interface.jl")
|
||||
include("models/print.jl")
|
||||
|
||||
include("models/abc/types.jl")
|
||||
include("models/abc/particle.jl")
|
||||
include("models/abc/compute.jl")
|
||||
include("models/abc/create.jl")
|
||||
include("models/abc/properties.jl")
|
||||
include("models/abc/parse.jl")
|
||||
include("models/abc/print.jl")
|
||||
include("models/physics_models/interface.jl")
|
||||
|
||||
include("models/qed/types.jl")
|
||||
include("models/qed/particle.jl")
|
||||
include("models/qed/diagrams.jl")
|
||||
include("models/qed/compute.jl")
|
||||
include("models/qed/create.jl")
|
||||
include("models/qed/properties.jl")
|
||||
include("models/qed/parse.jl")
|
||||
include("models/qed/print.jl")
|
||||
#=
|
||||
include("models/physics_models/abc/types.jl")
|
||||
include("models/physics_models/abc/particle.jl")
|
||||
include("models/physics_models/abc/compute.jl")
|
||||
include("models/physics_models/abc/create.jl")
|
||||
include("models/physics_models/abc/properties.jl")
|
||||
include("models/physics_models/abc/parse.jl")
|
||||
include("models/physics_models/abc/print.jl")
|
||||
=#
|
||||
|
||||
include("models/physics_models/qed/types.jl")
|
||||
include("models/physics_models/qed/particle.jl")
|
||||
include("models/physics_models/qed/diagrams.jl")
|
||||
include("models/physics_models/qed/compute.jl")
|
||||
include("models/physics_models/qed/create.jl")
|
||||
include("models/physics_models/qed/properties.jl")
|
||||
include("models/physics_models/qed/parse.jl")
|
||||
include("models/physics_models/qed/print.jl")
|
||||
|
||||
include("devices/measure.jl")
|
||||
include("devices/detect.jl")
|
||||
@ -198,7 +203,7 @@ include("devices/impl.jl")
|
||||
include("devices/numa/impl.jl")
|
||||
include("devices/cuda/impl.jl")
|
||||
include("devices/rocm/impl.jl")
|
||||
include("devices/oneapi/impl.jl")
|
||||
#include("devices/oneapi/impl.jl")
|
||||
|
||||
include("scheduler/interface.jl")
|
||||
include("scheduler/greedy.jl")
|
||||
|
71
src/QEDprocesses_patch.jl
Normal file
71
src/QEDprocesses_patch.jl
Normal file
@ -0,0 +1,71 @@
|
||||
# patch QEDprocesses
|
||||
# see issue https://github.com/QEDjl-project/QEDprocesses.jl/issues/77
|
||||
@inline function QEDprocesses.number_particles(
|
||||
proc_def::QEDbase.AbstractProcessDefinition,
|
||||
dir::DIR,
|
||||
::PT,
|
||||
) where {DIR <: QEDbase.ParticleDirection, PT <: QEDbase.AbstractParticleType}
|
||||
return count(x -> x isa PT, particles(proc_def, dir))
|
||||
end
|
||||
|
||||
@inline function QEDprocesses.number_particles(
|
||||
proc_def::QEDbase.AbstractProcessDefinition,
|
||||
::PS,
|
||||
) where {
|
||||
DIR <: QEDbase.ParticleDirection,
|
||||
PT <: QEDbase.AbstractParticleType,
|
||||
EL <: AbstractFourMomentum,
|
||||
PS <: ParticleStateful{DIR, PT, EL},
|
||||
}
|
||||
return QEDprocesses.number_particles(proc_def, DIR(), PT())
|
||||
end
|
||||
|
||||
@inline function QEDprocesses.number_particles(
|
||||
proc_def::QEDbase.AbstractProcessDefinition,
|
||||
::Type{PS},
|
||||
) where {
|
||||
DIR <: QEDbase.ParticleDirection,
|
||||
PT <: QEDbase.AbstractParticleType,
|
||||
EL <: AbstractFourMomentum,
|
||||
PS <: ParticleStateful{DIR, PT, EL},
|
||||
}
|
||||
return QEDprocesses.number_particles(proc_def, DIR(), PT())
|
||||
end
|
||||
|
||||
@inline function QEDcore.ParticleStateful{DIR, SPECIES}(
|
||||
mom::AbstractFourMomentum,
|
||||
) where {DIR <: ParticleDirection, SPECIES <: AbstractParticleType}
|
||||
return ParticleStateful(DIR(), SPECIES(), mom)
|
||||
end
|
||||
|
||||
@inline function QEDcore.ParticleStateful{DIR, SPECIES, EL}(
|
||||
mom::EL,
|
||||
) where {DIR <: ParticleDirection, SPECIES <: AbstractParticleType, EL <: AbstractFourMomentum}
|
||||
return ParticleStateful(DIR(), SPECIES(), mom)
|
||||
end
|
||||
|
||||
@inline function QEDbase.momentum(
|
||||
psp::AbstractPhaseSpacePoint{MODEL, PROC, PS_DEF, INT, OUTT},
|
||||
dir::ParticleDirection,
|
||||
species::AbstractParticleType,
|
||||
n::Int,
|
||||
) where {MODEL, PROC, PS_DEF, INT, OUTT}
|
||||
# TODO: can be done through fancy template recursion too with 0 overhead
|
||||
i = 0
|
||||
c = n
|
||||
for p in particles(psp, dir)
|
||||
i += 1
|
||||
if particle_species(p) isa typeof(species)
|
||||
c -= 1
|
||||
end
|
||||
if c == 0
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if c != 0 || n <= 0
|
||||
throw(InvalidInputError("could not get $n-th momentum of $dir $species, does not exist"))
|
||||
end
|
||||
|
||||
return momenta(psp, dir)[i]
|
||||
end
|
@ -1,10 +1,10 @@
|
||||
"""
|
||||
get_compute_function(graph::DAG, process::AbstractProcessDescription, machine::Machine)
|
||||
get_compute_function(graph::DAG, instance, machine::Machine)
|
||||
|
||||
Return a function of signature `compute_<id>(input::AbstractProcessInput)`, which will return the result of the DAG computation on the given input.
|
||||
Return a function of signature `compute_<id>(input::input_type(instance))`, which will return the result of the DAG computation on the given input.
|
||||
"""
|
||||
function get_compute_function(graph::DAG, process::AbstractProcessDescription, machine::Machine)
|
||||
tape = gen_tape(graph, process, machine)
|
||||
function get_compute_function(graph::DAG, instance, machine::Machine)
|
||||
tape = gen_tape(graph, instance, machine)
|
||||
|
||||
initCaches = Expr(:block, tape.initCachesCode...)
|
||||
assignInputs = Expr(:block, expr_from_fc.(tape.inputAssignCode)...)
|
||||
@ -13,7 +13,7 @@ function get_compute_function(graph::DAG, process::AbstractProcessDescription, m
|
||||
functionId = to_var_name(UUIDs.uuid1(rng[1]))
|
||||
resSym = eval(gen_access_expr(entry_device(tape.machine), tape.outputSymbol))
|
||||
expr = Meta.parse(
|
||||
"function compute_$(functionId)(data_input::AbstractProcessInput) $(initCaches); $(assignInputs); $code; return $resSym; end",
|
||||
"function compute_$(functionId)(data_input::$(input_type(instance))) $(initCaches); $(assignInputs); $code; return $resSym; end",
|
||||
)
|
||||
|
||||
func = eval(expr)
|
||||
@ -22,12 +22,12 @@ function get_compute_function(graph::DAG, process::AbstractProcessDescription, m
|
||||
end
|
||||
|
||||
"""
|
||||
get_cuda_kernel(graph::DAG, process::AbstractProcessDescription, machine::Machine)
|
||||
get_cuda_kernel(graph::DAG, instance, machine::Machine)
|
||||
|
||||
Return a function of signature `compute_<id>(input::CuVector, output::CuVector, n::Int64)`, which will return the result of the DAG computation of the input on the given output variable.
|
||||
"""
|
||||
function get_cuda_kernel(graph::DAG, process::AbstractProcessDescription, machine::Machine)
|
||||
tape = gen_tape(graph, process, machine)
|
||||
function get_cuda_kernel(graph::DAG, instance, machine::Machine)
|
||||
tape = gen_tape(graph, instance, machine)
|
||||
|
||||
initCaches = Expr(:block, tape.initCachesCode...)
|
||||
assignInputs = Expr(:block, expr_from_fc.(tape.inputAssignCode)...)
|
||||
@ -54,19 +54,19 @@ function get_cuda_kernel(graph::DAG, process::AbstractProcessDescription, machin
|
||||
end
|
||||
|
||||
"""
|
||||
execute(graph::DAG, process::AbstractProcessDescription, machine::Machine, input::AbstractProcessInput)
|
||||
execute(graph::DAG, instance, machine::Machine, input)
|
||||
|
||||
Execute the code of the given `graph` on the given input particles.
|
||||
Execute the code of the given `graph` on the given input values.
|
||||
|
||||
This is essentially shorthand for
|
||||
```julia
|
||||
tape = gen_tape(graph, process, machine)
|
||||
tape = gen_tape(graph, instance, machine)
|
||||
return execute_tape(tape, input)
|
||||
```
|
||||
|
||||
See also: [`parse_dag`](@ref), [`parse_process`](@ref), [`gen_process_input`](@ref)
|
||||
"""
|
||||
function execute(graph::DAG, process::AbstractProcessDescription, machine::Machine, input::AbstractProcessInput)
|
||||
tape = gen_tape(graph, process, machine)
|
||||
function execute(graph::DAG, instance, machine::Machine, input)
|
||||
tape = gen_tape(graph, instance, machine)
|
||||
return execute_tape(tape, input)
|
||||
end
|
||||
|
@ -1,10 +1,11 @@
|
||||
# TODO: do this with macros
|
||||
function call_fc(fc::FunctionCall{VectorT, 0}, cache::Dict{Symbol, Any}) where {VectorT <: SVector{1}}
|
||||
cache[fc.return_symbol] = fc.func(cache[fc.arguments[1]])
|
||||
return nothing
|
||||
end
|
||||
|
||||
function call_fc(fc::FunctionCall{VectorT, 1}, cache::Dict{Symbol, Any}) where {VectorT <: SVector{1}}
|
||||
cache[fc.return_symbol] = fc.func(fc.additional_arguments[1], cache[fc.arguments[1]])
|
||||
cache[fc.return_symbol] = fc.func(fc.value_arguments[1], cache[fc.arguments[1]])
|
||||
return nothing
|
||||
end
|
||||
|
||||
@ -14,12 +15,12 @@ function call_fc(fc::FunctionCall{VectorT, 0}, cache::Dict{Symbol, Any}) where {
|
||||
end
|
||||
|
||||
function call_fc(fc::FunctionCall{VectorT, 1}, cache::Dict{Symbol, Any}) where {VectorT <: SVector{2}}
|
||||
cache[fc.return_symbol] = fc.func(fc.additional_arguments[1], cache[fc.arguments[1]], cache[fc.arguments[2]])
|
||||
cache[fc.return_symbol] = fc.func(fc.value_arguments[1], cache[fc.arguments[1]], cache[fc.arguments[2]])
|
||||
return nothing
|
||||
end
|
||||
|
||||
function call_fc(fc::FunctionCall{VectorT, 1}, cache::Dict{Symbol, Any}) where {VectorT}
|
||||
cache[fc.return_symbol] = fc.func(fc.additional_arguments[1], getindex.(Ref(cache), fc.arguments)...)
|
||||
cache[fc.return_symbol] = fc.func(fc.value_arguments[1], getindex.(Ref(cache), fc.arguments)...)
|
||||
return nothing
|
||||
end
|
||||
|
||||
@ -31,7 +32,7 @@ Execute the given [`FunctionCall`](@ref) on the dictionary.
|
||||
Several more specialized versions of this function exist to reduce vector unrolling work for common cases.
|
||||
"""
|
||||
function call_fc(fc::FunctionCall{VectorT, M}, cache::Dict{Symbol, Any}) where {VectorT, M}
|
||||
cache[fc.return_symbol] = fc.func(fc.additional_arguments..., getindex.(Ref(cache), fc.arguments)...)
|
||||
cache[fc.return_symbol] = fc.func(fc.value_arguments..., getindex.(Ref(cache), fc.arguments)...)
|
||||
return nothing
|
||||
end
|
||||
|
||||
@ -47,12 +48,8 @@ end
|
||||
For a given function call, return an expression evaluating it.
|
||||
"""
|
||||
function expr_from_fc(fc::FunctionCall{VectorT, M}) where {VectorT, M}
|
||||
func_call = Expr(
|
||||
:call,
|
||||
Symbol(fc.func),
|
||||
fc.additional_arguments...,
|
||||
eval.(gen_access_expr.(Ref(fc.device), fc.arguments))...,
|
||||
)
|
||||
func_call =
|
||||
Expr(:call, Symbol(fc.func), fc.value_arguments..., eval.(gen_access_expr.(Ref(fc.device), fc.arguments))...)
|
||||
|
||||
expr = :($(eval(gen_access_expr(fc.device, fc.return_symbol))) = $func_call)
|
||||
return expr
|
||||
@ -73,52 +70,31 @@ function gen_cache_init_code(machine::Machine)
|
||||
return initializeCaches
|
||||
end
|
||||
|
||||
"""
|
||||
part_from_x(type::Type, index::Int, x::AbstractProcessInput)
|
||||
|
||||
Return the [`ParticleValue`](@ref) of the given type of particle with the given `index` from the given process input.
|
||||
|
||||
Function is wrapped into a [`FunctionCall`](@ref) in [`gen_input_assignment_code`](@ref).
|
||||
"""
|
||||
part_from_x(type::Type, index::Int, x::AbstractProcessInput) =
|
||||
ParticleValue{type, ComplexF64}(get_particle(x, type, index), one(ComplexF64))
|
||||
|
||||
"""
|
||||
gen_input_assignment_code(
|
||||
inputSymbols::Dict{String, Vector{Symbol}},
|
||||
processDescription::AbstractProcessDescription,
|
||||
instance::AbstractProblemInstance,
|
||||
machine::Machine,
|
||||
processInputSymbol::Symbol = :input,
|
||||
problemInputSymbol::Symbol = :input,
|
||||
)
|
||||
|
||||
Return a `Vector{Expr}` doing the input assignments from the given `processInputSymbol` onto the `inputSymbols`.
|
||||
Return a `Vector{Expr}` doing the input assignments from the given `problemInputSymbol` onto the `inputSymbols`.
|
||||
"""
|
||||
function gen_input_assignment_code(
|
||||
inputSymbols::Dict{String, Vector{Symbol}},
|
||||
processDescription::AbstractProcessDescription,
|
||||
instance,
|
||||
machine::Machine,
|
||||
processInputSymbol::Symbol = :input,
|
||||
problemInputSymbol::Symbol = :input,
|
||||
)
|
||||
@assert length(inputSymbols) >=
|
||||
sum(values(in_particles(processDescription))) + sum(values(out_particles(processDescription))) "Number of input Symbols is smaller than the number of particles in the process description"
|
||||
|
||||
assignInputs = Vector{FunctionCall}()
|
||||
for (name, symbols) in inputSymbols
|
||||
(type, index) = type_index_from_name(model(processDescription), name)
|
||||
# make a function for this, since we can't use anonymous functions in the FunctionCall
|
||||
|
||||
for symbol in symbols
|
||||
device = entry_device(machine)
|
||||
push!(
|
||||
assignInputs,
|
||||
FunctionCall(
|
||||
# x is the process input
|
||||
part_from_x,
|
||||
SVector{1, Symbol}(processInputSymbol),
|
||||
SVector{2, Any}(type, index),
|
||||
symbol,
|
||||
device,
|
||||
),
|
||||
FunctionCall(input_expr, SVector{1, Any}(name), SVector{1, Symbol}(problemInputSymbol), symbol, device),
|
||||
)
|
||||
end
|
||||
end
|
||||
@ -127,14 +103,14 @@ function gen_input_assignment_code(
|
||||
end
|
||||
|
||||
"""
|
||||
gen_tape(graph::DAG, process::AbstractProcessDescription, machine::Machine)
|
||||
gen_tape(graph::DAG, instance::AbstractProblemInstance, machine::Machine, scheduler::AbstractScheduler = GreedyScheduler())
|
||||
|
||||
Generate the code for a given graph. The return value is a [`Tape`](@ref).
|
||||
|
||||
See also: [`execute`](@ref), [`execute_tape`](@ref)
|
||||
"""
|
||||
function gen_tape(graph::DAG, process::AbstractProcessDescription, machine::Machine)
|
||||
schedule = schedule_dag(GreedyScheduler(), graph, machine)
|
||||
function gen_tape(graph::DAG, instance, machine::Machine, scheduler::AbstractScheduler = GreedyScheduler())
|
||||
schedule = schedule_dag(scheduler, graph, machine)
|
||||
|
||||
# get inSymbols
|
||||
inputSyms = Dict{String, Vector{Symbol}}()
|
||||
@ -150,23 +126,24 @@ function gen_tape(graph::DAG, process::AbstractProcessDescription, machine::Mach
|
||||
outSym = Symbol(to_var_name(get_exit_node(graph).id))
|
||||
|
||||
initCaches = gen_cache_init_code(machine)
|
||||
assignInputs = gen_input_assignment_code(inputSyms, process, machine, :input)
|
||||
assignInputs = gen_input_assignment_code(inputSyms, instance, machine, :input)
|
||||
|
||||
return Tape(initCaches, assignInputs, schedule, inputSyms, outSym, Dict(), process, machine)
|
||||
return Tape{input_type(instance)}(initCaches, assignInputs, schedule, inputSyms, outSym, Dict(), instance, machine)
|
||||
end
|
||||
|
||||
"""
|
||||
execute_tape(tape::Tape, input::AbstractProcessInput)
|
||||
execute_tape(tape::Tape, input::Input) where {Input}
|
||||
|
||||
Execute the given tape with the given input.
|
||||
|
||||
For implementation reasons, this disregards the set [`CacheStrategy`](@ref) of the devices and always uses a dictionary.
|
||||
"""
|
||||
function execute_tape(tape::Tape, input::AbstractProcessInput)
|
||||
function execute_tape(tape::Tape, input)
|
||||
cache = Dict{Symbol, Any}()
|
||||
cache[:input] = input
|
||||
# simply execute all the code snippets here
|
||||
# TODO: `@assert` that process input fits the tape.process
|
||||
@assert typeof(input) == input_type(tape.instance)
|
||||
# TODO: `@assert` that input fits the tape.instance
|
||||
for expr in tape.initCachesCode
|
||||
@eval $expr
|
||||
end
|
||||
|
@ -1,19 +1,21 @@
|
||||
|
||||
"""
|
||||
Tape
|
||||
Tape{INPUT}
|
||||
|
||||
TODO: update docs
|
||||
- `INPUT` the input type of the problem instance
|
||||
|
||||
- `code::Vector{Expr}`: The julia expression containing the code for the whole graph.
|
||||
- `inputSymbols::Dict{String, Vector{Symbol}}`: A dictionary of symbols mapping the names of the input nodes of the graph to the symbols their inputs should be provided on.
|
||||
- `outputSymbol::Symbol`: The symbol of the final calculated value
|
||||
"""
|
||||
struct Tape
|
||||
struct Tape{INPUT}
|
||||
initCachesCode::Vector{Expr}
|
||||
inputAssignCode::Vector{FunctionCall}
|
||||
computeCode::Vector{FunctionCall}
|
||||
inputSymbols::Dict{String, Vector{Symbol}}
|
||||
outputSymbol::Symbol
|
||||
cache::Dict{Symbol, Any}
|
||||
process::AbstractProcessDescription
|
||||
instance::Any
|
||||
machine::Machine
|
||||
end
|
||||
|
@ -1,120 +1,46 @@
|
||||
import QEDbase.mass
|
||||
import QEDbase.AbstractParticle
|
||||
|
||||
"""
|
||||
AbstractPhysicsModel
|
||||
AbstractModel
|
||||
|
||||
Base type for a model, e.g. ABC-Model or QED. This is used to dispatch many functions.
|
||||
Base type for all models. From this, [`AbstractProblemInstance`](@ref)s can be constructed.
|
||||
|
||||
See also: [`problem_instance`](@ref)
|
||||
"""
|
||||
abstract type AbstractPhysicsModel end
|
||||
abstract type AbstractModel end
|
||||
|
||||
"""
|
||||
ParticleValue{ParticleType <: AbstractParticle}
|
||||
problem_instance(::AbstractModel, ::Vararg)
|
||||
|
||||
A struct describing a particle during a calculation of a Feynman Diagram, together with the value that's being calculated. `AbstractParticle` is the type from the QEDbase package.
|
||||
|
||||
`sizeof(ParticleValue())` = 48 Byte
|
||||
Interface function that must be implemented for any implementation of [`AbstractModel`](@ref). This function should return a specific [`AbstractProblemInstance`](@ref) given some parameters.
|
||||
"""
|
||||
struct ParticleValue{ParticleType <: AbstractParticle, ValueType}
|
||||
p::ParticleType
|
||||
v::ValueType
|
||||
end
|
||||
function problem_instance end
|
||||
|
||||
"""
|
||||
AbstractProcessDescription
|
||||
AbstractProblemInstance
|
||||
|
||||
Base type for process descriptions. An object of this type of a corresponding [`AbstractPhysicsModel`](@ref) should uniquely identify a process in that model.
|
||||
Base type for problem instances. An object of this type of a corresponding [`AbstractModel`](@ref) should uniquely identify a problem instance of that model.
|
||||
|
||||
See also: [`parse_process`](@ref)
|
||||
"""
|
||||
abstract type AbstractProcessDescription end
|
||||
abstract type AbstractProblemInstance end
|
||||
|
||||
"""
|
||||
AbstractProcessInput
|
||||
input_type(problem::AbstractProblemInstance)
|
||||
|
||||
Base type for process inputs. An object of this type contains the input values (e.g. momenta) of the particles in a process.
|
||||
|
||||
See also: [`gen_process_input`](@ref)
|
||||
Return the fully specified input type for a specific [`AbstractProblemInstance`](@ref).
|
||||
"""
|
||||
abstract type AbstractProcessInput end
|
||||
function input_type end
|
||||
|
||||
"""
|
||||
interaction_result(t1::Type{T1}, t2::Type{T2}) where {T1 <: AbstractParticle, T2 <: AbstractParticle}
|
||||
graph(::AbstractProblemInstance)
|
||||
|
||||
Interface function that must be implemented for every subtype of [`AbstractParticle`](@ref), returning the result particle type when the two given particles interact.
|
||||
Generate the [`DAG`](@ref) for the given [`AbstractProblemInstance`](@ref). Every entry node (see [`get_entry_nodes`](@ref)) to the graph must have a name set. Implement [`input_expr`](@ref) to return a valid expression for each of those names.
|
||||
"""
|
||||
function interaction_result end
|
||||
function graph end
|
||||
|
||||
"""
|
||||
types(::AbstractPhysicsModel)
|
||||
input_expr(::AbstractProblemInstance, name::String, input)
|
||||
|
||||
Interface function that must be implemented for every subtype of [`AbstractPhysicsModel`](@ref), returning a `Vector` of the available particle types in the model.
|
||||
For a given [`AbstractProblemInstance`](@ref), the problem input (of type `input_type(...)`) and an entry node name, return a that specific input value from the input symbol.
|
||||
"""
|
||||
function types end
|
||||
|
||||
"""
|
||||
in_particles(::AbstractProcessDescription)
|
||||
|
||||
Interface function that must be implemented for every subtype of [`AbstractProcessDescription`](@ref).
|
||||
Returns a `<: Dict{Type{AbstractParticle}, Int}` object, representing the number of incoming particles for the process per particle type.
|
||||
|
||||
|
||||
in_particles(::AbstractProcessInput)
|
||||
|
||||
Interface function that must be implemented for every subtype of [`AbstractProcessInput`](@ref).
|
||||
Returns a `<: Vector{AbstractParticle}` object with the values of all incoming particles for the corresponding `ProcessDescription`.
|
||||
"""
|
||||
function in_particles end
|
||||
|
||||
"""
|
||||
out_particles(::AbstractProcessDescription)
|
||||
|
||||
Interface function that must be implemented for every subtype of [`AbstractProcessDescription`](@ref).
|
||||
Returns a `<: Dict{Type{AbstractParticle}, Int}` object, representing the number of outgoing particles for the process per particle type.
|
||||
|
||||
|
||||
out_particles(::AbstractProcessInput)
|
||||
|
||||
Interface function that must be implemented for every subtype of [`AbstractProcessInput`](@ref).
|
||||
Returns a `<: Vector{AbstractParticle}` object with the values of all outgoing particles for the corresponding `ProcessDescription`.
|
||||
"""
|
||||
function out_particles end
|
||||
|
||||
"""
|
||||
get_particle(::AbstractProcessInput, t::Type, n::Int)
|
||||
|
||||
Interface function that must be implemented for every subtype of [`AbstractProcessInput`](@ref).
|
||||
Returns the `n`th particle of type `t`.
|
||||
"""
|
||||
function get_particle end
|
||||
|
||||
"""
|
||||
parse_process(::AbstractString, ::AbstractPhysicsModel)
|
||||
|
||||
Interface function that must be implemented for every subtype of [`AbstractPhysicsModel`](@ref).
|
||||
Returns a `ProcessDescription` object.
|
||||
"""
|
||||
function parse_process end
|
||||
|
||||
"""
|
||||
gen_process_input(::AbstractProcessDescription)
|
||||
|
||||
Interface function that must be implemented for every specific [`AbstractProcessDescription`](@ref).
|
||||
Returns a randomly generated and valid corresponding `ProcessInput`.
|
||||
"""
|
||||
function gen_process_input end
|
||||
|
||||
"""
|
||||
model(::AbstractProcessDescription)
|
||||
model(::AbstarctProcessInput)
|
||||
|
||||
Return the model of this process description or input.
|
||||
"""
|
||||
function model end
|
||||
|
||||
"""
|
||||
type_from_name(model::AbstractModel, name::String)
|
||||
|
||||
For a name of a particle in the given [`AbstractModel`](@ref), return the particle's [`Type`] and index as a tuple. The input string can be expetced to be of the form \"<name><index>\".
|
||||
"""
|
||||
function type_index_from_name end
|
||||
function input_expr end
|
||||
|
142
src/models/physics_models/interface.jl
Normal file
142
src/models/physics_models/interface.jl
Normal file
@ -0,0 +1,142 @@
|
||||
import QEDbase.AbstractParticle
|
||||
|
||||
"""
|
||||
AbstractPhysicsModel
|
||||
|
||||
Base type for a model, e.g. ABC-Model or QED. This is used to dispatch many functions.
|
||||
"""
|
||||
abstract type AbstractPhysicsModel <: AbstractModel end
|
||||
|
||||
"""
|
||||
ParticleValue{ParticleType <: AbstractParticleStateful}
|
||||
|
||||
A struct describing a particle during a calculation of a Feynman Diagram, together with the value that's being calculated. `AbstractParticleStateful` is the type from the QEDbase package.
|
||||
|
||||
`sizeof(ParticleValue())` = 48 Byte
|
||||
"""
|
||||
struct ParticleValue{ParticleType <: AbstractParticleStateful, ValueType}
|
||||
p::ParticleType
|
||||
v::ValueType
|
||||
end
|
||||
|
||||
"""
|
||||
TBW
|
||||
|
||||
particle value + spin/pol info, only used on the external legs (u tasks)
|
||||
"""
|
||||
struct ParticleValueSP{ParticleType <: AbstractParticleStateful, SP <: AbstractSpinOrPolarization, ValueType}
|
||||
p::ParticleType
|
||||
v::ValueType
|
||||
sp::SP
|
||||
end
|
||||
|
||||
"""
|
||||
AbstractProcessDescription <: AbstractProblemInstance
|
||||
|
||||
Base type for particle scattering process descriptions. An object of this type of a corresponding [`AbstractPhysicsModel`](@ref) should uniquely identify a scattering process in that model.
|
||||
|
||||
See also: [`parse_process`](@ref), [`AbstractProblemInstance`](@ref)
|
||||
"""
|
||||
abstract type AbstractProcessDescription end
|
||||
|
||||
|
||||
#TODO: i don't think giving this a base type is a good idea, the input type should just be returned of some function, allowing anything as an input type
|
||||
"""
|
||||
AbstractProcessInput
|
||||
|
||||
Base type for process inputs. An object of this type contains the input values (e.g. momenta) of the particles in a process.
|
||||
|
||||
See also: [`gen_process_input`](@ref)
|
||||
"""
|
||||
abstract type AbstractProcessInput end
|
||||
|
||||
"""
|
||||
interaction_result(t1::Type{T1}, t2::Type{T2}) where {T1 <: AbstractParticle, T2 <: AbstractParticle}
|
||||
|
||||
Interface function that must be implemented for every subtype of [`AbstractParticle`](@ref), returning the result particle type when the two given particles interact.
|
||||
"""
|
||||
function interaction_result end
|
||||
|
||||
"""
|
||||
types(::AbstractPhysicsModel)
|
||||
|
||||
Interface function that must be implemented for every subtype of [`AbstractPhysicsModel`](@ref), returning a `Vector` of the available particle types in the model.
|
||||
"""
|
||||
function types end
|
||||
|
||||
"""
|
||||
in_particles(::AbstractProcessDescription)
|
||||
|
||||
Interface function that must be implemented for every subtype of [`AbstractProcessDescription`](@ref).
|
||||
Returns a `<: Dict{Type{AbstractParticle}, Int}` object, representing the number of incoming particles for the process per particle type.
|
||||
|
||||
|
||||
in_particles(::AbstractProcessInput)
|
||||
|
||||
Interface function that must be implemented for every subtype of [`AbstractProcessInput`](@ref).
|
||||
Returns a `<: Vector{AbstractParticle}` object with the values of all incoming particles for the corresponding `ProcessDescription`.
|
||||
"""
|
||||
function in_particles end
|
||||
|
||||
"""
|
||||
out_particles(::AbstractProcessDescription)
|
||||
|
||||
Interface function that must be implemented for every subtype of [`AbstractProcessDescription`](@ref).
|
||||
Returns a `<: Dict{Type{AbstractParticle}, Int}` object, representing the number of outgoing particles for the process per particle type.
|
||||
|
||||
|
||||
out_particles(::AbstractProcessInput)
|
||||
|
||||
Interface function that must be implemented for every subtype of [`AbstractProcessInput`](@ref).
|
||||
Returns a `<: Vector{AbstractParticle}` object with the values of all outgoing particles for the corresponding `ProcessDescription`.
|
||||
"""
|
||||
function out_particles end
|
||||
|
||||
"""
|
||||
get_particle(::AbstractProcessInput, t::Type, n::Int)
|
||||
|
||||
Interface function that must be implemented for every subtype of [`AbstractProcessInput`](@ref).
|
||||
Returns the `n`th particle of type `t`.
|
||||
"""
|
||||
function get_particle end
|
||||
|
||||
"""
|
||||
parse_process(::AbstractString, ::AbstractPhysicsModel)
|
||||
|
||||
Interface function that must be implemented for every subtype of [`AbstractPhysicsModel`](@ref).
|
||||
Returns a `ProcessDescription` object.
|
||||
"""
|
||||
function parse_process end
|
||||
|
||||
"""
|
||||
gen_process_input(::AbstractProcessDescription)
|
||||
|
||||
Interface function that must be implemented for every specific [`AbstractProcessDescription`](@ref).
|
||||
Returns a randomly generated and valid corresponding `ProcessInput`.
|
||||
"""
|
||||
function gen_process_input end
|
||||
|
||||
"""
|
||||
model(::AbstractProcessDescription)
|
||||
model(::AbstractProcessInput)
|
||||
|
||||
Return the model of this process description or input.
|
||||
"""
|
||||
function model end
|
||||
|
||||
"""
|
||||
type_from_name(model::AbstractModel, name::String)
|
||||
|
||||
For a name of a particle in the given [`AbstractModel`](@ref), return the particle's [`Type`] and index as a tuple. The input string can be expetced to be of the form \"<name><index>\".
|
||||
"""
|
||||
function type_index_from_name end
|
||||
|
||||
"""
|
||||
part_from_x(type::Type, index::Int, x::AbstractProcessInput)
|
||||
|
||||
Return the [`ParticleValue`](@ref) of the given type of particle with the given `index` from the given process input.
|
||||
|
||||
Function is wrapped into a [`FunctionCall`](@ref) in [`gen_input_assignment_code`](@ref).
|
||||
"""
|
||||
part_from_x(type::Type, index::Int, x::AbstractProcessInput) =
|
||||
ParticleValue{type, ComplexF64}(get_particle(x, type, index), one(ComplexF64))
|
@ -1,41 +1,42 @@
|
||||
using StaticArrays
|
||||
|
||||
"""
|
||||
compute(::ComputeTaskQED_P, data::QEDParticleValue)
|
||||
function input_expr(name::String, psp::PhaseSpacePoint)
|
||||
(type, index) = type_index_from_name(QEDModel(), name)
|
||||
|
||||
Return the particle as is and initialize the Value.
|
||||
"""
|
||||
function compute(::ComputeTaskQED_P, data::QEDParticleValue{P}) where {P<:QEDParticle}
|
||||
# TODO do we actually need this for anything?
|
||||
return ParticleValue{P,DiracMatrix}(data.p, one(DiracMatrix))
|
||||
return ParticleValueSP(
|
||||
type(momentum(psp, particle_direction(type), particle_species(type), index)),
|
||||
0.0im,
|
||||
spin_or_pol(process(psp), type, index),
|
||||
)
|
||||
end
|
||||
|
||||
"""
|
||||
compute(::ComputeTaskQED_U, data::QEDParticleValue)
|
||||
compute(::ComputeTaskQED_U, data::ParticleValueSP)
|
||||
|
||||
Compute an outer edge. Return the particle value with the same particle and the value multiplied by an outer_edge factor.
|
||||
"""
|
||||
function compute(
|
||||
::ComputeTaskQED_U, data::PV
|
||||
) where {P<:QEDParticle,PV<:QEDParticleValue{P}}
|
||||
::ComputeTaskQED_U,
|
||||
data::ParticleValueSP{P, SP, V},
|
||||
) where {P <: ParticleStateful, V <: ValueType, SP <: AbstractSpinOrPolarization}
|
||||
part::P = data.p
|
||||
state = base_state(particle(part), direction(part), momentum(part), spin_or_pol(part))
|
||||
return ParticleValue{P,typeof(state)}(
|
||||
state = base_state(particle_species(part), particle_direction(part), momentum(part), SP())
|
||||
return ParticleValue{P, typeof(state)}(
|
||||
data.p,
|
||||
state, # will return a SLorentzVector{ComplexF64}, BiSpinor or AdjointBiSpinor
|
||||
)
|
||||
end
|
||||
|
||||
"""
|
||||
compute(::ComputeTaskQED_V, data1::QEDParticleValue, data2::QEDParticleValue)
|
||||
compute(::ComputeTaskQED_V, data1::ParticleValue, data2::ParticleValue)
|
||||
|
||||
Compute a vertex. Preserve momentum and particle types (e + gamma->p etc.) to create resulting particle, multiply values together and times a vertex factor.
|
||||
"""
|
||||
function compute(
|
||||
::ComputeTaskQED_V, data1::PV1, data2::PV2
|
||||
) where {
|
||||
P1<:QEDParticle,P2<:QEDParticle,PV1<:QEDParticleValue{P1},PV2<:QEDParticleValue{P2}
|
||||
}
|
||||
::ComputeTaskQED_V,
|
||||
data1::ParticleValue{P1, V1},
|
||||
data2::ParticleValue{P2, V2},
|
||||
) where {P1 <: ParticleStateful, P2 <: ParticleStateful, V1 <: ValueType, V2 <: ValueType}
|
||||
p3 = QED_conserve_momentum(data1.p, data2.p)
|
||||
P3 = interaction_result(P1, P2)
|
||||
state = QED_vertex()
|
||||
@ -50,12 +51,12 @@ function compute(
|
||||
state = state * data2.v
|
||||
end
|
||||
|
||||
dataOut = ParticleValue{P3,typeof(state)}(P3(momentum(p3)), state)
|
||||
dataOut = ParticleValue{P3, typeof(state)}(P3(momentum(p3)), state)
|
||||
return dataOut
|
||||
end
|
||||
|
||||
"""
|
||||
compute(::ComputeTaskQED_S2, data1::QEDParticleValue, data2::QEDParticleValue)
|
||||
compute(::ComputeTaskQED_S2, data1::ParticleValue, data2::ParticleValue)
|
||||
|
||||
Compute a final inner edge (2 input particles, no output particle).
|
||||
|
||||
@ -64,10 +65,19 @@ For valid inputs, both input particles should have the same momenta at this poin
|
||||
12 FLOP.
|
||||
"""
|
||||
function compute(
|
||||
::ComputeTaskQED_S2, data1::ParticleValue{P1}, data2::ParticleValue{P2}
|
||||
::ComputeTaskQED_S2,
|
||||
data1::ParticleValue{P1, V1},
|
||||
data2::ParticleValue{P2, V2},
|
||||
) where {
|
||||
P1<:Union{AntiFermionStateful,FermionStateful},
|
||||
P2<:Union{AntiFermionStateful,FermionStateful},
|
||||
D1 <: ParticleDirection,
|
||||
D2 <: ParticleDirection,
|
||||
S1 <: Union{Electron, Positron},
|
||||
S2 <: Union{Electron, Positron},
|
||||
V1 <: ValueType,
|
||||
V2 <: ValueType,
|
||||
EL <: AbstractFourMomentum,
|
||||
P1 <: ParticleStateful{D1, S1, EL},
|
||||
P2 <: ParticleStateful{D2, S2, EL},
|
||||
}
|
||||
#@assert isapprox(data1.p.momentum, data2.p.momentum, rtol = sqrt(eps()), atol = sqrt(eps())) "$(data1.p.momentum) vs. $(data2.p.momentum)"
|
||||
|
||||
@ -82,8 +92,10 @@ function compute(
|
||||
end
|
||||
|
||||
function compute(
|
||||
::ComputeTaskQED_S2, data1::ParticleValue{P1}, data2::ParticleValue{P2}
|
||||
) where {P1<:PhotonStateful,P2<:PhotonStateful}
|
||||
::ComputeTaskQED_S2,
|
||||
data1::ParticleValue{ParticleStateful{D1, Photon}, V1},
|
||||
data2::ParticleValue{ParticleStateful{D2, Photon}, V2},
|
||||
) where {D1 <: ParticleDirection, D2 <: ParticleDirection, V1 <: ValueType, V2 <: ValueType}
|
||||
# TODO: assert that data1 and data2 are opposites
|
||||
inner = QED_inner_edge(data1.p)
|
||||
# inner edge is just a scalar, data1 and data2 are photon states that are just Complex numbers here
|
||||
@ -91,11 +103,11 @@ function compute(
|
||||
end
|
||||
|
||||
"""
|
||||
compute(::ComputeTaskQED_S1, data::QEDParticleValue)
|
||||
compute(::ComputeTaskQED_S1, data::ParticleValue)
|
||||
|
||||
Compute inner edge (1 input particle, 1 output particle).
|
||||
"""
|
||||
function compute(::ComputeTaskQED_S1, data::QEDParticleValue{P}) where {P<:QEDParticle}
|
||||
function compute(::ComputeTaskQED_S1, data::ParticleValue{P, V}) where {P <: ParticleStateful, V <: ValueType}
|
||||
newP = propagation_result(P)
|
||||
new_p = newP(momentum(data.p))
|
||||
# inner edge is just a scalar, can multiply from either side
|
160
src/models/physics_models/qed/create.jl
Normal file
160
src/models/physics_models/qed/create.jl
Normal file
@ -0,0 +1,160 @@
|
||||
|
||||
ComputeTaskQED_Sum() = ComputeTaskQED_Sum(0)
|
||||
|
||||
function _svector_from_type(processDescription::GenericQEDProcess, type, particles)
|
||||
if haskey(in_particles(processDescription), type)
|
||||
return SVector{in_particles(processDescription)[type], type}(filter(x -> typeof(x) <: type, particles))
|
||||
end
|
||||
if haskey(out_particles(processDescription), type)
|
||||
return SVector{out_particles(processDescription)[type], type}(filter(x -> typeof(x) <: type, particles))
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
gen_process_input(processDescription::GenericQEDProcess)
|
||||
|
||||
Return a ProcessInput of randomly generated [`QEDParticle`](@ref)s from a [`GenericQEDProcess`](@ref). The process description can be created manually or parsed from a string using [`parse_process`](@ref).
|
||||
|
||||
Note: This uses RAMBO to create a valid process with conservation of momentum and energy.
|
||||
"""
|
||||
function gen_process_input(processDescription::GenericQEDProcess)
|
||||
massSum = 0
|
||||
inputMasses = Vector{Float64}()
|
||||
for particle in incoming_particles(processDescription)
|
||||
massSum += mass(particle)
|
||||
push!(inputMasses, mass(particle))
|
||||
end
|
||||
outputMasses = Vector{Float64}()
|
||||
for particle in outgoing_particles(processDescription)
|
||||
massSum += mass(particle)
|
||||
push!(outputMasses, mass(particle))
|
||||
end
|
||||
|
||||
# add some extra random mass to allow for some momentum
|
||||
massSum += rand(rng[threadid()]) * (length(inputMasses) + length(outputMasses))
|
||||
|
||||
initial_momenta = generate_initial_moms(massSum, inputMasses)
|
||||
final_momenta = generate_physical_massive_moms(rng[threadid()], massSum, outputMasses)
|
||||
|
||||
processInput = PhaseSpacePoint(
|
||||
processDescription,
|
||||
PerturbativeQED(),
|
||||
PhasespaceDefinition(SphericalCoordinateSystem(), ElectronRestFrame()),
|
||||
tuple(initial_momenta...),
|
||||
tuple(final_momenta...),
|
||||
)
|
||||
|
||||
return processInput
|
||||
end
|
||||
|
||||
"""
|
||||
gen_graph(process_description::GenericQEDProcess)
|
||||
|
||||
For a given [`GenericQEDProcess`](@ref), return the [`DAG`](@ref) that computes it.
|
||||
"""
|
||||
function gen_graph(process_description::GenericQEDProcess)
|
||||
initial_diagram = FeynmanDiagram(process_description)
|
||||
diagrams = gen_diagrams(initial_diagram)
|
||||
|
||||
graph = DAG()
|
||||
|
||||
COMPLEX_SIZE = sizeof(ComplexF64)
|
||||
PARTICLE_VALUE_SIZE = 96.0
|
||||
|
||||
# TODO: Not all diagram outputs should always be summed at the end, if they differ by fermion exchange they need to be diffed
|
||||
# Should not matter for n-Photon Compton processes though
|
||||
sum_node = insert_node!(graph, make_node(ComputeTaskQED_Sum(0)); track = false, invalidate_cache = false)
|
||||
global_data_out = insert_node!(graph, make_node(DataTask(COMPLEX_SIZE)); track = false, invalidate_cache = false)
|
||||
insert_edge!(graph, sum_node, global_data_out; track = false, invalidate_cache = false)
|
||||
|
||||
# remember the data out nodes for connection
|
||||
dataOutNodes = Dict()
|
||||
|
||||
for particle in initial_diagram.particles
|
||||
# generate data in and U tasks
|
||||
data_in = insert_node!(
|
||||
graph,
|
||||
make_node(DataTask(PARTICLE_VALUE_SIZE), String(particle));
|
||||
track = false,
|
||||
invalidate_cache = false,
|
||||
) # read particle data node
|
||||
compute_u = insert_node!(graph, make_node(ComputeTaskQED_U()); track = false, invalidate_cache = false) # compute U node
|
||||
data_out =
|
||||
insert_node!(graph, make_node(DataTask(PARTICLE_VALUE_SIZE)); track = false, invalidate_cache = false) # transfer data out from u (one ABCParticleValue object)
|
||||
|
||||
insert_edge!(graph, data_in, compute_u; track = false, invalidate_cache = false)
|
||||
insert_edge!(graph, compute_u, data_out; track = false, invalidate_cache = false)
|
||||
|
||||
# remember the data_out node for future edges
|
||||
dataOutNodes[String(particle)] = data_out
|
||||
end
|
||||
|
||||
# TODO: this should be parallelizable somewhat easily
|
||||
for diagram in diagrams
|
||||
tie = diagram.tie[]
|
||||
|
||||
# handle the vertices
|
||||
for vertices in diagram.vertices
|
||||
for vertex in vertices
|
||||
data_in1 = dataOutNodes[String(vertex.in1)]
|
||||
data_in2 = dataOutNodes[String(vertex.in2)]
|
||||
|
||||
compute_V = insert_node!(graph, make_node(ComputeTaskQED_V()); track = false, invalidate_cache = false) # compute vertex
|
||||
|
||||
insert_edge!(graph, data_in1, compute_V; track = false, invalidate_cache = false)
|
||||
insert_edge!(graph, data_in2, compute_V; track = false, invalidate_cache = false)
|
||||
|
||||
data_V_out = insert_node!(
|
||||
graph,
|
||||
make_node(DataTask(PARTICLE_VALUE_SIZE));
|
||||
track = false,
|
||||
invalidate_cache = false,
|
||||
)
|
||||
|
||||
insert_edge!(graph, compute_V, data_V_out; track = false, invalidate_cache = false)
|
||||
|
||||
if (vertex.out == tie.in1 || vertex.out == tie.in2)
|
||||
# out particle is part of the tie -> there will be an S2 task with it later, don't make S1 task
|
||||
dataOutNodes[String(vertex.out)] = data_V_out
|
||||
continue
|
||||
end
|
||||
|
||||
# otherwise, add S1 task
|
||||
compute_S1 =
|
||||
insert_node!(graph, make_node(ComputeTaskQED_S1()); track = false, invalidate_cache = false) # compute propagator
|
||||
|
||||
insert_edge!(graph, data_V_out, compute_S1; track = false, invalidate_cache = false)
|
||||
|
||||
data_S1_out = insert_node!(
|
||||
graph,
|
||||
make_node(DataTask(PARTICLE_VALUE_SIZE));
|
||||
track = false,
|
||||
invalidate_cache = false,
|
||||
)
|
||||
|
||||
insert_edge!(graph, compute_S1, data_S1_out; track = false, invalidate_cache = false)
|
||||
|
||||
# overrides potentially different nodes from previous diagrams, which is intentional
|
||||
dataOutNodes[String(vertex.out)] = data_S1_out
|
||||
end
|
||||
end
|
||||
|
||||
# handle the tie
|
||||
data_in1 = dataOutNodes[String(tie.in1)]
|
||||
data_in2 = dataOutNodes[String(tie.in2)]
|
||||
|
||||
compute_S2 = insert_node!(graph, make_node(ComputeTaskQED_S2()); track = false, invalidate_cache = false)
|
||||
|
||||
data_S2 = insert_node!(graph, make_node(DataTask(PARTICLE_VALUE_SIZE)); track = false, invalidate_cache = false)
|
||||
|
||||
insert_edge!(graph, data_in1, compute_S2; track = false, invalidate_cache = false)
|
||||
insert_edge!(graph, data_in2, compute_S2; track = false, invalidate_cache = false)
|
||||
|
||||
insert_edge!(graph, compute_S2, data_S2; track = false, invalidate_cache = false)
|
||||
|
||||
insert_edge!(graph, data_S2, sum_node; track = false, invalidate_cache = false)
|
||||
add_child!(task(sum_node))
|
||||
end
|
||||
|
||||
return graph
|
||||
end
|
@ -8,10 +8,10 @@ import Base.show
|
||||
"""
|
||||
FeynmanParticle
|
||||
|
||||
Representation of a particle for use in [`FeynmanDiagram`](@ref)s. Consist of the [`QEDParticle`](@ref) type and an id.
|
||||
Representation of a particle for use in [`FeynmanDiagram`](@ref)s. Consist of the `ParticleStateful` type and an id.
|
||||
"""
|
||||
struct FeynmanParticle
|
||||
particle::Type{<:QEDParticle}
|
||||
particle::Type{<:ParticleStateful}
|
||||
id::Int
|
||||
end
|
||||
|
||||
@ -45,37 +45,27 @@ The [`FeynmanTie`](@ref) represents the final inner edge of the diagram.
|
||||
"""
|
||||
struct FeynmanDiagram
|
||||
vertices::Vector{Set{FeynmanVertex}}
|
||||
tie::Ref{Union{FeynmanTie,Missing}}
|
||||
tie::Ref{Union{FeynmanTie, Missing}}
|
||||
particles::Vector{FeynmanParticle}
|
||||
type_ids::Dict{Type,Int64} # lut for number of used ids for a particle type
|
||||
type_ids::Dict{Type, Int64} # lut for number of used ids for a particle type
|
||||
end
|
||||
|
||||
"""
|
||||
FeynmanDiagram(pd::QEDProcessDescription)
|
||||
FeynmanDiagram(pd::GenericQEDProcess)
|
||||
|
||||
Create an initial [`FeynmanDiagram`](@ref) with only its initial particles set and no vertices or ties.
|
||||
|
||||
Use [`gen_diagrams`](@ref) to generate all possible diagrams from this one.
|
||||
"""
|
||||
function FeynmanDiagram(pd::QEDProcessDescription)
|
||||
function FeynmanDiagram(pd::GenericQEDProcess)
|
||||
parts = Vector{FeynmanParticle}()
|
||||
for (type, n) in pd.inParticles
|
||||
for i in 1:n
|
||||
|
||||
ids = Dict{Type, Int64}()
|
||||
for type in types(model(pd))
|
||||
for i in 1:number_particles(pd, type)
|
||||
push!(parts, FeynmanParticle(type, i))
|
||||
end
|
||||
end
|
||||
for (type, n) in pd.outParticles
|
||||
for i in 1:n
|
||||
push!(parts, FeynmanParticle(type, i))
|
||||
end
|
||||
end
|
||||
ids = Dict{Type,Int64}()
|
||||
for t in types(QEDModel())
|
||||
if (isincoming(t))
|
||||
ids[t] = get(pd.inParticles, t, 0)
|
||||
else
|
||||
ids[t] = get(pd.outParticles, t, 0)
|
||||
end
|
||||
ids[type] = number_particles(pd, type)
|
||||
end
|
||||
|
||||
return FeynmanDiagram([], missing, parts, ids)
|
||||
@ -83,17 +73,13 @@ end
|
||||
|
||||
function particle_after_tie(p::FeynmanParticle, t::FeynmanTie)
|
||||
if p == t.in1 || p == t.in2
|
||||
return FeynmanParticle(FermionStateful{Incoming,SpinUp}, -1) # placeholder particle and id for tied particles
|
||||
return FeynmanParticle(ParticleStateful{Incoming, Electron, SFourMomentum}, -1) # placeholder particle and id for tied particles
|
||||
end
|
||||
return p
|
||||
end
|
||||
|
||||
function vertex_after_tie(v::FeynmanVertex, t::FeynmanTie)
|
||||
return FeynmanVertex(
|
||||
particle_after_tie(v.in1, t),
|
||||
particle_after_tie(v.in2, t),
|
||||
particle_after_tie(v.out, t),
|
||||
)
|
||||
return FeynmanVertex(particle_after_tie(v.in1, t), particle_after_tie(v.in2, t), particle_after_tie(v.out, t))
|
||||
end
|
||||
|
||||
function vertex_after_tie(v::FeynmanVertex, t::Missing)
|
||||
@ -108,9 +94,7 @@ function vertex_set_after_tie(vs::Set{FeynmanVertex}, t::Missing)
|
||||
return vs
|
||||
end
|
||||
|
||||
function vertex_set_after_tie(
|
||||
vs::Set{FeynmanVertex}, t1::Union{FeynmanTie,Missing}, t2::Union{FeynmanTie,Missing}
|
||||
)
|
||||
function vertex_set_after_tie(vs::Set{FeynmanVertex}, t1::Union{FeynmanTie, Missing}, t2::Union{FeynmanTie, Missing})
|
||||
return Set{FeynmanVertex}(vertex_after_tie(vertex_after_tie(v, t1), t2) for v in vs)
|
||||
end
|
||||
|
||||
@ -120,7 +104,7 @@ end
|
||||
Return a string representation of the [`FeynmanParticle`](@ref) in a format that is readable by [`type_index_from_name`](@ref).
|
||||
"""
|
||||
function String(p::FeynmanParticle)
|
||||
return "$(String(p.particle))$(String(direction(p.particle)))$(p.id)"
|
||||
return "$(String(p.particle))$(String(particle_direction(p.particle)))$(p.id)"
|
||||
end
|
||||
|
||||
function hash(v::FeynmanVertex)
|
||||
@ -144,8 +128,7 @@ function ==(t1::FeynmanTie, t2::FeynmanTie)
|
||||
end
|
||||
|
||||
function ==(d1::FeynmanDiagram, d2::FeynmanDiagram)
|
||||
if (!ismissing(d1.tie[]) && ismissing(d2.tie[])) ||
|
||||
(ismissing(d1.tie[]) && !ismissing(d2.tie[]))
|
||||
if (!ismissing(d1.tie[]) && ismissing(d2.tie[])) || (ismissing(d1.tie[]) && !ismissing(d2.tie[]))
|
||||
return false
|
||||
end
|
||||
if d1.particles != d2.particles
|
||||
@ -157,8 +140,7 @@ function ==(d1::FeynmanDiagram, d2::FeynmanDiagram)
|
||||
|
||||
# TODO can i prove that this works?
|
||||
for (v1, v2) in zip(d1.vertices, d2.vertices)
|
||||
if vertex_set_after_tie(v1, d1.tie[], d2.tie[]) !=
|
||||
vertex_set_after_tie(v2, d1.tie[], d2.tie[])
|
||||
if vertex_set_after_tie(v1, d1.tie[], d2.tie[]) != vertex_set_after_tie(v2, d1.tie[], d2.tie[])
|
||||
return false
|
||||
end
|
||||
end
|
||||
@ -171,17 +153,15 @@ function ==(d1::FeynmanDiagram, d2::FeynmanDiagram)
|
||||
end
|
||||
|
||||
function copy(fd::FeynmanDiagram)
|
||||
return FeynmanDiagram(
|
||||
deepcopy(fd.vertices), copy(fd.tie[]), deepcopy(fd.particles), copy(fd.type_ids)
|
||||
)
|
||||
return FeynmanDiagram(deepcopy(fd.vertices), copy(fd.tie[]), deepcopy(fd.particles), copy(fd.type_ids))
|
||||
end
|
||||
|
||||
"""
|
||||
id_for_type(d::FeynmanDiagram, t::Type{<:QEDParticle})
|
||||
id_for_type(d::FeynmanDiagram, t::Type{<:ParticleStateful})
|
||||
|
||||
Return the highest id of any particle of the given type in the diagram + 1.
|
||||
"""
|
||||
function id_for_type(d::FeynmanDiagram, t::Type{<:QEDParticle})
|
||||
function id_for_type(d::FeynmanDiagram, t::Type{<:ParticleStateful})
|
||||
return d.type_ids[t] + 1
|
||||
end
|
||||
|
||||
@ -240,7 +220,7 @@ end
|
||||
|
||||
Return a vector of the particles after applying the vertices and tie of the diagram up to the given level. If no level is given, apply all. The tie comes last and is its own "level".
|
||||
"""
|
||||
function get_particles(fd::FeynmanDiagram, level::Int=-1)
|
||||
function get_particles(fd::FeynmanDiagram, level::Int = -1)
|
||||
if level == -1
|
||||
level = length(fd.vertices) + 1
|
||||
end
|
||||
@ -376,14 +356,8 @@ function possible_vertices(fd::FeynmanDiagram)
|
||||
p1 = particles[i]
|
||||
p2 = particles[j]
|
||||
if (caninteract(p1.particle, p2.particle))
|
||||
interaction_res = propagation_result(
|
||||
interaction_result(p1.particle, p2.particle)
|
||||
)
|
||||
v = FeynmanVertex(
|
||||
p1,
|
||||
p2,
|
||||
FeynmanParticle(interaction_res, id_for_type(fd, interaction_res)),
|
||||
)
|
||||
interaction_res = propagation_result(interaction_result(p1.particle, p2.particle))
|
||||
v = FeynmanVertex(p1, p2, FeynmanParticle(interaction_res, id_for_type(fd, interaction_res)))
|
||||
#@assert !(v.out in particles) "$v is in $fd"
|
||||
if !can_apply_vertex(fully_generated_particles, v)
|
||||
continue
|
||||
@ -456,18 +430,19 @@ function remove_duplicates(compare_set::Set{FeynmanDiagram})
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
is_compton(fd::FeynmanDiagram)
|
||||
|
||||
Returns true iff the given feynman diagram is an (empty) diagram of a compton process like ke->k^ne
|
||||
"""
|
||||
function is_compton(fd::FeynmanDiagram)
|
||||
return fd.type_ids[FermionStateful{Incoming}] == 1 &&
|
||||
fd.type_ids[FermionStateful{Outgoing}] == 1 &&
|
||||
fd.type_ids[AntiFermionStateful{Incoming}] == 0 &&
|
||||
fd.type_ids[AntiFermionStateful{Outgoing}] == 0 &&
|
||||
fd.type_ids[PhotonStateful{Incoming}] >= 1 &&
|
||||
fd.type_ids[PhotonStateful{Outgoing}] >= 1
|
||||
return fd.type_ids[ParticleStateful{Incoming, Electron, SFourMomentum}] == 1 &&
|
||||
fd.type_ids[ParticleStateful{Outgoing, Electron, SFourMomentum}] == 1 &&
|
||||
fd.type_ids[ParticleStateful{Incoming, Positron, SFourMomentum}] == 0 &&
|
||||
fd.type_ids[ParticleStateful{Outgoing, Positron, SFourMomentum}] == 0 &&
|
||||
fd.type_ids[ParticleStateful{Incoming, Photon, SFourMomentum}] >= 1 &&
|
||||
fd.type_ids[ParticleStateful{Outgoing, Photon, SFourMomentum}] >= 1
|
||||
end
|
||||
|
||||
"""
|
||||
@ -477,19 +452,19 @@ Helper function for [`gen_compton_diagrams`](@Ref). Generates a single diagram f
|
||||
"""
|
||||
function gen_compton_diagram_from_order(order::Vector{Int}, inFerm, outFerm, n::Int, m::Int)
|
||||
photons = vcat(
|
||||
[FeynmanParticle(PhotonStateful{Incoming,PolX}, i) for i in 1:n],
|
||||
[FeynmanParticle(PhotonStateful{Outgoing,PolX}, i) for i in 1:m],
|
||||
[FeynmanParticle(ParticleStateful{Incoming, Photon, SFourMomentum}, i) for i in 1:n],
|
||||
[FeynmanParticle(ParticleStateful{Outgoing, Photon, SFourMomentum}, i) for i in 1:m],
|
||||
)
|
||||
|
||||
new_diagram = FeynmanDiagram(
|
||||
[],
|
||||
missing,
|
||||
[inFerm, outFerm, photons...],
|
||||
Dict{Type,Int64}(
|
||||
FermionStateful{Incoming,SpinUp} => 1,
|
||||
FermionStateful{Outgoing,SpinUp} => 1,
|
||||
PhotonStateful{Incoming,PolX} => n,
|
||||
PhotonStateful{Outgoing,PolX} => m,
|
||||
Dict{Type, Int64}(
|
||||
ParticleStateful{Incoming, Electron, SFourMomentum} => 1,
|
||||
ParticleStateful{Outgoing, Electron, SFourMomentum} => 1,
|
||||
ParticleStateful{Incoming, Photon, SFourMomentum} => n,
|
||||
ParticleStateful{Outgoing, Photon, SFourMomentum} => m,
|
||||
),
|
||||
)
|
||||
|
||||
@ -501,9 +476,9 @@ function gen_compton_diagram_from_order(order::Vector{Int}, inFerm, outFerm, n::
|
||||
while left_index <= right_index
|
||||
# left side
|
||||
v_left = FeynmanVertex(
|
||||
FeynmanParticle(FermionStateful{Incoming,SpinUp}, iterations),
|
||||
FeynmanParticle(ParticleStateful{Incoming, Electron, SFourMomentum}, iterations),
|
||||
photons[order[left_index]],
|
||||
FeynmanParticle(FermionStateful{Incoming,SpinUp}, iterations + 1),
|
||||
FeynmanParticle(ParticleStateful{Incoming, Electron, SFourMomentum}, iterations + 1),
|
||||
)
|
||||
left_index += 1
|
||||
add_vertex!(new_diagram, v_left)
|
||||
@ -514,9 +489,9 @@ function gen_compton_diagram_from_order(order::Vector{Int}, inFerm, outFerm, n::
|
||||
|
||||
# right side
|
||||
v_right = FeynmanVertex(
|
||||
FeynmanParticle(FermionStateful{Outgoing,SpinUp}, iterations),
|
||||
FeynmanParticle(ParticleStateful{Outgoing, Electron, SFourMomentum}, iterations),
|
||||
photons[order[right_index]],
|
||||
FeynmanParticle(FermionStateful{Outgoing,SpinUp}, iterations + 1),
|
||||
FeynmanParticle(ParticleStateful{Outgoing, Electron, SFourMomentum}, iterations + 1),
|
||||
)
|
||||
right_index -= 1
|
||||
add_vertex!(new_diagram, v_right)
|
||||
@ -529,6 +504,7 @@ function gen_compton_diagram_from_order(order::Vector{Int}, inFerm, outFerm, n::
|
||||
return new_diagram
|
||||
end
|
||||
|
||||
#=
|
||||
"""
|
||||
gen_compton_diagram_from_order_one_side(order::Vector{Int}, inFerm, outFerm, n::Int, m::Int)
|
||||
|
||||
@ -538,19 +514,19 @@ function gen_compton_diagram_from_order_one_side(
|
||||
order::Vector{Int}, inFerm, outFerm, n::Int, m::Int
|
||||
)
|
||||
photons = vcat(
|
||||
[FeynmanParticle(PhotonStateful{Incoming,PolX}, i) for i in 1:n],
|
||||
[FeynmanParticle(PhotonStateful{Outgoing,PolX}, i) for i in 1:m],
|
||||
[FeynmanParticle(ParticleStateful{Incoming, Photon}, i) for i in 1:n],
|
||||
[FeynmanParticle(ParticleStateful{Outgoing, Photon}, i) for i in 1:m],
|
||||
)
|
||||
|
||||
new_diagram = FeynmanDiagram(
|
||||
[],
|
||||
missing,
|
||||
[inFerm, outFerm, photons...],
|
||||
Dict{Type,Int64}(
|
||||
FermionStateful{Incoming,SpinUp} => 1,
|
||||
FermionStateful{Outgoing,SpinUp} => 1,
|
||||
PhotonStateful{Incoming,PolX} => n,
|
||||
PhotonStateful{Outgoing,PolX} => m,
|
||||
Dict{Type, Int64}(
|
||||
ParticleStateful{Incoming, Electron} => 1,
|
||||
ParticleStateful{Outgoing, Electron} => 1,
|
||||
ParticleStateful{Incoming, Photon} => n,
|
||||
ParticleStateful{Outgoing, Photon} => m,
|
||||
),
|
||||
)
|
||||
|
||||
@ -562,9 +538,9 @@ function gen_compton_diagram_from_order_one_side(
|
||||
while left_index <= right_index
|
||||
# left side
|
||||
v_left = FeynmanVertex(
|
||||
FeynmanParticle(FermionStateful{Incoming,SpinUp}, iterations),
|
||||
FeynmanParticle(ParticleStateful{Incoming, Electron}, iterations),
|
||||
photons[order[left_index]],
|
||||
FeynmanParticle(FermionStateful{Incoming,SpinUp}, iterations + 1),
|
||||
FeynmanParticle(ParticleStateful{Incoming, Electron}, iterations + 1),
|
||||
)
|
||||
left_index += 1
|
||||
add_vertex!(new_diagram, v_left)
|
||||
@ -577,9 +553,9 @@ function gen_compton_diagram_from_order_one_side(
|
||||
if (iterations == 1)
|
||||
# right side
|
||||
v_right = FeynmanVertex(
|
||||
FeynmanParticle(FermionStateful{Outgoing,SpinUp}, iterations),
|
||||
FeynmanParticle(ParticleStateful{Outgoing, Electron}, iterations),
|
||||
photons[order[right_index]],
|
||||
FeynmanParticle(FermionStateful{Outgoing,SpinUp}, iterations + 1),
|
||||
FeynmanParticle(ParticleStateful{Outgoing, Electron}, iterations + 1),
|
||||
)
|
||||
right_index -= 1
|
||||
add_vertex!(new_diagram, v_right)
|
||||
@ -593,6 +569,7 @@ function gen_compton_diagram_from_order_one_side(
|
||||
add_tie!(new_diagram, FeynmanTie(ps[1], ps[2]))
|
||||
return new_diagram
|
||||
end
|
||||
=#
|
||||
|
||||
"""
|
||||
gen_compton_diagrams(n::Int, m::Int)
|
||||
@ -600,17 +577,14 @@ end
|
||||
Special case diagram generation for Compton processes, i.e., processes of the form k^ne->k^me
|
||||
"""
|
||||
function gen_compton_diagrams(n::Int, m::Int)
|
||||
inFerm = FeynmanParticle(FermionStateful{Incoming,SpinUp}, 1)
|
||||
outFerm = FeynmanParticle(FermionStateful{Outgoing,SpinUp}, 1)
|
||||
inFerm = FeynmanParticle(ParticleStateful{Incoming, Electron, SFourMomentum}, 1)
|
||||
outFerm = FeynmanParticle(ParticleStateful{Outgoing, Electron, SFourMomentum}, 1)
|
||||
|
||||
perms = [permutations([i for i in 1:(n + m)])...]
|
||||
|
||||
diagrams = [Vector{FeynmanDiagram}() for i in 1:nthreads()]
|
||||
@threads for order in perms
|
||||
push!(
|
||||
diagrams[threadid()],
|
||||
gen_compton_diagram_from_order(order, inFerm, outFerm, n, m),
|
||||
)
|
||||
push!(diagrams[threadid()], gen_compton_diagram_from_order(order, inFerm, outFerm, n, m))
|
||||
end
|
||||
|
||||
return vcat(diagrams...)
|
||||
@ -622,17 +596,14 @@ end
|
||||
Special case diagram generation for Compton processes, i.e., processes of the form k^ne->k^me, but generating from one end, yielding larger diagrams
|
||||
"""
|
||||
function gen_compton_diagrams_one_side(n::Int, m::Int)
|
||||
inFerm = FeynmanParticle(FermionStateful{Incoming,SpinUp}, 1)
|
||||
outFerm = FeynmanParticle(FermionStateful{Outgoing,SpinUp}, 1)
|
||||
inFerm = FeynmanParticle(ParticleStateful{Incoming, Electron, SFourMomentum}, 1)
|
||||
outFerm = FeynmanParticle(ParticleStateful{Outgoing, Electron, SFourMomentum}, 1)
|
||||
|
||||
perms = [permutations([i for i in 1:(n + m)])...]
|
||||
|
||||
diagrams = [Vector{FeynmanDiagram}() for i in 1:nthreads()]
|
||||
@threads for order in perms
|
||||
push!(
|
||||
diagrams[threadid()],
|
||||
gen_compton_diagram_from_order_one_side(order, inFerm, outFerm, n, m),
|
||||
)
|
||||
push!(diagrams[threadid()], gen_compton_diagram_from_order_one_side(order, inFerm, outFerm, n, m))
|
||||
end
|
||||
|
||||
return vcat(diagrams...)
|
||||
@ -645,11 +616,15 @@ From a given feynman diagram in its initial state, e.g. when created through the
|
||||
"""
|
||||
function gen_diagrams(fd::FeynmanDiagram)
|
||||
if is_compton(fd)
|
||||
return gen_compton_diagrams_one_side(
|
||||
fd.type_ids[PhotonStateful{Incoming}], fd.type_ids[PhotonStateful{Outgoing}]
|
||||
return gen_compton_diagrams(
|
||||
fd.type_ids[ParticleStateful{Incoming, Photon, SFourMomentum}],
|
||||
fd.type_ids[ParticleStateful{Outgoing, Photon, SFourMomentum}],
|
||||
)
|
||||
end
|
||||
|
||||
throw(error("Unimplemented for non-compton!"))
|
||||
|
||||
#=
|
||||
working = Set{FeynmanDiagram}()
|
||||
results = Set{FeynmanDiagram}()
|
||||
|
||||
@ -688,4 +663,5 @@ function gen_diagrams(fd::FeynmanDiagram)
|
||||
end
|
||||
|
||||
return remove_duplicates(results)
|
||||
=#
|
||||
end
|
69
src/models/physics_models/qed/parse.jl
Normal file
69
src/models/physics_models/qed/parse.jl
Normal file
@ -0,0 +1,69 @@
|
||||
|
||||
# TODO generalize this somehow, probably using AllSpin/AllPol as defaults
|
||||
"""
|
||||
parse_process(string::AbstractString, model::QEDModel)
|
||||
|
||||
Parse a string representation of a process, such as "ke->ke" into the corresponding [`QEDProcessDescription`](@ref).
|
||||
"""
|
||||
function parse_process(
|
||||
str::AbstractString,
|
||||
model::QEDModel,
|
||||
inphpol::AbstractDefinitePolarization,
|
||||
inelspin::AbstractDefiniteSpin,
|
||||
outphpol::AbstractDefinitePolarization,
|
||||
outelspin::AbstractDefiniteSpin,
|
||||
)
|
||||
inParticles = Dict(
|
||||
ParticleStateful{Incoming, Photon, SFourMomentum} => 0,
|
||||
ParticleStateful{Incoming, Electron, SFourMomentum} => 0,
|
||||
ParticleStateful{Incoming, Positron, SFourMomentum} => 0,
|
||||
)
|
||||
outParticles = Dict(
|
||||
ParticleStateful{Outgoing, Photon, SFourMomentum} => 0,
|
||||
ParticleStateful{Outgoing, Electron, SFourMomentum} => 0,
|
||||
ParticleStateful{Outgoing, Positron, SFourMomentum} => 0,
|
||||
)
|
||||
|
||||
if !(contains(str, "->"))
|
||||
throw("Did not find -> while parsing process \"$str\"")
|
||||
end
|
||||
|
||||
(inStr, outStr) = split(str, "->")
|
||||
|
||||
if (isempty(inStr) || isempty(outStr))
|
||||
throw("Process (\"$str\") input or output part is empty!")
|
||||
end
|
||||
|
||||
for t in types(model)
|
||||
if (is_incoming(t))
|
||||
inCount = count(x -> x == String(t)[1], inStr)
|
||||
|
||||
if inCount != 0
|
||||
inParticles[t] = inCount
|
||||
end
|
||||
end
|
||||
if (is_outgoing(t))
|
||||
outCount = count(x -> x == String(t)[1], outStr)
|
||||
if outCount != 0
|
||||
outParticles[t] = outCount
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if length(inStr) != sum(values(inParticles))
|
||||
throw("Encountered unknown characters in the input part of process \"$str\"")
|
||||
elseif length(outStr) != sum(values(outParticles))
|
||||
throw("Encountered unknown characters in the output part of process \"$str\"")
|
||||
end
|
||||
|
||||
in_ph = inParticles[ParticleStateful{Incoming, Photon, SFourMomentum}]
|
||||
in_el = inParticles[ParticleStateful{Incoming, Electron, SFourMomentum}]
|
||||
in_pos = inParticles[ParticleStateful{Incoming, Positron, SFourMomentum}]
|
||||
out_ph = outParticles[ParticleStateful{Outgoing, Photon, SFourMomentum}]
|
||||
out_el = outParticles[ParticleStateful{Outgoing, Electron, SFourMomentum}]
|
||||
out_pos = outParticles[ParticleStateful{Outgoing, Positron, SFourMomentum}]
|
||||
in_spin_pols = tuple([i <= in_ph ? inphpol : inelspin for i in 1:(in_ph + in_el)]...)
|
||||
out_spin_pols = tuple([i <= out_ph ? outphpol : outelspin for i in 1:(out_ph + out_el)]...)
|
||||
|
||||
return GenericQEDProcess(in_ph, out_ph, in_el, out_el, in_pos, out_pos, in_spin_pols, out_spin_pols)
|
||||
end
|
377
src/models/physics_models/qed/particle.jl
Normal file
377
src/models/physics_models/qed/particle.jl
Normal file
@ -0,0 +1,377 @@
|
||||
using QEDprocesses
|
||||
using StaticArrays
|
||||
|
||||
const e = sqrt(4π / 137)
|
||||
|
||||
"""
|
||||
QEDModel <: AbstractPhysicsModel
|
||||
|
||||
Singleton definition for identification of the QED-Model.
|
||||
"""
|
||||
struct QEDModel <: AbstractPhysicsModel end
|
||||
|
||||
QEDbase.is_incoming(::Type{<:ParticleStateful{Incoming}}) = true
|
||||
QEDbase.is_outgoing(::Type{<:ParticleStateful{Outgoing}}) = true
|
||||
QEDbase.is_incoming(::Type{<:ParticleStateful{Outgoing}}) = false
|
||||
QEDbase.is_outgoing(::Type{<:ParticleStateful{Incoming}}) = false
|
||||
|
||||
QEDbase.particle_direction(::Type{<:ParticleStateful{DIR}}) where {DIR <: ParticleDirection} = DIR()
|
||||
QEDbase.particle_species(
|
||||
::Type{<:ParticleStateful{DIR, SPECIES}},
|
||||
) where {DIR <: ParticleDirection, SPECIES <: AbstractParticleType} = SPECIES()
|
||||
|
||||
_assert_particle_type_tuple(::Tuple{}) = nothing
|
||||
_assert_particle_type_tuple(t::Tuple{AbstractParticleType, Vararg}) = _assert_particle_type_tuple(t[2:end])
|
||||
_assert_particle_type_tuple(t::Any) =
|
||||
throw(InvalidInputError("invalid input, provide a tuple of AbstractParticleTypes to construct a GenericQEDProcess"))
|
||||
|
||||
struct GenericQEDProcess{INT, OUTT, INSP, OUTSP} <:
|
||||
AbstractProcessDefinition where {INT <: Tuple, OUTT <: Tuple, INSP <: Tuple, OUTSP <: Tuple}
|
||||
incoming_particles::INT
|
||||
outgoing_particles::OUTT
|
||||
|
||||
incoming_spins_pols::INSP
|
||||
outgoing_spins_pols::OUTSP
|
||||
|
||||
function GenericQEDProcess(
|
||||
in_particles::INT,
|
||||
out_particles::OUTT,
|
||||
in_sp::INSP,
|
||||
out_sp::OUTSP,
|
||||
) where {INT <: Tuple, OUTT <: Tuple, INSP <: Tuple, OUTSP <: Tuple}
|
||||
_assert_particle_type_tuple(in_particles)
|
||||
_assert_particle_type_tuple(out_particles)
|
||||
|
||||
# TODO: check in_sp/out_sp fits to particles (spin->fermion, pol->photon)
|
||||
|
||||
return new{INT, OUTT, INSP, OUTSP}(in_particles, out_particles, in_sp, out_sp)
|
||||
end
|
||||
|
||||
"""
|
||||
GenericQEDProcess{INSP, OUTSP}(in_ph::Int, out_ph::Int, in_el::Int, out_el::Int, in_po::Int, out_po::Int, in_sp::INSP, out_sp::OUTSP)
|
||||
|
||||
Convenience constructor from numbers of input/output photons, electrons and positrons.
|
||||
|
||||
`in_sp` and `out_sp` are tuples of the spin and polarization configurations of the given particles. Their order is Photons, then Electrons, then Positrons for both incoming and outgoing particles.
|
||||
|
||||
# TODO: make default for in_sp and out_sp available for convenience
|
||||
"""
|
||||
function GenericQEDProcess(
|
||||
in_ph::Int,
|
||||
out_ph::Int,
|
||||
in_el::Int,
|
||||
out_el::Int,
|
||||
in_po::Int,
|
||||
out_po::Int,
|
||||
in_sp::INSP,
|
||||
out_sp::OUTSP,
|
||||
) where {INSP <: Tuple, OUTSP <: Tuple}
|
||||
in_p = ntuple(i -> i <= in_ph ? Photon() : i <= in_ph + in_el ? Electron() : Positron(), in_ph + in_el + in_po)
|
||||
out_p = ntuple(
|
||||
i -> i <= out_ph ? Photon() : i <= out_ph + out_el ? Electron() : Positron(),
|
||||
out_ph + out_el + out_po,
|
||||
)
|
||||
return GenericQEDProcess(in_p, out_p, in_sp, out_sp)
|
||||
end
|
||||
end
|
||||
|
||||
function spin_or_pol(
|
||||
process::GenericQEDProcess,
|
||||
type::Type{ParticleStateful{DIR, SPECIES, EL}},
|
||||
n::Int,
|
||||
) where {DIR <: ParticleDirection, SPECIES <: AbstractParticleType, EL <: AbstractFourMomentum}
|
||||
i = 0
|
||||
c = n
|
||||
for p in particles(process, DIR())
|
||||
i += 1
|
||||
if p == SPECIES()
|
||||
c -= 1
|
||||
end
|
||||
if c == 0
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if c != 0 || n <= 0
|
||||
throw(InvalidInputError("could not get $n-th spin/pol of $(DIR()) $species, does not exist"))
|
||||
end
|
||||
|
||||
if DIR <: Incoming
|
||||
return process.incoming_spins_pols[i]
|
||||
elseif DIR <: Outgoing
|
||||
return process.outgoing_spins_pols[i]
|
||||
else
|
||||
throw(InvalidInputError("unknown direction $(DIR()) given"))
|
||||
end
|
||||
end
|
||||
|
||||
QEDprocesses.incoming_particles(proc::GenericQEDProcess) = proc.incoming_particles
|
||||
QEDprocesses.outgoing_particles(proc::GenericQEDProcess) = proc.outgoing_particles
|
||||
|
||||
function isphysical(proc::GenericQEDProcess)
|
||||
return (
|
||||
number_particles(proc, Incoming(), Electron()) + number_particles(proc, Outgoing(), Positron()) ==
|
||||
number_particles(proc, Incoming(), Positron()) + number_particles(proc, Outgoing(), Electron())
|
||||
) && number_particles(proc, Incoming()) + number_particles(proc, Outgoing()) >= 2
|
||||
end
|
||||
|
||||
function input_type(p::GenericQEDProcess)
|
||||
in_t = QEDcore._assemble_tuple_type(incoming_particles(p), Incoming(), SFourMomentum)
|
||||
out_t = QEDcore._assemble_tuple_type(outgoing_particles(p), Outgoing(), SFourMomentum)
|
||||
return PhaseSpacePoint{
|
||||
typeof(p),
|
||||
PerturbativeQED,
|
||||
PhasespaceDefinition{SphericalCoordinateSystem, ElectronRestFrame},
|
||||
Tuple{in_t...},
|
||||
Tuple{out_t...},
|
||||
}
|
||||
end
|
||||
|
||||
ValueType = Union{BiSpinor, AdjointBiSpinor, DiracMatrix, SLorentzVector{Float64}, ComplexF64}
|
||||
|
||||
"""
|
||||
interaction_result(t1::Type{T1}, t2::Type{T2}) where {T1 <: QEDParticle, T2 <: QEDParticle}
|
||||
|
||||
For two given particle types that can interact, return the third.
|
||||
"""
|
||||
function interaction_result(t1::Type{T1}, t2::Type{T2}) where {T1 <: ParticleStateful, T2 <: ParticleStateful}
|
||||
@assert false "Invalid interaction between particles of types $t1 and $t2"
|
||||
end
|
||||
|
||||
interaction_result(
|
||||
::Type{ParticleStateful{Incoming, Electron, EL}},
|
||||
::Type{ParticleStateful{Outgoing, Electron, EL}},
|
||||
) where {EL <: AbstractFourMomentum} = ParticleStateful{Incoming, Photon, EL}
|
||||
interaction_result(
|
||||
::Type{ParticleStateful{Incoming, Electron, EL}},
|
||||
::Type{ParticleStateful{Incoming, Positron, EL}},
|
||||
) where {EL <: AbstractFourMomentum} = ParticleStateful{Incoming, Photon, EL}
|
||||
interaction_result(
|
||||
::Type{ParticleStateful{Incoming, Electron, EL}},
|
||||
::Type{ParticleStateful{DIR, Photon, EL}},
|
||||
) where {EL <: AbstractFourMomentum, DIR <: ParticleDirection} = ParticleStateful{Outgoing, Electron, EL}
|
||||
|
||||
interaction_result(
|
||||
::Type{ParticleStateful{Outgoing, Electron, EL}},
|
||||
::Type{ParticleStateful{Incoming, Electron, EL}},
|
||||
) where {EL <: AbstractFourMomentum} = ParticleStateful{Incoming, Photon, EL}
|
||||
interaction_result(
|
||||
::Type{ParticleStateful{Outgoing, Electron, EL}},
|
||||
::Type{ParticleStateful{Outgoing, Positron, EL}},
|
||||
) where {EL <: AbstractFourMomentum} = ParticleStateful{Incoming, Photon, EL}
|
||||
interaction_result(
|
||||
::Type{ParticleStateful{Outgoing, Electron, EL}},
|
||||
::Type{ParticleStateful{DIR, Photon, EL}},
|
||||
) where {EL <: AbstractFourMomentum, DIR <: ParticleDirection} = ParticleStateful{Incoming, Electron, EL}
|
||||
|
||||
# antifermion mirror
|
||||
interaction_result(
|
||||
::Type{ParticleStateful{Incoming, Positron, EL}},
|
||||
t2::Type{<:ParticleStateful},
|
||||
) where {EL <: AbstractFourMomentum} = interaction_result(ParticleStateful{Outgoing, Electron, EL}, t2)
|
||||
interaction_result(
|
||||
::Type{ParticleStateful{Outgoing, Positron, EL}},
|
||||
t2::Type{<:ParticleStateful},
|
||||
) where {EL <: AbstractFourMomentum} = interaction_result(ParticleStateful{Incoming, Electron, EL}, t2)
|
||||
|
||||
# photon commutativity
|
||||
interaction_result(
|
||||
t1::Type{ParticleStateful{DIR, Photon, EL}},
|
||||
t2::Type{<:ParticleStateful},
|
||||
) where {EL <: AbstractFourMomentum, DIR <: ParticleDirection} = interaction_result(t2, t1)
|
||||
|
||||
# but prevent stack overflow
|
||||
function interaction_result(
|
||||
t1::Type{ParticleStateful{DIR1, Photon, EL}},
|
||||
t2::Type{ParticleStateful{DIR2, Photon, EL}},
|
||||
) where {DIR1 <: ParticleDirection, DIR2 <: ParticleDirection, EL <: AbstractFourMomentum}
|
||||
@assert false "Invalid interaction between particles of types $t1 and $t2"
|
||||
end
|
||||
|
||||
"""
|
||||
propagation_result(t1::Type{T}) where {T <: QEDParticle}
|
||||
|
||||
Return the type of the inverted direction. E.g.
|
||||
"""
|
||||
propagation_result(::Type{ParticleStateful{Incoming, Electron, EL}}) where {EL <: AbstractFourMomentum} =
|
||||
ParticleStateful{Outgoing, Electron, EL}
|
||||
propagation_result(::Type{ParticleStateful{Outgoing, Electron, EL}}) where {EL <: AbstractFourMomentum} =
|
||||
ParticleStateful{Incoming, Electron, EL}
|
||||
propagation_result(::Type{ParticleStateful{Incoming, Positron, EL}}) where {EL <: AbstractFourMomentum} =
|
||||
ParticleStateful{Outgoing, Positron, EL}
|
||||
propagation_result(::Type{ParticleStateful{Outgoing, Positron, EL}}) where {EL <: AbstractFourMomentum} =
|
||||
ParticleStateful{Incoming, Positron, EL}
|
||||
propagation_result(::Type{ParticleStateful{Incoming, Photon, EL}}) where {EL <: AbstractFourMomentum} =
|
||||
ParticleStateful{Outgoing, Photon, EL}
|
||||
propagation_result(::Type{ParticleStateful{Outgoing, Photon, EL}}) where {EL <: AbstractFourMomentum} =
|
||||
ParticleStateful{Incoming, Photon, EL}
|
||||
|
||||
"""
|
||||
types(::QEDModel)
|
||||
|
||||
Return a Vector of the possible types of particle in the [`QEDModel`](@ref).
|
||||
"""
|
||||
function types(::QEDModel)
|
||||
return [
|
||||
ParticleStateful{Incoming, Photon, SFourMomentum},
|
||||
ParticleStateful{Outgoing, Photon, SFourMomentum},
|
||||
ParticleStateful{Incoming, Electron, SFourMomentum},
|
||||
ParticleStateful{Outgoing, Electron, SFourMomentum},
|
||||
ParticleStateful{Incoming, Positron, SFourMomentum},
|
||||
ParticleStateful{Outgoing, Positron, SFourMomentum},
|
||||
]
|
||||
end
|
||||
|
||||
# type piracy?
|
||||
String(::Type{Incoming}) = "Incoming"
|
||||
String(::Type{Outgoing}) = "Outgoing"
|
||||
|
||||
String(::Type{PolX}) = "polx"
|
||||
String(::Type{PolY}) = "poly"
|
||||
|
||||
String(::Type{SpinUp}) = "spinup"
|
||||
String(::Type{SpinDown}) = "spindown"
|
||||
|
||||
String(::Incoming) = "i"
|
||||
String(::Outgoing) = "o"
|
||||
|
||||
function String(::Type{<:ParticleStateful{DIR, Photon}}) where {DIR <: ParticleDirection}
|
||||
return "k"
|
||||
end
|
||||
function String(::Type{<:ParticleStateful{DIR, Electron}}) where {DIR <: ParticleDirection}
|
||||
return "e"
|
||||
end
|
||||
function String(::Type{<:ParticleStateful{DIR, Positron}}) where {DIR <: ParticleDirection}
|
||||
return "p"
|
||||
end
|
||||
|
||||
"""
|
||||
caninteract(T1::Type{<:ParticleStateful}, T2::Type{<:ParticleStateful})
|
||||
|
||||
For two given `ParticleStateful` types, return whether they can interact at a vertex. This is equivalent to `!issame(T1, T2)`.
|
||||
|
||||
See also: [`issame`](@ref) and [`interaction_result`](@ref)
|
||||
"""
|
||||
function caninteract(
|
||||
T1::Type{<:ParticleStateful{D1, S1}},
|
||||
T2::Type{<:ParticleStateful{D2, S2}},
|
||||
) where {D1 <: ParticleDirection, S1 <: AbstractParticleType, D2 <: ParticleDirection, S2 <: AbstractParticleType}
|
||||
if (T1 == T2)
|
||||
return false
|
||||
end
|
||||
if (S1 == Photon && S2 == Photon)
|
||||
return false
|
||||
end
|
||||
|
||||
for (P1, P2) in [(T1, T2), (T2, T1)]
|
||||
if (P1 <: ParticleStateful{Incoming, Electron} && P2 <: ParticleStateful{Outgoing, Positron})
|
||||
return false
|
||||
end
|
||||
if (P1 <: ParticleStateful{Outgoing, Electron} && P2 <: ParticleStateful{Incoming, Positron})
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function type_index_from_name(::QEDModel, name::String)
|
||||
if startswith(name, "ki")
|
||||
return (ParticleStateful{Incoming, Photon, SFourMomentum}, parse(Int, name[3:end]))
|
||||
elseif startswith(name, "ko")
|
||||
return (ParticleStateful{Outgoing, Photon, SFourMomentum}, parse(Int, name[3:end]))
|
||||
elseif startswith(name, "ei")
|
||||
return (ParticleStateful{Incoming, Electron, SFourMomentum}, parse(Int, name[3:end]))
|
||||
elseif startswith(name, "eo")
|
||||
return (ParticleStateful{Outgoing, Electron, SFourMomentum}, parse(Int, name[3:end]))
|
||||
elseif startswith(name, "pi")
|
||||
return (ParticleStateful{Incoming, Positron, SFourMomentum}, parse(Int, name[3:end]))
|
||||
elseif startswith(name, "po")
|
||||
return (ParticleStateful{Outgoing, Positron, SFourMomentum}, parse(Int, name[3:end]))
|
||||
else
|
||||
throw("Invalid name for a particle in the QED model")
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
issame(T1::Type{<:ParticleStateful}, T2::Type{<:ParticleStateful})
|
||||
|
||||
For two given `ParticleStateful` types, return whether they are equivalent for the purpose of a Feynman Diagram. That means e.g. an `Incoming` `AntiFermion` is the same as an `Outgoing` `Fermion`. This is equivalent to `!caninteract(T1, T2)`.
|
||||
|
||||
See also: [`caninteract`](@ref) and [`interaction_result`](@ref)
|
||||
"""
|
||||
function issame(T1::Type{<:ParticleStateful}, T2::Type{<:ParticleStateful})
|
||||
return !caninteract(T1, T2)
|
||||
end
|
||||
|
||||
"""
|
||||
QED_vertex()
|
||||
|
||||
Return the factor of a vertex in a QED feynman diagram.
|
||||
"""
|
||||
@inline function QED_vertex()::SLorentzVector{DiracMatrix}
|
||||
# Peskin-Schroeder notation
|
||||
return -1im * e * gamma()
|
||||
end
|
||||
|
||||
@inline function QED_inner_edge(p::ParticleStateful)
|
||||
return propagator(particle_species(p), momentum(p))
|
||||
end
|
||||
|
||||
"""
|
||||
QED_conserve_momentum(p1::ParticleStateful, p2::ParticleStateful)
|
||||
|
||||
Calculate and return a new particle from two given interacting ones at a vertex.
|
||||
"""
|
||||
function QED_conserve_momentum(
|
||||
p1::P1,
|
||||
p2::P2,
|
||||
) where {
|
||||
Dir1 <: ParticleDirection,
|
||||
Dir2 <: ParticleDirection,
|
||||
Species1 <: AbstractParticleType,
|
||||
Species2 <: AbstractParticleType,
|
||||
P1 <: ParticleStateful{Dir1, Species1},
|
||||
P2 <: ParticleStateful{Dir2, Species2},
|
||||
}
|
||||
P3 = interaction_result(P1, P2)
|
||||
p1_mom = momentum(p1)
|
||||
if (Dir1 <: Outgoing)
|
||||
p1_mom *= -1
|
||||
end
|
||||
p2_mom = momentum(p2)
|
||||
if (Dir2 <: Outgoing)
|
||||
p2_mom *= -1
|
||||
end
|
||||
|
||||
p3_mom = p1_mom + p2_mom
|
||||
if (particle_direction(P3) isa Incoming)
|
||||
return ParticleStateful(particle_direction(P3), particle_species(P3), -p3_mom)
|
||||
end
|
||||
return ParticleStateful(particle_direction(P3), particle_species(P3), p3_mom)
|
||||
end
|
||||
|
||||
"""
|
||||
model(::AbstractProcessDescription)
|
||||
|
||||
Return the model of this process description.
|
||||
"""
|
||||
model(::GenericQEDProcess) = QEDModel()
|
||||
model(::PhaseSpacePoint) = QEDModel()
|
||||
|
||||
function get_particle(
|
||||
input::PhaseSpacePoint,
|
||||
t::Type{ParticleStateful{DIR, SPECIES}},
|
||||
n::Int,
|
||||
) where {DIR <: ParticleDirection, SPECIES <: AbstractParticleType}
|
||||
i = 0
|
||||
for p in particles(input, DIR())
|
||||
if p isa t
|
||||
i += 1
|
||||
if i == n
|
||||
return p
|
||||
end
|
||||
end
|
||||
end
|
||||
@assert false "Invalid type given"
|
||||
end
|
@ -1,8 +1,9 @@
|
||||
|
||||
#=
|
||||
"""
|
||||
show(io::IO, process::QEDProcessDescription)
|
||||
show(io::IO, process::GenericQEDProcess)
|
||||
|
||||
Pretty print an [`QEDProcessDescription`](@ref) (no newlines).
|
||||
Pretty print an [`GenericQEDProcess`](@ref) (no newlines).
|
||||
|
||||
```jldoctest
|
||||
julia> using MetagraphOptimization
|
||||
@ -14,7 +15,7 @@ julia> print(parse_process("kk->ep", QEDModel()))
|
||||
QED Process: 'kk->ep'
|
||||
```
|
||||
"""
|
||||
function show(io::IO, process::QEDProcessDescription)
|
||||
function show(io::IO, process::GenericQEDProcess)
|
||||
# types() gives the types in order (QED) instead of random like keys() would
|
||||
print(io, "QED Process: \'")
|
||||
for type in types(QEDModel())
|
||||
@ -34,7 +35,7 @@ end
|
||||
|
||||
|
||||
"""
|
||||
String(process::QEDProcessDescription)
|
||||
String(process::GenericQEDProcess)
|
||||
|
||||
Create a short string suitable as a filename or similar, describing the given process.
|
||||
|
||||
@ -64,7 +65,9 @@ function String(process::QEDProcessDescription)
|
||||
end
|
||||
return str
|
||||
end
|
||||
=#
|
||||
|
||||
#=
|
||||
"""
|
||||
show(io::IO, processInput::QEDProcessInput)
|
||||
|
||||
@ -92,7 +95,9 @@ function show(io::IO, processInput::QEDProcessInput)
|
||||
end
|
||||
return nothing
|
||||
end
|
||||
=#
|
||||
|
||||
#=
|
||||
"""
|
||||
show(io::IO, particle::T) where {T <: QEDParticle}
|
||||
|
||||
@ -102,13 +107,14 @@ function show(io::IO, particle::T) where {T <: QEDParticle}
|
||||
print(io, "$(String(typeof(particle))): $(particle.momentum)")
|
||||
return nothing
|
||||
end
|
||||
=#
|
||||
|
||||
"""
|
||||
show(io::IO, particle::FeynmanParticle)
|
||||
|
||||
Pretty print a [`FeynmanParticle`](@ref) (no newlines).
|
||||
"""
|
||||
show(io::IO, p::FeynmanParticle) = print(io, "$(String(p.particle))_$(String(direction(p.particle)))_$(p.id)")
|
||||
show(io::IO, p::FeynmanParticle) = print(io, "$(String(p.particle))_$(String(particle_direction(p.particle)))_$(p.id)")
|
||||
|
||||
"""
|
||||
show(io::IO, particle::FeynmanVertex)
|
@ -1,10 +0,0 @@
|
||||
|
||||
"""
|
||||
show(io::IO, particleValue::ParticleValue)
|
||||
|
||||
Pretty print a [`ParticleValue`](@ref), no newlines.
|
||||
"""
|
||||
function show(io::IO, particleValue::ParticleValue)
|
||||
print(io, "($(particleValue.p), value: $(particleValue.v))")
|
||||
return nothing
|
||||
end
|
@ -1,253 +0,0 @@
|
||||
|
||||
ComputeTaskQED_Sum() = ComputeTaskQED_Sum(0)
|
||||
|
||||
function _svector_from_type(
|
||||
processDescription::QEDProcessDescription, type::Type{T}, particles
|
||||
) where {DIR<:ParticleDirection,T<:QEDParticle{DIR}}
|
||||
if DIR <: Incoming
|
||||
l = 0
|
||||
for (k, v) in in_particles(processDescription)
|
||||
if T <: k
|
||||
l = v
|
||||
break
|
||||
end
|
||||
end
|
||||
return SVector{l,T}(filter(x -> typeof(x) <: T, particles))
|
||||
elseif DIR <: Outgoing
|
||||
l = 0
|
||||
for (k, v) in out_particles(processDescription)
|
||||
if T <: k
|
||||
l = v
|
||||
break
|
||||
end
|
||||
end
|
||||
return SVector{l,T}(filter(x -> typeof(x) <: T, particles))
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
gen_process_input(processDescription::QEDProcessDescription)
|
||||
|
||||
Return a ProcessInput of randomly generated [`QEDParticle`](@ref)s from a [`QEDProcessDescription`](@ref). The process description can be created manually or parsed from a string using [`parse_process`](@ref).
|
||||
|
||||
Note: This uses RAMBO to create a valid process with conservation of momentum and energy.
|
||||
"""
|
||||
function gen_process_input(processDescription::QEDProcessDescription)
|
||||
massSum = 0
|
||||
inputMasses = Vector{Float64}()
|
||||
for (particle, n) in processDescription.inParticles
|
||||
for _ in 1:n
|
||||
massSum += mass(particle)
|
||||
push!(inputMasses, mass(particle))
|
||||
end
|
||||
end
|
||||
outputMasses = Vector{Float64}()
|
||||
for (particle, n) in processDescription.outParticles
|
||||
for _ in 1:n
|
||||
massSum += mass(particle)
|
||||
push!(outputMasses, mass(particle))
|
||||
end
|
||||
end
|
||||
|
||||
# add some extra random mass to allow for some momentum
|
||||
massSum += rand(rng[threadid()]) * (length(inputMasses) + length(outputMasses))
|
||||
|
||||
particles = Vector{QEDParticle}()
|
||||
initialMomenta = generate_initial_moms(massSum, inputMasses)
|
||||
index = 1
|
||||
for (particle, n) in processDescription.inParticles
|
||||
for _ in 1:n
|
||||
mom = initialMomenta[index]
|
||||
push!(particles, particle(mom))
|
||||
index += 1
|
||||
end
|
||||
end
|
||||
|
||||
final_momenta = generate_physical_massive_moms(rng[threadid()], massSum, outputMasses)
|
||||
index = 1
|
||||
for (particle, n) in processDescription.outParticles
|
||||
for _ in 1:n
|
||||
push!(particles, particle(final_momenta[index]))
|
||||
index += 1
|
||||
end
|
||||
end
|
||||
|
||||
inFerms = _svector_from_type(
|
||||
processDescription, FermionStateful{Incoming,SpinUp}, particles
|
||||
)
|
||||
outFerms = _svector_from_type(
|
||||
processDescription, FermionStateful{Outgoing,SpinUp}, particles
|
||||
)
|
||||
inAntiferms = _svector_from_type(
|
||||
processDescription, AntiFermionStateful{Incoming,SpinUp}, particles
|
||||
)
|
||||
outAntiferms = _svector_from_type(
|
||||
processDescription, AntiFermionStateful{Outgoing,SpinUp}, particles
|
||||
)
|
||||
inPhotons = _svector_from_type(
|
||||
processDescription, PhotonStateful{Incoming,PolX}, particles
|
||||
)
|
||||
outPhotons = _svector_from_type(
|
||||
processDescription, PhotonStateful{Outgoing,PolX}, particles
|
||||
)
|
||||
|
||||
processInput = QEDProcessInput(
|
||||
processDescription,
|
||||
inFerms,
|
||||
outFerms,
|
||||
inAntiferms,
|
||||
outAntiferms,
|
||||
inPhotons,
|
||||
outPhotons,
|
||||
)
|
||||
|
||||
return processInput
|
||||
end
|
||||
|
||||
"""
|
||||
gen_graph(process_description::QEDProcessDescription)
|
||||
|
||||
For a given [`QEDProcessDescription`](@ref), return the [`DAG`](@ref) that computes it.
|
||||
"""
|
||||
function gen_graph(process_description::QEDProcessDescription)
|
||||
initial_diagram = FeynmanDiagram(process_description)
|
||||
diagrams = gen_diagrams(initial_diagram)
|
||||
|
||||
graph = DAG()
|
||||
|
||||
COMPLEX_SIZE = sizeof(ComplexF64)
|
||||
PARTICLE_VALUE_SIZE = 96.0
|
||||
|
||||
# TODO: Not all diagram outputs should always be summed at the end, if they differ by fermion exchange they need to be diffed
|
||||
# Should not matter for n-Photon Compton processes though
|
||||
sum_node = insert_node!(
|
||||
graph, make_node(ComputeTaskQED_Sum(0)); track=false, invalidate_cache=false
|
||||
)
|
||||
global_data_out = insert_node!(
|
||||
graph, make_node(DataTask(COMPLEX_SIZE)); track=false, invalidate_cache=false
|
||||
)
|
||||
insert_edge!(graph, sum_node, global_data_out; track=false, invalidate_cache=false)
|
||||
|
||||
# remember the data out nodes for connection
|
||||
dataOutNodes = Dict()
|
||||
|
||||
for particle in initial_diagram.particles
|
||||
# generate data in and U tasks
|
||||
data_in = insert_node!(
|
||||
graph,
|
||||
make_node(DataTask(PARTICLE_VALUE_SIZE), String(particle));
|
||||
track=false,
|
||||
invalidate_cache=false,
|
||||
) # read particle data node
|
||||
compute_u = insert_node!(
|
||||
graph, make_node(ComputeTaskQED_U()); track=false, invalidate_cache=false
|
||||
) # compute U node
|
||||
data_out = insert_node!(
|
||||
graph,
|
||||
make_node(DataTask(PARTICLE_VALUE_SIZE));
|
||||
track=false,
|
||||
invalidate_cache=false,
|
||||
) # transfer data out from u (one ABCParticleValue object)
|
||||
|
||||
insert_edge!(graph, data_in, compute_u; track=false, invalidate_cache=false)
|
||||
insert_edge!(graph, compute_u, data_out; track=false, invalidate_cache=false)
|
||||
|
||||
# remember the data_out node for future edges
|
||||
dataOutNodes[String(particle)] = data_out
|
||||
end
|
||||
|
||||
# TODO: this should be parallelizable somewhat easily
|
||||
for diagram in diagrams
|
||||
tie = diagram.tie[]
|
||||
|
||||
# handle the vertices
|
||||
for vertices in diagram.vertices
|
||||
for vertex in vertices
|
||||
data_in1 = dataOutNodes[String(vertex.in1)]
|
||||
data_in2 = dataOutNodes[String(vertex.in2)]
|
||||
|
||||
compute_V = insert_node!(
|
||||
graph,
|
||||
make_node(ComputeTaskQED_V());
|
||||
track=false,
|
||||
invalidate_cache=false,
|
||||
) # compute vertex
|
||||
|
||||
insert_edge!(
|
||||
graph, data_in1, compute_V; track=false, invalidate_cache=false
|
||||
)
|
||||
insert_edge!(
|
||||
graph, data_in2, compute_V; track=false, invalidate_cache=false
|
||||
)
|
||||
|
||||
data_V_out = insert_node!(
|
||||
graph,
|
||||
make_node(DataTask(PARTICLE_VALUE_SIZE));
|
||||
track=false,
|
||||
invalidate_cache=false,
|
||||
)
|
||||
|
||||
insert_edge!(
|
||||
graph, compute_V, data_V_out; track=false, invalidate_cache=false
|
||||
)
|
||||
|
||||
if (vertex.out == tie.in1 || vertex.out == tie.in2)
|
||||
# out particle is part of the tie -> there will be an S2 task with it later, don't make S1 task
|
||||
dataOutNodes[String(vertex.out)] = data_V_out
|
||||
continue
|
||||
end
|
||||
|
||||
# otherwise, add S1 task
|
||||
compute_S1 = insert_node!(
|
||||
graph,
|
||||
make_node(ComputeTaskQED_S1());
|
||||
track=false,
|
||||
invalidate_cache=false,
|
||||
) # compute propagator
|
||||
|
||||
insert_edge!(
|
||||
graph, data_V_out, compute_S1; track=false, invalidate_cache=false
|
||||
)
|
||||
|
||||
data_S1_out = insert_node!(
|
||||
graph,
|
||||
make_node(DataTask(PARTICLE_VALUE_SIZE));
|
||||
track=false,
|
||||
invalidate_cache=false,
|
||||
)
|
||||
|
||||
insert_edge!(
|
||||
graph, compute_S1, data_S1_out; track=false, invalidate_cache=false
|
||||
)
|
||||
|
||||
# overrides potentially different nodes from previous diagrams, which is intentional
|
||||
dataOutNodes[String(vertex.out)] = data_S1_out
|
||||
end
|
||||
end
|
||||
|
||||
# handle the tie
|
||||
data_in1 = dataOutNodes[String(tie.in1)]
|
||||
data_in2 = dataOutNodes[String(tie.in2)]
|
||||
|
||||
compute_S2 = insert_node!(
|
||||
graph, make_node(ComputeTaskQED_S2()); track=false, invalidate_cache=false
|
||||
)
|
||||
|
||||
data_S2 = insert_node!(
|
||||
graph,
|
||||
make_node(DataTask(PARTICLE_VALUE_SIZE));
|
||||
track=false,
|
||||
invalidate_cache=false,
|
||||
)
|
||||
|
||||
insert_edge!(graph, data_in1, compute_S2; track=false, invalidate_cache=false)
|
||||
insert_edge!(graph, data_in2, compute_S2; track=false, invalidate_cache=false)
|
||||
|
||||
insert_edge!(graph, compute_S2, data_S2; track=false, invalidate_cache=false)
|
||||
|
||||
insert_edge!(graph, data_S2, sum_node; track=false, invalidate_cache=false)
|
||||
add_child!(task(sum_node))
|
||||
end
|
||||
|
||||
return graph
|
||||
end
|
@ -1,44 +0,0 @@
|
||||
|
||||
"""
|
||||
parse_process(string::AbstractString, model::QEDModel)
|
||||
|
||||
Parse a string representation of a process, such as "ke->ke" into the corresponding [`QEDProcessDescription`](@ref).
|
||||
"""
|
||||
function parse_process(str::AbstractString, model::QEDModel)
|
||||
inParticles = Dict{Type, Int}()
|
||||
outParticles = Dict{Type, Int}()
|
||||
|
||||
if !(contains(str, "->"))
|
||||
throw("Did not find -> while parsing process \"$str\"")
|
||||
end
|
||||
|
||||
(inStr, outStr) = split(str, "->")
|
||||
|
||||
if (isempty(inStr) || isempty(outStr))
|
||||
throw("Process (\"$str\") input or output part is empty!")
|
||||
end
|
||||
|
||||
for t in types(model)
|
||||
if (isincoming(t))
|
||||
inCount = count(x -> x == String(t)[1], inStr)
|
||||
|
||||
if inCount != 0
|
||||
inParticles[t] = inCount
|
||||
end
|
||||
end
|
||||
if (isoutgoing(t))
|
||||
outCount = count(x -> x == String(t)[1], outStr)
|
||||
if outCount != 0
|
||||
outParticles[t] = outCount
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if length(inStr) != sum(values(inParticles))
|
||||
throw("Encountered unknown characters in the input part of process \"$str\"")
|
||||
elseif length(outStr) != sum(values(outParticles))
|
||||
throw("Encountered unknown characters in the output part of process \"$str\"")
|
||||
end
|
||||
|
||||
return QEDProcessDescription(inParticles, outParticles)
|
||||
end
|
@ -1,532 +0,0 @@
|
||||
using QEDprocesses
|
||||
using StaticArrays
|
||||
import QEDbase.mass
|
||||
|
||||
# TODO check
|
||||
const e = sqrt(4π / 137)
|
||||
|
||||
"""
|
||||
QEDModel <: AbstractPhysicsModel
|
||||
|
||||
Singleton definition for identification of the QED-Model.
|
||||
"""
|
||||
struct QEDModel <: AbstractPhysicsModel end
|
||||
|
||||
"""
|
||||
QEDParticle
|
||||
|
||||
Base type for all particles in the [`QEDModel`](@ref).
|
||||
|
||||
Its template parameter specifies the particle's direction.
|
||||
|
||||
The concrete types contain singletons of the types that they are, like `Photon` and `Electron` from QEDbase, and their state descriptions.
|
||||
"""
|
||||
abstract type QEDParticle{Direction<:ParticleDirection} <: AbstractParticle end
|
||||
|
||||
"""
|
||||
QEDProcessDescription <: AbstractProcessDescription
|
||||
|
||||
A description of a process in the QED-Model. Contains the input and output particles.
|
||||
|
||||
See also: [`in_particles`](@ref), [`out_particles`](@ref), [`parse_process`](@ref)
|
||||
"""
|
||||
struct QEDProcessDescription <: AbstractProcessDescription
|
||||
inParticles::Dict{Type{<:QEDParticle{Incoming}},Int}
|
||||
outParticles::Dict{Type{<:QEDParticle{Outgoing}},Int}
|
||||
end
|
||||
|
||||
QEDParticleValue{ParticleType<:QEDParticle} = Union{
|
||||
ParticleValue{ParticleType,BiSpinor},
|
||||
ParticleValue{ParticleType,AdjointBiSpinor},
|
||||
ParticleValue{ParticleType,DiracMatrix},
|
||||
ParticleValue{ParticleType,SLorentzVector{Float64}},
|
||||
ParticleValue{ParticleType,ComplexF64},
|
||||
}
|
||||
|
||||
"""
|
||||
PhotonStateful <: QEDParticle
|
||||
|
||||
A photon of the [`QEDModel`](@ref) with its state.
|
||||
"""
|
||||
struct PhotonStateful{Direction<:ParticleDirection,Pol<:AbstractDefinitePolarization} <:
|
||||
QEDParticle{Direction}
|
||||
momentum::SFourMomentum
|
||||
|
||||
function PhotonStateful{Direction,Pol}(
|
||||
mom::SFourMomentum
|
||||
) where {Direction<:ParticleDirection,Pol<:AbstractDefinitePolarization}
|
||||
return new{Direction,Pol}(mom)
|
||||
end
|
||||
|
||||
function PhotonStateful{Direction}(
|
||||
mom::SFourMomentum
|
||||
) where {Direction<:ParticleDirection}
|
||||
return new{Direction,AbstractDefinitePolarization}(mom)
|
||||
end
|
||||
|
||||
function PhotonStateful{Direction}(
|
||||
mom::SFourMomentum, pol::AbstractDefinitePolarization
|
||||
) where {Direction<:ParticleDirection}
|
||||
return new{Direction,typeof(pol)}(mom)
|
||||
end
|
||||
|
||||
function PhotonStateful{Dir,Pol}(ph::PhotonStateful) where {Dir,Pol}
|
||||
return new{Dir,Pol}(ph.momentum)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
FermionStateful <: QEDParticle
|
||||
|
||||
A fermion of the [`QEDModel`](@ref) with its state.
|
||||
"""
|
||||
struct FermionStateful{Direction<:ParticleDirection,Spin<:AbstractDefiniteSpin} <:
|
||||
QEDParticle{Direction}
|
||||
momentum::SFourMomentum
|
||||
# TODO: mass for electron/muon/tauon representation?
|
||||
|
||||
function FermionStateful{Direction,Spin}(
|
||||
mom::SFourMomentum
|
||||
) where {Direction<:ParticleDirection,Spin<:AbstractDefiniteSpin}
|
||||
return new{Direction,Spin}(mom)
|
||||
end
|
||||
|
||||
function FermionStateful{Direction}(
|
||||
mom::SFourMomentum
|
||||
) where {Direction<:ParticleDirection}
|
||||
return new{Direction,AbstractDefiniteSpin}(mom)
|
||||
end
|
||||
|
||||
function FermionStateful{Direction}(
|
||||
mom::SFourMomentum, spin::AbstractDefiniteSpin
|
||||
) where {Direction<:ParticleDirection}
|
||||
return new{Direction,typeof(spin)}(mom)
|
||||
end
|
||||
|
||||
function FermionStateful{Dir,Spin}(f::FermionStateful) where {Dir,Spin}
|
||||
return new{Dir,Spin}(f.momentum)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
AntiFermionStateful <: QEDParticle
|
||||
|
||||
An anti-fermion of the [`QEDModel`](@ref) with its state.
|
||||
"""
|
||||
struct AntiFermionStateful{Direction<:ParticleDirection,Spin<:AbstractDefiniteSpin} <:
|
||||
QEDParticle{Direction}
|
||||
momentum::SFourMomentum
|
||||
# TODO: mass for electron/muon/tauon representation?
|
||||
|
||||
function AntiFermionStateful{Direction,Spin}(
|
||||
mom::SFourMomentum
|
||||
) where {Direction<:ParticleDirection,Spin<:AbstractDefiniteSpin}
|
||||
return new{Direction,Spin}(mom)
|
||||
end
|
||||
|
||||
function AntiFermionStateful{Direction}(
|
||||
mom::SFourMomentum
|
||||
) where {Direction<:ParticleDirection}
|
||||
return new{Direction,AbstractDefiniteSpin}(mom)
|
||||
end
|
||||
|
||||
function AntiFermionStateful{Direction}(
|
||||
mom::SFourMomentum, spin::AbstractDefiniteSpin
|
||||
) where {Direction<:ParticleDirection}
|
||||
return new{Direction,typeof(spin)}(mom)
|
||||
end
|
||||
|
||||
function AntiFermionStateful{Dir,Spin}(f::AntiFermionStateful) where {Dir,Spin}
|
||||
return new{Dir,Spin}(f.momentum)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
interaction_result(t1::Type{T1}, t2::Type{T2}) where {T1 <: QEDParticle, T2 <: QEDParticle}
|
||||
|
||||
For two given particle types that can interact, return the third.
|
||||
"""
|
||||
function interaction_result(
|
||||
t1::Type{T1}, t2::Type{T2}
|
||||
) where {T1<:QEDParticle,T2<:QEDParticle}
|
||||
@assert false "Invalid interaction between particles of types $t1 and $t2"
|
||||
end
|
||||
|
||||
function interaction_result(
|
||||
::Type{FermionStateful{Incoming,Spin1}}, ::Type{FermionStateful{Outgoing,Spin2}}
|
||||
) where {Spin1,Spin2}
|
||||
return PhotonStateful{Incoming,PolX}
|
||||
end
|
||||
function interaction_result(
|
||||
::Type{FermionStateful{Incoming,Spin1}}, ::Type{AntiFermionStateful{Incoming,Spin2}}
|
||||
) where {Spin1,Spin2}
|
||||
return PhotonStateful{Incoming,PolX}
|
||||
end
|
||||
function interaction_result(
|
||||
::Type{FermionStateful{Incoming,Spin1}}, ::Type{<:PhotonStateful}
|
||||
) where {Spin1}
|
||||
return FermionStateful{Outgoing,SpinUp}
|
||||
end
|
||||
|
||||
function interaction_result(
|
||||
::Type{FermionStateful{Outgoing,Spin1}}, ::Type{FermionStateful{Incoming,Spin2}}
|
||||
) where {Spin1,Spin2}
|
||||
return PhotonStateful{Incoming,PolX}
|
||||
end
|
||||
function interaction_result(
|
||||
::Type{FermionStateful{Outgoing,Spin1}}, ::Type{AntiFermionStateful{Outgoing,Spin2}}
|
||||
) where {Spin1,Spin2}
|
||||
return PhotonStateful{Incoming,PolX}
|
||||
end
|
||||
function interaction_result(
|
||||
::Type{FermionStateful{Outgoing,Spin1}}, ::Type{<:PhotonStateful}
|
||||
) where {Spin1}
|
||||
return FermionStateful{Incoming,SpinUp}
|
||||
end
|
||||
|
||||
# antifermion mirror
|
||||
function interaction_result(
|
||||
::Type{AntiFermionStateful{Incoming,Spin}}, t2::Type{<:QEDParticle}
|
||||
) where {Spin}
|
||||
return interaction_result(FermionStateful{Outgoing,Spin}, t2)
|
||||
end
|
||||
function interaction_result(
|
||||
::Type{AntiFermionStateful{Outgoing,Spin}}, t2::Type{<:QEDParticle}
|
||||
) where {Spin}
|
||||
return interaction_result(FermionStateful{Incoming,Spin}, t2)
|
||||
end
|
||||
|
||||
# photon commutativity
|
||||
function interaction_result(t1::Type{<:PhotonStateful}, t2::Type{<:QEDParticle})
|
||||
return interaction_result(t2, t1)
|
||||
end
|
||||
|
||||
# but prevent stack overflow
|
||||
function interaction_result(t1::Type{<:PhotonStateful}, t2::Type{<:PhotonStateful})
|
||||
@assert false "Invalid interaction between particles of types $t1 and $t2"
|
||||
end
|
||||
|
||||
"""
|
||||
propagation_result(t1::Type{T}) where {T <: QEDParticle}
|
||||
|
||||
Return the type of the inverted direction. E.g.
|
||||
"""
|
||||
propagation_result(
|
||||
::Type{FermionStateful{Incoming,Spin}}
|
||||
) where {Spin<:AbstractDefiniteSpin} = FermionStateful{Outgoing,Spin}
|
||||
function propagation_result(
|
||||
::Type{FermionStateful{Outgoing,Spin}}
|
||||
) where {Spin<:AbstractDefiniteSpin}
|
||||
return FermionStateful{Incoming,Spin}
|
||||
end
|
||||
function propagation_result(
|
||||
::Type{AntiFermionStateful{Incoming,Spin}}
|
||||
) where {Spin<:AbstractDefiniteSpin}
|
||||
return AntiFermionStateful{Outgoing,Spin}
|
||||
end
|
||||
function propagation_result(
|
||||
::Type{AntiFermionStateful{Outgoing,Spin}}
|
||||
) where {Spin<:AbstractDefiniteSpin}
|
||||
return AntiFermionStateful{Incoming,Spin}
|
||||
end
|
||||
function propagation_result(
|
||||
::Type{PhotonStateful{Incoming,Pol}}
|
||||
) where {Pol<:AbstractDefinitePolarization}
|
||||
return PhotonStateful{Outgoing,Pol}
|
||||
end
|
||||
function propagation_result(
|
||||
::Type{PhotonStateful{Outgoing,Pol}}
|
||||
) where {Pol<:AbstractDefinitePolarization}
|
||||
return PhotonStateful{Incoming,Pol}
|
||||
end
|
||||
|
||||
"""
|
||||
types(::QEDModel)
|
||||
|
||||
Return a Vector of the possible types of particle in the [`QEDModel`](@ref).
|
||||
"""
|
||||
function types(::QEDModel)
|
||||
return [
|
||||
PhotonStateful{Incoming},
|
||||
PhotonStateful{Outgoing},
|
||||
FermionStateful{Incoming},
|
||||
FermionStateful{Outgoing},
|
||||
AntiFermionStateful{Incoming},
|
||||
AntiFermionStateful{Outgoing},
|
||||
]
|
||||
end
|
||||
|
||||
# type piracy?
|
||||
String(::Type{Incoming}) = "Incoming"
|
||||
String(::Type{Outgoing}) = "Outgoing"
|
||||
|
||||
String(::Type{PolX}) = "polx"
|
||||
String(::Type{PolY}) = "poly"
|
||||
|
||||
String(::Type{SpinUp}) = "spinup"
|
||||
String(::Type{SpinDown}) = "spindown"
|
||||
|
||||
String(::Incoming) = "i"
|
||||
String(::Outgoing) = "o"
|
||||
|
||||
function String(::Type{<:PhotonStateful})
|
||||
return "k"
|
||||
end
|
||||
function String(::Type{<:FermionStateful})
|
||||
return "e"
|
||||
end
|
||||
function String(::Type{<:AntiFermionStateful})
|
||||
return "p"
|
||||
end
|
||||
|
||||
function unique_name(::Type{PhotonStateful{Dir,Pol}}) where {Dir,Pol}
|
||||
return String(PhotonStateful) * String(Dir) * String(Pol)
|
||||
end
|
||||
function unique_name(::Type{FermionStateful{Dir,Spin}}) where {Dir,Spin}
|
||||
return String(FermionStateful) * String(Dir) * String(Spin)
|
||||
end
|
||||
function unique_name(::Type{AntiFermionStateful{Dir,Spin}}) where {Dir,Spin}
|
||||
return String(AntiFermionStateful) * String(Dir) * String(Spin)
|
||||
end
|
||||
|
||||
@inline particle(::PhotonStateful) = Photon()
|
||||
@inline particle(::FermionStateful) = Electron()
|
||||
@inline particle(::AntiFermionStateful) = Positron()
|
||||
|
||||
@inline particle(::Type{<:PhotonStateful}) = Photon()
|
||||
@inline particle(::Type{<:FermionStateful}) = Electron()
|
||||
@inline particle(::Type{<:AntiFermionStateful}) = Positron()
|
||||
|
||||
@inline momentum(p::PhotonStateful)::SFourMomentum = p.momentum
|
||||
@inline momentum(p::FermionStateful)::SFourMomentum = p.momentum
|
||||
@inline momentum(p::AntiFermionStateful)::SFourMomentum = p.momentum
|
||||
|
||||
@inline spin_or_pol(
|
||||
p::PhotonStateful{Dir,Pol}
|
||||
) where {Dir,Pol<:AbstractDefinitePolarization} = Pol()
|
||||
@inline spin_or_pol(p::FermionStateful{Dir,Spin}) where {Dir,Spin<:AbstractDefiniteSpin} =
|
||||
Spin()
|
||||
@inline spin_or_pol(
|
||||
p::AntiFermionStateful{Dir,Spin}
|
||||
) where {Dir,Spin<:AbstractDefiniteSpin} = Spin()
|
||||
|
||||
@inline direction(
|
||||
::Type{P}
|
||||
) where {
|
||||
P<:Union{
|
||||
FermionStateful{Incoming},AntiFermionStateful{Incoming},PhotonStateful{Incoming}
|
||||
},
|
||||
} = Incoming()
|
||||
@inline direction(
|
||||
::Type{P}
|
||||
) where {
|
||||
P<:Union{
|
||||
FermionStateful{Outgoing},AntiFermionStateful{Outgoing},PhotonStateful{Outgoing}
|
||||
},
|
||||
} = Outgoing()
|
||||
|
||||
@inline direction(
|
||||
::P
|
||||
) where {
|
||||
P<:Union{
|
||||
FermionStateful{Incoming},AntiFermionStateful{Incoming},PhotonStateful{Incoming}
|
||||
},
|
||||
} = Incoming()
|
||||
@inline direction(
|
||||
::P
|
||||
) where {
|
||||
P<:Union{
|
||||
FermionStateful{Outgoing},AntiFermionStateful{Outgoing},PhotonStateful{Outgoing}
|
||||
},
|
||||
} = Outgoing()
|
||||
|
||||
@inline isincoming(::QEDParticle{Incoming}) = true
|
||||
@inline isincoming(::QEDParticle{Outgoing}) = false
|
||||
@inline isoutgoing(::QEDParticle{Incoming}) = false
|
||||
@inline isoutgoing(::QEDParticle{Outgoing}) = true
|
||||
|
||||
@inline isincoming(::Type{<:QEDParticle{Incoming}}) = true
|
||||
@inline isincoming(::Type{<:QEDParticle{Outgoing}}) = false
|
||||
@inline isoutgoing(::Type{<:QEDParticle{Incoming}}) = false
|
||||
@inline isoutgoing(::Type{<:QEDParticle{Outgoing}}) = true
|
||||
|
||||
@inline mass(::Type{<:FermionStateful}) = 1.0
|
||||
@inline mass(::Type{<:AntiFermionStateful}) = 1.0
|
||||
@inline mass(::Type{<:PhotonStateful}) = 0.0
|
||||
|
||||
@inline invert_momentum(p::FermionStateful{Dir,Spin}) where {Dir,Spin} =
|
||||
FermionStateful{Dir,Spin}(-p.momentum, p.spin)
|
||||
@inline invert_momentum(p::AntiFermionStateful{Dir,Spin}) where {Dir,Spin} =
|
||||
AntiFermionStateful{Dir,Spin}(-p.momentum, p.spin)
|
||||
@inline invert_momentum(k::PhotonStateful{Dir,Spin}) where {Dir,Spin} =
|
||||
PhotonStateful{Dir,Spin}(-k.momentum, k.polarization)
|
||||
|
||||
"""
|
||||
caninteract(T1::Type{<:QEDParticle}, T2::Type{<:QEDParticle})
|
||||
|
||||
For two given [`QEDParticle`](@ref) types, return whether they can interact at a vertex. This is equivalent to `!issame(T1, T2)`.
|
||||
|
||||
See also: [`issame`](@ref) and [`interaction_result`](@ref)
|
||||
"""
|
||||
function caninteract(T1::Type{<:QEDParticle}, T2::Type{<:QEDParticle})
|
||||
if (T1 == T2)
|
||||
return false
|
||||
end
|
||||
if (T1 <: PhotonStateful && T2 <: PhotonStateful)
|
||||
return false
|
||||
end
|
||||
|
||||
for (P1, P2) in [(T1, T2), (T2, T1)]
|
||||
if (P1 <: FermionStateful{Incoming} && P2 <: AntiFermionStateful{Outgoing})
|
||||
return false
|
||||
end
|
||||
if (P1 <: FermionStateful{Outgoing} && P2 <: AntiFermionStateful{Incoming})
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function type_index_from_name(::QEDModel, name::String)
|
||||
if startswith(name, "ki")
|
||||
return (PhotonStateful{Incoming,PolX}, parse(Int, name[3:end]))
|
||||
elseif startswith(name, "ko")
|
||||
return (PhotonStateful{Outgoing,PolX}, parse(Int, name[3:end]))
|
||||
elseif startswith(name, "ei")
|
||||
return (FermionStateful{Incoming,SpinUp}, parse(Int, name[3:end]))
|
||||
elseif startswith(name, "eo")
|
||||
return (FermionStateful{Outgoing,SpinUp}, parse(Int, name[3:end]))
|
||||
elseif startswith(name, "pi")
|
||||
return (AntiFermionStateful{Incoming,SpinUp}, parse(Int, name[3:end]))
|
||||
elseif startswith(name, "po")
|
||||
return (AntiFermionStateful{Outgoing,SpinUp}, parse(Int, name[3:end]))
|
||||
else
|
||||
throw("Invalid name for a particle in the QED model")
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
issame(T1::Type{<:QEDParticle}, T2::Type{<:QEDParticle})
|
||||
|
||||
For two given [`QEDParticle`](@ref) types, return whether they are equivalent for the purpose of a Feynman Diagram. That means e.g. an `Incoming` `AntiFermion` is the same as an `Outgoing` `Fermion`. This is equivalent to `!caninteract(T1, T2)`.
|
||||
|
||||
See also: [`caninteract`](@ref) and [`interaction_result`](@ref)
|
||||
"""
|
||||
function issame(T1::Type{<:QEDParticle}, T2::Type{<:QEDParticle})
|
||||
return !caninteract(T1, T2)
|
||||
end
|
||||
|
||||
"""
|
||||
QED_vertex()
|
||||
|
||||
Return the factor of a vertex in a QED feynman diagram.
|
||||
"""
|
||||
@inline function QED_vertex()::SLorentzVector{DiracMatrix}
|
||||
# Peskin-Schroeder notation
|
||||
return -1im * e * gamma()
|
||||
end
|
||||
|
||||
@inline function QED_inner_edge(p::QEDParticle)
|
||||
return QEDbase.propagator(particle(p), p.momentum)
|
||||
end
|
||||
|
||||
"""
|
||||
QED_conserve_momentum(p1::QEDParticle, p2::QEDParticle)
|
||||
|
||||
Calculate and return a new particle from two given interacting ones at a vertex.
|
||||
"""
|
||||
function QED_conserve_momentum(
|
||||
p1::P1, p2::P2
|
||||
) where {
|
||||
Dir1<:ParticleDirection,
|
||||
Dir2<:ParticleDirection,
|
||||
SpinPol1<:AbstractSpinOrPolarization,
|
||||
SpinPol2<:AbstractSpinOrPolarization,
|
||||
P1<:Union{
|
||||
FermionStateful{Dir1,SpinPol1},
|
||||
AntiFermionStateful{Dir1,SpinPol1},
|
||||
PhotonStateful{Dir1,SpinPol1},
|
||||
},
|
||||
P2<:Union{
|
||||
FermionStateful{Dir2,SpinPol2},
|
||||
AntiFermionStateful{Dir2,SpinPol2},
|
||||
PhotonStateful{Dir2,SpinPol2},
|
||||
},
|
||||
}
|
||||
P3 = interaction_result(P1, P2)
|
||||
p1_mom = p1.momentum
|
||||
if (Dir1 <: Outgoing)
|
||||
p1_mom *= -1
|
||||
end
|
||||
p2_mom = p2.momentum
|
||||
if (Dir2 <: Outgoing)
|
||||
p2_mom *= -1
|
||||
end
|
||||
|
||||
p3_mom = p1_mom + p2_mom
|
||||
if (typeof(direction(P3)) <: Incoming)
|
||||
return P3(-p3_mom)
|
||||
end
|
||||
return P3(p3_mom)
|
||||
end
|
||||
|
||||
"""
|
||||
QEDProcessInput <: AbstractProcessInput
|
||||
|
||||
Input for a QED Process. Contains the [`QEDProcessDescription`](@ref) of the process it is an input for, and the values of the in and out particles.
|
||||
|
||||
See also: [`gen_process_input`](@ref)
|
||||
"""
|
||||
struct QEDProcessInput{N1,N2,N3,N4,N5,N6,S1,S2,S3,S4,P1,P2} <: AbstractProcessInput
|
||||
process::QEDProcessDescription
|
||||
inFerms::SVector{N1,FermionStateful{Incoming,S1}}
|
||||
outFerms::SVector{N2,FermionStateful{Outgoing,S2}}
|
||||
inAntiferms::SVector{N3,AntiFermionStateful{Incoming,S3}}
|
||||
outAntiferms::SVector{N4,AntiFermionStateful{Outgoing,S4}}
|
||||
inPhotons::SVector{N5,PhotonStateful{Incoming,P1}}
|
||||
outPhotons::SVector{N6,PhotonStateful{Outgoing,P2}}
|
||||
end
|
||||
|
||||
"""
|
||||
model(::AbstractProcessDescription)
|
||||
|
||||
Return the model of this process description.
|
||||
"""
|
||||
model(::QEDProcessDescription) = QEDModel()
|
||||
model(::QEDProcessInput) = QEDModel()
|
||||
|
||||
function copy(process::QEDProcessDescription)
|
||||
return QEDProcessDescription(copy(process.inParticles), copy(process.outParticles))
|
||||
end
|
||||
|
||||
function ==(p1::QEDProcessDescription, p2::QEDProcessDescription)
|
||||
return p1.inParticles == p2.inParticles && p1.outParticles == p2.outParticles
|
||||
end
|
||||
|
||||
function in_particles(process::QEDProcessDescription)
|
||||
return process.inParticles
|
||||
end
|
||||
|
||||
function out_particles(process::QEDProcessDescription)
|
||||
return process.outParticles
|
||||
end
|
||||
|
||||
function get_particle(
|
||||
input::QEDProcessInput, t::Type{Particle}, n::Int
|
||||
)::Particle where {Particle}
|
||||
if (t <: FermionStateful{Incoming})
|
||||
return input.inFerms[n]
|
||||
elseif (t <: FermionStateful{Outgoing})
|
||||
return input.outFerms[n]
|
||||
elseif (t <: AntiFermionStateful{Incoming})
|
||||
return input.inAntiferms[n]
|
||||
elseif (t <: AntiFermionStateful{Outgoing})
|
||||
return input.outAntiferms[n]
|
||||
elseif (t <: PhotonStateful{Incoming})
|
||||
return input.inPhotons[n]
|
||||
elseif (t <: PhotonStateful{Outgoing})
|
||||
return input.outPhotons[n]
|
||||
end
|
||||
@assert false "Invalid type given"
|
||||
end
|
@ -4,7 +4,7 @@
|
||||
|
||||
A greedy implementation of a scheduler, creating a topological ordering of nodes and naively balancing them onto the different devices.
|
||||
"""
|
||||
struct GreedyScheduler end
|
||||
struct GreedyScheduler <: AbstractScheduler end
|
||||
|
||||
function schedule_dag(::GreedyScheduler, graph::DAG, machine::Machine)
|
||||
nodeQueue = PriorityQueue{Node, Int}()
|
||||
|
@ -1,10 +1,10 @@
|
||||
|
||||
"""
|
||||
Scheduler
|
||||
AbstractScheduler
|
||||
|
||||
Abstract base type for scheduler implementations. The scheduler is used to assign each node to a device and create a topological ordering of tasks.
|
||||
"""
|
||||
abstract type Scheduler end
|
||||
abstract type AbstractScheduler end
|
||||
|
||||
"""
|
||||
schedule_dag(::Scheduler, ::DAG, ::Machine)
|
||||
|
@ -5,10 +5,11 @@ using StaticArrays
|
||||
|
||||
Type representing a function call with `N` parameters. Contains the function to call, argument symbols, the return symbol and the device to execute on.
|
||||
"""
|
||||
struct FunctionCall{VectorType <: AbstractVector, M}
|
||||
struct FunctionCall{VectorType <: AbstractVector, N}
|
||||
func::Function
|
||||
arguments::VectorType
|
||||
additional_arguments::SVector{M, Any} # additional arguments (as values) for the function call, will be prepended to the other arguments
|
||||
# TODO: this should be a tuple
|
||||
value_arguments::SVector{N, Any} # value arguments for the function call, will be prepended to the other arguments
|
||||
arguments::VectorType # symbols of the inputs to the function call
|
||||
return_symbol::Symbol
|
||||
device::AbstractDevice
|
||||
end
|
||||
|
@ -32,7 +32,7 @@ function get_function_call(
|
||||
inSymbols::AbstractVector,
|
||||
outSymbol::Symbol,
|
||||
) where {CompTask <: AbstractComputeTask}
|
||||
return [FunctionCall(compute, inSymbols, SVector{1, Any}(t), outSymbol, device)]
|
||||
return [FunctionCall(compute, SVector{1, Any}(t), inSymbols, outSymbol, device)]
|
||||
end
|
||||
|
||||
function get_function_call(node::ComputeTaskNode)
|
||||
@ -64,8 +64,8 @@ function get_function_call(node::DataTaskNode)
|
||||
return [
|
||||
FunctionCall(
|
||||
unpack_identity,
|
||||
SVector{1, Symbol}(Symbol(to_var_name(first(children(node)).id))),
|
||||
SVector{0, Any}(),
|
||||
SVector{1, Symbol}(Symbol(to_var_name(first(children(node)).id))),
|
||||
Symbol(to_var_name(node.id)),
|
||||
first(children(node)).device,
|
||||
),
|
||||
@ -77,8 +77,8 @@ function get_init_function_call(node::DataTaskNode, device::AbstractDevice)
|
||||
|
||||
return FunctionCall(
|
||||
unpack_identity,
|
||||
SVector{1, Symbol}(Symbol("$(to_var_name(node.id))_in")),
|
||||
SVector{0, Any}(),
|
||||
SVector{1, Symbol}(Symbol("$(to_var_name(node.id))_in")),
|
||||
Symbol(to_var_name(node.id)),
|
||||
device,
|
||||
)
|
||||
|
@ -3,28 +3,21 @@
|
||||
|
||||
Fallback implementation of the compute function of a compute task, throwing an error.
|
||||
"""
|
||||
function compute(t::AbstractTask, data...)
|
||||
return error("Need to implement compute()")
|
||||
end
|
||||
function compute end
|
||||
|
||||
"""
|
||||
compute_effort(t::AbstractTask)
|
||||
|
||||
Fallback implementation of the compute effort of a task, throwing an error.
|
||||
"""
|
||||
function compute_effort(t::AbstractTask)::Float64
|
||||
# default implementation using compute
|
||||
return error("Need to implement compute_effort()")
|
||||
end
|
||||
function compute_effort end
|
||||
|
||||
"""
|
||||
data(t::AbstractTask)
|
||||
|
||||
Fallback implementation of the data of a task, throwing an error.
|
||||
"""
|
||||
function data(t::AbstractTask)::Float64
|
||||
return error("Need to implement data()")
|
||||
end
|
||||
function data end
|
||||
|
||||
"""
|
||||
compute_effort(t::AbstractDataTask)
|
||||
|
@ -1,3 +1,6 @@
|
||||
using Roots
|
||||
using ForwardDiff
|
||||
|
||||
"""
|
||||
noop()
|
||||
|
||||
@ -249,7 +252,6 @@ end
|
||||
|
||||
first_derivative(func) = x -> ForwardDiff.derivative(func, float(x))
|
||||
|
||||
|
||||
function generate_physical_massive_moms(rng, ss, masses; x0 = 0.1)
|
||||
n = length(masses)
|
||||
massless_moms = generate_physical_massless_moms(rng, ss, n)
|
||||
|
@ -1,10 +0,0 @@
|
||||
[deps]
|
||||
AccurateArithmetic = "22286c92-06ac-501d-9306-4abd417d9753"
|
||||
QEDbase = "10e22c08-3ccb-4172-bfcf-7d7aa3d04d93"
|
||||
QEDprocesses = "46de9c38-1bb3-4547-a1ec-da24d767fdad"
|
||||
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
||||
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
|
||||
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
|
||||
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
|
||||
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
|
||||
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
|
@ -1,5 +1,6 @@
|
||||
using SafeTestsets
|
||||
|
||||
#=
|
||||
@safetestset "Utility Unit Tests " begin
|
||||
include("unit_tests_utility.jl")
|
||||
end
|
||||
@ -18,9 +19,11 @@ end
|
||||
@safetestset "ABC-Model Unit Tests " begin
|
||||
include("unit_tests_abcmodel.jl")
|
||||
end
|
||||
=#
|
||||
@safetestset "QED-Model Unit Tests " begin
|
||||
include("unit_tests_qedmodel.jl")
|
||||
end
|
||||
#=
|
||||
@safetestset "QED Feynman Diagram Generation Tests" begin
|
||||
include("unit_tests_qed_diagrams.jl")
|
||||
end
|
||||
@ -39,3 +42,4 @@ end
|
||||
@safetestset "Known Graph Tests " begin
|
||||
include("known_graphs.jl")
|
||||
end
|
||||
=#
|
@ -22,7 +22,7 @@ trident = ("Trident", parse_process("ke->epe", model), 8)
|
||||
|
||||
n_particles = 0
|
||||
for type in types(model)
|
||||
if (isincoming(type))
|
||||
if (is_incoming(type))
|
||||
n_particles += get(process.inParticles, type, 0)
|
||||
else
|
||||
n_particles += get(process.outParticles, type, 0)
|
||||
|
@ -1,5 +1,6 @@
|
||||
using MetagraphOptimization
|
||||
using QEDbase
|
||||
using QEDcore
|
||||
using QEDprocesses
|
||||
using StatsBase # for countmap
|
||||
using Random
|
||||
@ -9,8 +10,6 @@ import MetagraphOptimization.caninteract
|
||||
import MetagraphOptimization.issame
|
||||
import MetagraphOptimization.interaction_result
|
||||
import MetagraphOptimization.propagation_result
|
||||
import MetagraphOptimization.direction
|
||||
import MetagraphOptimization.spin_or_pol
|
||||
import MetagraphOptimization.QED_vertex
|
||||
|
||||
def_momentum = SFourMomentum(1.0, 0.0, 0.0, 0.0)
|
||||
@ -18,32 +17,32 @@ def_momentum = SFourMomentum(1.0, 0.0, 0.0, 0.0)
|
||||
RNG = Random.MersenneTwister(0)
|
||||
|
||||
testparticleTypes = [
|
||||
PhotonStateful{Incoming,PolX},
|
||||
PhotonStateful{Outgoing,PolX},
|
||||
FermionStateful{Incoming,SpinUp},
|
||||
FermionStateful{Outgoing,SpinUp},
|
||||
AntiFermionStateful{Incoming,SpinUp},
|
||||
AntiFermionStateful{Outgoing,SpinUp},
|
||||
ParticleStateful{Incoming, Photon, SFourMomentum},
|
||||
ParticleStateful{Outgoing, Photon, SFourMomentum},
|
||||
ParticleStateful{Incoming, Electron, SFourMomentum},
|
||||
ParticleStateful{Outgoing, Electron, SFourMomentum},
|
||||
ParticleStateful{Incoming, Positron, SFourMomentum},
|
||||
ParticleStateful{Outgoing, Positron, SFourMomentum},
|
||||
]
|
||||
|
||||
testparticleTypesPropagated = [
|
||||
PhotonStateful{Outgoing,PolX},
|
||||
PhotonStateful{Incoming,PolX},
|
||||
FermionStateful{Outgoing,SpinUp},
|
||||
FermionStateful{Incoming,SpinUp},
|
||||
AntiFermionStateful{Outgoing,SpinUp},
|
||||
AntiFermionStateful{Incoming,SpinUp},
|
||||
ParticleStateful{Outgoing, Photon, SFourMomentum},
|
||||
ParticleStateful{Incoming, Photon, SFourMomentum},
|
||||
ParticleStateful{Outgoing, Electron, SFourMomentum},
|
||||
ParticleStateful{Incoming, Electron, SFourMomentum},
|
||||
ParticleStateful{Outgoing, Positron, SFourMomentum},
|
||||
ParticleStateful{Incoming, Positron, SFourMomentum},
|
||||
]
|
||||
|
||||
function compton_groundtruth(input::QEDProcessInput)
|
||||
function compton_groundtruth(input::PhaseSpacePoint)
|
||||
# p1k1 -> p2k2
|
||||
# formula: −(ie)^2 (u(p2) slashed(ε1) S(p2 − k1) slashed(ε2) u(p1) + u(p2) slashed(ε2) S(p1 + k1) slashed(ε1) u(p1))
|
||||
|
||||
p1 = input.inFerms[1]
|
||||
p2 = input.outFerms[1]
|
||||
p1 = momentum(psp, Incoming(), 2)
|
||||
p2 = momentum(psp, Outgoing(), 2)
|
||||
|
||||
k1 = input.inPhotons[1]
|
||||
k2 = input.outPhotons[1]
|
||||
k1 = momentum(psp, Incoming(), 1)
|
||||
k2 = momentum(psp, Outgoing(), 1)
|
||||
|
||||
u_p1 = base_state(Electron(), Incoming(), p1.momentum, spin_or_pol(p1))
|
||||
u_p2 = base_state(Electron(), Outgoing(), p2.momentum, spin_or_pol(p2))
|
||||
@ -87,26 +86,22 @@ end
|
||||
@test issame(typeof(resultParticle), interaction_result(p1, p2))
|
||||
|
||||
totalMom = zero(SFourMomentum)
|
||||
for (p, mom) in [
|
||||
(p1, testParticle1.momentum),
|
||||
(p2, testParticle2.momentum),
|
||||
(p3, resultParticle.momentum),
|
||||
]
|
||||
if (typeof(direction(p)) <: Incoming)
|
||||
for (p, mom) in [(p1, momentum(testParticle1)), (p2, momentum(testParticle2)), (p3, momentum(resultParticle))]
|
||||
if (typeof(particle_direction(p)) <: Incoming)
|
||||
totalMom += mom
|
||||
else
|
||||
totalMom -= mom
|
||||
end
|
||||
end
|
||||
|
||||
@test isapprox(totalMom, zero(SFourMomentum); atol=sqrt(eps()))
|
||||
@test isapprox(totalMom, zero(SFourMomentum); atol = sqrt(eps()))
|
||||
end
|
||||
end
|
||||
|
||||
@testset "Propagation Result" begin
|
||||
for (p, propResult) in zip(testparticleTypes, testparticleTypesPropagated)
|
||||
@test issame(propagation_result(p), propResult)
|
||||
@test direction(propagation_result(p)(def_momentum)) != direction(p(def_momentum))
|
||||
@test particle_direction(propagation_result(p)(def_momentum)) != particle_direction(p(def_momentum))
|
||||
end
|
||||
end
|
||||
|
||||
@ -116,64 +111,27 @@ end
|
||||
@test parse_process("ke->ke", QEDModel()) == parse_process("ek->ek", QEDModel())
|
||||
@test parse_process("ke->ke", QEDModel()) == parse_process("ke->ek", QEDModel())
|
||||
|
||||
@test parse_process("kkke->eep", QEDModel()) ==
|
||||
parse_process("kkek->epe", QEDModel())
|
||||
@test parse_process("kkke->eep", QEDModel()) == parse_process("kkek->epe", QEDModel())
|
||||
end
|
||||
|
||||
@testset "Known processes" begin
|
||||
compton_process = QEDProcessDescription(
|
||||
Dict{Type,Int}(
|
||||
PhotonStateful{Incoming,PolX} => 1, FermionStateful{Incoming,SpinUp} => 1
|
||||
),
|
||||
Dict{Type,Int}(
|
||||
PhotonStateful{Outgoing,PolX} => 1, FermionStateful{Outgoing,SpinUp} => 1
|
||||
),
|
||||
)
|
||||
compton_process = GenericQEDProcess(1, 1, 1, 1, 0, 0)
|
||||
|
||||
@test parse_process("ke->ke", QEDModel()) == compton_process
|
||||
|
||||
positron_compton_process = QEDProcessDescription(
|
||||
Dict{Type,Int}(
|
||||
PhotonStateful{Incoming,PolX} => 1,
|
||||
AntiFermionStateful{Incoming,SpinUp} => 1,
|
||||
),
|
||||
Dict{Type,Int}(
|
||||
PhotonStateful{Outgoing,PolX} => 1,
|
||||
AntiFermionStateful{Outgoing,SpinUp} => 1,
|
||||
),
|
||||
)
|
||||
positron_compton_process = GenericQEDProcess(1, 1, 0, 0, 1, 1)
|
||||
|
||||
@test parse_process("kp->kp", QEDModel()) == positron_compton_process
|
||||
|
||||
trident_process = QEDProcessDescription(
|
||||
Dict{Type,Int}(
|
||||
PhotonStateful{Incoming,PolX} => 1, FermionStateful{Incoming,SpinUp} => 1
|
||||
),
|
||||
Dict{Type,Int}(
|
||||
FermionStateful{Outgoing,SpinUp} => 2,
|
||||
AntiFermionStateful{Outgoing,SpinUp} => 1,
|
||||
),
|
||||
)
|
||||
trident_process = GenericQEDProcess(1, 0, 1, 2, 0, 1)
|
||||
|
||||
@test parse_process("ke->eep", QEDModel()) == trident_process
|
||||
|
||||
pair_production_process = QEDProcessDescription(
|
||||
Dict{Type,Int}(PhotonStateful{Incoming,PolX} => 2),
|
||||
Dict{Type,Int}(
|
||||
FermionStateful{Outgoing,SpinUp} => 1,
|
||||
AntiFermionStateful{Outgoing,SpinUp} => 1,
|
||||
),
|
||||
)
|
||||
pair_production_process = GenericQEDProcess(2, 0, 0, 1, 0, 1)
|
||||
|
||||
@test parse_process("kk->pe", QEDModel()) == pair_production_process
|
||||
|
||||
pair_annihilation_process = QEDProcessDescription(
|
||||
Dict{Type,Int}(
|
||||
FermionStateful{Incoming,SpinUp} => 1,
|
||||
AntiFermionStateful{Incoming,SpinUp} => 1,
|
||||
),
|
||||
Dict{Type,Int}(PhotonStateful{Outgoing,PolX} => 2),
|
||||
)
|
||||
pair_annihilation_process = GenericQEDProcess(0, 2, 1, 0, 1, 0)
|
||||
|
||||
@test parse_process("pe->kk", QEDModel()) == pair_annihilation_process
|
||||
end
|
||||
@ -187,17 +145,17 @@ end
|
||||
for i in 1:100
|
||||
input = gen_process_input(process)
|
||||
@test length(input.inFerms) ==
|
||||
get(process.inParticles, FermionStateful{Incoming,SpinUp}, 0)
|
||||
get(process.inParticles, ParticleStateful{Incoming, Electron, SFourMomentum}, 0)
|
||||
@test length(input.inAntiferms) ==
|
||||
get(process.inParticles, AntiFermionStateful{Incoming,SpinUp}, 0)
|
||||
get(process.inParticles, ParticleStateful{Incoming, Positron, SFourMomentum}, 0)
|
||||
@test length(input.inPhotons) ==
|
||||
get(process.inParticles, PhotonStateful{Incoming,PolX}, 0)
|
||||
get(process.inParticles, ParticleStateful{Incoming, Photon, SFourMomentum}, 0)
|
||||
@test length(input.outFerms) ==
|
||||
get(process.outParticles, FermionStateful{Outgoing,SpinUp}, 0)
|
||||
get(process.outParticles, ParticleStateful{Outgoing, Electron, SFourMomentum}, 0)
|
||||
@test length(input.outAntiferms) ==
|
||||
get(process.outParticles, AntiFermionStateful{Outgoing,SpinUp}, 0)
|
||||
get(process.outParticles, ParticleStateful{Outgoing, Positron, SFourMomentum}, 0)
|
||||
@test length(input.outPhotons) ==
|
||||
get(process.outParticles, PhotonStateful{Outgoing,PolX}, 0)
|
||||
get(process.outParticles, ParticleStateful{Outgoing, Photon, SFourMomentum}, 0)
|
||||
|
||||
@test isapprox(
|
||||
sum([
|
||||
@ -210,12 +168,13 @@ end
|
||||
getfield.(input.outAntiferms, :momentum)...,
|
||||
getfield.(input.outPhotons, :momentum)...,
|
||||
]);
|
||||
atol=sqrt(eps()),
|
||||
atol = sqrt(eps()),
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#=
|
||||
@testset "Compton" begin
|
||||
import MetagraphOptimization.insert_node!
|
||||
import MetagraphOptimization.insert_edge!
|
||||
@ -381,3 +340,4 @@ end
|
||||
@test isapprox(compute_function.(input), reduced_compute_function.(input))
|
||||
end
|
||||
end
|
||||
=#
|
Loading…
x
Reference in New Issue
Block a user