n-Pair Trident Scattering Process
In this file, we set up an n-pair trident scattering process. A trident process looks like $k e^- \to e^- (e^- e^+)^n$.
You can download this file as a jupyter notebook.
using QEDFeynmanDiagrams
We need QEDcore of the QEDjl-project for base functionality and a process type, for which we can use the Mocks
submodule from QEDbase for this tutorial. Downstream, a ScatteringProcess
from QEDprocesses.jl could be used, for example.
using QEDcore
using QEDbase.Mocks
Let's decide how many pairs our trident should produce:
n = 2;
Now we setup the scattering process accordingly. We only consider a single spin/polarization combination here. For an example with many spin and polarization combinations, refer to the n-photon Compton example
proc = QEDbase.Mocks.MockProcessSP(
(Electron(), Photon()), # incoming particles
(Electron(), ntuple(_ -> Electron(), n)..., ntuple(_ -> Positron(), n)...), # outgoing particles
(SpinUp(), PolX()), # incoming particle spin/pols
(SpinUp(), ntuple(_ -> SpinUp(), 2 * n)...), # outgoing particle spin/pols
)
QEDbase.Mocks.MockProcessSP{Tuple{Electron, Photon}, Tuple{Electron, Electron, Electron, Positron, Positron}, Tuple{SpinUp, PolarizationX}, NTuple{5, SpinUp}}((electron, photon), (electron, electron, electron, positron, positron), (spin up, x-polarized), (spin up, spin up, spin up, spin up, spin up))
The number_of_diagrams
function returns how many valid Feynman diagrams there are for a given process.
number_of_diagrams(proc)
252
Next, we can generate the DAG representing the computation for our scattering process' squared matrix element. This uses ComputableDAGs.jl
.
dag = graph(proc)
Graph:
Nodes: Total: 943, QEDFeynmanDiagrams.ComputeTask_PropagatePairs: 60, QEDFeynmanDiagrams.ComputeTask_Pair: 60,
DataTask: 505, QEDFeynmanDiagrams.ComputeTask_SpinPolCumulation: 1, QEDFeynmanDiagrams.ComputeTask_CollectTriples: 1,
QEDFeynmanDiagrams.ComputeTask_Propagator: 60, QEDFeynmanDiagrams.ComputeTask_CollectPairs: 60, QEDFeynmanDiagrams.ComputeTask_TripleNegated: 150,
QEDFeynmanDiagrams.ComputeTask_BaseState: 7, QEDFeynmanDiagrams.ComputeTask_PairNegated: 9, QEDFeynmanDiagrams.ComputeTask_Triple: 30
Edges: 1553
Total Compute Effort: 0.0
Total Data Transfer: 0.0
Total Compute Intensity: 0.0
To continue, we will need ComputableDAGs.jl
. Since ComputableDAGs.jl
uses RuntimeGeneratedFunction
s as the return type of ComputableDAGs.get_compute_function
, we need to initialize it in our current module.
using ComputableDAGs
using RuntimeGeneratedFunctions
RuntimeGeneratedFunctions.init(@__MODULE__)
Now we need an input for the function, which is a QEDcore.PhaseSpacePoint
. For now, we generate random momenta for every particle. In the future, QEDevents will be able to generate physical PhaseSpacePoint
s.
psp = PhaseSpacePoint(
proc,
MockModel(),
FlatPhaseSpaceLayout(TwoBodyRestSystem()),
tuple((rand(SFourMomentum) for _ in 1:number_incoming_particles(proc))...),
tuple((rand(SFourMomentum) for _ in 1:number_outgoing_particles(proc))...),
)
PhaseSpacePoint:
process: QEDbase.Mocks.MockProcessSP{Tuple{Electron, Photon}, Tuple{Electron, Electron, Electron, Positron, Positron}, Tuple{SpinUp, PolarizationX}, NTuple{5, SpinUp}}((electron, photon), (electron, electron, electron, positron, positron), (spin up, x-polarized), (spin up, spin up, spin up, spin up, spin up))
model: mock model
phase space layout: FlatPhaseSpaceLayout{TwoBodyTargetSystem{Energy{2}}}(TwoBodyTargetSystem{Energy{2}}(Energy{2}()))
incoming particles:
-> incoming electron: [0.43935058639660307, 0.4329509446554315, 0.9896933529542659, 0.6833678787071071]
-> incoming photon: [0.8163067980762747, 0.7797309953340767, 0.8193100798747175, 0.9297330179835894]
outgoing particles:
-> outgoing electron: [0.9651228080130873, 0.9501606857885305, 0.2818493197917229, 0.15828458212118401]
-> outgoing electron: [0.6649893344768903, 0.595730058105144, 0.8904107896192701, 0.718993087322187]
-> outgoing electron: [0.5732403242026651, 0.5558605586831579, 0.31515464991358766, 0.16617205644917]
-> outgoing positron: [0.16564714751386334, 0.13711548571589594, 0.28864889525577875, 0.2508929903195146]
-> outgoing positron: [0.8741279989079298, 0.40534550785370416, 0.38985084564636596, 0.12310938616737033]
With the DAG, the process, RuntimeGeneratedFunctions
initialized, and an input type to use we can now generate the actual computable function:
func = get_compute_function(
dag, proc, cpu_st(), @__MODULE__; concrete_input_type = typeof(psp)
);
Finally, we can test that the function actually runs and computes something by simply calling it on the PhaseSpacePoint
:
func(psp)
789.2054858115299
We can benchmark the execution speed too:
using BenchmarkTools
@benchmark func($psp)
BenchmarkTools.Trial: 10000 samples with 1 evaluation per sample.
Range (min … max): 19.566 μs … 43.712 μs ┊ GC (min … max): 0.00% … 0.00%
Time (median): 19.777 μs ┊ GC (median): 0.00%
Time (mean ± σ): 20.077 μs ± 1.496 μs ┊ GC (mean ± σ): 0.00% ± 0.00%
▆█▅▁ ▁▁ ▁ ▁
████▆▆█▆▅▁▃▁▁▃▄███▇▆▆▄▅▄▄▃▃▅▄▅▄▄▄▁▃▁▁▄▁▃▁▁▃▃▄▁▁▁▄▃▄▅▄▃▃▄▇██ █
19.6 μs Histogram: log(frequency) by time 28.6 μs <
Memory estimate: 256 bytes, allocs estimate: 2.
This page was generated using Literate.jl.