Skip to content

Commit f502397

Browse files
Fix significant performance regression (#81)
* Read correct internal EDM type for benchmarking Use EEjet for e+e-, PseudoJet for pp * Factorise compact array updates Keep the main loop code cleaner by factorising the compact array updates into functions * Use clearer notation for jet indexes Resolve the actual jet indexes more explicitly * Fix ClusterSequence to be type specific It is vital that ClusterSequence is a fully concrete type. Change the constructor to be parametrised on the type of the jets themselves. * Small docs fix * Format fixes
1 parent 28d7f0d commit f502397

File tree

6 files changed

+86
-49
lines changed

6 files changed

+86
-49
lines changed

docs/make.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ makedocs(sitename = "JetReconstruction.jl",
1818
"Particle Inputs" => "particles.md",
1919
"Reconstruction Strategies" => "strategy.md",
2020
"Reference Docs" => Any["Public API" => "lib/public.md",
21-
"Internal API" => "lib/internal.md"],
21+
"Internal API" => "lib/internal.md"],
2222
"Extras" => Any["Serialisation" => "extras/serialisation.md"]
2323
])
2424

examples/instrumented-jetreco.jl

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ happens inside the JetReconstruction package itself.
6767
Some other ustilities are also supported here, such as profiling and
6868
serialising the reconstructed jet outputs.
6969
"""
70-
function jet_process(events::Vector{Vector{PseudoJet}};
70+
function jet_process(events::Vector{Vector{T}};
7171
distance::Real = 0.4,
7272
algorithm::Union{JetAlgorithm.Algorithm, Nothing} = nothing,
7373
p::Union{Real, Nothing} = nothing,
@@ -80,7 +80,7 @@ function jet_process(events::Vector{Vector{PseudoJet}};
8080
profile = nothing,
8181
alloc::Bool = false,
8282
dump::Union{String, Nothing} = nothing,
83-
dump_cs = false)
83+
dump_cs = false) where {T <: JetReconstruction.FourMomentum}
8484

8585
# If we are dumping the results, setup the JSON structure
8686
if !isnothing(dump)
@@ -294,9 +294,16 @@ function main()
294294
logger = ConsoleLogger(stdout, Logging.Warn)
295295
end
296296
global_logger(logger)
297-
events::Vector{Vector{PseudoJet}} = read_final_state_particles(args[:file],
298-
maxevents = args[:maxevents],
299-
skipevents = args[:skip])
297+
# Try to read events into the correct type!
298+
if JetReconstruction.is_ee(args[:algorithm])
299+
jet_type = EEjet
300+
else
301+
jet_type = PseudoJet
302+
end
303+
events::Vector{Vector{jet_type}} = read_final_state_particles(args[:file],
304+
maxevents = args[:maxevents],
305+
skipevents = args[:skip],
306+
T = jet_type)
300307
if isnothing(args[:algorithm]) && isnothing(args[:power])
301308
@warn "Neither algorithm nor power specified, defaulting to AntiKt"
302309
args[:algorithm] = JetAlgorithm.AntiKt

examples/jetreco.jl

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,16 @@ happens inside the JetReconstruction package itself.
2323
2424
Final jets can be serialised if the "dump" option is given
2525
"""
26-
function jet_process(events::Vector{Vector{PseudoJet}};
26+
function jet_process(events::Vector{Vector{T}};
2727
distance::Real = 0.4,
2828
algorithm::Union{JetAlgorithm.Algorithm, Nothing} = nothing,
2929
p::Union{Real, Nothing} = nothing,
3030
ptmin::Real = 5.0,
3131
dcut = nothing,
3232
njets = nothing,
3333
strategy::RecoStrategy.Strategy,
34-
dump::Union{String, Nothing} = nothing)
34+
dump::Union{String, Nothing} = nothing) where {T <:
35+
JetReconstruction.FourMomentum}
3536

