Congruent incoming photons implementation (#11)
Co-authored-by: Rubydragon <anton.reinhard@proton.me> Reviewed-on: #11
This commit is contained in:
parent
1b4ba285c3
commit
e29622c8f1
10
Project.toml
10
Project.toml
@ -14,16 +14,22 @@ JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899"
|
||||
KernelAbstractions = "63c18a36-062a-441e-b654-da1e3ab1ce7c"
|
||||
NumaAllocators = "21436f30-1b4a-4f08-87af-e26101bb5379"
|
||||
QEDbase = "10e22c08-3ccb-4172-bfcf-7d7aa3d04d93"
|
||||
QEDcore = "35dc0263-cb5f-4c33-a114-1d7f54ab753e"
|
||||
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"]
|
||||
|
194
examples/congruent_in_ph.jl
Normal file
194
examples/congruent_in_ph.jl
Normal file
@ -0,0 +1,194 @@
|
||||
ENV["UCX_ERROR_SIGNALS"] = "SIGILL,SIGBUS,SIGFPE"
|
||||
|
||||
using MetagraphOptimization
|
||||
using QEDbase
|
||||
using QEDcore
|
||||
using QEDprocesses
|
||||
using Random
|
||||
using UUIDs
|
||||
|
||||
using CUDA
|
||||
|
||||
using NamedDims
|
||||
using CSV
|
||||
using JLD2
|
||||
using FlexiMaps
|
||||
|
||||
RNG = Random.MersenneTwister(123)
|
||||
|
||||
function mock_machine()
|
||||
return Machine(
|
||||
[
|
||||
MetagraphOptimization.NumaNode(
|
||||
0,
|
||||
1,
|
||||
MetagraphOptimization.default_strategy(MetagraphOptimization.NumaNode),
|
||||
-1.0,
|
||||
UUIDs.uuid1(),
|
||||
),
|
||||
],
|
||||
[-1.0;;],
|
||||
)
|
||||
end
|
||||
|
||||
function congruent_input_momenta(processDescription::GenericQEDProcess, omega::Number)
|
||||
# generate an input sample for given e + nk -> e' + k' process, where the nk are equal
|
||||
inputMasses = Vector{Float64}()
|
||||
for particle in incoming_particles(processDescription)
|
||||
push!(inputMasses, mass(particle))
|
||||
end
|
||||
outputMasses = Vector{Float64}()
|
||||
for particle in outgoing_particles(processDescription)
|
||||
push!(outputMasses, mass(particle))
|
||||
end
|
||||
|
||||
initial_momenta = [
|
||||
i == length(inputMasses) ? SFourMomentum(1, 0, 0, 0) : SFourMomentum(omega, 0, 0, omega) for
|
||||
i in 1:length(inputMasses)
|
||||
]
|
||||
|
||||
ss = sqrt(sum(initial_momenta) * sum(initial_momenta))
|
||||
final_momenta = MetagraphOptimization.generate_physical_massive_moms(RNG, ss, outputMasses)
|
||||
|
||||
return (tuple(initial_momenta...), tuple(final_momenta...))
|
||||
end
|
||||
|
||||
# theta ∈ [0, 2π] and phi ∈ [0, 2π]
|
||||
function congruent_input_momenta_scenario_2(
|
||||
processDescription::GenericQEDProcess,
|
||||
omega::Number,
|
||||
theta::Number,
|
||||
phi::Number,
|
||||
)
|
||||
# -------------
|
||||
# same as above
|
||||
|
||||
# generate an input sample for given e + nk -> e' + k' process, where the nk are equal
|
||||
inputMasses = Vector{Float64}()
|
||||
for particle in incoming_particles(processDescription)
|
||||
push!(inputMasses, mass(particle))
|
||||
end
|
||||
outputMasses = Vector{Float64}()
|
||||
for particle in outgoing_particles(processDescription)
|
||||
push!(outputMasses, mass(particle))
|
||||
end
|
||||
|
||||
initial_momenta = [
|
||||
i == length(inputMasses) ? SFourMomentum(1, 0, 0, 0) : SFourMomentum(omega, 0, 0, omega) for
|
||||
i in 1:length(inputMasses)
|
||||
]
|
||||
|
||||
ss = sqrt(sum(initial_momenta) * sum(initial_momenta))
|
||||
|
||||
# up to here
|
||||
# ----------
|
||||
|
||||
# now calculate the final_momenta from omega, cos_theta and phi
|
||||
n = number_particles(processDescription, Incoming(), Photon())
|
||||
|
||||
cos_theta = cos(theta)
|
||||
omega_prime = (n * omega) / (1 + n * omega * (1 - cos_theta))
|
||||
|
||||
k_prime =
|
||||
omega_prime * SFourMomentum(1, sqrt(1 - cos_theta^2) * cos(phi), sqrt(1 - cos_theta^2) * sin(phi), cos_theta)
|
||||
p_prime = sum(initial_momenta) - k_prime
|
||||
|
||||
final_momenta = (k_prime, p_prime)
|
||||
|
||||
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
|
||||
|
||||
# hack to fix stacksize for threading
|
||||
with_stacksize(f, n) = fetch(schedule(Task(f, n)))
|
||||
|
||||
# scenario 2
|
||||
N = 1024 # thetas
|
||||
M = 1024 # phis
|
||||
K = 64 # omegas
|
||||
|
||||
thetas = collect(LinRange(0, 2π, N))
|
||||
phis = collect(LinRange(0, 2π, M))
|
||||
omegas = collect(maprange(log, 2e-2, 2e-7, K))
|
||||
|
||||
for photons in 1:5
|
||||
# temp process to generate momenta
|
||||
println("Generating $(K*N*M) inputs for $photons photons (Scenario 2 grid walk)...")
|
||||
temp_process = parse_process("k"^photons * "e->ke", QEDModel(), PolX(), SpinUp(), PolX(), SpinUp())
|
||||
|
||||
input_momenta =
|
||||
Array{typeof(congruent_input_momenta_scenario_2(temp_process, omegas[1], thetas[1], phis[1]))}(undef, (K, N, M))
|
||||
|
||||
Threads.@threads for k in 1:K
|
||||
Threads.@threads for i in 1:N
|
||||
Threads.@threads for j in 1:M
|
||||
input_momenta[k, i, j] = congruent_input_momenta_scenario_2(temp_process, omegas[k], thetas[i], phis[j])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
cu_results = CuArray{Float64}(undef, size(input_momenta))
|
||||
fill!(cu_results, 0.0)
|
||||
|
||||
i = 1
|
||||
for (in_pol, in_spin, out_pol, out_spin) in
|
||||
Iterators.product([PolX(), PolY()], [SpinUp(), SpinDown()], [PolX(), PolY()], [SpinUp(), SpinDown()])
|
||||
|
||||
print(
|
||||
"[$i/16] 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 = Array{typeof(build_psp(process, input_momenta[1, 1, 1]))}(undef, (K, N, M))
|
||||
#println("input_momenta: $input_momenta")
|
||||
Threads.@threads for k in 1:K
|
||||
Threads.@threads for i in 1:N
|
||||
Threads.@threads for j in 1:M
|
||||
inputs[k, i, j] = build_psp(process, input_momenta[k, i, j])
|
||||
end
|
||||
end
|
||||
end
|
||||
cu_inputs = CuArray(inputs)
|
||||
|
||||
print("Preparing graph... ")
|
||||
graph = gen_graph(process)
|
||||
optimize_to_fixpoint!(ReductionOptimizer(), graph)
|
||||
print("Preparing function... ")
|
||||
kernel! = get_cuda_kernel(graph, process, mock_machine())
|
||||
#func = get_compute_function(graph, process, mock_machine())
|
||||
|
||||
print("Calculating... ")
|
||||
ts = 32
|
||||
bs = Int64(length(cu_inputs) / 32)
|
||||
|
||||
outputs = CuArray{ComplexF64}(undef, size(cu_inputs))
|
||||
|
||||
@cuda threads = ts blocks = bs always_inline = true kernel!(cu_inputs, outputs, length(cu_inputs))
|
||||
CUDA.device_synchronize()
|
||||
cu_results += abs2.(outputs)
|
||||
|
||||
println("Done.")
|
||||
i += 1
|
||||
end
|
||||
|
||||
println("Writing results")
|
||||
|
||||
out_ph_moms = getindex.(getindex.(input_momenta, 2), 1)
|
||||
out_el_moms = getindex.(getindex.(input_momenta, 2), 2)
|
||||
|
||||
results = NamedDimsArray{(:omegas, :thetas, :phis)}(Array(cu_results))
|
||||
println("Named results array: $(typeof(results))")
|
||||
|
||||
@save "$(photons)_congruent_photons_grid.jld2" omegas thetas phis results
|
||||
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,
|
||||
|
@ -6,6 +6,8 @@ A module containing tools to work on DAGs.
|
||||
module MetagraphOptimization
|
||||
|
||||
using QEDbase
|
||||
using QEDcore
|
||||
using QEDprocesses
|
||||
|
||||
# graph types
|
||||
export DAG
|
||||
@ -64,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
|
||||
@ -99,9 +100,6 @@ export ==, in, show, isempty, delete!, length
|
||||
|
||||
export bytes_to_human_readable
|
||||
|
||||
# TODO: this is probably not good
|
||||
import QEDprocesses.compute
|
||||
|
||||
import Base.length
|
||||
import Base.show
|
||||
import Base.==
|
||||
@ -114,6 +112,7 @@ import Base.delete!
|
||||
import Base.insert!
|
||||
import Base.collect
|
||||
|
||||
include("QEDprocesses_patch.jl")
|
||||
|
||||
include("devices/interface.jl")
|
||||
include("task/type.jl")
|
||||
@ -173,22 +172,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")
|
||||
@ -197,7 +200,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")
|
||||
|
25
src/QEDprocesses_patch.jl
Normal file
25
src/QEDprocesses_patch.jl
Normal file
@ -0,0 +1,25 @@
|
||||
# patch QEDprocesses
|
||||
# see issue https://github.com/QEDjl-project/QEDprocesses.jl/issues/77
|
||||
@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
|
@ -1,19 +1,19 @@
|
||||
"""
|
||||
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)...)
|
||||
assignInputs = Expr(:block, tape.inputAssignCode...)
|
||||
code = Expr(:block, expr_from_fc.(tape.computeCode)...)
|
||||
|
||||
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,15 +22,15 @@ 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)...)
|
||||
assignInputs = Expr(:block, tape.inputAssignCode...)
|
||||
code = Expr(:block, expr_from_fc.(tape.computeCode)...)
|
||||
|
||||
functionId = to_var_name(UUIDs.uuid1(rng[1]))
|
||||
@ -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 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
|
||||
|
@ -5,7 +5,7 @@ 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{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
|
||||
|
||||
@ -15,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
|
||||
|
||||
@ -32,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
|
||||
|
||||
@ -48,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
|
||||
@ -79,33 +75,27 @@ end
|
||||
inputSymbols::Dict{String, Vector{Symbol}},
|
||||
instance::AbstractProblemInstance,
|
||||
machine::Machine,
|
||||
problemInputSymbol::Symbol = :input,
|
||||
problemInputSymbol::Symbol = :data_input,
|
||||
)
|
||||
|
||||
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}},
|
||||
instance::AbstractProblemInstance,
|
||||
instance,
|
||||
machine::Machine,
|
||||
problemInputSymbol::Symbol = :input,
|
||||
problemInputSymbol::Symbol = :data_input,
|
||||
)
|
||||
assignInputs = Vector{FunctionCall}()
|
||||
assignInputs = Vector{Expr}()
|
||||
for (name, symbols) in inputSymbols
|
||||
(type, index) = type_index_from_name(model(instance), 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{2, Any}(type, index),
|
||||
SVector{1, Symbol}(problemInputSymbol),
|
||||
symbol,
|
||||
device,
|
||||
Meta.parse(
|
||||
"$(eval(gen_access_expr(device, symbol))) = $(input_expr(instance, name, problemInputSymbol))",
|
||||
),
|
||||
)
|
||||
end
|
||||
@ -121,12 +111,7 @@ 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,
|
||||
instance::AbstractProblemInstance,
|
||||
machine::Machine,
|
||||
scheduler::AbstractScheduler = GreedyScheduler(),
|
||||
)
|
||||
function gen_tape(graph::DAG, instance, machine::Machine, scheduler::AbstractScheduler = GreedyScheduler())
|
||||
schedule = schedule_dag(scheduler, graph, machine)
|
||||
|
||||
# get inSymbols
|
||||
@ -143,9 +128,9 @@ function gen_tape(
|
||||
outSym = Symbol(to_var_name(get_exit_node(graph).id))
|
||||
|
||||
initCaches = gen_cache_init_code(machine)
|
||||
assignInputs = gen_input_assignment_code(inputSyms, instance, machine, :input)
|
||||
assignInputs = gen_input_assignment_code(inputSyms, instance, machine, :data_input)
|
||||
|
||||
return Tape(initCaches, assignInputs, schedule, inputSyms, outSym, Dict(), instance, machine)
|
||||
return Tape{input_type(instance)}(initCaches, assignInputs, schedule, inputSyms, outSym, Dict(), instance, machine)
|
||||
end
|
||||
|
||||
"""
|
||||
@ -157,7 +142,7 @@ For implementation reasons, this disregards the set [`CacheStrategy`](@ref) of t
|
||||
"""
|
||||
function execute_tape(tape::Tape, input)
|
||||
cache = Dict{Symbol, Any}()
|
||||
cache[:input] = input
|
||||
cache[:data_input] = input
|
||||
# simply execute all the code snippets here
|
||||
@assert typeof(input) == input_type(tape.instance)
|
||||
# TODO: `@assert` that input fits the tape.instance
|
||||
|
@ -3,17 +3,19 @@
|
||||
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{INPUT}
|
||||
initCachesCode::Vector{Expr}
|
||||
inputAssignCode::Vector{FunctionCall}
|
||||
inputAssignCode::Vector{Expr}
|
||||
computeCode::Vector{FunctionCall}
|
||||
inputSymbols::Dict{String, Vector{Symbol}}
|
||||
outputSymbol::Symbol
|
||||
cache::Dict{Symbol, Any}
|
||||
instance::AbstractProblemInstance
|
||||
instance::Any
|
||||
machine::Machine
|
||||
end
|
||||
|
@ -39,8 +39,8 @@ Generate the [`DAG`](@ref) for the given [`AbstractProblemInstance`](@ref). Ever
|
||||
function graph end
|
||||
|
||||
"""
|
||||
input_expr(::AbstractProblemInstance, input_sym::Symbol, name::String)
|
||||
input_expr(instance::AbstractProblemInstance, name::String, input_symbol::Symbol)
|
||||
|
||||
For a given [`AbstractProblemInstance`](@ref), a `Symbol` on which the problem input is available (see [`input_type`](@ref)), and entry node name, return an `Expr` getting that specific input value from the
|
||||
For the given [`AbstractProblemInstance`](@ref), the entry node name, and the symbol of the problem input (where a variable of type `input_type(...)` will exist), return an `Expr` that gets that specific input value from the input symbol.
|
||||
"""
|
||||
function input_expr end
|
||||
|
@ -1,4 +1,3 @@
|
||||
import QEDbase.mass
|
||||
import QEDbase.AbstractParticle
|
||||
|
||||
"""
|
||||
@ -9,17 +8,28 @@ Base type for a model, e.g. ABC-Model or QED. This is used to dispatch many func
|
||||
abstract type AbstractPhysicsModel <: AbstractModel end
|
||||
|
||||
"""
|
||||
ParticleValue{ParticleType <: AbstractParticle}
|
||||
ParticleValue{ParticleType <: AbstractParticleStateful}
|
||||
|
||||
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.
|
||||
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 <: AbstractParticle, ValueType}
|
||||
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
|
||||
|
||||
@ -30,6 +40,7 @@ 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
|
||||
|
||||
|
@ -1,23 +1,40 @@
|
||||
using StaticArrays
|
||||
|
||||
"""
|
||||
compute(::ComputeTaskQED_P, data::QEDParticleValue)
|
||||
construction_string(::Incoming) = "Incoming()"
|
||||
construction_string(::Outgoing) = "Outgoing()"
|
||||
|
||||
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))
|
||||
construction_string(::Electron) = "Electron()"
|
||||
construction_string(::Positron) = "Positron()"
|
||||
construction_string(::Photon) = "Photon()"
|
||||
|
||||
construction_string(::PolX) = "PolX()"
|
||||
construction_string(::PolY) = "PolY()"
|
||||
construction_string(::SpinUp) = "SpinUp()"
|
||||
construction_string(::SpinDown) = "SpinDown()"
|
||||
|
||||
function input_expr(instance::GenericQEDProcess, name::String, psp_symbol::Symbol)
|
||||
(type, index) = type_index_from_name(QEDModel(), name)
|
||||
|
||||
return Meta.parse(
|
||||
"ParticleValueSP(
|
||||
$type(momentum($psp_symbol, $(construction_string(particle_direction(type))), $(construction_string(particle_species(type))), Val($index))),
|
||||
0.0im,
|
||||
$(construction_string(spin_or_pol(instance, 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}}
|
||||
function compute(
|
||||
::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))
|
||||
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
|
||||
@ -25,15 +42,15 @@ function compute(::ComputeTaskQED_U, data::PV) where {P <: QEDParticle, PV <: QE
|
||||
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}}
|
||||
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()
|
||||
@ -53,7 +70,7 @@ function compute(
|
||||
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).
|
||||
|
||||
@ -63,9 +80,19 @@ For valid inputs, both input particles should have the same momenta at this poin
|
||||
"""
|
||||
function compute(
|
||||
::ComputeTaskQED_S2,
|
||||
data1::ParticleValue{P1},
|
||||
data2::ParticleValue{P2},
|
||||
) where {P1 <: Union{AntiFermionStateful, FermionStateful}, P2 <: Union{AntiFermionStateful, FermionStateful}}
|
||||
data1::ParticleValue{P1, V1},
|
||||
data2::ParticleValue{P2, V2},
|
||||
) where {
|
||||
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)"
|
||||
|
||||
inner = QED_inner_edge(propagation_result(P1)(momentum(data1.p)))
|
||||
@ -80,9 +107,9 @@ end
|
||||
|
||||
function compute(
|
||||
::ComputeTaskQED_S2,
|
||||
data1::ParticleValue{P1},
|
||||
data2::ParticleValue{P2},
|
||||
) where {P1 <: PhotonStateful, P2 <: PhotonStateful}
|
||||
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
|
||||
@ -90,11 +117,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
|
||||
|
@ -1,83 +1,58 @@
|
||||
|
||||
ComputeTaskQED_Sum() = ComputeTaskQED_Sum(0)
|
||||
|
||||
function _svector_from_type(processDescription::QEDProcessDescription, type, particles)
|
||||
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
|
||||
return SVector{0, type}()
|
||||
end
|
||||
|
||||
"""
|
||||
gen_process_input(processDescription::QEDProcessDescription)
|
||||
gen_process_input(processDescription::GenericQEDProcess)
|
||||
|
||||
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).
|
||||
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::QEDProcessDescription)
|
||||
function gen_process_input(processDescription::GenericQEDProcess)
|
||||
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
|
||||
|
||||
# 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
|
||||
|
||||
initial_momenta = generate_initial_moms(massSum, inputMasses)
|
||||
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)
|
||||
processInput = PhaseSpacePoint(
|
||||
processDescription,
|
||||
PerturbativeQED(),
|
||||
PhasespaceDefinition(SphericalCoordinateSystem(), ElectronRestFrame()),
|
||||
tuple(initial_momenta...),
|
||||
tuple(final_momenta...),
|
||||
)
|
||||
|
||||
return processInput
|
||||
end
|
||||
|
||||
"""
|
||||
gen_graph(process_description::QEDProcessDescription)
|
||||
gen_graph(process_description::GenericQEDProcess)
|
||||
|
||||
For a given [`QEDProcessDescription`](@ref), return the [`DAG`](@ref) that computes it.
|
||||
For a given [`GenericQEDProcess`](@ref), return the [`DAG`](@ref) that computes it.
|
||||
"""
|
||||
function gen_graph(process_description::QEDProcessDescription)
|
||||
function gen_graph(process_description::GenericQEDProcess)
|
||||
initial_diagram = FeynmanDiagram(process_description)
|
||||
diagrams = gen_diagrams(initial_diagram)
|
||||
|
||||
@ -88,9 +63,9 @@ function gen_graph(process_description::QEDProcessDescription)
|
||||
|
||||
# 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)
|
||||
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()
|
||||
@ -99,16 +74,16 @@ function gen_graph(process_description::QEDProcessDescription)
|
||||
# generate data in and U tasks
|
||||
data_in = insert_node!(
|
||||
graph,
|
||||
make_node(DataTask(PARTICLE_VALUE_SIZE), String(particle)),
|
||||
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
|
||||
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_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)
|
||||
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
|
||||
@ -124,19 +99,19 @@ function gen_graph(process_description::QEDProcessDescription)
|
||||
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
|
||||
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)
|
||||
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)),
|
||||
make_node(DataTask(PARTICLE_VALUE_SIZE));
|
||||
track = false,
|
||||
invalidate_cache = false,
|
||||
)
|
||||
|
||||
insert_edge!(graph, compute_V, data_V_out, 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
|
||||
@ -146,18 +121,18 @@ function gen_graph(process_description::QEDProcessDescription)
|
||||
|
||||
# otherwise, add S1 task
|
||||
compute_S1 =
|
||||
insert_node!(graph, make_node(ComputeTaskQED_S1()), track = false, invalidate_cache = false) # compute propagator
|
||||
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)
|
||||
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)),
|
||||
make_node(DataTask(PARTICLE_VALUE_SIZE));
|
||||
track = false,
|
||||
invalidate_cache = false,
|
||||
)
|
||||
|
||||
insert_edge!(graph, compute_S1, data_S1_out, 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
|
||||
@ -168,16 +143,16 @@ function gen_graph(process_description::QEDProcessDescription)
|
||||
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)
|
||||
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)
|
||||
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, 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, compute_S2, data_S2; track = false, invalidate_cache = false)
|
||||
|
||||
insert_edge!(graph, data_S2, sum_node, track = false, invalidate_cache = false)
|
||||
insert_edge!(graph, data_S2, sum_node; track = false, invalidate_cache = false)
|
||||
add_child!(task(sum_node))
|
||||
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
|
||||
|
||||
@ -51,31 +51,21 @@ struct FeynmanDiagram
|
||||
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
|
||||
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)
|
||||
for type in types(model(pd))
|
||||
for i in 1:number_particles(pd, type)
|
||||
push!(parts, FeynmanParticle(type, i))
|
||||
end
|
||||
ids[type] = number_particles(pd, type)
|
||||
end
|
||||
|
||||
return FeynmanDiagram([], missing, parts, ids)
|
||||
@ -83,7 +73,7 @@ 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
|
||||
@ -114,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)
|
||||
@ -162,15 +152,16 @@ function ==(d1::FeynmanDiagram, d2::FeynmanDiagram)
|
||||
)=#
|
||||
end
|
||||
|
||||
copy(fd::FeynmanDiagram) =
|
||||
FeynmanDiagram(deepcopy(fd.vertices), copy(fd.tie[]), deepcopy(fd.particles), copy(fd.type_ids))
|
||||
function copy(fd::FeynmanDiagram)
|
||||
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
|
||||
|
||||
@ -439,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, SpinUp}] == 1 &&
|
||||
fd.type_ids[FermionStateful{Outgoing, SpinUp}] == 1 &&
|
||||
fd.type_ids[AntiFermionStateful{Incoming, SpinUp}] == 0 &&
|
||||
fd.type_ids[AntiFermionStateful{Outgoing, SpinUp}] == 0 &&
|
||||
fd.type_ids[PhotonStateful{Incoming, PolX}] >= 1 &&
|
||||
fd.type_ids[PhotonStateful{Outgoing, PolX}] >= 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
|
||||
|
||||
"""
|
||||
@ -460,8 +452,8 @@ 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(
|
||||
@ -469,10 +461,10 @@ function gen_compton_diagram_from_order(order::Vector{Int}, inFerm, outFerm, n::
|
||||
missing,
|
||||
[inFerm, outFerm, photons...],
|
||||
Dict{Type, Int64}(
|
||||
FermionStateful{Incoming, SpinUp} => 1,
|
||||
FermionStateful{Outgoing, SpinUp} => 1,
|
||||
PhotonStateful{Incoming, PolX} => n,
|
||||
PhotonStateful{Outgoing, PolX} => m,
|
||||
ParticleStateful{Incoming, Electron, SFourMomentum} => 1,
|
||||
ParticleStateful{Outgoing, Electron, SFourMomentum} => 1,
|
||||
ParticleStateful{Incoming, Photon, SFourMomentum} => n,
|
||||
ParticleStateful{Outgoing, Photon, SFourMomentum} => m,
|
||||
),
|
||||
)
|
||||
|
||||
@ -484,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)
|
||||
@ -497,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)
|
||||
@ -512,7 +504,6 @@ 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)
|
||||
|
||||
@ -520,8 +511,8 @@ Helper function for [`gen_compton_diagrams`](@Ref). Generates a single diagram f
|
||||
"""
|
||||
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, SFourMomentum}, i) for i in 1:n],
|
||||
[FeynmanParticle(ParticleStateful{Outgoing, Photon, SFourMomentum}, i) for i in 1:m],
|
||||
)
|
||||
|
||||
new_diagram = FeynmanDiagram(
|
||||
@ -529,10 +520,10 @@ function gen_compton_diagram_from_order_one_side(order::Vector{Int}, inFerm, out
|
||||
missing,
|
||||
[inFerm, outFerm, photons...],
|
||||
Dict{Type, Int64}(
|
||||
FermionStateful{Incoming, SpinUp} => 1,
|
||||
FermionStateful{Outgoing, SpinUp} => 1,
|
||||
PhotonStateful{Incoming, PolX} => n,
|
||||
PhotonStateful{Outgoing, PolX} => m,
|
||||
ParticleStateful{Incoming, Electron, SFourMomentum} => 1,
|
||||
ParticleStateful{Outgoing, Electron, SFourMomentum} => 1,
|
||||
ParticleStateful{Incoming, Photon, SFourMomentum} => n,
|
||||
ParticleStateful{Outgoing, Photon, SFourMomentum} => m,
|
||||
),
|
||||
)
|
||||
|
||||
@ -544,9 +535,9 @@ function gen_compton_diagram_from_order_one_side(order::Vector{Int}, inFerm, out
|
||||
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)
|
||||
@ -559,9 +550,9 @@ function gen_compton_diagram_from_order_one_side(order::Vector{Int}, inFerm, out
|
||||
if (iterations == 1)
|
||||
# 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)
|
||||
@ -576,15 +567,14 @@ function gen_compton_diagram_from_order_one_side(order::Vector{Int}, inFerm, out
|
||||
return new_diagram
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
gen_compton_diagrams(n::Int, m::Int)
|
||||
|
||||
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)])...]
|
||||
|
||||
@ -596,15 +586,14 @@ function gen_compton_diagrams(n::Int, m::Int)
|
||||
return vcat(diagrams...)
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
gen_compton_diagrams_one_side(n::Int, m::Int)
|
||||
|
||||
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)])...]
|
||||
|
||||
@ -623,12 +612,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, PolX}],
|
||||
fd.type_ids[PhotonStateful{Outgoing, PolX}],
|
||||
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}()
|
||||
|
||||
@ -667,4 +659,5 @@ function gen_diagrams(fd::FeynmanDiagram)
|
||||
end
|
||||
|
||||
return remove_duplicates(results)
|
||||
=#
|
||||
end
|
||||
|
@ -1,12 +1,28 @@
|
||||
|
||||
# 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)
|
||||
inParticles = Dict{Type, Int}()
|
||||
outParticles = Dict{Type, Int}()
|
||||
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\"")
|
||||
@ -19,14 +35,14 @@ function parse_process(str::AbstractString, model::QEDModel)
|
||||
end
|
||||
|
||||
for t in types(model)
|
||||
if (isincoming(t))
|
||||
if (is_incoming(t))
|
||||
inCount = count(x -> x == String(t)[1], inStr)
|
||||
|
||||
if inCount != 0
|
||||
inParticles[t] = inCount
|
||||
end
|
||||
end
|
||||
if (isoutgoing(t))
|
||||
if (is_outgoing(t))
|
||||
outCount = count(x -> x == String(t)[1], outStr)
|
||||
if outCount != 0
|
||||
outParticles[t] = outCount
|
||||
@ -40,5 +56,14 @@ function parse_process(str::AbstractString, model::QEDModel)
|
||||
throw("Encountered unknown characters in the output part of process \"$str\"")
|
||||
end
|
||||
|
||||
return QEDProcessDescription(inParticles, outParticles)
|
||||
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
|
||||
|
@ -1,8 +1,6 @@
|
||||
using QEDprocesses
|
||||
using StaticArrays
|
||||
import QEDbase.mass
|
||||
|
||||
# TODO check
|
||||
const e = sqrt(4π / 137)
|
||||
|
||||
"""
|
||||
@ -12,123 +10,181 @@ Singleton definition for identification of the QED-Model.
|
||||
"""
|
||||
struct QEDModel <: AbstractPhysicsModel end
|
||||
|
||||
"""
|
||||
QEDParticle
|
||||
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
|
||||
|
||||
Base type for all particles in the [`QEDModel`](@ref).
|
||||
QEDbase.particle_direction(::Type{<:ParticleStateful{DIR}}) where {DIR <: ParticleDirection} = DIR()
|
||||
QEDbase.particle_species(
|
||||
::Type{<:ParticleStateful{DIR, SPECIES}},
|
||||
) where {DIR <: ParticleDirection, SPECIES <: AbstractParticleType} = SPECIES()
|
||||
|
||||
Its template parameter specifies the particle's direction.
|
||||
_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"))
|
||||
|
||||
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
|
||||
struct GenericQEDProcess{INT, OUTT, INSP, OUTSP} <:
|
||||
AbstractProcessDefinition where {INT <: Tuple, OUTT <: Tuple, INSP <: Tuple, OUTSP <: Tuple}
|
||||
incoming_particles::INT
|
||||
outgoing_particles::OUTT
|
||||
|
||||
"""
|
||||
QEDProcessDescription <: AbstractProcessDescription
|
||||
incoming_spins_pols::INSP
|
||||
outgoing_spins_pols::OUTSP
|
||||
|
||||
A description of a process in the QED-Model. Contains the input and output particles.
|
||||
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)
|
||||
|
||||
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}
|
||||
# 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
|
||||
|
||||
QEDParticleValue{ParticleType <: QEDParticle} = Union{
|
||||
ParticleValue{ParticleType, BiSpinor},
|
||||
ParticleValue{ParticleType, AdjointBiSpinor},
|
||||
ParticleValue{ParticleType, DiracMatrix},
|
||||
ParticleValue{ParticleType, SLorentzVector{Float64}},
|
||||
ParticleValue{ParticleType, ComplexF64},
|
||||
}
|
||||
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
|
||||
|
||||
"""
|
||||
PhotonStateful <: QEDParticle
|
||||
if c != 0 || n <= 0
|
||||
throw(InvalidInputError("could not get $n-th spin/pol of $(DIR()) $species, does not exist"))
|
||||
end
|
||||
|
||||
A photon of the [`QEDModel`](@ref) with its state.
|
||||
"""
|
||||
struct PhotonStateful{Direction <: ParticleDirection, Pol <: AbstractDefinitePolarization} <: QEDParticle{Direction}
|
||||
momentum::SFourMomentum
|
||||
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
|
||||
|
||||
PhotonStateful{Direction}(mom::SFourMomentum) where {Direction <: ParticleDirection} =
|
||||
PhotonStateful{Direction, PolX}(mom)
|
||||
QEDprocesses.incoming_particles(proc::GenericQEDProcess) = proc.incoming_particles
|
||||
QEDprocesses.outgoing_particles(proc::GenericQEDProcess) = proc.outgoing_particles
|
||||
|
||||
PhotonStateful{Dir, Pol}(ph::PhotonStateful) where {Dir, Pol} = PhotonStateful{Dir, Pol}(ph.momentum)
|
||||
|
||||
"""
|
||||
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 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
|
||||
|
||||
FermionStateful{Direction}(mom::SFourMomentum) where {Direction <: ParticleDirection} =
|
||||
FermionStateful{Direction, SpinUp}(mom)
|
||||
|
||||
FermionStateful{Dir, Spin}(f::FermionStateful) where {Dir, Spin} = FermionStateful{Dir, Spin}(f.momentum)
|
||||
|
||||
"""
|
||||
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 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
|
||||
|
||||
AntiFermionStateful{Direction}(mom::SFourMomentum) where {Direction <: ParticleDirection} =
|
||||
AntiFermionStateful{Direction, SpinUp}(mom)
|
||||
|
||||
AntiFermionStateful{Dir, Spin}(f::AntiFermionStateful) where {Dir, Spin} = AntiFermionStateful{Dir, Spin}(f.momentum)
|
||||
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 <: QEDParticle, T2 <: QEDParticle}
|
||||
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{FermionStateful{Incoming, Spin1}},
|
||||
::Type{FermionStateful{Outgoing, Spin2}},
|
||||
) where {Spin1, Spin2} = PhotonStateful{Incoming, PolX}
|
||||
::Type{ParticleStateful{Incoming, Electron, EL}},
|
||||
::Type{ParticleStateful{Outgoing, Electron, EL}},
|
||||
) where {EL <: AbstractFourMomentum} = ParticleStateful{Incoming, Photon, EL}
|
||||
interaction_result(
|
||||
::Type{FermionStateful{Incoming, Spin1}},
|
||||
::Type{AntiFermionStateful{Incoming, Spin2}},
|
||||
) where {Spin1, Spin2} = PhotonStateful{Incoming, PolX}
|
||||
interaction_result(::Type{FermionStateful{Incoming, Spin1}}, ::Type{<:PhotonStateful}) where {Spin1} =
|
||||
FermionStateful{Outgoing, SpinUp}
|
||||
::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{FermionStateful{Outgoing, Spin1}},
|
||||
::Type{FermionStateful{Incoming, Spin2}},
|
||||
) where {Spin1, Spin2} = PhotonStateful{Incoming, PolX}
|
||||
::Type{ParticleStateful{Outgoing, Electron, EL}},
|
||||
::Type{ParticleStateful{Incoming, Electron, EL}},
|
||||
) where {EL <: AbstractFourMomentum} = ParticleStateful{Incoming, Photon, EL}
|
||||
interaction_result(
|
||||
::Type{FermionStateful{Outgoing, Spin1}},
|
||||
::Type{AntiFermionStateful{Outgoing, Spin2}},
|
||||
) where {Spin1, Spin2} = PhotonStateful{Incoming, PolX}
|
||||
interaction_result(::Type{FermionStateful{Outgoing, Spin1}}, ::Type{<:PhotonStateful}) where {Spin1} =
|
||||
FermionStateful{Incoming, SpinUp}
|
||||
::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{AntiFermionStateful{Incoming, Spin}}, t2::Type{<:QEDParticle}) where {Spin} =
|
||||
interaction_result(FermionStateful{Outgoing, Spin}, t2)
|
||||
interaction_result(::Type{AntiFermionStateful{Outgoing, Spin}}, t2::Type{<:QEDParticle}) where {Spin} =
|
||||
interaction_result(FermionStateful{Incoming, Spin}, t2)
|
||||
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{<:PhotonStateful}, t2::Type{<:QEDParticle}) = interaction_result(t2, t1)
|
||||
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{<:PhotonStateful}, t2::Type{<:PhotonStateful})
|
||||
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
|
||||
|
||||
@ -137,18 +193,18 @@ end
|
||||
|
||||
Return the type of the inverted direction. E.g.
|
||||
"""
|
||||
propagation_result(::Type{FermionStateful{Incoming, Spin}}) where {Spin <: AbstractDefiniteSpin} =
|
||||
FermionStateful{Outgoing, Spin}
|
||||
propagation_result(::Type{FermionStateful{Outgoing, Spin}}) where {Spin <: AbstractDefiniteSpin} =
|
||||
FermionStateful{Incoming, Spin}
|
||||
propagation_result(::Type{AntiFermionStateful{Incoming, Spin}}) where {Spin <: AbstractDefiniteSpin} =
|
||||
AntiFermionStateful{Outgoing, Spin}
|
||||
propagation_result(::Type{AntiFermionStateful{Outgoing, Spin}}) where {Spin <: AbstractDefiniteSpin} =
|
||||
AntiFermionStateful{Incoming, Spin}
|
||||
propagation_result(::Type{PhotonStateful{Incoming, Pol}}) where {Pol <: AbstractDefinitePolarization} =
|
||||
PhotonStateful{Outgoing, Pol}
|
||||
propagation_result(::Type{PhotonStateful{Outgoing, Pol}}) where {Pol <: AbstractDefinitePolarization} =
|
||||
PhotonStateful{Incoming, Pol}
|
||||
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)
|
||||
@ -157,12 +213,12 @@ Return a Vector of the possible types of particle in the [`QEDModel`](@ref).
|
||||
"""
|
||||
function types(::QEDModel)
|
||||
return [
|
||||
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},
|
||||
]
|
||||
end
|
||||
|
||||
@ -179,94 +235,39 @@ String(::Type{SpinDown}) = "spindown"
|
||||
String(::Incoming) = "i"
|
||||
String(::Outgoing) = "o"
|
||||
|
||||
function String(::Type{<:PhotonStateful})
|
||||
function String(::Type{<:ParticleStateful{DIR, Photon}}) where {DIR <: ParticleDirection}
|
||||
return "k"
|
||||
end
|
||||
function String(::Type{<:FermionStateful})
|
||||
function String(::Type{<:ParticleStateful{DIR, Electron}}) where {DIR <: ParticleDirection}
|
||||
return "e"
|
||||
end
|
||||
function String(::Type{<:AntiFermionStateful})
|
||||
function String(::Type{<:ParticleStateful{DIR, Positron}}) where {DIR <: ParticleDirection}
|
||||
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 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})
|
||||
caninteract(T1::Type{<:ParticleStateful}, T2::Type{<:ParticleStateful})
|
||||
|
||||
For two given [`QEDParticle`](@ref) types, return whether they can interact at a vertex. This is equivalent to `!issame(T1, T2)`.
|
||||
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{<:QEDParticle}, T2::Type{<:QEDParticle})
|
||||
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 (T1 <: PhotonStateful && T2 <: PhotonStateful)
|
||||
if (S1 == Photon && S2 == Photon)
|
||||
return false
|
||||
end
|
||||
|
||||
for (P1, P2) in [(T1, T2), (T2, T1)]
|
||||
if (P1 <: FermionStateful{Incoming} && P2 <: AntiFermionStateful{Outgoing})
|
||||
if (P1 <: ParticleStateful{Incoming, Electron} && P2 <: ParticleStateful{Outgoing, Positron})
|
||||
return false
|
||||
end
|
||||
if (P1 <: FermionStateful{Outgoing} && P2 <: AntiFermionStateful{Incoming})
|
||||
if (P1 <: ParticleStateful{Outgoing, Electron} && P2 <: ParticleStateful{Incoming, Positron})
|
||||
return false
|
||||
end
|
||||
end
|
||||
@ -276,30 +277,30 @@ end
|
||||
|
||||
function type_index_from_name(::QEDModel, name::String)
|
||||
if startswith(name, "ki")
|
||||
return (PhotonStateful{Incoming, PolX}, parse(Int, name[3:end]))
|
||||
return (ParticleStateful{Incoming, Photon, SFourMomentum}, parse(Int, name[3:end]))
|
||||
elseif startswith(name, "ko")
|
||||
return (PhotonStateful{Outgoing, PolX}, parse(Int, name[3:end]))
|
||||
return (ParticleStateful{Outgoing, Photon, SFourMomentum}, parse(Int, name[3:end]))
|
||||
elseif startswith(name, "ei")
|
||||
return (FermionStateful{Incoming, SpinUp}, parse(Int, name[3:end]))
|
||||
return (ParticleStateful{Incoming, Electron, SFourMomentum}, parse(Int, name[3:end]))
|
||||
elseif startswith(name, "eo")
|
||||
return (FermionStateful{Outgoing, SpinUp}, parse(Int, name[3:end]))
|
||||
return (ParticleStateful{Outgoing, Electron, SFourMomentum}, parse(Int, name[3:end]))
|
||||
elseif startswith(name, "pi")
|
||||
return (AntiFermionStateful{Incoming, SpinUp}, parse(Int, name[3:end]))
|
||||
return (ParticleStateful{Incoming, Positron, SFourMomentum}, parse(Int, name[3:end]))
|
||||
elseif startswith(name, "po")
|
||||
return (AntiFermionStateful{Outgoing, SpinUp}, parse(Int, name[3:end]))
|
||||
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{<:QEDParticle}, T2::Type{<:QEDParticle})
|
||||
issame(T1::Type{<:ParticleStateful}, T2::Type{<:ParticleStateful})
|
||||
|
||||
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)`.
|
||||
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{<:QEDParticle}, T2::Type{<:QEDParticle})
|
||||
function issame(T1::Type{<:ParticleStateful}, T2::Type{<:ParticleStateful})
|
||||
return !caninteract(T1, T2)
|
||||
end
|
||||
|
||||
@ -313,12 +314,12 @@ Return the factor of a vertex in a QED feynman diagram.
|
||||
return -1im * e * gamma()
|
||||
end
|
||||
|
||||
@inline function QED_inner_edge(p::QEDParticle)
|
||||
return propagator(particle(p), p.momentum)
|
||||
@inline function QED_inner_edge(p::ParticleStateful)
|
||||
return propagator(particle_species(p), momentum(p))
|
||||
end
|
||||
|
||||
"""
|
||||
QED_conserve_momentum(p1::QEDParticle, p2::QEDParticle)
|
||||
QED_conserve_momentum(p1::ParticleStateful, p2::ParticleStateful)
|
||||
|
||||
Calculate and return a new particle from two given interacting ones at a vertex.
|
||||
"""
|
||||
@ -328,43 +329,26 @@ function QED_conserve_momentum(
|
||||
) 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}},
|
||||
Species1 <: AbstractParticleType,
|
||||
Species2 <: AbstractParticleType,
|
||||
P1 <: ParticleStateful{Dir1, Species1},
|
||||
P2 <: ParticleStateful{Dir2, Species2},
|
||||
}
|
||||
P3 = interaction_result(P1, P2)
|
||||
p1_mom = p1.momentum
|
||||
p1_mom = momentum(p1)
|
||||
if (Dir1 <: Outgoing)
|
||||
p1_mom *= -1
|
||||
end
|
||||
p2_mom = p2.momentum
|
||||
p2_mom = momentum(p2)
|
||||
if (Dir2 <: Outgoing)
|
||||
p2_mom *= -1
|
||||
end
|
||||
|
||||
p3_mom = p1_mom + p2_mom
|
||||
if (typeof(direction(P3)) <: Incoming)
|
||||
return P3(-p3_mom)
|
||||
if (particle_direction(P3) isa Incoming)
|
||||
return ParticleStateful(particle_direction(P3), particle_species(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} <: AbstractProcessInput
|
||||
process::QEDProcessDescription
|
||||
inFerms::SVector{N1, FermionStateful{Incoming, SpinUp}}
|
||||
outFerms::SVector{N2, FermionStateful{Outgoing, SpinUp}}
|
||||
inAntiferms::SVector{N3, AntiFermionStateful{Incoming, SpinUp}}
|
||||
outAntiferms::SVector{N4, AntiFermionStateful{Outgoing, SpinUp}}
|
||||
inPhotons::SVector{N5, PhotonStateful{Incoming, PolX}}
|
||||
outPhotons::SVector{N6, PhotonStateful{Outgoing, PolX}}
|
||||
return ParticleStateful(particle_direction(P3), particle_species(P3), p3_mom)
|
||||
end
|
||||
|
||||
"""
|
||||
@ -372,37 +356,22 @@ end
|
||||
|
||||
Return the model of this process description.
|
||||
"""
|
||||
model(::QEDProcessDescription) = QEDModel()
|
||||
model(::QEDProcessInput) = QEDModel()
|
||||
model(::GenericQEDProcess) = QEDModel()
|
||||
model(::PhaseSpacePoint) = QEDModel()
|
||||
|
||||
function copy(process::QEDProcessDescription)
|
||||
return QEDProcessDescription(copy(process.inParticles), copy(process.outParticles))
|
||||
end
|
||||
|
||||
==(p1::QEDProcessDescription, p2::QEDProcessDescription) =
|
||||
p1.inParticles == p2.inParticles && p1.outParticles == p2.outParticles
|
||||
|
||||
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]
|
||||
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
|
@ -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))
|
||||
@ -57,8 +56,8 @@ function compton_groundtruth(input::QEDProcessInput)
|
||||
virt2_mom = p1.momentum + k1.momentum
|
||||
@test isapprox(p2.momentum + k2.momentum, virt2_mom)
|
||||
|
||||
s_p2_k1 = propagator(Electron(), virt1_mom)
|
||||
s_p1_k1 = propagator(Electron(), virt2_mom)
|
||||
s_p2_k1 = QEDbase.propagator(Electron(), virt1_mom)
|
||||
s_p1_k1 = QEDbase.propagator(Electron(), virt2_mom)
|
||||
|
||||
diagram1 = u_p2 * (eps_1 * QED_vertex()) * s_p2_k1 * (eps_2 * QED_vertex()) * u_p1
|
||||
diagram2 = u_p2 * (eps_2 * QED_vertex()) * s_p1_k1 * (eps_1 * QED_vertex()) * u_p1
|
||||
@ -66,7 +65,6 @@ function compton_groundtruth(input::QEDProcessInput)
|
||||
return diagram1 + diagram2
|
||||
end
|
||||
|
||||
|
||||
@testset "Interaction Result" begin
|
||||
import MetagraphOptimization.QED_conserve_momentum
|
||||
|
||||
@ -88,8 +86,8 @@ 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
|
||||
@ -103,7 +101,7 @@ 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
|
||||
|
||||
@ -117,38 +115,23 @@ end
|
||||
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
|
||||
@ -161,12 +144,18 @@ end
|
||||
|
||||
for i in 1:100
|
||||
input = gen_process_input(process)
|
||||
@test length(input.inFerms) == get(process.inParticles, FermionStateful{Incoming, SpinUp}, 0)
|
||||
@test length(input.inAntiferms) == get(process.inParticles, AntiFermionStateful{Incoming, SpinUp}, 0)
|
||||
@test length(input.inPhotons) == get(process.inParticles, PhotonStateful{Incoming, PolX}, 0)
|
||||
@test length(input.outFerms) == get(process.outParticles, FermionStateful{Outgoing, SpinUp}, 0)
|
||||
@test length(input.outAntiferms) == get(process.outParticles, AntiFermionStateful{Outgoing, SpinUp}, 0)
|
||||
@test length(input.outPhotons) == get(process.outParticles, PhotonStateful{Outgoing, PolX}, 0)
|
||||
@test length(input.inFerms) ==
|
||||
get(process.inParticles, ParticleStateful{Incoming, Electron, SFourMomentum}, 0)
|
||||
@test length(input.inAntiferms) ==
|
||||
get(process.inParticles, ParticleStateful{Incoming, Positron, SFourMomentum}, 0)
|
||||
@test length(input.inPhotons) ==
|
||||
get(process.inParticles, ParticleStateful{Incoming, Photon, SFourMomentum}, 0)
|
||||
@test length(input.outFerms) ==
|
||||
get(process.outParticles, ParticleStateful{Outgoing, Electron, SFourMomentum}, 0)
|
||||
@test length(input.outAntiferms) ==
|
||||
get(process.outParticles, ParticleStateful{Outgoing, Positron, SFourMomentum}, 0)
|
||||
@test length(input.outPhotons) ==
|
||||
get(process.outParticles, ParticleStateful{Outgoing, Photon, SFourMomentum}, 0)
|
||||
|
||||
@test isapprox(
|
||||
sum([
|
||||
@ -185,6 +174,7 @@ end
|
||||
end
|
||||
end
|
||||
|
||||
#=
|
||||
@testset "Compton" begin
|
||||
import MetagraphOptimization.insert_node!
|
||||
import MetagraphOptimization.insert_edge!
|
||||
@ -211,97 +201,97 @@ end
|
||||
graph = DAG()
|
||||
|
||||
# s to output (exit node)
|
||||
d_exit = insert_node!(graph, make_node(DataTask(16)), track = false)
|
||||
d_exit = insert_node!(graph, make_node(DataTask(16)); track=false)
|
||||
|
||||
sum_node = insert_node!(graph, make_node(ComputeTaskQED_Sum(2)), track = false)
|
||||
sum_node = insert_node!(graph, make_node(ComputeTaskQED_Sum(2)); track=false)
|
||||
|
||||
d_s0_sum = insert_node!(graph, make_node(DataTask(16)), track = false)
|
||||
d_s1_sum = insert_node!(graph, make_node(DataTask(16)), track = false)
|
||||
d_s0_sum = insert_node!(graph, make_node(DataTask(16)); track=false)
|
||||
d_s1_sum = insert_node!(graph, make_node(DataTask(16)); track=false)
|
||||
|
||||
# final s compute
|
||||
s0 = insert_node!(graph, make_node(ComputeTaskQED_S2()), track = false)
|
||||
s1 = insert_node!(graph, make_node(ComputeTaskQED_S2()), track = false)
|
||||
s0 = insert_node!(graph, make_node(ComputeTaskQED_S2()); track=false)
|
||||
s1 = insert_node!(graph, make_node(ComputeTaskQED_S2()); track=false)
|
||||
|
||||
# data from v0 and v1 to s0
|
||||
d_v0_s0 = insert_node!(graph, make_node(DataTask(96)), track = false)
|
||||
d_v1_s0 = insert_node!(graph, make_node(DataTask(96)), track = false)
|
||||
d_v2_s1 = insert_node!(graph, make_node(DataTask(96)), track = false)
|
||||
d_v3_s1 = insert_node!(graph, make_node(DataTask(96)), track = false)
|
||||
d_v0_s0 = insert_node!(graph, make_node(DataTask(96)); track=false)
|
||||
d_v1_s0 = insert_node!(graph, make_node(DataTask(96)); track=false)
|
||||
d_v2_s1 = insert_node!(graph, make_node(DataTask(96)); track=false)
|
||||
d_v3_s1 = insert_node!(graph, make_node(DataTask(96)); track=false)
|
||||
|
||||
# v0 and v1 compute
|
||||
v0 = insert_node!(graph, make_node(ComputeTaskQED_V()), track = false)
|
||||
v1 = insert_node!(graph, make_node(ComputeTaskQED_V()), track = false)
|
||||
v2 = insert_node!(graph, make_node(ComputeTaskQED_V()), track = false)
|
||||
v3 = insert_node!(graph, make_node(ComputeTaskQED_V()), track = false)
|
||||
v0 = insert_node!(graph, make_node(ComputeTaskQED_V()); track=false)
|
||||
v1 = insert_node!(graph, make_node(ComputeTaskQED_V()); track=false)
|
||||
v2 = insert_node!(graph, make_node(ComputeTaskQED_V()); track=false)
|
||||
v3 = insert_node!(graph, make_node(ComputeTaskQED_V()); track=false)
|
||||
|
||||
# data from uPhIn, uPhOut, uElIn, uElOut to v0 and v1
|
||||
d_uPhIn_v0 = insert_node!(graph, make_node(DataTask(96)), track = false)
|
||||
d_uElIn_v0 = insert_node!(graph, make_node(DataTask(96)), track = false)
|
||||
d_uPhOut_v1 = insert_node!(graph, make_node(DataTask(96)), track = false)
|
||||
d_uElOut_v1 = insert_node!(graph, make_node(DataTask(96)), track = false)
|
||||
d_uPhIn_v0 = insert_node!(graph, make_node(DataTask(96)); track=false)
|
||||
d_uElIn_v0 = insert_node!(graph, make_node(DataTask(96)); track=false)
|
||||
d_uPhOut_v1 = insert_node!(graph, make_node(DataTask(96)); track=false)
|
||||
d_uElOut_v1 = insert_node!(graph, make_node(DataTask(96)); track=false)
|
||||
|
||||
# data from uPhIn, uPhOut, uElIn, uElOut to v2 and v3
|
||||
d_uPhOut_v2 = insert_node!(graph, make_node(DataTask(96)), track = false)
|
||||
d_uElIn_v2 = insert_node!(graph, make_node(DataTask(96)), track = false)
|
||||
d_uPhIn_v3 = insert_node!(graph, make_node(DataTask(96)), track = false)
|
||||
d_uElOut_v3 = insert_node!(graph, make_node(DataTask(96)), track = false)
|
||||
d_uPhOut_v2 = insert_node!(graph, make_node(DataTask(96)); track=false)
|
||||
d_uElIn_v2 = insert_node!(graph, make_node(DataTask(96)); track=false)
|
||||
d_uPhIn_v3 = insert_node!(graph, make_node(DataTask(96)); track=false)
|
||||
d_uElOut_v3 = insert_node!(graph, make_node(DataTask(96)); track=false)
|
||||
|
||||
# uPhIn, uPhOut, uElIn and uElOut computes
|
||||
uPhIn = insert_node!(graph, make_node(ComputeTaskQED_U()), track = false)
|
||||
uPhOut = insert_node!(graph, make_node(ComputeTaskQED_U()), track = false)
|
||||
uElIn = insert_node!(graph, make_node(ComputeTaskQED_U()), track = false)
|
||||
uElOut = insert_node!(graph, make_node(ComputeTaskQED_U()), track = false)
|
||||
uPhIn = insert_node!(graph, make_node(ComputeTaskQED_U()); track=false)
|
||||
uPhOut = insert_node!(graph, make_node(ComputeTaskQED_U()); track=false)
|
||||
uElIn = insert_node!(graph, make_node(ComputeTaskQED_U()); track=false)
|
||||
uElOut = insert_node!(graph, make_node(ComputeTaskQED_U()); track=false)
|
||||
|
||||
# data into U
|
||||
d_uPhIn = insert_node!(graph, make_node(DataTask(16), "ki1"), track = false)
|
||||
d_uPhOut = insert_node!(graph, make_node(DataTask(16), "ko1"), track = false)
|
||||
d_uElIn = insert_node!(graph, make_node(DataTask(16), "ei1"), track = false)
|
||||
d_uElOut = insert_node!(graph, make_node(DataTask(16), "eo1"), track = false)
|
||||
d_uPhIn = insert_node!(graph, make_node(DataTask(16), "ki1"); track=false)
|
||||
d_uPhOut = insert_node!(graph, make_node(DataTask(16), "ko1"); track=false)
|
||||
d_uElIn = insert_node!(graph, make_node(DataTask(16), "ei1"); track=false)
|
||||
d_uElOut = insert_node!(graph, make_node(DataTask(16), "eo1"); track=false)
|
||||
|
||||
# now for all the edges
|
||||
insert_edge!(graph, d_uPhIn, uPhIn, track = false)
|
||||
insert_edge!(graph, d_uPhOut, uPhOut, track = false)
|
||||
insert_edge!(graph, d_uElIn, uElIn, track = false)
|
||||
insert_edge!(graph, d_uElOut, uElOut, track = false)
|
||||
insert_edge!(graph, d_uPhIn, uPhIn; track=false)
|
||||
insert_edge!(graph, d_uPhOut, uPhOut; track=false)
|
||||
insert_edge!(graph, d_uElIn, uElIn; track=false)
|
||||
insert_edge!(graph, d_uElOut, uElOut; track=false)
|
||||
|
||||
insert_edge!(graph, uPhIn, d_uPhIn_v0, track = false)
|
||||
insert_edge!(graph, uPhOut, d_uPhOut_v1, track = false)
|
||||
insert_edge!(graph, uElIn, d_uElIn_v0, track = false)
|
||||
insert_edge!(graph, uElOut, d_uElOut_v1, track = false)
|
||||
insert_edge!(graph, uPhIn, d_uPhIn_v0; track=false)
|
||||
insert_edge!(graph, uPhOut, d_uPhOut_v1; track=false)
|
||||
insert_edge!(graph, uElIn, d_uElIn_v0; track=false)
|
||||
insert_edge!(graph, uElOut, d_uElOut_v1; track=false)
|
||||
|
||||
insert_edge!(graph, uPhIn, d_uPhIn_v3, track = false)
|
||||
insert_edge!(graph, uPhOut, d_uPhOut_v2, track = false)
|
||||
insert_edge!(graph, uElIn, d_uElIn_v2, track = false)
|
||||
insert_edge!(graph, uElOut, d_uElOut_v3, track = false)
|
||||
insert_edge!(graph, uPhIn, d_uPhIn_v3; track=false)
|
||||
insert_edge!(graph, uPhOut, d_uPhOut_v2; track=false)
|
||||
insert_edge!(graph, uElIn, d_uElIn_v2; track=false)
|
||||
insert_edge!(graph, uElOut, d_uElOut_v3; track=false)
|
||||
|
||||
insert_edge!(graph, d_uPhIn_v0, v0, track = false)
|
||||
insert_edge!(graph, d_uPhOut_v1, v1, track = false)
|
||||
insert_edge!(graph, d_uElIn_v0, v0, track = false)
|
||||
insert_edge!(graph, d_uElOut_v1, v1, track = false)
|
||||
insert_edge!(graph, d_uPhIn_v0, v0; track=false)
|
||||
insert_edge!(graph, d_uPhOut_v1, v1; track=false)
|
||||
insert_edge!(graph, d_uElIn_v0, v0; track=false)
|
||||
insert_edge!(graph, d_uElOut_v1, v1; track=false)
|
||||
|
||||
insert_edge!(graph, d_uPhIn_v3, v3, track = false)
|
||||
insert_edge!(graph, d_uPhOut_v2, v2, track = false)
|
||||
insert_edge!(graph, d_uElIn_v2, v2, track = false)
|
||||
insert_edge!(graph, d_uElOut_v3, v3, track = false)
|
||||
insert_edge!(graph, d_uPhIn_v3, v3; track=false)
|
||||
insert_edge!(graph, d_uPhOut_v2, v2; track=false)
|
||||
insert_edge!(graph, d_uElIn_v2, v2; track=false)
|
||||
insert_edge!(graph, d_uElOut_v3, v3; track=false)
|
||||
|
||||
insert_edge!(graph, v0, d_v0_s0, track = false)
|
||||
insert_edge!(graph, v1, d_v1_s0, track = false)
|
||||
insert_edge!(graph, v2, d_v2_s1, track = false)
|
||||
insert_edge!(graph, v3, d_v3_s1, track = false)
|
||||
insert_edge!(graph, v0, d_v0_s0; track=false)
|
||||
insert_edge!(graph, v1, d_v1_s0; track=false)
|
||||
insert_edge!(graph, v2, d_v2_s1; track=false)
|
||||
insert_edge!(graph, v3, d_v3_s1; track=false)
|
||||
|
||||
insert_edge!(graph, d_v0_s0, s0, track = false)
|
||||
insert_edge!(graph, d_v1_s0, s0, track = false)
|
||||
insert_edge!(graph, d_v0_s0, s0; track=false)
|
||||
insert_edge!(graph, d_v1_s0, s0; track=false)
|
||||
|
||||
insert_edge!(graph, d_v2_s1, s1, track = false)
|
||||
insert_edge!(graph, d_v3_s1, s1, track = false)
|
||||
insert_edge!(graph, d_v2_s1, s1; track=false)
|
||||
insert_edge!(graph, d_v3_s1, s1; track=false)
|
||||
|
||||
insert_edge!(graph, s0, d_s0_sum, track = false)
|
||||
insert_edge!(graph, s1, d_s1_sum, track = false)
|
||||
insert_edge!(graph, s0, d_s0_sum; track=false)
|
||||
insert_edge!(graph, s1, d_s1_sum; track=false)
|
||||
|
||||
insert_edge!(graph, d_s0_sum, sum_node, track = false)
|
||||
insert_edge!(graph, d_s1_sum, sum_node, track = false)
|
||||
insert_edge!(graph, d_s0_sum, sum_node; track=false)
|
||||
insert_edge!(graph, d_s1_sum, sum_node; track=false)
|
||||
|
||||
insert_edge!(graph, sum_node, d_exit, track = false)
|
||||
insert_edge!(graph, sum_node, d_exit; track=false)
|
||||
|
||||
input = [gen_process_input(process) for _ in 1:1000]
|
||||
|
||||
@ -314,9 +304,12 @@ end
|
||||
@test isapprox(compton_function.(input), compton_groundtruth.(input))
|
||||
end
|
||||
|
||||
@testset "Equal results after optimization" for optimizer in
|
||||
[ReductionOptimizer(), RandomWalkOptimizer(MersenneTwister(0))]
|
||||
@testset "Process $proc_str" for proc_str in ["ke->ke", "kp->kp", "kk->ep", "ep->kk", "ke->kke", "ke->kkke"]
|
||||
@testset "Equal results after optimization" for optimizer in [
|
||||
ReductionOptimizer(), RandomWalkOptimizer(MersenneTwister(0))
|
||||
]
|
||||
@testset "Process $proc_str" for proc_str in [
|
||||
"ke->ke", "kp->kp", "kk->ep", "ep->kk", "ke->kke", "ke->kkke"
|
||||
]
|
||||
model = QEDModel()
|
||||
process = parse_process(proc_str, model)
|
||||
machine = Machine(
|
||||
@ -347,3 +340,4 @@ end
|
||||
@test isapprox(compute_function.(input), reduced_compute_function.(input))
|
||||
end
|
||||
end
|
||||
=#
|
Loading…
x
Reference in New Issue
Block a user