Skip to content

Commit 443408a

Browse files
feat: Truth Jet Algorithm using FastJet (#4267)
This PR introduces a not-yet-tuned truth jet algorithm that uses the FastJet plug-in as implemented in [PR: 3617](#3617). The algorithm takes truth particles from Pythia8 and, by using their kinematic information, applies jet clustering. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a FastJet plugin with optional build support, enabling jet clustering capabilities. - Added a new TruthJet algorithm for clustering simulated particles into jets using FastJet. - Integrated the TruthJet algorithm into the Python interface and provided corresponding Python utilities and scripts. - Added example and test scripts for truth jet reconstruction workflows. - **Documentation** - Updated documentation to describe the new FastJet plugin build option. - **Chores** - Enhanced build configuration to support conditional inclusion of FastJet components and plugins. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Paul Gessinger <[email protected]>
1 parent 57a08e7 commit 443408a

File tree

20 files changed

+339
-5
lines changed

20 files changed

+339
-5
lines changed

.github/actions/dependencies/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ inputs:
1313
spack_version:
1414
description: 'Version of Spack to use'
1515
required: false
16-
default: 'develop-2025-04-20'
16+
default: 'develop-2025-05-25'
1717

1818
runs:
1919
using: 'composite'

.github/workflows/analysis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ env:
2222
CCACHE_MAXSIZE: 1.25G
2323
CCACHE_KEY_SUFFIX: r2
2424
ACTS_LOG_FAILURE_THRESHOLD: WARNING
25-
DEPENDENCY_TAG: v9.0.0
25+
DEPENDENCY_TAG: v10.0.0
2626

2727
# NOTE this only builds core unittests to reduce the output size. if we
2828
# found a way to have Github actions not fail regularly with this job

.github/workflows/builds.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ env:
2020
CCACHE_DIR: ${{ github.workspace }}/ccache
2121
CCACHE_MAXSIZE: 500M
2222
CCACHE_KEY_SUFFIX: r2
23-
DEPENDENCY_TAG: v9.0.0
23+
DEPENDENCY_TAG: v10.0.0
2424

2525
jobs:
2626
linux_ubuntu:

.gitlab-ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ variables:
44
CCACHE_KEY_SUFFIX: r2
55
CTEST_OUTPUT_ON_FAILURE: 1
66

7-
SPACK_VERSION: develop-2025-04-20
7+
SPACK_VERSION: develop-2025-05-25
88
LOCKFILE_CACHE_DIR: ${CI_PROJECT_DIR}/spack_lockfile_cache
99

10-
DEPENDENCY_TAG: v9.0.0
10+
DEPENDENCY_TAG: v10.0.0
1111

1212
.ccache_base:
1313
cache:

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ option(ACTS_BUILD_PLUGIN_DD4HEP "Build DD4hep plugin" OFF)
8181
option(ACTS_BUILD_PLUGIN_PODIO "Build Podio plugin" OFF)
8282
option(ACTS_BUILD_PLUGIN_EDM4HEP "Build EDM4hep plugin" OFF)
8383
option(ACTS_BUILD_PLUGIN_FPEMON "Build FPE monitoring plugin" OFF)
84+
option(ACTS_BUILD_PLUGIN_FASTJET "Build FastJet plugin" OFF)
8485
option(ACTS_BUILD_PLUGIN_GEOMODEL "Build GeoModel plugin" OFF)
8586
option(ACTS_BUILD_PLUGIN_TRACCC "Build Traccc plugin" OFF)
8687
option(ACTS_BUILD_PLUGIN_GEANT4 "Build Geant4 plugin" OFF)
@@ -290,6 +291,7 @@ set(_acts_covfie_version 0.12.1)
290291
set(_acts_vecmem_version 1.14.0)
291292
set(_acts_algebraplugins_version 0.26.2)
292293
set(_acts_annoy_version 1.17.3)
294+
set(_acts_fastjet_version 3.4.1)
293295

294296
# recommended dependency version. if there is an opportunity to reach
295297
# this version we will try so.
@@ -403,6 +405,9 @@ if(ACTS_BUILD_PLUGIN_JSON)
403405
add_subdirectory(thirdparty/nlohmann_json)
404406
endif()
405407
endif()
408+
if(ACTS_BUILD_PLUGIN_FASTJET)
409+
find_package(FastJet ${_acts_fastjet_version} REQUIRED)
410+
endif()
406411
if(ACTS_BUILD_PLUGIN_GEOMODEL)
407412
find_package(GeoModelCore CONFIG)
408413
if(NOT GeoModelCore_FOUND)

CMakePresets.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
"ACTS_BUILD_PLUGIN_JSON": "ON",
6969
"ACTS_BUILD_PLUGIN_ONNX": "OFF",
7070
"ACTS_BUILD_PLUGIN_TGEO": "ON",
71+
"ACTS_BUILD_PLUGIN_FASTJET": "ON",
7172
"ACTS_BUILD_EXAMPLES_EDM4HEP": "ON",
7273
"ACTS_BUILD_EXAMPLES_PODIO": "ON",
7374
"ACTS_BUILD_EXAMPLES_EXATRKX": "OFF",

Examples/Algorithms/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ add_subdirectory(TrackFinding)
1212
add_subdirectory_if(TrackFindingExaTrkX ACTS_BUILD_EXAMPLES_EXATRKX)
1313
add_subdirectory_if(TrackFindingML ACTS_BUILD_PLUGIN_ONNX)
1414
add_subdirectory(TrackFitting)
15+
add_subdirectory_if(Jets ACTS_BUILD_PLUGIN_FASTJET)
1516
add_subdirectory(TruthTracking)
1617
add_subdirectory(Vertexing)
1718
add_subdirectory_if(Alignment ACTS_BUILD_ALIGNMENT)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
add_library(ActsExamplesJets SHARED src/TruthJetAlgorithm.cpp)
2+
target_include_directories(
3+
ActsExamplesJets
4+
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
5+
)
6+
target_link_libraries(
7+
ActsExamplesJets
8+
PUBLIC ActsCore ActsPluginFastJet ActsExamplesFramework
9+
)
10+
11+
acts_compile_headers(ActsExamplesJets GLOB "include/**/*.hpp")
12+
13+
install(TARGETS ActsExamplesJets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// This file is part of the ACTS project.
2+
//
3+
// Copyright (C) 2016 CERN for the benefit of the ACTS project
4+
//
5+
// This Source Code Form is subject to the terms of the Mozilla Public
6+
// License, v. 2.0. If a copy of the MPL was not distributed with this
7+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8+
9+
#pragma once
10+
11+
#include "Acts/Utilities/Logger.hpp"
12+
#include "ActsExamples/EventData/SimParticle.hpp"
13+
#include "ActsExamples/Framework/DataHandle.hpp"
14+
#include "ActsExamples/Framework/IAlgorithm.hpp"
15+
#include "ActsExamples/Framework/ProcessCode.hpp"
16+
17+
#include <string>
18+
19+
namespace fastjet {
20+
class PseudoJet;
21+
}
22+
23+
namespace ActsExamples {
24+
struct AlgorithmContext;
25+
26+
class TruthJetAlgorithm final : public IAlgorithm {
27+
public:
28+
struct Config {
29+
/// Input particles collection.
30+
std::string inputTruthParticles;
31+
/// Output jets collection.
32+
std::string outputJets;
33+
/// Minimum jet pT.
34+
double jetPtMin;
35+
};
36+
37+
TruthJetAlgorithm(const Config& cfg, Acts::Logging::Level lvl);
38+
39+
ProcessCode execute(const AlgorithmContext& ctx) const override;
40+
ProcessCode finalize() override;
41+
42+
const Config& config() const { return m_cfg; }
43+
44+
private:
45+
Config m_cfg;
46+
ReadDataHandle<SimParticleContainer> m_inputTruthParticles{
47+
this, "inputTruthParticles"};
48+
WriteDataHandle<std::vector<fastjet::PseudoJet>> m_outputJets{this,
49+
"outputJets"};
50+
};
51+
52+
} // namespace ActsExamples
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// This file is part of the ACTS project.
2+
//
3+
// Copyright (C) 2016 CERN for the benefit of the ACTS project
4+
//
5+
// This Source Code Form is subject to the terms of the Mozilla Public
6+
// License, v. 2.0. If a copy of the MPL was not distributed with this
7+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8+
9+
#include "ActsExamples/Jets/TruthJetAlgorithm.hpp"
10+
11+
#include "Acts/Definitions/Units.hpp"
12+
#include "Acts/Utilities/Logger.hpp"
13+
#include "ActsExamples/EventData/SimParticle.hpp"
14+
#include "ActsExamples/Framework/AlgorithmContext.hpp"
15+
#include "ActsFatras/EventData/ProcessType.hpp"
16+
17+
#include <ostream>
18+
#include <stdexcept>
19+
20+
#include <fastjet/ClusterSequence.hh>
21+
#include <fastjet/JetDefinition.hh>
22+
#include <fastjet/PseudoJet.hh>
23+
24+
namespace ActsExamples {
25+
26+
TruthJetAlgorithm::TruthJetAlgorithm(const Config& cfg,
27+
Acts::Logging::Level lvl)
28+
: IAlgorithm("TruthJetAlgorithm", lvl), m_cfg(cfg) {
29+
if (m_cfg.inputTruthParticles.empty()) {
30+
throw std::invalid_argument("Input particles collection is not configured");
31+
}
32+
m_inputTruthParticles.initialize(m_cfg.inputTruthParticles);
33+
m_outputJets.initialize(m_cfg.outputJets);
34+
}
35+
36+
ProcessCode ActsExamples::TruthJetAlgorithm::execute(
37+
const ActsExamples::AlgorithmContext& ctx) const {
38+
const auto& truthParticles = m_inputTruthParticles(ctx);
39+
40+
ACTS_DEBUG("Number of truth particles: " << truthParticles.size());
41+
42+
const fastjet::JetDefinition defaultJetDefinition =
43+
fastjet::JetDefinition(fastjet::antikt_algorithm, 0.4);
44+
45+
// Get the 4-momentum information from the simulated truth particles
46+
// and create fastjet::PseudoJet objects
47+
std::vector<fastjet::PseudoJet> inputPseudoJets;
48+
49+
int particleIndex = 0;
50+
for (const auto& particle : truthParticles) {
51+
fastjet::PseudoJet pseudoJet(particle.momentum().x(),
52+
particle.momentum().y(),
53+
particle.momentum().z(), particle.energy());
54+
55+
pseudoJet.set_user_index(particleIndex);
56+
inputPseudoJets.push_back(pseudoJet);
57+
particleIndex++;
58+
}
59+
ACTS_DEBUG("Number of input pseudo jets: " << inputPseudoJets.size());
60+
// Run the jet clustering
61+
fastjet::ClusterSequence clusterSeq(inputPseudoJets, defaultJetDefinition);
62+
// Get the jets above a certain pt threshold
63+
std::vector<fastjet::PseudoJet> jets =
64+
sorted_by_pt(clusterSeq.inclusive_jets(m_cfg.jetPtMin));
65+
ACTS_DEBUG("Number of clustered jets: " << jets.size());
66+
// Store the jets in the output data handle
67+
m_outputJets(ctx, std::move(jets));
68+
69+
return ProcessCode::SUCCESS;
70+
}
71+
72+
ProcessCode ActsExamples::TruthJetAlgorithm::finalize() {
73+
ACTS_INFO("Finalizing truth jet clustering");
74+
return ProcessCode::SUCCESS;
75+
}
76+
77+
}; // namespace ActsExamples

Examples/Python/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,13 @@ else()
258258
target_sources(ActsPythonBindings PRIVATE src/OnnxNeuralCalibratorStub.cpp)
259259
endif()
260260

261+
if(ACTS_BUILD_PLUGIN_FASTJET)
262+
target_link_libraries(ActsPythonBindings PUBLIC ActsExamplesJets)
263+
target_sources(ActsPythonBindings PRIVATE src/TruthJet.cpp)
264+
else()
265+
target_sources(ActsPythonBindings PRIVATE src/TruthJetStub.cpp)
266+
endif()
267+
261268
if(ACTS_BUILD_EXAMPLES_HASHING)
262269
target_link_libraries(ActsPythonBindings PUBLIC ActsPluginHashing)
263270
target_sources(ActsPythonBindings PRIVATE src/Hashing.cpp)

Examples/Python/python/acts/examples/simulation.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@
5353
defaults=[(None, None)] * 10 + [None] * 4,
5454
)
5555

56+
TruthJetConfig = namedtuple(
57+
"TruthJetConfig",
58+
["inputTruthParticles", "outputJets", "jetPtMin"],
59+
defaults=[None, None],
60+
)
61+
5662

5763
def _getParticleSelectionKWargs(config: ParticleSelectorConfig) -> dict:
5864
return {
@@ -83,6 +89,14 @@ def _getParticleSelectionKWargs(config: ParticleSelectorConfig) -> dict:
8389
}
8490

8591

92+
def _getTruthJetKWargs(config: TruthJetConfig) -> dict:
93+
return {
94+
"inputTruthParticles": config.inputTruthParticles,
95+
"outputJets": config.outputJets,
96+
"jetPtMin": config.jetPtMin,
97+
}
98+
99+
86100
@acts.examples.NamedTypeArgs(
87101
momentumConfig=MomentumConfig,
88102
etaConfig=EtaConfig,
@@ -836,3 +850,19 @@ def addDigiParticleSelection(
836850
s.addWhiteboardAlias(
837851
"particles_digitized_selected", selector.config.outputParticles
838852
)
853+
854+
855+
def addTruthJetAlg(
856+
s: acts.examples.Sequencer,
857+
config: TruthJetConfig,
858+
loglevel: Optional[acts.logging.Level] = None,
859+
) -> None:
860+
from acts.examples import TruthJetAlgorithm
861+
862+
customLogLevel = acts.examples.defaultLogging(s, loglevel)
863+
truthJetAlg = acts.examples.TruthJetAlgorithm(
864+
**acts.examples.defaultKWArgs(**_getTruthJetKWargs(config)),
865+
level=customLogLevel(),
866+
)
867+
868+
s.addAlgorithm(truthJetAlg)

Examples/Python/src/ModuleEntry.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ void addGenerators(Context& ctx);
5252
void addTruthTracking(Context& ctx);
5353
void addTrackFitting(Context& ctx);
5454
void addTrackFinding(Context& ctx);
55+
void addTruthJet(Context& ctx);
5556
void addVertexing(Context& ctx);
5657
void addAmbiguityResolution(Context& ctx);
5758
void addUtilities(Context& ctx);
@@ -127,6 +128,7 @@ PYBIND11_MODULE(ActsPythonBindings, m) {
127128
addTruthTracking(ctx);
128129
addTrackFitting(ctx);
129130
addTrackFinding(ctx);
131+
addTruthJet(ctx);
130132
addVertexing(ctx);
131133
addAmbiguityResolution(ctx);
132134
addUtilities(ctx);

Examples/Python/src/TruthJet.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// This file is part of the ACTS project.
2+
//
3+
// Copyright (C) 2016 CERN for the benefit of the ACTS project
4+
//
5+
// This Source Code Form is subject to the terms of the Mozilla Public
6+
// License, v. 2.0. If a copy of the MPL was not distributed with this
7+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8+
9+
#include "Acts/Plugins/Python/Utilities.hpp"
10+
#include "Acts/Utilities/Logger.hpp"
11+
#include "ActsExamples/Jets/TruthJetAlgorithm.hpp"
12+
13+
#include <cstddef>
14+
#include <memory>
15+
16+
#include <pybind11/pybind11.h>
17+
#include <pybind11/stl.h>
18+
19+
namespace py = pybind11;
20+
21+
using namespace ActsExamples;
22+
using namespace Acts;
23+
24+
namespace Acts::Python {
25+
26+
void addTruthJet(Context& ctx) {
27+
auto mex = ctx.get("examples");
28+
29+
ACTS_PYTHON_DECLARE_ALGORITHM(ActsExamples::TruthJetAlgorithm, mex,
30+
"TruthJetAlgorithm", inputTruthParticles,
31+
outputJets, jetPtMin);
32+
} // addTruthJet
33+
} // namespace Acts::Python

Examples/Python/src/TruthJetStub.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// This file is part of the ACTS project.
2+
//
3+
// Copyright (C) 2016 CERN for the benefit of the ACTS project
4+
//
5+
// This Source Code Form is subject to the terms of the Mozilla Public
6+
// License, v. 2.0. If a copy of the MPL was not distributed with this
7+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8+
9+
// This is a stub version when the FastJet plugin is not available
10+
#include "Acts/Plugins/Python/Utilities.hpp"
11+
12+
namespace Acts::Python {
13+
void addTruthJet(Context& /*ctx*/) {}
14+
} // namespace Acts::Python
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/env python3
2+
import acts
3+
import acts.examples
4+
from acts.examples.simulation import addPythia8, addTruthJetAlg, TruthJetConfig
5+
6+
7+
outputDir = "./truth_jet_test_output"
8+
u = acts.UnitConstants
9+
rnd = acts.examples.RandomNumbers(seed=42)
10+
11+
s = acts.examples.Sequencer(events=10, outputDir=outputDir)
12+
13+
addPythia8(
14+
s,
15+
hardProcess=["Top:qqbar2ttbar=on"],
16+
npileup=50,
17+
vtxGen=acts.examples.GaussianVertexGenerator(
18+
mean=acts.Vector4(0, 0, 0, 0),
19+
stddev=acts.Vector4(0.0125 * u.mm, 0.0125 * u.mm, 55.5 * u.mm, 5.0 * u.ns),
20+
),
21+
rnd=rnd,
22+
outputDirRoot=outputDir,
23+
outputDirCsv=outputDir,
24+
)
25+
26+
addTruthJetAlg(
27+
s,
28+
TruthJetConfig(
29+
inputTruthParticles="particles_generated",
30+
outputJets="output_jets",
31+
jetPtMin=20 * u.GeV,
32+
),
33+
loglevel=acts.logging.INFO,
34+
)
35+
36+
s.run()

Plugins/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# independent plugins
44
add_component_if(ActSVG PluginActSVG ACTS_BUILD_PLUGIN_ACTSVG)
55
add_component_if(Cuda PluginCuda ACTS_BUILD_PLUGIN_CUDA)
6+
add_component_if(FastJet PluginFastJet ACTS_BUILD_PLUGIN_FASTJET)
67
add_component_if(FpeMonitoring PluginFpeMonitoring ACTS_BUILD_PLUGIN_FPEMON)
78
add_component_if(Geant4 PluginGeant4 ACTS_BUILD_PLUGIN_GEANT4)
89
add_component_if(GeoModel PluginGeoModel ACTS_BUILD_PLUGIN_GEOMODEL)

0 commit comments

Comments
 (0)