3637
# Set consistent algorithm and power
3738
(p, algorithm) = JetReconstruction.get_algorithm_power_consistency(p = p,
@@ -138,9 +139,16 @@ function main()
138139
args = parse_command_line(ARGS)
139140
logger = ConsoleLogger(stdout, Logging.Info)
140141
global_logger(logger)
141-
events::Vector{Vector{PseudoJet}} = read_final_state_particles(args[:file],
142-
maxevents = args[:maxevents],
143-
skipevents = args[:skip])
142+
# Try to read events into the correct type!
143+
if JetReconstruction.is_ee(args[:algorithm])
144+
jet_type = EEjet
145+
else
146+
jet_type = PseudoJet
147+
end
148+
events::Vector{Vector{jet_type}} = read_final_state_particles(args[:file],
149+
maxevents = args[:maxevents],
150+
skipevents = args[:skip],
151+
T = jet_type)
144152
if isnothing(args[:algorithm]) && isnothing(args[:power])
145153
@warn "Neither algorithm nor power specified, defaulting to AntiKt"
146154
args[:algorithm] = JetAlgorithm.AntiKt

src/ClusterSequence.jl

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,28 +108,28 @@ final jets.
108108
- `power::Float64`: The power value used for the clustering algorithm (not that
109109
this value is always stored as a Float64 to be type stable)
110110
- `R::Float64`: The R parameter used for the clustering algorithm.
111-
- `jets::Vector{PseudoJet}`: The physical PseudoJets in the cluster sequence.
112-
Each PseudoJet corresponds to a position in the history.
111+
- `jets::Vector{T}`: The actual jets in the cluster sequence, which are of type
112+
`T <: FourMomentum`.
113113
- `n_initial_jets::Int`: The initial number of particles used for exclusive
114114
jets.
115115
- `history::Vector{HistoryElement}`: The branching history of the cluster
116116
sequence. Each stage in the history indicates where to look in the jets vector
117117
to get the physical PseudoJet.
118118
- `Qtot::Any`: The total energy of the event.
119119
"""
120-
struct ClusterSequence
120+
struct ClusterSequence{T}
121121
algorithm::JetAlgorithm.Algorithm
122122
power::Float64
123123
R::Float64
124124
strategy::RecoStrategy.Strategy
125-
jets::Vector{FourMomentum}
125+
jets::Vector{T}
126126
n_initial_jets::Int
127127
history::Vector{HistoryElement}
128128
Qtot::Any
129129
end
130130

131131
"""
132-
ClusterSequence(algorithm::JetAlgorithm.Algorithm, p::Real, R::Float64, strategy::RecoStrategy.Strategy, jets, history, Qtot)
132+
ClusterSequence(algorithm::JetAlgorithm.Algorithm, p::Real, R::Float64, strategy::RecoStrategy.Strategy, jets::T, history, Qtot) where T <: FourMomentum
133133
134134
Construct a `ClusterSequence` object.
135135
@@ -138,13 +138,14 @@ Construct a `ClusterSequence` object.
138138
- `p::Real`: The power value used for the clustering algorithm.
139139
- `R::Float64`: The R parameter used for the clustering algorithm.
140140
- `strategy::RecoStrategy.Strategy`: The strategy used for clustering.
141-
- `jets::Vector{PseudoJet}`: The physical PseudoJets in the cluster sequence.
141+
- `jets::Vector{T}`: The jets in the cluster sequence, which are of T <: FourMomentum
142142
- `history::Vector{HistoryElement}`: The branching history of the cluster
143143
sequence.
144144
- `Qtot::Any`: The total energy of the event.
145145
"""
146-
ClusterSequence(algorithm::JetAlgorithm.Algorithm, p::Real, R::Float64, strategy::RecoStrategy.Strategy, jets, history, Qtot) = begin
147-
ClusterSequence(algorithm, Float64(p), R, strategy, jets, length(jets), history, Qtot)
146+
ClusterSequence(algorithm::JetAlgorithm.Algorithm, p::Real, R::Float64, strategy::RecoStrategy.Strategy, jets::Vector{T}, history, Qtot) where {T <: FourMomentum} = begin
147+
ClusterSequence{T}(algorithm, Float64(p), R, strategy, jets, length(jets), history,
148+
Qtot)
148149
end
149150

150151
"""

src/EEAlgorithm.jl

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,45 @@ function ee_check_consistency(clusterseq, eereco, N)
151151
@debug "Consistency check passed at $msg"
152152
end
153153

154+
function fill_reco_array!(eereco, particles, R2, p)
155+
for i in eachindex(particles)
156+
eereco.index[i] = i
157+
eereco.nni[i] = 0
158+
eereco.nndist[i] = R2
159+
# eereco.dijdist[i] = UNDEF # Does not need to be initialised
160+
eereco.nx[i] = nx(particles[i])
161+
eereco.ny[i] = ny(particles[i])
162+
eereco.nz[i] = nz(particles[i])
163+
eereco.E2p[i] = energy(particles[i])^(2p)
164+
end
165+
end
166+
167+
@inline function insert_new_jet!(eereco, i, newjet_k, R2, merged_jet, p)
168+
eereco.index[i] = newjet_k
169+
eereco.nni[i] = 0
170+
eereco.nndist[i] = R2
171+
eereco.nx[i] = nx(merged_jet)
172+
eereco.ny[i] = ny(merged_jet)
173+
eereco.nz[i] = nz(merged_jet)
174+
eereco.E2p[i] = energy(merged_jet)^(2p)
175+
end
176+
177+
"""
178+
copy_to_slot!(eereco, i, j)
179+
180+
Copy the contents of slot `i` in the `eereco` array to slot `j`.
181+
"""
182+
@inline function copy_to_slot!(eereco, i, j)
183+
eereco.index[j] = eereco.index[i]
184+
eereco.nni[j] = eereco.nni[i]
185+
eereco.nndist[j] = eereco.nndist[i]
186+
eereco.dijdist[j] = eereco.dijdist[i]
187+
eereco.nx[j] = eereco.nx[i]
188+
eereco.ny[j] = eereco.ny[i]
189+
eereco.nz[j] = eereco.nz[i]
190+
eereco.E2p[j] = eereco.E2p[i]
191+
end
192+
154193
"""
155194
ee_genkt_algorithm(particles::Vector{T}; p = -1, R = 4.0,
156195
algorithm::JetAlgorithm.Algorithm = JetAlgorithm.Durham,
@@ -251,16 +290,7 @@ function _ee_genkt_algorithm(; particles::Vector{EEjet}, p = 1, R = 4.0,
251290
# jet information and populate it accordingly
252291
# We need N slots for this array
253292
eereco = StructArray{EERecoJet}(undef, N)
254-
for i in eachindex(particles)
255-
eereco.index[i] = i
256-
eereco.nni[i] = 0
257-
eereco.nndist[i] = R2
258-
# eereco[i].dijdist = UNDEF # Not needed
259-
eereco.nx[i] = nx(particles[i])
260-
eereco.ny[i] = ny(particles[i])
261-
eereco.nz[i] = nz(particles[i])
262-
eereco.E2p[i] = energy(particles[i])^(2p)
263-
end
293+
fill_reco_array!(eereco, particles, R2, p)
264294

265295
# Setup the initial history and get the total energy
266296
history, Qtot = initial_history(particles)
@@ -301,13 +331,17 @@ function _ee_genkt_algorithm(; particles::Vector{EEjet}, p = 1, R = 4.0,
301331
ijetA, ijetB = ijetB, ijetA
302332
end
303333

334+
# Resolve the jet indexes to access the actual jets
335+
jetA_idx = eereco[ijetA].index
336+
jetB_idx = eereco[ijetB].index
337+
304338
# Source "history" for merge
305-
hist_jetA = clusterseq.jets[eereco[ijetA].index]._cluster_hist_index
306-
hist_jetB = clusterseq.jets[eereco[ijetB].index]._cluster_hist_index
339+
hist_jetA = clusterseq.jets[jetA_idx]._cluster_hist_index
340+
hist_jetB = clusterseq.jets[jetB_idx]._cluster_hist_index
307341

308342
# Recombine jetA and jetB into the next jet
309-
merged_jet = recombine(clusterseq.jets[eereco[ijetA].index],
310-
clusterseq.jets[eereco[ijetB].index])
343+
merged_jet = recombine(clusterseq.jets[jetA_idx],
344+
clusterseq.jets[jetB_idx])
311345
merged_jet._cluster_hist_index = length(clusterseq.history) + 1
312346

313347
# Now add the jet to the sequence, and update the history
@@ -317,26 +351,13 @@ function _ee_genkt_algorithm(; particles::Vector{EEjet}, p = 1, R = 4.0,
317351
newjet_k, dij_min)
318352

319353
# Update the compact arrays, reusing the JetA slot
320-
eereco.index[ijetA] = newjet_k
321-
eereco.nni[ijetA] = 0
322-
eereco.nndist[ijetA] = R2
323-
eereco.nx[ijetA] = nx(merged_jet)
324-
eereco.ny[ijetA] = ny(merged_jet)
325-
eereco.nz[ijetA] = nz(merged_jet)
326-
eereco.E2p[ijetA] = energy(merged_jet)^(2p)
354+
insert_new_jet!(eereco, ijetA, newjet_k, R2, merged_jet, p)
327355
end
328356

329357
# Squash step - copy the final jet's compact data into the jetB slot
330358
# unless we are at the end of the array, in which case do nothing
331359
if ijetB != N
332-
eereco.index[ijetB] = eereco.index[N]
333-
eereco.nni[ijetB] = eereco.nni[N]
334-
eereco.nndist[ijetB] = eereco.nndist[N]
335-
eereco.dijdist[ijetB] = eereco.dijdist[N]
336-
eereco.nx[ijetB] = eereco.nx[N]
337-
eereco.ny[ijetB] = eereco.ny[N]
338-
eereco.nz[ijetB] = eereco.nz[N]
339-
eereco.E2p[ijetB] = eereco.E2p[N]
360+
copy_to_slot!(eereco, N, ijetB)
340361
end
341362

342363
# Now number of active jets is decreased by one

src/Utils.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ function read_final_state_particles(fname; maxevents = -1, skipevents = 0, T = P
3737
if p.status == 1
3838
# Annoyingly PseudoJet and LorentzVector constructors
3939
# disagree on the order of arguments...
40-
if T == PseudoJet
40+
if T <: FourMomentum
4141
particle = T(p.momentum.x, p.momentum.y, p.momentum.z, p.momentum.t)
4242
else
4343
particle = T(p.momentum.t, p.momentum.x, p.momentum.y, p.momentum.z)

0 commit comments

Comments
 (0)