diff --git a/CI/physmon/phys_perf_mon.sh b/CI/physmon/phys_perf_mon.sh index c2944f0dd06..8482f92c4b6 100755 --- a/CI/physmon/phys_perf_mon.sh +++ b/CI/physmon/phys_perf_mon.sh @@ -265,6 +265,15 @@ function trackfinding() { $path/performance_finding_ckf_ambi.html \ $path/performance_finding_ckf_ambi fi + + if [ -f $refdir/$path/performance_finding_ckf_ml_solver.root ]; then + run_histcmp \ + $outdir/data/$path/performance_finding_ckf_ml_solver.root \ + $refdir/$path/performance_finding_ckf_ml_solver.root \ + "ML Ambisolver | ${name}" \ + $path/performance_finding_ckf_ml_solver.html \ + $path/performance_finding_ckf_ml_solver + fi } function vertexing() { diff --git a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_finding_ckf_ml_solver.root b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_finding_ckf_ml_solver.root new file mode 100644 index 00000000000..db22a916d9e Binary files /dev/null and b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_finding_ckf_ml_solver.root differ diff --git a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_fitting_ckf_ml_solver.root b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_fitting_ckf_ml_solver.root new file mode 100644 index 00000000000..0a40506d1bb Binary files /dev/null and b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_fitting_ckf_ml_solver.root differ diff --git a/CI/physmon/workflows/physmon_trackfinding_ttbar_pu200.py b/CI/physmon/workflows/physmon_trackfinding_ttbar_pu200.py index 99f12d0170d..4b4c75e1f36 100755 --- a/CI/physmon/workflows/physmon_trackfinding_ttbar_pu200.py +++ b/CI/physmon/workflows/physmon_trackfinding_ttbar_pu200.py @@ -19,7 +19,9 @@ CkfConfig, addCKFTracks, addAmbiguityResolution, + addAmbiguityResolutionML, AmbiguityResolutionConfig, + AmbiguityResolutionMLConfig, addVertexFitting, VertexFinder, TrackSelectorConfig, @@ -134,6 +136,17 @@ outputDirRoot=tp, ) + addAmbiguityResolutionML( + s, + AmbiguityResolutionMLConfig( + maximumSharedHits=3, maximumIterations=1000000, nMeasurementsMin=6 + ), + tracks="ckf_tracks", + outputDirRoot=tp, + onnxModelFile=Path(__file__).resolve().parent.parent.parent.parent + / "thirdparty/OpenDataDetector/data/duplicateClassifier.onnx", + ) + addAmbiguityResolution( s, AmbiguityResolutionConfig( @@ -141,6 +154,7 @@ maximumIterations=100000, nMeasurementsMin=6, ), + tracks="ckf_tracks", outputDirRoot=tp, ) @@ -187,6 +201,17 @@ tp / "performance_fitting_ambi.root", tp / "performance_fitting_ckf_ambi.root", ) + + shutil.move( + tp / "performance_finding_ambiML.root", + tp / "performance_finding_ckf_ml_solver.root", + ) + + shutil.move( + tp / "performance_fitting_ambiML.root", + tp / "performance_fitting_ckf_ml_solver.root", + ) + for vertexing in ["amvf_gauss_notime", "amvf_grid_time"]: shutil.move( tp / f"{vertexing}/performance_vertexing.root", @@ -200,6 +225,8 @@ "performance_fitting_ckf.root", "performance_finding_ckf_ambi.root", "performance_fitting_ckf_ambi.root", + "performance_finding_ckf_ml_solver.root", + "performance_fitting_ckf_ml_solver.root", "performance_vertexing_amvf_gauss_notime.root", "performance_vertexing_amvf_grid_time.root", ]: diff --git a/Core/include/Acts/AmbiguityResolution/AmbiguityNetworkConcept.hpp b/Core/include/Acts/AmbiguityResolution/AmbiguityNetworkConcept.hpp new file mode 100644 index 00000000000..a69e1fee9fe --- /dev/null +++ b/Core/include/Acts/AmbiguityResolution/AmbiguityNetworkConcept.hpp @@ -0,0 +1,51 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "Acts/EventData/TrackContainer.hpp" +#include "Acts/EventData/TrackContainerFrontendConcept.hpp" +#include "Acts/EventData/VectorMultiTrajectory.hpp" +#include "Acts/EventData/VectorTrackContainer.hpp" +#include "Acts/Utilities/Concepts.hpp" + +namespace Acts { + +/// @brief Concept for the ambiguity network used in the ambiguity resolution +/// +/// The ambiguity network correspond to the AmbiguityTrackClassifier found in +/// the Onnx plugin. It is used to score the tracks and select the best ones. +/// +/// The constructor of the Ambiguity Solver network should take string as input +/// corresponding to the path of the ONNX model. +/// The implementation of the Ambiguity Solver network should have two methods: +/// - inferScores: takes clusters (a list of track ID associated with a cluster +/// ID) and the track container and return an outputTensor (list of scores for +/// each track in the clusters). +/// - trackSelection: Takes clusters and the output tensor from the inferScores +/// method and return the list of track ID to keep. +/// +/// @tparam N the type of the network +template +concept AmbiguityNetworkConcept = requires( + TrackContainer &tracks, + std::unordered_map> &clusters, + std::vector> &outputTensor, const char *modelPath, + network_t &n) { + { network_t(modelPath) } -> std::same_as; + + { + n.inferScores(clusters, tracks) + } -> std::same_as>>; + { + n.trackSelection(clusters, outputTensor) + } -> std::same_as>; +}; + +} // namespace Acts diff --git a/Core/include/Acts/AmbiguityResolution/AmbiguityResolutionML.hpp b/Core/include/Acts/AmbiguityResolution/AmbiguityResolutionML.hpp new file mode 100644 index 00000000000..66717e3f8ee --- /dev/null +++ b/Core/include/Acts/AmbiguityResolution/AmbiguityResolutionML.hpp @@ -0,0 +1,136 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "Acts/AmbiguityResolution/AmbiguityNetworkConcept.hpp" +#include "Acts/Definitions/Units.hpp" +#include "Acts/EventData/TrackContainer.hpp" +#include "Acts/Utilities/Delegate.hpp" +#include "Acts/Utilities/Logger.hpp" + +#include +#include +#include +#include +#include +#include + +namespace Acts { + +/// Generic implementation of the machine learning ambiguity resolution +/// Contains method for data preparations +template +class AmbiguityResolutionML { + public: + struct Config { + /// Path to the model file for the duplicate neural network + std::string inputDuplicateNN = ""; + /// Minimum number of measurement to form a track. + std::size_t nMeasurementsMin = 7; + }; + /// Construct the ambiguity resolution algorithm. + /// + /// @param cfg is the algorithm configuration + /// @param logger is the logging instance + AmbiguityResolutionML(const Config& cfg, + std::unique_ptr logger = getDefaultLogger( + "AmbiguityResolutionML", Logging::INFO)) + : m_cfg{cfg}, + m_duplicateClassifier(m_cfg.inputDuplicateNN.c_str()), + m_logger{std::move(logger)} {} + + /// Associate the hits to the tracks + /// + /// This algorithm performs the mapping of hits ID to track ID. Our final goal + /// is too loop over all the tracks (and their associated hits) by order of + /// decreasing number hits for this we use a multimap where the key is the + /// number of hits as this will automatically perform the sorting. + /// + /// @param tracks is the input track container + /// @param sourceLinkHash is the hash function for the source link, will be used to associate to tracks + /// @param sourceLinkEquality is the equality function for the source link used used to associated hits to tracks + /// @return an ordered list containing pairs of track ID and associated measurement ID + template + std::multimap>> + mapTrackHits(const track_container_t& tracks, + const source_link_hash_t& sourceLinkHash, + const source_link_equality_t& sourceLinkEquality) const { + // A map to store (and generate) the measurement index for each source link + auto measurementIndexMap = + std::unordered_map(0, sourceLinkHash, + sourceLinkEquality); + + // A map to store the track Id and their associated measurements ID, a + // multimap is used to automatically sort the tracks by the number of + // measurements + std::multimap>> + trackMap; + std::size_t trackIndex = 0; + std::vector measurements; + // Loop over all the trajectories in the events + for (const auto& track : tracks) { + // Kick out tracks that do not fulfill our initial requirements + if (track.nMeasurements() < m_cfg.nMeasurementsMin) { + continue; + } + measurements.clear(); + for (auto ts : track.trackStatesReversed()) { + if (ts.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) { + SourceLink sourceLink = ts.getUncalibratedSourceLink(); + // assign a new measurement index if the source link was not seen yet + auto emplace = measurementIndexMap.try_emplace( + sourceLink, measurementIndexMap.size()); + measurements.push_back(emplace.first->second); + } + } + trackMap.emplace(track.nMeasurements(), + std::make_pair(trackIndex, measurements)); + ++trackIndex; + } + return trackMap; + } + + /// Select the track associated with each cluster + /// + /// In this algorithm the call the neural network to score the tracks and then + /// select the track with the highest score in each cluster + /// + /// @param clusters is a map of clusters, each cluster correspond to a vector of track ID + /// @param tracks is the input track container + /// @return a vector of trackID corresponding tho the good tracks + template + std::vector solveAmbiguity( + std::unordered_map>& clusters, + const track_container_t& tracks) const { + std::vector> outputTensor = + m_duplicateClassifier.inferScores(clusters, tracks); + std::vector goodTracks = + m_duplicateClassifier.trackSelection(clusters, outputTensor); + + return goodTracks; + } + + private: + // Configuration + Config m_cfg; + + // The neural network for duplicate classification, the network + // implementation is chosen with the AmbiguityNetwork template parameter + AmbiguityNetwork m_duplicateClassifier; + + /// Logging instance + std::unique_ptr m_logger = nullptr; + + /// Private access to logging instance + const Logger& logger() const { return *m_logger; } +}; + +} // namespace Acts diff --git a/Core/include/Acts/TrackFinding/detail/AmbiguityTrackClustering.hpp b/Core/include/Acts/TrackFinding/detail/AmbiguityTrackClustering.hpp index 6bc565f80eb..644a0fa34fd 100644 --- a/Core/include/Acts/TrackFinding/detail/AmbiguityTrackClustering.hpp +++ b/Core/include/Acts/TrackFinding/detail/AmbiguityTrackClustering.hpp @@ -15,7 +15,15 @@ namespace Acts::detail { -/// Clusterise tracks based on shared hits +/// Cluster tracks based on shared hits. +/// +/// In this algorithm we will loop through all the tracks by decreasing number +/// of measurements. Cluster are created when a new track is encountered that +/// doesn't share hits with the leading track of a previous cluster (with the +/// leading track defined as the track that lead to the cluster creation). If a +/// track shares hits with the leading track of a cluster, it is added to that +/// cluster. If a track shares hits with multiple clusters, it is associated to +/// the cluster with the leading track with the most hits. /// /// @param trackMap : Multimap storing pair of track ID and vector of measurement ID. The keys are the number of measurement and are just there to facilitate the ordering. /// @return an unordered map representing the clusters, the keys the ID of the primary track of each cluster and the store a vector of track IDs. diff --git a/Core/src/TrackFinding/AmbiguityTrackClustering.cpp b/Core/src/TrackFinding/AmbiguityTrackClustering.cpp index ff0e95cbb3d..8586f571aec 100644 --- a/Core/src/TrackFinding/AmbiguityTrackClustering.cpp +++ b/Core/src/TrackFinding/AmbiguityTrackClustering.cpp @@ -21,8 +21,9 @@ Acts::detail::clusterDuplicateTracks( // different clusters. std::unordered_map hitToTrack; - // Loop over all the tracks - for (const auto& [_, trackValue] : trackMap) { + // Loop backward over all the tracks + for (auto track = trackMap.rbegin(); track != trackMap.rend(); ++track) { + const auto& trackValue = track->second; std::vector hits = trackValue.second; auto matchedTrack = hitToTrack.end(); // Loop over all the hits in the track diff --git a/Examples/Algorithms/TrackFindingML/CMakeLists.txt b/Examples/Algorithms/TrackFindingML/CMakeLists.txt index d826b224f2c..80f55f60579 100644 --- a/Examples/Algorithms/TrackFindingML/CMakeLists.txt +++ b/Examples/Algorithms/TrackFindingML/CMakeLists.txt @@ -1,7 +1,5 @@ set(SOURCES - src/AmbiguityResolutionML.cpp src/AmbiguityResolutionMLAlgorithm.cpp - src/AmbiguityResolutionMLDBScanAlgorithm.cpp src/SeedFilterMLAlgorithm.cpp ) diff --git a/Examples/Algorithms/TrackFindingML/include/ActsExamples/TrackFindingML/AmbiguityDBScanClustering.hpp b/Examples/Algorithms/TrackFindingML/include/ActsExamples/TrackFindingML/AmbiguityDBScanClustering.hpp deleted file mode 100644 index 45fe4cb5480..00000000000 --- a/Examples/Algorithms/TrackFindingML/include/ActsExamples/TrackFindingML/AmbiguityDBScanClustering.hpp +++ /dev/null @@ -1,79 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/. - -#pragma once - -#include "Acts/EventData/TrackContainer.hpp" -#include "Acts/EventData/TrackContainerFrontendConcept.hpp" -#include "Acts/TrackFinding/detail/AmbiguityTrackClustering.hpp" -#include "Acts/Utilities/DBScan.hpp" - -#include -#include -#include - -namespace Acts { - -/// Clusterise tracks based on shared hits -/// -/// @param trackMap Multimap storing pair of track ID and vector of measurement ID. The keys are the number of measurement and are just there to facilitate the ordering. -/// @param tracks Track container with all the track to be clustered -/// @param epsilon Maximum distance between 2 tracks to be clustered -/// @param minPoints Minimum number of tracks to create a cluster -/// @return an unordered map representing the clusters, the keys the ID of the primary track of each cluster and the store a vector of track IDs. -template -std::unordered_map> dbscanTrackClustering( - std::multimap>>& - trackMap, - const track_container_t& tracks, float epsilon = 0.07, int minPoints = 2) { - // Unordered map associating a vector with all the track ID of a cluster to - // the ID of the first track of the cluster - std::unordered_map> cluster; - // Unordered map associating hits to the ID of the first track of the - // different clusters. - std::unordered_map hitToTrack; - - // Initialize a DBScan of dimension 4 (phi, eta, z, Pt) - using DBSCAN = Acts::DBScan<4, double, 4>; - DBSCAN dbscan(epsilon, minPoints, true); - - std::vector> data; - std::size_t trackID = 0; - std::vector clusterAssignments; - - // Get the input feature of the network for all the tracks - for (const auto& [key, val] : trackMap) { - auto traj = tracks.getTrack(val.first); - data.push_back({Acts::VectorHelpers::eta(traj.momentum()), - Acts::VectorHelpers::phi(traj.momentum())}); - } - std::size_t clusterNb = dbscan.cluster(data, clusterAssignments); - - // Cluster track with DBScan - std::vector< - std::multimap>>> - dbscanClusters(clusterNb); - for (const auto& [key, val] : trackMap) { - std::size_t clusterID = clusterAssignments[trackID]; - dbscanClusters[clusterID].emplace(key, val); - trackID++; - } - - // Perform a subClustering of the DBScan cluster using the measurement ID - // clustering - for (const auto& dbscanCluster : dbscanClusters) { - auto subCluster = Acts::detail::clusterDuplicateTracks(dbscanCluster); - cluster.merge(subCluster); - if (!subCluster.empty()) { - std::cout << "Overlapping track ID, there must be an error" << std::endl; - } - } - return cluster; -} - -} // namespace Acts diff --git a/Examples/Algorithms/TrackFindingML/include/ActsExamples/TrackFindingML/AmbiguityResolutionML.hpp b/Examples/Algorithms/TrackFindingML/include/ActsExamples/TrackFindingML/AmbiguityResolutionML.hpp deleted file mode 100644 index ea967a23c22..00000000000 --- a/Examples/Algorithms/TrackFindingML/include/ActsExamples/TrackFindingML/AmbiguityResolutionML.hpp +++ /dev/null @@ -1,48 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/. - -#pragma once - -#include "ActsExamples/EventData/Track.hpp" -#include "ActsExamples/Framework/IAlgorithm.hpp" - -#include -#include -#include - -namespace ActsExamples { - -/// Generic implementation of the machine learning ambiguity resolution -/// Contains method for data preparations -class AmbiguityResolutionML : public IAlgorithm { - public: - /// Construct the ambiguity resolution algorithm. - /// - /// @param name name of the algorithm - /// @param lvl is the logging level - AmbiguityResolutionML(std::string name, Acts::Logging::Level lvl); - - protected: - /// Associated measurements ID to Tracks ID - /// - /// @param tracks is the input track container - /// @param nMeasurementsMin minimum number of measurement per track - /// @return an ordered list containing pairs of track ID and associated measurement ID - std::multimap>> - mapTrackHits(const ConstTrackContainer& tracks, int nMeasurementsMin) const; - - /// Prepare the output track container to be written - /// - /// @param tracks is the input track container - /// @param goodTracks is list of the IDs of all the tracks we want to keep - ConstTrackContainer prepareOutputTrack( - const ConstTrackContainer& tracks, - std::vector& goodTracks) const; -}; - -} // namespace ActsExamples diff --git a/Examples/Algorithms/TrackFindingML/include/ActsExamples/TrackFindingML/AmbiguityResolutionMLAlgorithm.hpp b/Examples/Algorithms/TrackFindingML/include/ActsExamples/TrackFindingML/AmbiguityResolutionMLAlgorithm.hpp index 2e5d22ac01d..e591b2e201a 100644 --- a/Examples/Algorithms/TrackFindingML/include/ActsExamples/TrackFindingML/AmbiguityResolutionMLAlgorithm.hpp +++ b/Examples/Algorithms/TrackFindingML/include/ActsExamples/TrackFindingML/AmbiguityResolutionMLAlgorithm.hpp @@ -8,10 +8,11 @@ #pragma once +#include "Acts/AmbiguityResolution/AmbiguityResolutionML.hpp" #include "Acts/Plugins/Onnx/AmbiguityTrackClassifier.hpp" #include "ActsExamples/EventData/Track.hpp" #include "ActsExamples/Framework/DataHandle.hpp" -#include "ActsExamples/TrackFindingML/AmbiguityResolutionML.hpp" +#include "ActsExamples/Framework/IAlgorithm.hpp" #include @@ -23,7 +24,10 @@ namespace ActsExamples { /// 1) Cluster together nearby tracks using shared hits /// 2) For each track use a neural network to compute a score /// 3) In each cluster keep the track with the highest score -class AmbiguityResolutionMLAlgorithm final : public AmbiguityResolutionML { +class AmbiguityResolutionMLAlgorithm final : public IAlgorithm { + using AmbiguityResolution = + Acts::AmbiguityResolutionML; + public: struct Config { /// Input track collection. @@ -33,7 +37,11 @@ class AmbiguityResolutionMLAlgorithm final : public AmbiguityResolutionML { /// Output track collection. std::string outputTracks; /// Minimum number of measurement to form a track. - int nMeasurementsMin = 7; + std::size_t nMeasurementsMin = 7; + /// Construct the ML ambiguity resolution configuration. + AmbiguityResolution::Config toAmbiguityResolutionMLConfig() const { + return {inputDuplicateNN, nMeasurementsMin}; + } }; /// Construct the ambiguity resolution algorithm. @@ -53,8 +61,7 @@ class AmbiguityResolutionMLAlgorithm final : public AmbiguityResolutionML { private: Config m_cfg; - // ONNX model for track selection - Acts::AmbiguityTrackClassifier m_duplicateClassifier; + AmbiguityResolution m_ambiML; ReadDataHandle m_inputTracks{this, "InputTracks"}; WriteDataHandle m_outputTracks{this, "OutputTracks"}; }; diff --git a/Examples/Algorithms/TrackFindingML/include/ActsExamples/TrackFindingML/AmbiguityResolutionMLDBScanAlgorithm.hpp b/Examples/Algorithms/TrackFindingML/include/ActsExamples/TrackFindingML/AmbiguityResolutionMLDBScanAlgorithm.hpp deleted file mode 100644 index 6ad387ffdc4..00000000000 --- a/Examples/Algorithms/TrackFindingML/include/ActsExamples/TrackFindingML/AmbiguityResolutionMLDBScanAlgorithm.hpp +++ /dev/null @@ -1,68 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/. - -#pragma once - -#include "Acts/Plugins/Onnx/AmbiguityTrackClassifier.hpp" -#include "ActsExamples/EventData/Track.hpp" -#include "ActsExamples/Framework/DataHandle.hpp" -#include "ActsExamples/TrackFindingML/AmbiguityResolutionML.hpp" - -#include - -namespace ActsExamples { - -/// Evicts tracks that seem to be duplicated and fake. -/// -/// The implementation works as follows: -/// 1) Cluster together nearby tracks using a DBScan -/// 2) Create subcluster based on tracks with shared hits -/// 3) For each track use a neural network to compute a score -/// 4) In each cluster keep the track with the highest score -class AmbiguityResolutionMLDBScanAlgorithm final - : public AmbiguityResolutionML { - public: - struct Config { - /// Input trajectories collection. - std::string inputTracks; - /// Path to the ONNX model for the duplicate neural network - std::string inputDuplicateNN; - /// Output trajectories collection. - std::string outputTracks; - /// Minimum number of measurement to form a track. - int nMeasurementsMin = 7; - /// Maximum distance between 2 tracks to be clustered in the DBScan - float epsilonDBScan = 0.07; - /// Minimum number of tracks to create a cluster in the DBScan - int minPointsDBScan = 2; - }; - - /// Construct the ambiguity resolution algorithm. - /// - /// @param cfg is the algorithm configuration - /// @param lvl is the logging level - AmbiguityResolutionMLDBScanAlgorithm(Config cfg, Acts::Logging::Level lvl); - - /// Run the ambiguity resolution algorithm. - /// - /// @param cxt is the algorithm context with event information - /// @return a process code indication success or failure - ProcessCode execute(const AlgorithmContext& ctx) const final; - - /// Const access to the config - const Config& config() const { return m_cfg; } - - private: - Config m_cfg; - // ONNX model for track selection - Acts::AmbiguityTrackClassifier m_duplicateClassifier; - ReadDataHandle m_inputTracks{this, "InputTracks"}; - WriteDataHandle m_outputTracks{this, "OutputTracks"}; -}; - -} // namespace ActsExamples diff --git a/Examples/Algorithms/TrackFindingML/include/ActsExamples/TrackFindingML/SeedFilterMLAlgorithm.hpp b/Examples/Algorithms/TrackFindingML/include/ActsExamples/TrackFindingML/SeedFilterMLAlgorithm.hpp index 6472a6e8d2b..53659a33e4f 100644 --- a/Examples/Algorithms/TrackFindingML/include/ActsExamples/TrackFindingML/SeedFilterMLAlgorithm.hpp +++ b/Examples/Algorithms/TrackFindingML/include/ActsExamples/TrackFindingML/SeedFilterMLAlgorithm.hpp @@ -12,7 +12,7 @@ #include "ActsExamples/EventData/SimSeed.hpp" #include "ActsExamples/EventData/Track.hpp" #include "ActsExamples/Framework/DataHandle.hpp" -#include "ActsExamples/TrackFindingML/AmbiguityResolutionML.hpp" +#include "ActsExamples/Framework/IAlgorithm.hpp" #include diff --git a/Examples/Algorithms/TrackFindingML/src/AmbiguityResolutionML.cpp b/Examples/Algorithms/TrackFindingML/src/AmbiguityResolutionML.cpp deleted file mode 100644 index f3282a15d94..00000000000 --- a/Examples/Algorithms/TrackFindingML/src/AmbiguityResolutionML.cpp +++ /dev/null @@ -1,76 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/. - -#include "ActsExamples/TrackFindingML/AmbiguityResolutionML.hpp" - -#include "ActsExamples/EventData/IndexSourceLink.hpp" -#include "ActsExamples/EventData/Measurement.hpp" - -ActsExamples::AmbiguityResolutionML::AmbiguityResolutionML( - std::string name, Acts::Logging::Level lvl) - : ActsExamples::IAlgorithm(name, lvl) {} - -std::multimap>> -ActsExamples::AmbiguityResolutionML::mapTrackHits( - const ActsExamples::ConstTrackContainer& tracks, - int nMeasurementsMin) const { - std::multimap>> trackMap; - // Loop over all the trajectories in the events - for (const auto& track : tracks) { - std::vector hits; - int nbMeasurements = 0; - // Store the hits id for the trajectory and compute the number of - // measurement - tracks.trackStateContainer().visitBackwards( - track.tipIndex(), [&](const auto& state) { - if (state.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) { - std::size_t indexHit = - state.getUncalibratedSourceLink() - .template get() - .index(); - hits.emplace_back(indexHit); - ++nbMeasurements; - } - }); - if (nbMeasurements < nMeasurementsMin) { - continue; - } - trackMap.emplace(nbMeasurements, std::make_pair(track.index(), hits)); - } - return trackMap; -} - -ActsExamples::ConstTrackContainer -ActsExamples::AmbiguityResolutionML::prepareOutputTrack( - const ActsExamples::ConstTrackContainer& tracks, - std::vector& goodTracks) const { - std::shared_ptr trackStateContainer = - tracks.trackStateContainerHolder(); - auto trackContainer = std::make_shared(); - trackContainer->reserve(goodTracks.size()); - // Temporary empty track state container: we don't change the original one, - // but we need one for filtering - auto tempTrackStateContainer = - std::make_shared(); - - TrackContainer solvedTracks{trackContainer, tempTrackStateContainer}; - solvedTracks.ensureDynamicColumns(tracks); - - for (auto&& iTrack : goodTracks) { - auto destProxy = solvedTracks.makeTrack(); - auto srcProxy = tracks.getTrack(iTrack); - destProxy.copyFrom(srcProxy, false); - destProxy.tipIndex() = srcProxy.tipIndex(); - } - - ConstTrackContainer outputTracks{ - std::make_shared( - std::move(*trackContainer)), - trackStateContainer}; - return outputTracks; -} diff --git a/Examples/Algorithms/TrackFindingML/src/AmbiguityResolutionMLAlgorithm.cpp b/Examples/Algorithms/TrackFindingML/src/AmbiguityResolutionMLAlgorithm.cpp index ba2e9abeb98..805913e60ae 100644 --- a/Examples/Algorithms/TrackFindingML/src/AmbiguityResolutionMLAlgorithm.cpp +++ b/Examples/Algorithms/TrackFindingML/src/AmbiguityResolutionMLAlgorithm.cpp @@ -8,18 +8,30 @@ #include "ActsExamples/TrackFindingML/AmbiguityResolutionMLAlgorithm.hpp" +#include "ActsExamples/EventData/IndexSourceLink.hpp" +#include "ActsExamples/EventData/Measurement.hpp" #include "ActsExamples/Framework/ProcessCode.hpp" #include #include +static std::size_t sourceLinkHash(const Acts::SourceLink& a) { + return static_cast( + a.get().index()); +} + +static bool sourceLinkEquality(const Acts::SourceLink& a, + const Acts::SourceLink& b) { + return a.get().index() == + b.get().index(); +} + ActsExamples::AmbiguityResolutionMLAlgorithm::AmbiguityResolutionMLAlgorithm( ActsExamples::AmbiguityResolutionMLAlgorithm::Config cfg, Acts::Logging::Level lvl) - : ActsExamples::AmbiguityResolutionML("AmbiguityResolutionMLAlgorithm", - lvl), + : ActsExamples::IAlgorithm("AmbiguityResolutionMLAlgorithm", lvl), m_cfg(std::move(cfg)), - m_duplicateClassifier(m_cfg.inputDuplicateNN.c_str()) { + m_ambiML(m_cfg.toAmbiguityResolutionMLConfig(), logger().clone()) { if (m_cfg.inputTracks.empty()) { throw std::invalid_argument("Missing trajectories input collection"); } @@ -34,15 +46,32 @@ ActsExamples::ProcessCode ActsExamples::AmbiguityResolutionMLAlgorithm::execute( const AlgorithmContext& ctx) const { // Read input data const auto& tracks = m_inputTracks(ctx); - // Associate measurement to their respective tracks + // Associate measurement to their respective tracks to prepare the track + // shared hits based clustering std::multimap>> - trackMap = mapTrackHits(tracks, m_cfg.nMeasurementsMin); + trackMap = + m_ambiML.mapTrackHits(tracks, &sourceLinkHash, &sourceLinkEquality); + // Cluster the tracks based on the shared hits auto cluster = Acts::detail::clusterDuplicateTracks(trackMap); // Select the ID of the track we want to keep std::vector goodTracks = - m_duplicateClassifier.solveAmbiguity(cluster, tracks); + m_ambiML.solveAmbiguity(cluster, tracks); // Prepare the output track collection from the IDs - auto outputTracks = prepareOutputTrack(tracks, goodTracks); + TrackContainer solvedTracks{std::make_shared(), + std::make_shared()}; + solvedTracks.ensureDynamicColumns(tracks); + for (auto iTrack : goodTracks) { + auto destProxy = solvedTracks.makeTrack(); + auto srcProxy = tracks.getTrack(iTrack); + destProxy.copyFrom(srcProxy, false); + destProxy.tipIndex() = srcProxy.tipIndex(); + } + + ActsExamples::ConstTrackContainer outputTracks{ + std::make_shared( + std::move(solvedTracks.container())), + tracks.trackStateContainerHolder()}; + m_outputTracks(ctx, std::move(outputTracks)); return ActsExamples::ProcessCode::SUCCESS; diff --git a/Examples/Algorithms/TrackFindingML/src/AmbiguityResolutionMLDBScanAlgorithm.cpp b/Examples/Algorithms/TrackFindingML/src/AmbiguityResolutionMLDBScanAlgorithm.cpp deleted file mode 100644 index 6f0c7529208..00000000000 --- a/Examples/Algorithms/TrackFindingML/src/AmbiguityResolutionMLDBScanAlgorithm.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/. - -#include "ActsExamples/TrackFindingML/AmbiguityResolutionMLDBScanAlgorithm.hpp" - -#include "ActsExamples/Framework/ProcessCode.hpp" -#include "ActsExamples/Framework/WhiteBoard.hpp" -#include "ActsExamples/TrackFindingML/AmbiguityDBScanClustering.hpp" - -#include -#include - -ActsExamples::AmbiguityResolutionMLDBScanAlgorithm:: - AmbiguityResolutionMLDBScanAlgorithm( - ActsExamples::AmbiguityResolutionMLDBScanAlgorithm::Config cfg, - Acts::Logging::Level lvl) - : ActsExamples::AmbiguityResolutionML( - "AmbiguityResolutionMLDBScanAlgorithm", lvl), - m_cfg(std::move(cfg)), - m_duplicateClassifier(m_cfg.inputDuplicateNN.c_str()) { - if (m_cfg.inputTracks.empty()) { - throw std::invalid_argument("Missing trajectories input collection"); - } - if (m_cfg.outputTracks.empty()) { - throw std::invalid_argument("Missing trajectories output collection"); - } - m_inputTracks.initialize(m_cfg.inputTracks); - m_outputTracks.initialize(m_cfg.outputTracks); -} - -ActsExamples::ProcessCode -ActsExamples::AmbiguityResolutionMLDBScanAlgorithm::execute( - const AlgorithmContext& ctx) const { - // Read input data - const auto& tracks = m_inputTracks(ctx); - // Associate measurement to their respective tracks - std::multimap>> - trackMap = mapTrackHits(tracks, m_cfg.nMeasurementsMin); - // Cluster the tracks using DBscan - auto cluster = Acts::dbscanTrackClustering( - trackMap, tracks, m_cfg.epsilonDBScan, m_cfg.minPointsDBScan); - // Select the ID of the track we want to keep - std::vector goodTracks = - m_duplicateClassifier.solveAmbiguity(cluster, tracks); - // Prepare the output track collection from the IDs - auto outputTracks = prepareOutputTrack(tracks, goodTracks); - m_outputTracks(ctx, std::move(outputTracks)); - - return ActsExamples::ProcessCode::SUCCESS; -} diff --git a/Examples/Io/Csv/include/ActsExamples/Io/Csv/CsvSpacepointWriter.hpp b/Examples/Io/Csv/include/ActsExamples/Io/Csv/CsvSpacePointWriter.hpp similarity index 93% rename from Examples/Io/Csv/include/ActsExamples/Io/Csv/CsvSpacepointWriter.hpp rename to Examples/Io/Csv/include/ActsExamples/Io/Csv/CsvSpacePointWriter.hpp index 1e24eb4bc97..ea7315d4927 100644 --- a/Examples/Io/Csv/include/ActsExamples/Io/Csv/CsvSpacepointWriter.hpp +++ b/Examples/Io/Csv/include/ActsExamples/Io/Csv/CsvSpacePointWriter.hpp @@ -34,7 +34,7 @@ namespace ActsExamples { /// ... /// /// Intrinsically thread-safe as one file per event. -class CsvSpacepointWriter final : public WriterT { +class CsvSpacePointWriter final : public WriterT { public: struct Config { /// Which measurement collection to write. @@ -48,10 +48,10 @@ class CsvSpacepointWriter final : public WriterT { /// Constructor with /// @param config configuration struct /// @param level logging level - CsvSpacepointWriter(const Config& config, Acts::Logging::Level level); + CsvSpacePointWriter(const Config& config, Acts::Logging::Level level); /// Virtual destructor - ~CsvSpacepointWriter() override; + ~CsvSpacePointWriter() override; /// End-of-run hook ProcessCode finalize() override; diff --git a/Examples/Io/Csv/src/CsvSpacePointWriter.cpp b/Examples/Io/Csv/src/CsvSpacePointWriter.cpp index 9eb440f7692..4e71020a390 100644 --- a/Examples/Io/Csv/src/CsvSpacePointWriter.cpp +++ b/Examples/Io/Csv/src/CsvSpacePointWriter.cpp @@ -6,7 +6,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -#include "ActsExamples/Io/Csv/CsvSpacepointWriter.hpp" +#include "ActsExamples/Io/Csv/CsvSpacePointWriter.hpp" #include "Acts/EventData/SourceLink.hpp" #include "Acts/Geometry/GeometryIdentifier.hpp" @@ -24,20 +24,20 @@ #include "CsvOutputData.hpp" -ActsExamples::CsvSpacepointWriter::CsvSpacepointWriter( - const ActsExamples::CsvSpacepointWriter::Config& config, +ActsExamples::CsvSpacePointWriter::CsvSpacePointWriter( + const ActsExamples::CsvSpacePointWriter::Config& config, Acts::Logging::Level level) - : WriterT(config.inputSpacepoints, "CsvSpacepointWriter", level), + : WriterT(config.inputSpacepoints, "CsvSpacePointWriter", level), m_cfg(config) {} -ActsExamples::CsvSpacepointWriter::~CsvSpacepointWriter() = default; +ActsExamples::CsvSpacePointWriter::~CsvSpacePointWriter() = default; -ActsExamples::ProcessCode ActsExamples::CsvSpacepointWriter::finalize() { +ActsExamples::ProcessCode ActsExamples::CsvSpacePointWriter::finalize() { // Write the tree return ProcessCode::SUCCESS; } -ActsExamples::ProcessCode ActsExamples::CsvSpacepointWriter::writeT( +ActsExamples::ProcessCode ActsExamples::CsvSpacePointWriter::writeT( const AlgorithmContext& ctx, const SimSpacePointContainer& spacepoints) { // Open per-event file for all components std::string pathSP = diff --git a/Examples/Python/python/acts/examples/reconstruction.py b/Examples/Python/python/acts/examples/reconstruction.py index ceb234f1419..727bf9e9785 100644 --- a/Examples/Python/python/acts/examples/reconstruction.py +++ b/Examples/Python/python/acts/examples/reconstruction.py @@ -234,12 +234,6 @@ def trackSelectorDefaultKWArgs(c): defaults=[None] * 3, ) -AmbiguityResolutionMLDBScanConfig = namedtuple( - "AmbiguityResolutionMLDBScanConfig", - ["nMeasurementsMin", "epsilonDBScan", "minPointsDBScan"], - defaults=[None] * 3, -) - SeedFilterMLDBScanConfig = namedtuple( "SeedFilterMLDBScanConfig", ["epsilonDBScan", "minPointsDBScan", "minSeedScore"], @@ -1972,14 +1966,31 @@ def addScoreBasedAmbiguityResolution( s.addAlgorithm(algScoreBased) s.addWhiteboardAlias("tracks", algScoreBased.config.outputTracks) + matchAlg = acts.examples.TrackTruthMatcher( + level=customLogLevel(), + inputTracks=algScoreBased.config.outputTracks, + inputParticles="particles", + inputMeasurementParticlesMap="measurement_particles_map", + outputTrackParticleMatching="ambi_scorebased_track_particle_matching", + outputParticleTrackMatching="ambi_scorebased_particle_track_matching", + doubleMatching=True, + ) + s.addAlgorithm(matchAlg) + s.addWhiteboardAlias( + "track_particle_matching", matchAlg.config.outputTrackParticleMatching + ) + s.addWhiteboardAlias( + "particle_track_matching", matchAlg.config.outputParticleTrackMatching + ) + addTrackWriters( s, name="ambi_scorebased", tracks=algScoreBased.config.outputTracks, outputDirCsv=outputDirCsv, outputDirRoot=outputDirRoot, - writeSummary=writeTrackStates, - writeStates=writeTrackSummary, + writeSummary=writeTrackSummary, + writeStates=writeTrackStates, writeFitterPerformance=writePerformance, writeFinderPerformance=writePerformance, writeCovMat=writeCovMat, @@ -1995,6 +2006,7 @@ def addScoreBasedAmbiguityResolution( def addAmbiguityResolutionML( s, config: AmbiguityResolutionMLConfig = AmbiguityResolutionMLConfig(), + tracks: str = "tracks", onnxModelFile: Optional[Union[Path, str]] = None, outputDirCsv: Optional[Union[Path, str]] = None, outputDirRoot: Optional[Union[Path, str]] = None, @@ -2008,10 +2020,9 @@ def addAmbiguityResolutionML( from acts.examples import GreedyAmbiguityResolutionAlgorithm customLogLevel = acts.examples.defaultLogging(s, logLevel) - algML = AmbiguityResolutionMLAlgorithm( level=customLogLevel(), - inputTracks="tracks", + inputTracks=tracks, inputDuplicateNN=onnxModelFile, outputTracks="ambiTracksML", **acts.examples.defaultKWArgs( @@ -2033,63 +2044,33 @@ def addAmbiguityResolutionML( s.addAlgorithm(algML) s.addAlgorithm(algGreedy) - addTrackWriters( - s, - name="ambiML", - tracks=algGreedy.config.outputTracks, - outputDirCsv=outputDirCsv, - outputDirRoot=outputDirRoot, - writeSummary=writeTrackStates, - writeStates=writeTrackSummary, - writeFitterPerformance=writePerformance, - writeFinderPerformance=writePerformance, - writeCovMat=writeCovMat, - logLevel=logLevel, - ) + s.addWhiteboardAlias("tracks", algGreedy.config.outputTracks) - return s - - -@acts.examples.NamedTypeArgs( - config=AmbiguityResolutionMLDBScanConfig, -) -def addAmbiguityResolutionMLDBScan( - s, - config: AmbiguityResolutionMLDBScanConfig = AmbiguityResolutionMLDBScanConfig(), - onnxModelFile: Optional[Union[Path, str]] = None, - outputDirCsv: Optional[Union[Path, str]] = None, - outputDirRoot: Optional[Union[Path, str]] = None, - writeTrackSummary: bool = True, - writeTrackStates: bool = False, - writePerformance: bool = True, - writeCovMat=False, - logLevel: Optional[acts.logging.Level] = None, -) -> None: - from acts.examples import AmbiguityResolutionMLDBScanAlgorithm - - customLogLevel = acts.examples.defaultLogging(s, logLevel) - - alg = AmbiguityResolutionMLDBScanAlgorithm( + matchAlg = acts.examples.TrackTruthMatcher( level=customLogLevel(), - inputTracks="tracks", - inputDuplicateNN=onnxModelFile, - outputTracks="ambiTracksMLDBScan", - **acts.examples.defaultKWArgs( - nMeasurementsMin=config.nMeasurementsMin, - epsilonDBScan=config.epsilonDBScan, - minPointsDBScan=config.minPointsDBScan, - ), + inputTracks=algGreedy.config.outputTracks, + inputParticles="particles", + inputMeasurementParticlesMap="measurement_particles_map", + outputTrackParticleMatching="ambiML_track_particle_matching", + outputParticleTrackMatching="ambiML_particle_track_matching", + doubleMatching=True, + ) + s.addAlgorithm(matchAlg) + s.addWhiteboardAlias( + "track_particle_matching", matchAlg.config.outputTrackParticleMatching + ) + s.addWhiteboardAlias( + "particle_track_matching", matchAlg.config.outputParticleTrackMatching ) - s.addAlgorithm(alg) addTrackWriters( s, - name="ambiMLDBScan", - trajectories=alg.config.outputTracks, - outputDirRoot=outputDirRoot, + name="ambiML", + tracks=algGreedy.config.outputTracks, outputDirCsv=outputDirCsv, - writeSummary=writeTrackStates, - writeStates=writeTrackSummary, + outputDirRoot=outputDirRoot, + writeSummary=writeTrackSummary, + writeStates=writeTrackStates, writeFitterPerformance=writePerformance, writeFinderPerformance=writePerformance, writeCovMat=writeCovMat, diff --git a/Examples/Python/src/Onnx.cpp b/Examples/Python/src/Onnx.cpp index c22e595bb43..8bd75a3047a 100644 --- a/Examples/Python/src/Onnx.cpp +++ b/Examples/Python/src/Onnx.cpp @@ -8,7 +8,6 @@ #include "Acts/Plugins/Python/Utilities.hpp" #include "ActsExamples/TrackFindingML/AmbiguityResolutionMLAlgorithm.hpp" -#include "ActsExamples/TrackFindingML/AmbiguityResolutionMLDBScanAlgorithm.hpp" #include "ActsExamples/TrackFindingML/SeedFilterMLAlgorithm.hpp" #include @@ -31,11 +30,6 @@ void addOnnx(Context& ctx) { inputTracks, inputDuplicateNN, outputTracks, nMeasurementsMin); - ACTS_PYTHON_DECLARE_ALGORITHM( - ActsExamples::AmbiguityResolutionMLDBScanAlgorithm, onnx, - "AmbiguityResolutionMLDBScanAlgorithm", inputTracks, inputDuplicateNN, - outputTracks, nMeasurementsMin, epsilonDBScan, minPointsDBScan); - ACTS_PYTHON_DECLARE_ALGORITHM(ActsExamples::SeedFilterMLAlgorithm, onnx, "SeedFilterMLAlgorithm", inputTrackParameters, inputSimSeeds, inputSeedFilterNN, diff --git a/Examples/Python/src/Output.cpp b/Examples/Python/src/Output.cpp index 41f7bb5f564..838649816f6 100644 --- a/Examples/Python/src/Output.cpp +++ b/Examples/Python/src/Output.cpp @@ -17,8 +17,8 @@ #include "ActsExamples/Io/Csv/CsvProtoTrackWriter.hpp" #include "ActsExamples/Io/Csv/CsvSeedWriter.hpp" #include "ActsExamples/Io/Csv/CsvSimHitWriter.hpp" +#include "ActsExamples/Io/Csv/CsvSpacePointWriter.hpp" #include "ActsExamples/Io/Csv/CsvSpacePointsBucketWriter.hpp" -#include "ActsExamples/Io/Csv/CsvSpacepointWriter.hpp" #include "ActsExamples/Io/Csv/CsvTrackParameterWriter.hpp" #include "ActsExamples/Io/Csv/CsvTrackWriter.hpp" #include "ActsExamples/Io/Csv/CsvTrackingGeometryWriter.hpp" @@ -375,8 +375,8 @@ void addOutput(Context& ctx) { "CsvSimHitWriter", inputSimHits, outputDir, outputStem, outputPrecision); - ACTS_PYTHON_DECLARE_WRITER(ActsExamples::CsvSpacepointWriter, mex, - "CsvSpacepointWriter", inputSpacepoints, outputDir, + ACTS_PYTHON_DECLARE_WRITER(ActsExamples::CsvSpacePointWriter, mex, + "CsvSpacePointWriter", inputSpacepoints, outputDir, outputPrecision); ACTS_PYTHON_DECLARE_WRITER(ActsExamples::CsvSpacePointsBucketWriter, mex, diff --git a/Examples/Scripts/Python/MLAmbiguityResolution/ambiguity_solver_network.py b/Examples/Scripts/Python/MLAmbiguityResolution/ambiguity_solver_network.py index 15f596414f7..5e241fdf717 100644 --- a/Examples/Scripts/Python/MLAmbiguityResolution/ambiguity_solver_network.py +++ b/Examples/Scripts/Python/MLAmbiguityResolution/ambiguity_solver_network.py @@ -16,7 +16,7 @@ def prepareDataSet(data: pd.DataFrame) -> pd.DataFrame: data = data # Remove tracks with less than 7 measurements data = data[data["nMeasurements"] > 6] - # data = data.sort_values("good/duplicate/fake", ascending=False) + data = data.sort_values("good/duplicate/fake", ascending=False) # Remove pure duplicate (tracks purely identical) keep the ones good one if among them. data = data.drop_duplicates( subset=[ diff --git a/Plugins/Onnx/include/Acts/Plugins/Onnx/AmbiguityTrackClassifier.hpp b/Plugins/Onnx/include/Acts/Plugins/Onnx/AmbiguityTrackClassifier.hpp index 3e1450f2b85..b0ddbd09bc7 100644 --- a/Plugins/Onnx/include/Acts/Plugins/Onnx/AmbiguityTrackClassifier.hpp +++ b/Plugins/Onnx/include/Acts/Plugins/Onnx/AmbiguityTrackClassifier.hpp @@ -102,23 +102,6 @@ class AmbiguityTrackClassifier { return goodTracks; } - /// Select the track associated with each cluster - /// - /// @param clusters is a map of clusters, each cluster correspond to a vector of track ID - /// @param tracks is the input track container - /// @return a vector of trackID corresponding tho the good tracks - template - std::vector solveAmbiguity( - std::unordered_map>& clusters, - const track_container_t& tracks) const { - std::vector> outputTensor = - inferScores(clusters, tracks); - std::vector goodTracks = - trackSelection(clusters, outputTensor); - - return goodTracks; - } - private: // ONNX environment Ort::Env m_env;