Skip to content

Commit 5a799cd

Browse files
Durham algorithm (#73)
Implementation of the e+e- k_T algorithm, aka Durham algorithm. This is implemented in a new specific implementation as the distance metrics are rather different from those used for pp events. In particular, the reconstruction happens in (theta, phi) space. A new EEjet structure is used, that stores the 4-momentum, but with different internal cache variables for optimising the distance calculations. (In particular the normalised momentum is cached, as the dot product is used to calculate the angle between two jets). Various accessors are added for components of the struct, as well as derived values, such as phi and rapidity. initial_history() is moved to the ClusterSequence.jl file, which is where it should be (used by all algorithms/strategies). ClusterSequence structs are updated to take jets as vectors of the abstract type FourMomentum. The algorithm stores the vector of EEjets in the ClusterSequence as before (original and all intermediate jets) and optimised compact arrays for finding the closest jets are used. Currently the implementation is about x3 slower than FastJet (which doesn't use any compact arrays). Timing on M2Pro for the ee->H input file per event is: - JetReconstruction.jl Durham 59us - FastJet Durham 21us - JetReconstruction.jl AntiKt/N2Plain 33us The consistency handling of p and algorithm is updated to take this new algorithm into account and new functions are added that map algorithms to either pp or e+e- cases (is_pp() and is_ee()). Documentation is updated to favour passing the algorithm to the reconstruction instead of implying it from the p value (though that mode is still supported and will imply pp reconstruction). There is also a major refactoring of tests to make testing Julia reconstruction against FastJet much easier and more independent of assumptions about the p <-> alg mapping. A new test file with e+e- -> H events is added and the 13TeV pp event file is renamed.
1 parent d98e7db commit 5a799cd

37 files changed

+708
-112163
lines changed

README.md

+25-14
Original file line numberDiff line numberDiff line change
@@ -12,41 +12,50 @@ Algorithms used are based on the C++ FastJet package (<https://fastjet.fr>,
1212
[arXiv:1111.6097](https://arxiv.org/abs/1111.6097)), reimplemented natively in Julia.
1313

1414
The algorithms include anti-$`{k}_\text{T}`$, Cambridge/Aachen, inclusive
15-
$`k_\text{T}`$ and generalised $`k_\text{T}`$.
15+
$`k_\text{T}`$, generalised $`k_\text{T}`$ for pp events; and the Durham algorithm for e+e-.
1616

1717
### Interface
1818

1919
The simplest interface is to call:
2020

2121
```julia
22-
cs = jet_reconstruct(particles::Vector{T}; p = -1, R = 1.0, recombine = +, strategy = RecoStrategy.Best)
22+
cs = jet_reconstruct(particles::Vector{T}; algorithm = JetAlgorithm.AntiKt, R = 1.0, [p = -1,] [recombine = +,] [strategy = RecoStrategy.Best])
2323
```
2424

2525
- `particles` - a vector of input particles for the clustering
2626
- Any type that supplies the methods `pt2()`, `phi()`, `rapidity()`, `px()`, `py()`, `pz()`, `energy()` can be used
2727
- These methods have to be defined in the namespace of this package, i.e., `JetReconstruction.pt2(::T)`
2828
- The `PseudoJet` type from this package, or a 4-vector from `LorentzVectorHEP` are suitable (and have the appropriate definitions)
29-
- `p` - the transverse momentum power used in the $d_{ij}$ metric for deciding on closest jets, as $k^{2p}_\text{T}$. Different values of $p$ then give different reconstruction algorithms:
30-
- `-1` gives anti-$`{k}_\text{T}`$ clustering (default)
31-
- `0` gives Cambridge/Aachen
32-
- `1` gives inclusive $k_\text{T}$
33-
- `R` - the cone size parameter; no particles more geometrically distance than `R` will be merged (default 1.0)
29+
- `algorithm` is the name of the jet algorithm to be used (from the `JetAlgorithm` enum)
30+
- `JetAlgorithm.AntiKt` anti-$`{k}_\text{T}`$ clustering (default)
31+
- `JetAlgorithm.CA` Cambridge/Aachen clustering
32+
- `JetAlgorithm.Kt` inclusive $k_\text{T}$
33+
- `JetAlgorithm.GenKt` generalised $k_\text{T}$ (which also requires specification of `p`)
34+
- `JetAlgorithm.Durham` the $e^+e-$ $k_\text{T}$ algorithm, also known as the Durham algorithm
35+
- `R` - the cone size parameter; no particles more geometrically distance than `R` will be merged (default 1.0; note this parameter is ignored for the Durham algorithm)
3436
- `recombine` - the function used to merge two pseudojets (default is a simple 4-vector addition of $`(E, \mathbf{p})`$)
3537
- `strategy` - the algorithm strategy to adopt, as described below (default `RecoStrategy.Best`)
3638

3739
The object returned is a `ClusterSequence`, which internally tracks all merge steps.
3840

39-
Alternatively one can swap the `p=...` parameter for
40-
`algorithm=JetReconstruction.{AntiKt,CA,Kt}` for explicit algorithm selection. (Generalised $`{k}_\text{T}`$ requires `algorithm=JetReconstruction.GenKt` *and* `p=N`.)
41+
Alternatively, *for pp reconstruction*, one can swap the `algorithm=...`
42+
parameter for the value of `p`, the transverse momentum power used in the
43+
$d_{ij}$ metric for deciding on closest jets, as $k^{2p}_\text{T}$. Different
44+
values of $p$ then correspond to different reconstruction algorithms:
45+
46+
- `-1` gives anti-$`{k}_\text{T}`$ clustering (default)
47+
- `0` gives Cambridge/Aachen
48+
- `1` gives inclusive $k_\text{T}$
49+
50+
(for the `GenKt` algorithm the `p` value *must* also be given to specify the algorithm fully).
4151

4252
To obtain the final inclusive jets, use the `inclusive_jets` method:
4353

4454
```julia
4555
final_jets = inclusive_jets(cs::ClusterSequence; ptmin=0.0)
4656
```
47-
Only jets passing the cut $p_T > p_{Tmin}$ will be returned. The result is returned as a `Vector{LorentzVectorHEP}`.
48-
4957

58+
Only jets passing the cut $p_T > p_{Tmin}$ will be returned. The result is returned as a `Vector{LorentzVectorHEP}`.
5059

5160
#### Sorting
5261

@@ -72,7 +81,7 @@ Another option, if one wishes to use a specific strategy, is to call that strate
7281

7382
```julia
7483
# For N2Plain strategy called directly
75-
plain_jet_reconstruct(particles::Vector{T}; p = -1, R = 1.0, recombine = +)
84+
plain_jet_reconstruct(particles::Vector{T}; algorithm = JetAlgorithm.AntiKt, R = 1.0, recombine = +)
7685
```
7786

7887
Note that there is no `strategy` option in these interfaces.
@@ -84,9 +93,11 @@ In the examples directory there are a number of example scripts.
8493
See the `jetreco.jl` script for an example of how to call jet reconstruction.
8594

8695
```sh
87-
julia --project=. examples/jetreco.jl --maxevents=100 --nsamples=1 --strategy=N2Plain test/data/events.hepmc3
96+
julia --project=examples examples/jetreco.jl --algorithm=AntiKt test/data/events.pp13TeV.hepmc3.gz
97+
...
98+
julia --project=examples examples/jetreco.jl --algorithm=Durham test/data/events.eeH.hepmc3.gz
8899
...
89-
julia --project=. examples/jetreco.jl --maxevents=100 --nsamples=1 --strategy=N2Tiled test/data/events.hepmc3
100+
julia --project=examples examples/jetreco.jl --maxevents=10 --strategy=N2Plain --algorithm=Kt --exclusive-njets=3 test/data/events.pp13TeV.hepmc3.gz
90101
...
91102
```
92103

docs/src/examples.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ perform a jet reconstruction, with different algorithms and (optionally)
1313
strategy, producing exclusive and inclusive jet selections.
1414

1515
```sh
16-
julia --project=. examples/jetreco.jl --maxevents=100 --strategy=N2Plain test/data/events.hepmc3
16+
julia --project=examples examples/jetreco.jl --algorithm=AntiKt test/data/events.pp13TeV.hepmc3.gz
1717
...
18-
julia --project=. examples/jetreco.jl --maxevents=100 --strategy=N2Tiled test/data/events.hepmc3
18+
julia --project=examples examples/jetreco.jl --algorithm=Durham test/data/events.eeH.hepmc3.gz
19+
...
20+
julia --project=examples examples/jetreco.jl --maxevents=10 --strategy=N2Plain --algorithm=Kt --exclusive-njets=3 test/data/events.pp13TeV.hepmc3.gz
1921
...
2022
```
2123

docs/src/index.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ jet_reconstruct(particles; algorithm = JetAlgorithm.AntiKt, R = 1.0)
5050
```
5151

5252
Where `particles` is a collection of 4-vector objects to reconstruct and the
53-
algorithm is either given explicitly or implied by the power value. For the case of generalised $k_T$ both the algorithm (`JetAlgorithm.GenKt`) and `p` are needed.
53+
algorithm is either given explicitly or implied by the power value. For the case
54+
of generalised $k_T$ both the algorithm (`JetAlgorithm.GenKt`) and `p` are
55+
needed. For the case of the Durham algorithm the `R` value is ignored.
5456

5557
The object returned is a [`ClusterSequence`](@ref), which internally tracks all
5658
merge steps.

examples/instrumented-jetreco.jl

+5-6
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ function jet_process(events::Vector{Vector{PseudoJet}};
9797
for event in events
9898
_ = inclusive_jets(jet_reconstruct(event, R = distance, p = p,
9999
algorithm = algorithm,
100-
strategy = strategy), ptmin)
100+
strategy = strategy); ptmin = ptmin)
101101
end
102102
end
103103

@@ -113,7 +113,7 @@ function jet_process(events::Vector{Vector{PseudoJet}};
113113
@timev for event in events
114114
_ = inclusive_jets(jet_reconstruct(event, R = distance, p = p,
115115
algorithm = algorithm,
116-
strategy = strategy), ptmin)
116+
strategy = strategy), ptmin = ptmin)
117117
end
118118
return nothing
119119
end
@@ -129,13 +129,12 @@ function jet_process(events::Vector{Vector{PseudoJet}};
129129
for (ievt, event) in enumerate(events)
130130
cs = jet_reconstruct(event, R = distance, p = p, algorithm = algorithm,
131131
strategy = strategy)
132-
strategy = strategy
133132
if !isnothing(njets)
134-
finaljets = exclusive_jets(cs, njets = njets)
133+
finaljets = exclusive_jets(cs; njets = njets)
135134
elseif !isnothing(dcut)
136-
finaljets = exclusive_jets(cs, dcut = dcut)
135+
finaljets = exclusive_jets(cs; dcut = dcut)
137136
else
138-
finaljets = inclusive_jets(cs, ptmin = ptmin)
137+
finaljets = inclusive_jets(cs; ptmin = ptmin)
139138
end
140139
# Only print the jet content once
141140
if irun == 1

src/AlgorithmStrategyEnums.jl

+30-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ Base.tryparse(E::Type{<:Enum}, str::String) =
7070
end
7171

7272
"""
73-
set_algorithm_power_consistency(; p::Union{Real, Nothing}, algorithm::Union{JetAlgorithm, Nothing})
73+
get_algorithm_power_consistency(; p::Union{Real, Nothing}, algorithm::Union{JetAlgorithm, Nothing})
7474
7575
Get the algorithm and power consistency correct
7676
@@ -103,6 +103,11 @@ function get_algorithm_power_consistency(; p::Union{Real, Nothing},
103103
return (p = p, algorithm = algorithm)
104104
end
105105

106+
# Some algorithms have fixed power values
107+
if algorithm == JetAlgorithm.Durham
108+
return (p = 1, algorithm = algorithm)
109+
end
110+
106111
# Otherwise we check the consistency between the algorithm and power
107112
if !isnothing(algorithm)
108113
power_from_alg = algorithm2power[algorithm]
@@ -127,3 +132,27 @@ function check_algorithm_power_consistency(; p::Union{Real, Nothing},
127132
get_algorithm_power_consistency(p = p, algorithm = algorithm)
128133
return true
129134
end
135+
136+
"""
137+
is_pp(algorithm::JetAlgorithm.Algorithm)
138+
139+
Check if the algorithm is a pp reconstruction algorithm.
140+
141+
# Returns
142+
`true` if the algorithm is a pp reconstruction algorithm, `false` otherwise.
143+
"""
144+
function is_pp(algorithm::JetAlgorithm.Algorithm)
145+
return algorithm in [JetAlgorithm.AntiKt, JetAlgorithm.CA, JetAlgorithm.Kt]
146+
end
147+
148+
"""
149+
is_ee(algorithm::JetAlgorithm.Algorithm)
150+
151+
Check if the algorithm is a e+e- reconstruction algorithm.
152+
153+
# Returns
154+
`true` if the algorithm is a e+e- reconstruction algorithm, `false` otherwise.
155+
"""
156+
function is_ee(algorithm::JetAlgorithm.Algorithm)
157+
return algorithm in [JetAlgorithm.EEKt, JetAlgorithm.Durham]
158+
end

src/ClusterSequence.jl

+32-1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,37 @@ A `HistoryElement` object.
6565
HistoryElement(jetp_index) = HistoryElement(NonexistentParent, NonexistentParent, Invalid,
6666
jetp_index, 0.0, 0.0)
6767

68+
"""
69+
initial_history(particles)
70+
71+
Create an initial history for the given particles.
72+
73+
# Arguments
74+
- `particles`: The initial vector of stable particles.
75+
76+
# Returns
77+
- `history`: An array of `HistoryElement` objects.
78+
- `Qtot`: The total energy in the event.
79+
"""
80+
function initial_history(particles)
81+
# reserve sufficient space for everything
82+
history = Vector{HistoryElement}(undef, length(particles))
83+
sizehint!(history, 2 * length(particles))
84+
85+
Qtot::Float64 = 0
86+
87+
for i in eachindex(particles)
88+
history[i] = HistoryElement(i)
89+
90+
# get cross-referencing right from the Jets
91+
particles[i]._cluster_hist_index = i
92+
93+
# determine the total energy in the event
94+
Qtot += particles[i].E
95+
end
96+
history, Qtot
97+
end
98+
6899
"""
69100
struct ClusterSequence
70101
@@ -89,7 +120,7 @@ struct ClusterSequence
89120
algorithm::JetAlgorithm.Algorithm
90121
power::Float64
91122
strategy::RecoStrategy.Strategy
92-
jets::Vector{PseudoJet}
123+
jets::Vector{FourMomentum}
93124
n_initial_jets::Int
94125
history::Vector{HistoryElement}
95126
Qtot::Any

0 commit comments

Comments
 (0)