From 55c9817a3469886767f0907a646dc6ca973cc449 Mon Sep 17 00:00:00 2001 From: Louis-Guillaume Gagnon Date: Mon, 16 Sep 2024 17:25:43 +0200 Subject: [PATCH] Add support for fastjet library --- CMakeLists.txt | 4 + Plugins/CMakeLists.txt | 1 + Plugins/FastJet/CMakeLists.txt | 16 ++ .../Acts/Plugins/FastJet/TrackJets.hpp | 71 +++++++++ .../Acts/Plugins/FastJet/TrackJets.ipp | 60 ++++++++ Tests/UnitTests/Plugins/CMakeLists.txt | 1 + .../UnitTests/Plugins/FastJet/CMakeLists.txt | 2 + .../Plugins/FastJet/TrackJetsTests.cpp | 139 ++++++++++++++++++ cmake/FindFastJet.cmake | 40 +++++ docs/getting_started.md | 1 + 10 files changed, 335 insertions(+) create mode 100644 Plugins/FastJet/CMakeLists.txt create mode 100644 Plugins/FastJet/include/Acts/Plugins/FastJet/TrackJets.hpp create mode 100644 Plugins/FastJet/include/Acts/Plugins/FastJet/TrackJets.ipp create mode 100644 Tests/UnitTests/Plugins/FastJet/CMakeLists.txt create mode 100644 Tests/UnitTests/Plugins/FastJet/TrackJetsTests.cpp create mode 100644 cmake/FindFastJet.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index f13ea348110..4bcde2b368e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,7 @@ option(ACTS_BUILD_PLUGIN_DD4HEP "Build DD4hep plugin" OFF) option(ACTS_BUILD_PLUGIN_PODIO "Build Podio plugin" OFF) option(ACTS_BUILD_PLUGIN_EDM4HEP "Build EDM4hep plugin" OFF) option(ACTS_BUILD_PLUGIN_FPEMON "Build FPE monitoring plugin" OFF) +option(ACTS_BUILD_PLUGIN_FASTJET "Build FastJet plugin" OFF) option(ACTS_BUILD_PLUGIN_GEOMODEL "Build GeoModel plugin" OFF) option(ACTS_BUILD_PLUGIN_TRACCC "Build Traccc plugin" OFF) option(ACTS_BUILD_PLUGIN_GEANT4 "Build Geant4 plugin" OFF) @@ -369,6 +370,9 @@ if(ACTS_BUILD_PLUGIN_JSON) add_subdirectory(thirdparty/nlohmann_json) endif() endif() +if(ACTS_BUILD_PLUGIN_FASTJET) + find_package(FastJet REQUIRED) +endif() if(ACTS_BUILD_PLUGIN_GEOMODEL) find_package(GeoModelCore ${_acts_geomodel_version} REQUIRED CONFIG) find_package(GeoModelIO ${_acts_geomodel_version} REQUIRED CONFIG) diff --git a/Plugins/CMakeLists.txt b/Plugins/CMakeLists.txt index f766f8d1293..9812c33cad9 100644 --- a/Plugins/CMakeLists.txt +++ b/Plugins/CMakeLists.txt @@ -3,6 +3,7 @@ # independent plugins add_component_if(ActSVG PluginActSVG ACTS_BUILD_PLUGIN_ACTSVG) add_component_if(Cuda PluginCuda ACTS_BUILD_PLUGIN_CUDA) +add_component_if(FastJet PluginFastJet ACTS_BUILD_PLUGIN_FASTJET) add_component_if(FpeMonitoring PluginFpeMonitoring ACTS_BUILD_PLUGIN_FPEMON) add_component_if(Geant4 PluginGeant4 ACTS_BUILD_PLUGIN_GEANT4) add_component_if(GeoModel PluginGeoModel ACTS_BUILD_PLUGIN_GEOMODEL) diff --git a/Plugins/FastJet/CMakeLists.txt b/Plugins/FastJet/CMakeLists.txt new file mode 100644 index 00000000000..6db33cebf15 --- /dev/null +++ b/Plugins/FastJet/CMakeLists.txt @@ -0,0 +1,16 @@ +add_library(ActsPluginFastJet INTERFACE) + +target_include_directories( + ActsPluginFastJet + INTERFACE + $ + $ +) +target_link_libraries(ActsPluginFastJet INTERFACE FastJet) + +install( + TARGETS ActsPluginFastJet + EXPORT ActsPluginFastJetTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} +) +install(DIRECTORY include/Acts DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/Plugins/FastJet/include/Acts/Plugins/FastJet/TrackJets.hpp b/Plugins/FastJet/include/Acts/Plugins/FastJet/TrackJets.hpp new file mode 100644 index 00000000000..6ff120083cf --- /dev/null +++ b/Plugins/FastJet/include/Acts/Plugins/FastJet/TrackJets.hpp @@ -0,0 +1,71 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2024 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include + +#include +#include + +#include +#include + +namespace Acts::FastJet { + +template +class TrackJetSequence { + public: + /// Get all the track jets passing the pT & eta cuts + /// + /// @param ptMin the minimum jet pT in GeV + /// @param etaMax the maximum jet absolute eta + /// + /// @return a vector of fastjet::PseudoJet objects + std::vector jets(float ptMin = 20 * + Acts::UnitConstants::GeV, + float etaMax = 2.5); + + /// Get the tracks making up a track-jet + /// + /// @param jet the jet from which to get the constituent tracks + /// @param coreR optional radius inside which to get the tracks + /// + /// @return a vector of TrackProxy + std::vector tracksInJet( + const fastjet::PseudoJet& jet, std::optional coreR = {}); + + /// Main constructor, but using the "makeTrackJets" function is recommended + /// + /// @param clusterSeq the fastjet::ClusterSequence object + /// @param inputTracks the input tracks that make up the sequence + TrackJetSequence(fastjet::ClusterSequence clusterSeq, + TrackContainer& inputTracks) + : m_clusterSeq{std::move(clusterSeq)}, m_inputTracks{inputTracks} {} + + private: + fastjet::ClusterSequence m_clusterSeq; + TrackContainer& m_inputTracks; +}; + +/// Default jet definition: Anti-kt with a radius of 0.4 +const fastjet::JetDefinition DefaultJetDefinition = + fastjet::JetDefinition(fastjet::antikt_algorithm, 0.4); + +/// Create a sequence of track jets +/// +/// @param tracks the input tracks +/// @jetDef the jet definition to use, defaults to "DefaultJetDefinition" +template +TrackJetSequence makeTrackJets( + TrackContainer& tracks, + fastjet::JetDefinition jetDef = DefaultJetDefinition); + +} // namespace Acts::FastJet + +#include "TrackJets.ipp" diff --git a/Plugins/FastJet/include/Acts/Plugins/FastJet/TrackJets.ipp b/Plugins/FastJet/include/Acts/Plugins/FastJet/TrackJets.ipp new file mode 100644 index 00000000000..b827d7c6de3 --- /dev/null +++ b/Plugins/FastJet/include/Acts/Plugins/FastJet/TrackJets.ipp @@ -0,0 +1,60 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2024 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include +#include + +template +Acts::FastJet::TrackJetSequence Acts::FastJet::makeTrackJets( + TrackContainer& tracks, fastjet::JetDefinition jetDef) { + std::vector inputs; + + for (std::size_t i = 0; i < tracks.size(); i++) { + typename TrackContainer::ConstTrackProxy track = tracks.getTrack(i); + Acts::Vector3 p = track.momentum(); + float m = track.particleHypothesis().mass(); + + float px = p[Acts::eMom0]; + float py = p[Acts::eMom1]; + float pz = p[Acts::eMom2]; + float e = std::sqrt(m * m + px * px + py * py + pz * pz); + + inputs.emplace_back(px, py, pz, e); + inputs.back().set_user_index(i); + } + + fastjet::ClusterSequence cs(inputs, jetDef); + + return TrackJetSequence(std::move(cs), tracks); +} + +template +std::vector +Acts::FastJet::TrackJetSequence::jets(float ptMin, + float etaMax) { + fastjet::Selector sel_eta = fastjet::SelectorAbsEtaMax(etaMax); + return sel_eta(m_clusterSeq.inclusive_jets(ptMin)); +} + +template +std::vector +Acts::FastJet::TrackJetSequence::tracksInJet( + const fastjet::PseudoJet& jet, std::optional coreR) { + fastjet::Selector sel = fastjet::SelectorIdentity(); + if (coreR.has_value()) { + sel = fastjet::SelectorCircle(coreR.value()); + sel.set_reference(jet); + } + + std::vector tracks; + for (fastjet::PseudoJet& cst : sel(jet.constituents())) { + tracks.push_back(m_inputTracks.getTrack(cst.user_index())); + } + + return tracks; +} diff --git a/Tests/UnitTests/Plugins/CMakeLists.txt b/Tests/UnitTests/Plugins/CMakeLists.txt index c9f412032e4..01d51e0ad6b 100644 --- a/Tests/UnitTests/Plugins/CMakeLists.txt +++ b/Tests/UnitTests/Plugins/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory_if(Cuda ACTS_BUILD_PLUGIN_CUDA) add_subdirectory_if(Detray ACTS_BUILD_PLUGIN_TRACCC) add_subdirectory_if(DD4hep ACTS_BUILD_PLUGIN_DD4HEP) add_subdirectory_if(ExaTrkX ACTS_BUILD_PLUGIN_EXATRKX) +add_subdirectory_if(FastJet ACTS_BUILD_PLUGIN_FASTJET) add_subdirectory_if(Geant4 ACTS_BUILD_PLUGIN_GEANT4) add_subdirectory_if(GeoModel ACTS_BUILD_PLUGIN_GEOMODEL) add_subdirectory_if(Json ACTS_BUILD_PLUGIN_JSON) diff --git a/Tests/UnitTests/Plugins/FastJet/CMakeLists.txt b/Tests/UnitTests/Plugins/FastJet/CMakeLists.txt new file mode 100644 index 00000000000..b20f3f8a67b --- /dev/null +++ b/Tests/UnitTests/Plugins/FastJet/CMakeLists.txt @@ -0,0 +1,2 @@ +set(unittest_extra_libraries ActsPluginFastJet) +add_unittest(TrackJetsTests TrackJetsTests.cpp) diff --git a/Tests/UnitTests/Plugins/FastJet/TrackJetsTests.cpp b/Tests/UnitTests/Plugins/FastJet/TrackJetsTests.cpp new file mode 100644 index 00000000000..33c38428ed4 --- /dev/null +++ b/Tests/UnitTests/Plugins/FastJet/TrackJetsTests.cpp @@ -0,0 +1,139 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2024 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include + +class ParticleHypothesis { + public: + float mass() { return 139.57061 * Acts::UnitConstants::MeV; } +}; + +class Track { + public: + Track(float pt, float eta, float phi) { + m_momentum[0] = pt * std::cos(phi); + m_momentum[1] = pt * std::sin(phi); + m_momentum[1] = pt * std::sinh(eta); + } + Acts::Vector3 momentum() const { return m_momentum; } + ParticleHypothesis particleHypothesis() const { return ParticleHypothesis(); } + + private: + Acts::Vector3 m_momentum; +}; + +bool operator==(Track const& lhs, Track const& rhs) { + return lhs.momentum() == rhs.momentum(); +} + +class TrackContainer { + public: + using TrackProxy = Track; + + TrackContainer() {} + void insert(Track track) { m_vec.push_back(std::move(track)); } + std::size_t size() { return m_vec.size(); } + + using ConstTrackProxy = const Track&; + ConstTrackProxy getTrack(std::size_t i) { + if (i < size()) { + return m_vec[i]; + } + throw std::runtime_error("Too few tracks"); + } + + private: + std::vector m_vec; +}; + +BOOST_AUTO_TEST_CASE(SingleTrack) { + TrackContainer tracks; + tracks.insert(Track(100, 0, 0)); + + Acts::FastJet::TrackJetSequence jetSeq = Acts::FastJet::makeTrackJets(tracks); + std::vector jets = jetSeq.jets(); + + BOOST_CHECK_EQUAL(jets.size(), 1); + BOOST_CHECK_EQUAL(jets[0].constituents().size(), 1); + BOOST_CHECK_EQUAL(jets[0].constituents()[0].user_index(), 0); + BOOST_CHECK_CLOSE(jets[0].pt(), 100, 1e-3); + BOOST_CHECK_CLOSE(jets[0].eta(), 0, 1e-3); + BOOST_CHECK_CLOSE(jets[0].phi(), 0, 1e-3); + BOOST_CHECK_CLOSE(jets[0].m(), ParticleHypothesis().mass(), 1); +} + +BOOST_AUTO_TEST_CASE(TwoTracksTwoJets) { + TrackContainer tracks; + tracks.insert(Track(100, 0, 0.0)); + tracks.insert(Track(100, 0, M_PI)); + + Acts::FastJet::TrackJetSequence jetSeq = Acts::FastJet::makeTrackJets(tracks); + std::vector jets = jetSeq.jets(); + + BOOST_CHECK_EQUAL(jets.size(), 2); + + std::vector trks_0 = jetSeq.tracksInJet(jets[0]); + BOOST_CHECK_EQUAL(trks_0.size(), 1); + BOOST_CHECK(trks_0[0] == tracks.getTrack(0) || + trks_0[0] == tracks.getTrack(1)); + + std::vector trks_1 = jetSeq.tracksInJet(jets[1]); + BOOST_CHECK_EQUAL(trks_1.size(), 1); + BOOST_CHECK(trks_1[0] == tracks.getTrack(0) || + trks_1[0] == tracks.getTrack(1)); + BOOST_CHECK(trks_0[0] != trks_1[0]); +} + +BOOST_AUTO_TEST_CASE(TwoTracksOneJet) { + TrackContainer tracks; + tracks.insert(Track(100, 0, 0.0)); + tracks.insert(Track(100, 0, 0.2)); + + Acts::FastJet::TrackJetSequence jetSeq = Acts::FastJet::makeTrackJets(tracks); + std::vector jets = jetSeq.jets(); + + BOOST_CHECK_EQUAL(jets.size(), 1); + + std::vector trks_0 = jetSeq.tracksInJet(jets[0]); + BOOST_CHECK_EQUAL(trks_0.size(), 2); + BOOST_CHECK(trks_0[0] == tracks.getTrack(0) || + trks_0[0] == tracks.getTrack(1)); + BOOST_CHECK(trks_0[1] == tracks.getTrack(0) || + trks_0[1] == tracks.getTrack(1)); + BOOST_CHECK(trks_0[0] != trks_0[1]); +} + +BOOST_AUTO_TEST_CASE(TracksInJetCore) { + TrackContainer tracks; + tracks.insert(Track(100, 0, 0)); + tracks.insert(Track(10, 0.05, 0)); + tracks.insert(Track(10, -0.05, 0)); + tracks.insert(Track(10, 0.2, 0)); + tracks.insert(Track(10, -0.2, 0)); + + Acts::FastJet::TrackJetSequence jetSeq = Acts::FastJet::makeTrackJets(tracks); + std::vector jets = jetSeq.jets(); + + BOOST_REQUIRE_EQUAL(jets.size(), 1); + + std::vector trks = jetSeq.tracksInJet(jets[0], 0.1); + BOOST_CHECK_EQUAL(trks.size(), 3); + + BOOST_CHECK(std::find(trks.begin(), trks.end(), tracks.getTrack(0)) != + trks.end()); + BOOST_CHECK(std::find(trks.begin(), trks.end(), tracks.getTrack(1)) != + trks.end()); + BOOST_CHECK(std::find(trks.begin(), trks.end(), tracks.getTrack(2)) != + trks.end()); + BOOST_CHECK(std::find(trks.begin(), trks.end(), tracks.getTrack(3)) == + trks.end()); + BOOST_CHECK(std::find(trks.begin(), trks.end(), tracks.getTrack(4)) == + trks.end()); +} diff --git a/cmake/FindFastJet.cmake b/cmake/FindFastJet.cmake new file mode 100644 index 00000000000..cdf663cd4ab --- /dev/null +++ b/cmake/FindFastJet.cmake @@ -0,0 +1,40 @@ +# Find the FastJet includes and libraries. + +find_library(FastJet_LIBRARY NAMES FastJet fastjet DOC "The FastJet library") + +find_path( + FastJet_INCLUDE_DIR + fastjet/version.hh + DOC "The FastJet include directory" +) + +file(READ "${FastJet_INCLUDE_DIR}/fastjet/config_auto.h" FastJet_VERSION_FILE) +string( + REGEX MATCH + "#define FASTJET_PACKAGE_VERSION \"([0-9]+\.[0-9]+\.[0-9]+)\"" + _ + ${FastJet_VERSION_FILE} +) + +set(FastJet_VERSION ${CMAKE_MATCH_1}) + +find_package_handle_standard_args( + FastJet + REQUIRED_VARS FastJet_LIBRARY FastJet_INCLUDE_DIR + VERSION_VAR FastJet_VERSION +) + +add_library(FastJet SHARED IMPORTED) +set_property(TARGET FastJet PROPERTY IMPORTED_LOCATION ${FastJet_LIBRARY}) +set_property( + TARGET FastJet + PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${FastJet_INCLUDE_DIR} +) + +mark_as_advanced(FastJet_FOUND FastJet_INCLUDE_DIR FastJet_LIBRARY) + +if(FastJet_FOUND) + message(STATUS "Found FastJet ${FastJet_VERSION} at ${FastJet_LIBRARY}") +else() + message(FATAL_ERROR "FastJet not found") +endif() diff --git a/docs/getting_started.md b/docs/getting_started.md index fbc247a3e05..b75de96e877 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -279,6 +279,7 @@ components. | ACTS_BUILD_PLUGIN_PODIO | Build Podio plugin
type: `bool`, default: `OFF` | | ACTS_BUILD_PLUGIN_EDM4HEP | Build EDM4hep plugin
type: `bool`, default: `OFF` | | ACTS_BUILD_PLUGIN_FPEMON | Build FPE monitoring plugin
type: `bool`, default: `OFF` | +| ACTS_BUILD_PLUGIN_FASTJET | Build FastJet plugin
type: `bool`, default: `OFF` | | ACTS_BUILD_PLUGIN_GEOMODEL | Build GeoModel plugin
type: `bool`, default: `OFF` | | ACTS_BUILD_PLUGIN_TRACCC | Build Traccc plugin
type: `bool`, default: `OFF` | | ACTS_BUILD_PLUGIN_GEANT4 | Build Geant4 plugin
type: `bool`, default: `OFF` |