n-Photon Compton Scattering Process

In this file, we set up an n-photon Compton scattering process. A Compton scattering process looks like $k^n e^- \to k e^-$.

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 photons our electron interacts with:

n = 4;

Now we setup the scattering process accordingly. We consider all spin/polarization combinations of the particles except for the incoming photons, where the polarizations are synced using QEDbase.SyncedPolarization. This emulates all synced photons having the same, but still indefinite, polarization, for example from a laser.

Note

Currently, this process uses outgoing photons instead of incoming photons, because there is not yet a PhaseSpaceLayout for more than two incoming particles in QEDcore.jl. See issue https://github.com/QEDjl-project/QEDcore.jl/issues/103

proc = QEDbase.Mocks.MockProcessSP(
    (Electron(), Photon()),                        # incoming particles
    (Electron(), ntuple(_ -> Photon(), n)...),     # outgoing particles
    (AllSpin(), AllPol()),                         # incoming particle spin/pols
    (AllSpin(), ntuple(_ -> SyncedPol(1), n)...),  # outgoing particle spin/pols
)
QEDbase.Mocks.MockProcessSP{Tuple{Electron, Photon}, Tuple{Electron, Vararg{Photon, 4}}, Tuple{AllSpin, AllPolarization}, Tuple{AllSpin, Vararg{SyncedPolarization{1}, 4}}}((electron, photon), (electron, photon, photon, photon, photon), (all spins, all polarizations), (all spins, synced polarization 1, synced polarization 1, synced polarization 1, synced polarization 1))

The number_of_diagrams function returns how many diagrams there are for a given process. For an n-photon Compton process with n incoming photons, this should be $(n+1)!$.

number_of_diagrams(proc)
120

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: 2262, QEDFeynmanDiagrams.ComputeTask_Pair: 264, ComputableDAGs.DataTask: 1153, 
         QEDFeynmanDiagrams.ComputeTask_SpinPolCumulation: 1, QEDFeynmanDiagrams.ComputeTask_PropagatePairs: 152, QEDFeynmanDiagrams.ComputeTask_Propagator: 30, 
         QEDFeynmanDiagrams.ComputeTask_CollectPairs: 152, QEDFeynmanDiagrams.ComputeTask_TripleNegated: 480, QEDFeynmanDiagrams.ComputeTask_CollectTriples: 16, 
         QEDFeynmanDiagrams.ComputeTask_BaseState: 14
  Edges: 4185
  Total Compute Effort: 0.0
  Total Data Transfer: 0.0
  Total Compute Intensity: 0.0

In this graph output you can see the number of nodes necessary to compute. Note that for larger processes, the number of total nodes can be lower than the number of Feynman diagrams, even with the added complexity of considering multiple spin and polarization combinations. This is the result of efficient reuse of reappearing parts of Feynman diagrams.

To continue, we will need to be using ComputableDAGs.jl.

using ComputableDAGs

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 PhaseSpacePoints.

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, Vararg{Photon, 4}}, Tuple{AllSpin, AllPolarization}, Tuple{AllSpin, Vararg{SyncedPolarization{1}, 4}}}((electron, photon), (electron, photon, photon, photon, photon), (all spins, all polarizations), (all spins, synced polarization 1, synced polarization 1, synced polarization 1, synced polarization 1))
    model: mock model
    phase space layout: FlatPhaseSpaceLayout{TwoBodyTargetSystem{Energy{2}}}(TwoBodyTargetSystem{Energy{2}}(Energy{2}()))
    incoming particles:
     -> incoming electron: [0.7736887075220069, 0.35530919232600267, 0.19107394406759215, 0.5716628810976371]
     -> incoming photon: [0.15110463418256292, 0.1765952084402691, 0.5383745896789901, 0.4446117420021254]
    outgoing particles:
     -> outgoing electron: [0.06948353124527762, 0.28190761140172216, 0.6889698801060679, 0.1861108577223617]
     -> outgoing photon: [0.6043621990437424, 0.133805101030247, 0.7261620132573611, 0.6606378594824523]
     -> outgoing photon: [0.3353410371186871, 0.003931594360206292, 0.738194143403746, 0.9050132733692242]
     -> outgoing photon: [0.4053545488870819, 0.45072440892243415, 0.5810952039232455, 0.5536778655291423]
     -> outgoing photon: [0.4638148677455678, 0.6304087016617194, 0.3972395126761913, 0.2603835160711412]

With the DAG, the process, and an input type to use, we can now generate the actual computable function:

func = compute_function(dag, proc, cpu_st(), @__MODULE__);

Finally, we can test that the function actually runs and computes something by simply calling it on the PhaseSpacePoint:

func(psp)
0.007627536896654144

We can benchmark the execution speed too:

using BenchmarkTools
@benchmark func($psp)
BenchmarkTools.Trial: 10000 samples with 1 evaluation per sample.
 Range (minmax):  82.944 μs  5.135 ms   GC (min … max): 0.00% … 97.17%
 Time  (median):     86.469 μs                GC (median):    0.00%
 Time  (mean ± σ):   95.290 μs ± 169.458 μs   GC (mean ± σ):  6.32% ±  3.50%

   ▄▇███▆▆▅▅▄▃▂▂▂▂       ▁▂▂▂▂▂▂▂▂         ▁▁    ▁            ▃
  ▇██████████████████▇██████████████▇▇▇▇██████▆███▆▆▅▆▄▄▅▅▅▅ █
  82.9 μs       Histogram: log(frequency) by time       118 μs <

 Memory estimate: 111.80 KiB, allocs estimate: 1373.

This page was generated using Literate.jl.