diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index c2ece0d20f2..7073e2a413a 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -5,3 +5,7 @@ DO NOT USE @-MENTIONS HERE! --- END COMMIT MESSAGE --- Any further description goes here, @-mentions are ok here! + +- Use a *conventional commits* prefix: [quick summary](https://www.conventionalcommits.org/en/v1.0.0/#summary) + - We mostly use `feat`, `fix`, `refactor`, `docs`, `chore` and `build` types. +- A milestone will be assigned by one of the maintainers diff --git a/.zenodo.json b/.zenodo.json index a274d3c2cf1..d9786fc4cf6 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -112,11 +112,15 @@ "affiliation": "CERN / University of Amsterdam", "name": "Stephen Nicholas Swatman", "orcid": "0000-0002-3747-3229" - } + }, { "affiliation": "CERN / TU Wien", "name": "Felix Russo", "orcid": "0009-0005-8975-2245" + }, + { + "affiliation": "UC Berkeley", + "name": "Carlo Varni" } ], "access_right": "open", diff --git a/AUTHORS b/AUTHORS index 4dab2740fe3..3e2e965ff27 100644 --- a/AUTHORS +++ b/AUTHORS @@ -21,3 +21,4 @@ The following people have contributed to the project (in alphabetical order): - Andreas Stefl, CERN, TU Wien - Stephen Nicholas Swatman, CERN, University of Amsterdam - Roman Urmanov, Weizmann Institute of Science +- Carlo Varni, UC Berkeley diff --git a/CI/physmon/reference/trackfinding_1muon/seeded/performance_fitting_ckf.root b/CI/physmon/reference/trackfinding_1muon/seeded/performance_fitting_ckf.root index 5ba97ecd168..94fcbafbdbf 100644 Binary files a/CI/physmon/reference/trackfinding_1muon/seeded/performance_fitting_ckf.root and b/CI/physmon/reference/trackfinding_1muon/seeded/performance_fitting_ckf.root differ diff --git a/CI/physmon/reference/trackfinding_1muon/truth_estimated/performance_fitting_ckf.root b/CI/physmon/reference/trackfinding_1muon/truth_estimated/performance_fitting_ckf.root index 3fcdb6021d1..652e0d8fd57 100644 Binary files a/CI/physmon/reference/trackfinding_1muon/truth_estimated/performance_fitting_ckf.root and b/CI/physmon/reference/trackfinding_1muon/truth_estimated/performance_fitting_ckf.root differ diff --git a/CI/physmon/reference/trackfinding_4muon_50vertices/performance_fitting_ckf.root b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_fitting_ckf.root index b90f40313eb..37ad131de0e 100644 Binary files a/CI/physmon/reference/trackfinding_4muon_50vertices/performance_fitting_ckf.root and b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_fitting_ckf.root differ diff --git a/CI/physmon/reference/trackfinding_4muon_50vertices/performance_vertexing_amvf_grid_time_hist.root b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_vertexing_amvf_grid_time_hist.root index d99436fa0f5..3b33e1bae98 100644 Binary files a/CI/physmon/reference/trackfinding_4muon_50vertices/performance_vertexing_amvf_grid_time_hist.root and b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_vertexing_amvf_grid_time_hist.root differ diff --git a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_fitting_ckf.root b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_fitting_ckf.root index 09d2dc033af..754dd91bb0a 100644 Binary files a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_fitting_ckf.root and b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_fitting_ckf.root differ diff --git a/CI/physmon/reference/trackfitting_gx2f/performance_trackfitting.root b/CI/physmon/reference/trackfitting_gx2f/performance_trackfitting.root index 21533ce8076..b2e2b47c2f5 100644 Binary files a/CI/physmon/reference/trackfitting_gx2f/performance_trackfitting.root and b/CI/physmon/reference/trackfitting_gx2f/performance_trackfitting.root differ diff --git a/CITATION.cff b/CITATION.cff index 910eade5312..95865537ecf 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -89,6 +89,9 @@ authors: family-names: Russo affiliation: CERN / TU Wien orcid: https://orcid.org/0009-0005-8975-2245 +- given-names: Carlo + family-names: Varni + affiliation: UC Berkeley version: 10.0.0 date-released: 2021-07-28 repository-code: https://github.com/acts-project/acts diff --git a/Core/include/Acts/AmbiguityResolution/ScoreBasedAmbiguityResolution.hpp b/Core/include/Acts/AmbiguityResolution/ScoreBasedAmbiguityResolution.hpp index fbccb611d1a..6ed24a71be8 100644 --- a/Core/include/Acts/AmbiguityResolution/ScoreBasedAmbiguityResolution.hpp +++ b/Core/include/Acts/AmbiguityResolution/ScoreBasedAmbiguityResolution.hpp @@ -12,6 +12,7 @@ #include "Acts/EventData/TrackContainer.hpp" #include "Acts/EventData/TrackContainerFrontendConcept.hpp" #include "Acts/EventData/TrackProxyConcept.hpp" +#include "Acts/EventData/TrackStateProxy.hpp" #include "Acts/Utilities/Delegate.hpp" #include "Acts/Utilities/Logger.hpp" @@ -81,11 +82,17 @@ class ScoreBasedAmbiguityResolution { std::size_t nSharedHits = 0; }; - /// @brief MeasurementInfo : contains the measurement ID and the detector ID - struct MeasurementInfo { - std::size_t iMeasurement = 0; - std::size_t detectorId = 0; - bool isOutlier = false; + enum class TrackStateTypes : std::uint8_t { + // A measurement not yet used in any other track + UnsharedHit, + // A measurement shared with another track + SharedHit, + // A hit that needs to be removed from the track + RejectedHit, + // An outlier, to be copied in case + Outlier, + // Other trackstate types to be copied in case + OtherTrackStateType }; /// @brief Configuration struct : contains the configuration for the ambiguity resolution. @@ -125,11 +132,17 @@ class ScoreBasedAmbiguityResolution { using OptionalScoreModifier = std::function; + + using OptionalHitSelection = std::function; + std::vector cuts = {}; std::vector weights = {}; /// applied only if useAmbiguityFunction is true std::vector scores = {}; + std::vector hitSelections = {}; }; ScoreBasedAmbiguityResolution( @@ -141,16 +154,10 @@ class ScoreBasedAmbiguityResolution { /// Compute the initial state of the tracks. /// /// @param tracks is the input track container - /// @param sourceLinkHash is the source links - /// @param sourceLinkEquality is the equality function for the source links - /// @param trackFeaturesVectors is the trackFeatures map from detector ID to trackFeatures - /// @return a vector of the initial state of the tracks - template - std::vector> computeInitialState( - const track_container_t& tracks, source_link_hash_t sourceLinkHash, - source_link_equality_t sourceLinkEquality, - std::vector>& trackFeaturesVectors) const; + /// @return trackFeaturesVectors is the trackFeatures map from detector ID to trackFeatures + template + std::vector> computeInitialState( + const track_container_t& tracks) const; /// Compute the score of each track. /// @@ -182,29 +189,35 @@ class ScoreBasedAmbiguityResolution { /// that have a score below a certain threshold or not enough hits. /// /// @brief Remove tracks that are not good enough based on cuts + /// @param track is the input track /// @param trackScore is the score of each track - /// @param trackFeaturesVectors is the trackFeatures map for each track /// @param measurementsPerTrack is the list of measurements for each track + /// @param nTracksPerMeasurement is the number of tracks per measurement + /// @param optionalHitSelections is the optional hit selections to be applied /// @return a vector of IDs of the tracks we want to keep - std::vector getCleanedOutTracks( - const std::vector& trackScore, - const std::vector>& trackFeaturesVectors, - const std::vector>& measurementsPerTrack) - const; + template + bool getCleanedOutTracks( + const track_proxy_t& track, const double& trackScore, + const std::vector& measurementsPerTrack, + const std::map& nTracksPerMeasurement, + const std::vector>& optionalHitSelections = {}) const; /// Remove tracks that are bad based on cuts and weighted scores. /// /// @brief Remove tracks that are not good enough /// @param tracks is the input track container - /// @param measurementsPerTrack is the list of measurements for each track - /// @param trackFeaturesVectors is the map of detector id to trackFeatures for each track + /// @param sourceLinkHash is the source links + /// @param sourceLinkEquality is the equality function for the source links /// @param optionalCuts is the optional cuts to be applied /// @return a vector of IDs of the tracks we want to keep - template + template std::vector solveAmbiguity( - const track_container_t& tracks, - const std::vector>& measurementsPerTrack, - const std::vector>& trackFeaturesVectors, + const track_container_t& tracks, source_link_hash_t sourceLinkHash, + source_link_equality_t sourceLinkEquality, const OptionalCuts& optionalCuts = {}) const; diff --git a/Core/include/Acts/AmbiguityResolution/ScoreBasedAmbiguityResolution.ipp b/Core/include/Acts/AmbiguityResolution/ScoreBasedAmbiguityResolution.ipp index 58742d7d11a..247b767dd3d 100644 --- a/Core/include/Acts/AmbiguityResolution/ScoreBasedAmbiguityResolution.ipp +++ b/Core/include/Acts/AmbiguityResolution/ScoreBasedAmbiguityResolution.ipp @@ -21,27 +21,17 @@ inline const Logger& ScoreBasedAmbiguityResolution::logger() const { return *m_logger; } -template -std::vector> +template +std::vector> ScoreBasedAmbiguityResolution::computeInitialState( - const track_container_t& tracks, source_link_hash_t sourceLinkHash, - source_link_equality_t sourceLinkEquality, - std::vector>& trackFeaturesVectors) const { - auto MeasurementIndexMap = - std::unordered_map(0, sourceLinkHash, - sourceLinkEquality); - - std::vector> measurementsPerTrack; - measurementsPerTrack.reserve(tracks.size()); + const track_container_t& tracks) const { ACTS_VERBOSE("Starting to compute initial state"); + std::vector> trackFeaturesVectors; + trackFeaturesVectors.reserve(tracks.size()); for (const auto& track : tracks) { int numberOfDetectors = m_cfg.detectorConfigs.size(); - int numberOfTrackStates = track.nTrackStates(); - std::vector measurements; - measurements.reserve(numberOfTrackStates); + std::vector trackFeaturesVector(numberOfDetectors); for (const auto& ts : track.trackStatesReversed()) { @@ -58,43 +48,25 @@ ScoreBasedAmbiguityResolution::computeInitialState( auto detectorId = volume_it->second; if (ts.typeFlags().test(Acts::TrackStateFlag::HoleFlag)) { - ACTS_DEBUG("Track state type is HoleFlag"); + ACTS_VERBOSE("Track state type is HoleFlag"); trackFeaturesVector[detectorId].nHoles++; } else if (ts.typeFlags().test(Acts::TrackStateFlag::OutlierFlag)) { - Acts::SourceLink sourceLink = ts.getUncalibratedSourceLink(); - ACTS_DEBUG("Track state type is OutlierFlag"); + ACTS_VERBOSE("Track state type is OutlierFlag"); trackFeaturesVector[detectorId].nOutliers++; - // assign a new measurement index if the source link was not seen yet - auto emplace = MeasurementIndexMap.try_emplace( - sourceLink, MeasurementIndexMap.size()); - - bool isOutliner = true; - - measurements.push_back({emplace.first->second, detectorId, isOutliner}); } else if (ts.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) { - Acts::SourceLink sourceLink = ts.getUncalibratedSourceLink(); - ACTS_DEBUG("Track state type is MeasurementFlag"); + ACTS_VERBOSE("Track state type is MeasurementFlag"); if (ts.typeFlags().test(Acts::TrackStateFlag::SharedHitFlag)) { trackFeaturesVector[detectorId].nSharedHits++; } trackFeaturesVector[detectorId].nHits++; - - // assign a new measurement index if the source link was not seen yet - auto emplace = MeasurementIndexMap.try_emplace( - sourceLink, MeasurementIndexMap.size()); - - bool isoutliner = false; - - measurements.push_back({emplace.first->second, detectorId, isoutliner}); } } - measurementsPerTrack.push_back(std::move(measurements)); trackFeaturesVectors.push_back(std::move(trackFeaturesVector)); } - return measurementsPerTrack; + return trackFeaturesVectors; } template @@ -363,12 +335,6 @@ std::vector Acts::ScoreBasedAmbiguityResolution::ambiguityScore( // choosing a scaling factor based on the number of hits in a track per // detector. std::size_t nHits = trackFeatures.nHits; - if (detector.factorHits.size() < nHits) { - ACTS_WARNING("Detector " << detectorId - << " has not enough factorhits in the " - "detector.factorHits vector"); - continue; - } if (nHits > detector.maxHits) { score = score * (detector.maxHits - nHits + 1); // hits are good ! nHits = detector.maxHits; @@ -381,12 +347,6 @@ std::vector Acts::ScoreBasedAmbiguityResolution::ambiguityScore( // choosing a scaling factor based on the number of holes in a track per // detector. std::size_t iHoles = trackFeatures.nHoles; - if (detector.factorHoles.size() < iHoles) { - ACTS_WARNING("Detector " << detectorId - << " has not enough factorholes in the " - "detector.factorHoles vector"); - continue; - } if (iHoles > detector.maxHoles) { score /= (iHoles - detector.maxHoles + 1); // holes are bad ! iHoles = detector.maxHoles; @@ -421,17 +381,20 @@ std::vector Acts::ScoreBasedAmbiguityResolution::ambiguityScore( return trackScore; } -template +template std::vector Acts::ScoreBasedAmbiguityResolution::solveAmbiguity( - const track_container_t& tracks, - const std::vector>& measurementsPerTrack, - const std::vector>& trackFeaturesVectors, + const track_container_t& tracks, source_link_hash_t sourceLinkHash, + source_link_equality_t sourceLinkEquality, const OptionalCuts& optionalCuts) const { ACTS_INFO("Number of tracks before Ambiguty Resolution: " << tracks.size()); // vector of trackFeaturesVectors. where each trackFeaturesVector contains the // number of hits/hole/outliers for each detector in a track. + const std::vector> trackFeaturesVectors = + computeInitialState(tracks); + std::vector trackScore; trackScore.reserve(tracks.size()); if (m_cfg.useAmbiguityFunction) { @@ -440,14 +403,72 @@ std::vector Acts::ScoreBasedAmbiguityResolution::solveAmbiguity( trackScore = simpleScore(tracks, trackFeaturesVectors, optionalCuts); } - std::vector cleanTracks = getCleanedOutTracks( - trackScore, trackFeaturesVectors, measurementsPerTrack); + auto MeasurementIndexMap = + std::unordered_map(0, sourceLinkHash, + sourceLinkEquality); + + std::vector> measurementsPerTrackVector; + std::map nTracksPerMeasurement; + + // Stores tracks measurement into a vector or vectors + // (measurementsPerTrackVector) and counts the number of tracks per + // measurement.(nTracksPerMeasurement) + + for (const auto& track : tracks) { + std::vector measurementsPerTrack; + for (const auto& ts : track.trackStatesReversed()) { + if (!ts.typeFlags().test(Acts::TrackStateFlag::OutlierFlag) && + !ts.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) { + continue; + } + Acts::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()); + std::size_t iMeasurement = emplace.first->second; + measurementsPerTrack.push_back(iMeasurement); + if (nTracksPerMeasurement.find(iMeasurement) == + nTracksPerMeasurement.end()) { + nTracksPerMeasurement[iMeasurement] = 0; + } + nTracksPerMeasurement[iMeasurement]++; + } + measurementsPerTrackVector.push_back(std::move(measurementsPerTrack)); + } std::vector goodTracks; int cleanTrackIndex = 0; - std::size_t iTrack = 0; - for (const auto& track : tracks) { - if (cleanTracks[iTrack]) { + + auto optionalHitSelections = optionalCuts.hitSelections; + + // Loop over all the tracks in the container + // For each track, check if the track has too many shared hits to be accepted. + // If the track is accepted, remove bad hits and check if the track has a + // score higher than the minimum score for shared tracks. + // If the track is good, add it to the goodTracks vector. + for (std::size_t iTrack = 0; const auto& track : tracks) { + // Check if the track has too many shared hits to be accepted. + auto trackFeaturesVector = trackFeaturesVectors.at(iTrack); + bool trkCouldBeAccepted = true; + for (std::size_t detectorId = 0; detectorId < m_cfg.detectorConfigs.size(); + detectorId++) { + auto detector = m_cfg.detectorConfigs.at(detectorId); + if (trackFeaturesVector[detectorId].nSharedHits > + detector.maxSharedHits) { + trkCouldBeAccepted = false; + break; + } + } + if (!trkCouldBeAccepted) { + iTrack++; + continue; + } + + trkCouldBeAccepted = getCleanedOutTracks( + track, trackScore[iTrack], measurementsPerTrackVector[iTrack], + nTracksPerMeasurement, optionalHitSelections); + if (trkCouldBeAccepted) { cleanTrackIndex++; if (trackScore[iTrack] >= m_cfg.minScore) { goodTracks.push_back(track.index()); @@ -455,10 +476,120 @@ std::vector Acts::ScoreBasedAmbiguityResolution::solveAmbiguity( } iTrack++; } - ACTS_VERBOSE("Number of clean tracks: " << cleanTrackIndex); + ACTS_INFO("Number of clean tracks: " << cleanTrackIndex); ACTS_VERBOSE("Min score: " << m_cfg.minScore); ACTS_INFO("Number of Good tracks: " << goodTracks.size()); return goodTracks; } +template +bool Acts::ScoreBasedAmbiguityResolution::getCleanedOutTracks( + const track_proxy_t& track, const double& trackScore, + const std::vector& measurementsPerTrack, + const std::map& nTracksPerMeasurement, + const std::vector< + std::function>& optionalHitSelections) const { + // For tracks with shared hits, we need to check and remove bad hits + + std::vector trackStateTypes; + // Loop over all measurements of the track and for each hit a + // trackStateTypes is assigned. + for (std::size_t index = 0; const auto& ts : track.trackStatesReversed()) { + if (ts.typeFlags().test(Acts::TrackStateFlag::OutlierFlag) || + ts.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) { + std::size_t iMeasurement = measurementsPerTrack[index]; + auto it = nTracksPerMeasurement.find(iMeasurement); + if (it == nTracksPerMeasurement.end()) { + trackStateTypes.push_back(TrackStateTypes::OtherTrackStateType); + index++; + continue; + } + + std::size_t nTracksShared = it->second; + auto isoutliner = ts.typeFlags().test(Acts::TrackStateFlag::OutlierFlag); + + if (isoutliner) { + ACTS_VERBOSE("Measurement is outlier on a fitter track, copy it over"); + trackStateTypes.push_back(TrackStateTypes::Outlier); + continue; + } + if (nTracksShared == 1) { + ACTS_VERBOSE("Measurement is not shared, copy it over"); + + trackStateTypes.push_back(TrackStateTypes::UnsharedHit); + continue; + } else if (nTracksShared > 1) { + ACTS_VERBOSE("Measurement is shared, copy it over"); + trackStateTypes.push_back(TrackStateTypes::SharedHit); + continue; + } + } + } + std::vector newMeasurementsPerTrack; + std::size_t measurement = 0; + std::size_t nshared = 0; + + // Loop over all measurements of the track and process them according to the + // trackStateTypes and other conditions. + // Good measurements are copied to the newMeasurementsPerTrack vector. + for (std::size_t index = 0; auto ts : track.trackStatesReversed()) { + if (ts.typeFlags().test(Acts::TrackStateFlag::OutlierFlag) || + ts.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) { + if (!ts.hasReferenceSurface()) { + ACTS_DEBUG("Track state has no reference surface"); + continue; + } + measurement = measurementsPerTrack[index]; + + auto it = nTracksPerMeasurement.find(measurement); + if (it == nTracksPerMeasurement.end()) { + index++; + continue; + } + auto nTracksShared = it->second; + + // Loop over all optionalHitSelections and apply them to trackStateType of + // the TrackState. + + for (const auto& hitSelection : optionalHitSelections) { + hitSelection(track, ts, trackStateTypes[index]); + } + + if (trackStateTypes[index] == TrackStateTypes::RejectedHit) { + ACTS_DEBUG("Dropping rejected hit"); + } else if (trackStateTypes[index] != TrackStateTypes::SharedHit) { + ACTS_DEBUG("Good TSOS, copy hit"); + newMeasurementsPerTrack.push_back(measurement); + + // a counter called nshared is used to keep track of the number of + // shared hits accepted. + } else if (nshared >= m_cfg.maxShared) { + ACTS_DEBUG("Too many shared hit, drop it"); + } + // If the track is shared, the hit is only accepted if the track has + // score higher than the minimum score for shared tracks. + else { + ACTS_DEBUG("Try to recover shared hit "); + if (nTracksShared <= m_cfg.maxSharedTracksPerMeasurement && + trackScore > m_cfg.minScoreSharedTracks) { + ACTS_DEBUG("Accepted hit shared with " << nTracksShared << " tracks"); + newMeasurementsPerTrack.push_back(measurement); + nshared++; + } else { + ACTS_DEBUG("Rejected hit shared with " << nTracksShared << " tracks"); + } + } + index++; + } + } + // Check if the track has enough hits to be accepted. + if (newMeasurementsPerTrack.size() < 3) { + return false; + } else { + return true; + } +} + } // namespace Acts diff --git a/Core/include/Acts/EventData/ProxyAccessor.hpp b/Core/include/Acts/EventData/ProxyAccessor.hpp index 429c0ef670b..d6a9a3497ce 100644 --- a/Core/include/Acts/EventData/ProxyAccessor.hpp +++ b/Core/include/Acts/EventData/ProxyAccessor.hpp @@ -75,7 +75,7 @@ struct ProxyAccessorBase { /// Create the accessor from a string key /// @param _key the key constexpr ProxyAccessorBase(const std::string& _key) - : key{hashString(_key)} {} + : key{hashStringDynamic(_key)} {} /// Access the stored key on the proxy given as an argument. Mutable version /// @tparam proxy_t the type of the proxy diff --git a/Core/include/Acts/EventData/TrackContainer.hpp b/Core/include/Acts/EventData/TrackContainer.hpp index f70c430f002..03f7f1f8bb1 100644 --- a/Core/include/Acts/EventData/TrackContainer.hpp +++ b/Core/include/Acts/EventData/TrackContainer.hpp @@ -252,7 +252,7 @@ class TrackContainer { /// Check if this track container has a specific dynamic column /// @param key the key to check for constexpr bool hasColumn(const std::string& key) const { - return m_container->hasColumn_impl(hashString(key)); + return m_container->hasColumn_impl(hashStringDynamic(key)); } /// Check if a this track container has a specific dynamic column diff --git a/Core/include/Acts/EventData/TrackProxy.hpp b/Core/include/Acts/EventData/TrackProxy.hpp index 5939022e2e8..6ccb0f402b2 100644 --- a/Core/include/Acts/EventData/TrackProxy.hpp +++ b/Core/include/Acts/EventData/TrackProxy.hpp @@ -710,7 +710,7 @@ class TrackProxy { constexpr T& component(std::string_view key) requires(!ReadOnly) { - return m_container->template component(hashString(key), m_index); + return m_container->template component(hashStringDynamic(key), m_index); } /// Retrieve a const reference to a component @@ -738,7 +738,7 @@ class TrackProxy { /// @return Const reference to the component given by @p key template constexpr const T& component(std::string_view key) const { - return m_container->template component(hashString(key), m_index); + return m_container->template component(hashStringDynamic(key), m_index); } /// @} diff --git a/Core/include/Acts/EventData/TrackStateProxy.hpp b/Core/include/Acts/EventData/TrackStateProxy.hpp index 34de86cd3d7..741bfa5b511 100644 --- a/Core/include/Acts/EventData/TrackStateProxy.hpp +++ b/Core/include/Acts/EventData/TrackStateProxy.hpp @@ -1101,7 +1101,7 @@ class TrackStateProxy { /// @note This might hash the @p key at runtime instead of compile-time /// @return true if the component exists, false if not constexpr bool has(std::string_view key) const { - return has(hashString(key)); + return has(hashStringDynamic(key)); } /// Retrieve a mutable reference to a component @@ -1135,7 +1135,7 @@ class TrackStateProxy { constexpr T& component(std::string_view key) requires(!ReadOnly) { - return m_traj->template component(hashString(key), m_istate); + return m_traj->template component(hashStringDynamic(key), m_istate); } /// Retrieve a const reference to a component @@ -1163,7 +1163,7 @@ class TrackStateProxy { /// @return Const reference to the component given by @p key template constexpr const T& component(std::string_view key) const { - return m_traj->template component(hashString(key), m_istate); + return m_traj->template component(hashStringDynamic(key), m_istate); } /// @} diff --git a/Core/include/Acts/EventData/VectorMultiTrajectory.hpp b/Core/include/Acts/EventData/VectorMultiTrajectory.hpp index 7d2d05cc9b9..3859239ae69 100644 --- a/Core/include/Acts/EventData/VectorMultiTrajectory.hpp +++ b/Core/include/Acts/EventData/VectorMultiTrajectory.hpp @@ -456,7 +456,7 @@ class VectorMultiTrajectory final template void addColumn_impl(std::string_view key) { - HashedString hashedKey = hashString(key); + HashedString hashedKey = hashStringDynamic(key); m_dynamic.insert({hashedKey, std::make_unique>()}); } diff --git a/Core/include/Acts/EventData/VectorTrackContainer.hpp b/Core/include/Acts/EventData/VectorTrackContainer.hpp index 09ecf7b5b2e..8734f69eb4c 100644 --- a/Core/include/Acts/EventData/VectorTrackContainer.hpp +++ b/Core/include/Acts/EventData/VectorTrackContainer.hpp @@ -225,7 +225,7 @@ class VectorTrackContainer final : public detail_vtc::VectorTrackContainerBase { template constexpr void addColumn_impl(const std::string_view& key) { - HashedString hashedKey = hashString(key); + HashedString hashedKey = hashStringDynamic(key); m_dynamic.insert({hashedKey, std::make_unique>()}); } diff --git a/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp b/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp index 93ef7a3eb7c..a2e374c0cc2 100644 --- a/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp +++ b/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp @@ -1103,8 +1103,8 @@ class MultiTrajectoryTestsCommon { auto test = [&](const std::string& col, auto value) { using T = decltype(value); std::string col2 = col + "_2"; - HashedString h{hashString(col)}; - HashedString h2{hashString(col2)}; + HashedString h{hashStringDynamic(col)}; + HashedString h2{hashStringDynamic(col2)}; trajectory_t traj = m_factory.create(); BOOST_CHECK(!traj.hasColumn(h)); @@ -1188,7 +1188,7 @@ class MultiTrajectoryTestsCommon { } }; - runTest([](const std::string& c) { return hashString(c.c_str()); }); + runTest([](const std::string& c) { return hashStringDynamic(c.c_str()); }); // runTest([](const std::string& c) { return c.c_str(); }); // runTest([](const std::string& c) { return c; }); // runTest([](std::string_view c) { return c; }); diff --git a/Core/include/Acts/Navigation/TryAllNavigationPolicy.hpp b/Core/include/Acts/Navigation/TryAllNavigationPolicy.hpp index e7dc4bb3ddc..677a1dbd6dc 100644 --- a/Core/include/Acts/Navigation/TryAllNavigationPolicy.hpp +++ b/Core/include/Acts/Navigation/TryAllNavigationPolicy.hpp @@ -27,12 +27,13 @@ class TryAllNavigationPolicy final : public INavigationPolicy { }; /// Constructor from a volume - /// @param config The configuration for the policy /// @param gctx is the geometry context /// @param volume is the volume to navigate /// @param logger is the logger - TryAllNavigationPolicy(const Config& config, const GeometryContext& gctx, - const TrackingVolume& volume, const Logger& logger); + /// @param config The configuration for the policy + TryAllNavigationPolicy(const GeometryContext& gctx, + const TrackingVolume& volume, const Logger& logger, + const Config& config); /// Constructor from a volume /// @param gctx is the geometry context diff --git a/Core/include/Acts/Seeding/EstimateTrackParamsFromSeed.hpp b/Core/include/Acts/Seeding/EstimateTrackParamsFromSeed.hpp index f4f56946c84..c59a55ad533 100644 --- a/Core/include/Acts/Seeding/EstimateTrackParamsFromSeed.hpp +++ b/Core/include/Acts/Seeding/EstimateTrackParamsFromSeed.hpp @@ -14,15 +14,94 @@ #include "Acts/Surfaces/Surface.hpp" #include "Acts/Utilities/Logger.hpp" #include "Acts/Utilities/MathHelpers.hpp" +#include "Acts/Utilities/Zip.hpp" #include #include -#include #include #include +#include namespace Acts { +/// Estimate the full track parameters from three space points +/// +/// This method is based on the conformal map transformation. It estimates the +/// full free track parameters, i.e. (x, y, z, t, dx, dy, dz, q/p) at the +/// bottom space point. The bottom space is assumed to be the first element +/// in the range defined by the iterators. The magnetic field (which might be +/// along any direction) is also necessary for the momentum estimation. +/// +/// This is a purely spatial estimation, i.e. the time parameter will be set to +/// 0. +/// +/// It resembles the method used in ATLAS for the track parameters +/// estimated from seed, i.e. the function InDet::SiTrackMaker_xk::getAtaPlane +/// here: +/// https://acode-browser.usatlas.bnl.gov/lxr/source/athena/InnerDetector/InDetRecTools/SiTrackMakerTool_xk/src/SiTrackMaker_xk.cxx +/// +/// @tparam spacepoint_iterator_t The type of space point iterator +/// +/// @param sp0 is the bottom space point +/// @param sp1 is the middle space point +/// @param sp2 is the top space point +/// @param bField is the magnetic field vector +/// +/// @return the free parameters +FreeVector estimateTrackParamsFromSeed(const Vector3& sp0, const Vector3& sp1, + const Vector3& sp2, + const Vector3& bField); + +/// Estimate the full track parameters from three space points +/// +/// This method is based on the conformal map transformation. It estimates the +/// full free track parameters, i.e. (x, y, z, t, dx, dy, dz, q/p) at the +/// bottom space point. The bottom space is assumed to be the first element +/// in the range defined by the iterators. The magnetic field (which might be +/// along any direction) is also necessary for the momentum estimation. +/// +/// It resembles the method used in ATLAS for the track parameters +/// estimated from seed, i.e. the function InDet::SiTrackMaker_xk::getAtaPlane +/// here: +/// https://acode-browser.usatlas.bnl.gov/lxr/source/athena/InnerDetector/InDetRecTools/SiTrackMakerTool_xk/src/SiTrackMaker_xk.cxx +/// +/// @tparam spacepoint_iterator_t The type of space point iterator +/// +/// @param spRange is the range of space points +/// @param bField is the magnetic field vector +/// +/// @return the free parameters +template +FreeVector estimateTrackParamsFromSeed(spacepoint_range_t spRange, + const Vector3& bField) { + // Check the number of provided space points + if (spRange.size() != 3) { + throw std::invalid_argument( + "There should be exactly three space points provided."); + } + + // The global positions of the bottom, middle and space points + std::array spPositions = {Vector3::Zero(), Vector3::Zero(), + Vector3::Zero()}; + std::array, 3> spTimes = {std::nullopt, std::nullopt, + std::nullopt}; + // The first, second and third space point are assumed to be bottom, middle + // and top space point, respectively + for (auto [sp, spPosition, spTime] : + Acts::zip(spRange, spPositions, spTimes)) { + if (sp == nullptr) { + throw std::invalid_argument("Empty space point found."); + } + spPosition = Vector3(sp->x(), sp->y(), sp->z()); + spTime = sp->t(); + } + + FreeVector params = estimateTrackParamsFromSeed( + spPositions[0], spPositions[1], spPositions[2], bField); + params[eFreeTime] = spTimes[0].value_or(0); + return params; +} + /// Estimate the full track parameters from three space points /// /// This method is based on the conformal map transformation. It estimates the @@ -46,8 +125,6 @@ namespace Acts { /// @param surface is the surface of the bottom space point. The estimated bound /// track parameters will be represented also at this surface /// @param bField is the magnetic field vector -/// @param bFieldMin is the minimum magnetic field required to trigger the -/// estimation of q/pt /// @param logger A logger instance /// /// @return optional bound parameters @@ -55,7 +132,7 @@ template std::optional estimateTrackParamsFromSeed( const GeometryContext& gctx, spacepoint_iterator_t spBegin, spacepoint_iterator_t spEnd, const Surface& surface, const Vector3& bField, - ActsScalar bFieldMin, const Acts::Logger& logger = getDummyLogger()) { + const Acts::Logger& logger = getDummyLogger()) { // Check the number of provided space points std::size_t numSP = std::distance(spBegin, spEnd); if (numSP != 3) { @@ -63,19 +140,6 @@ std::optional estimateTrackParamsFromSeed( return std::nullopt; } - // Convert bField to Tesla - ActsScalar bFieldInTesla = bField.norm() / UnitConstants::T; - ActsScalar bFieldMinInTesla = bFieldMin / UnitConstants::T; - // Check if magnetic field is too small - if (bFieldInTesla < bFieldMinInTesla) { - // @todo shall we use straight-line estimation and use default q/pt in such - // case? - ACTS_WARNING("The magnetic field at the bottom space point: B = " - << bFieldInTesla << " T is smaller than |B|_min = " - << bFieldMinInTesla << " T. Estimation is not performed."); - return std::nullopt; - } - // The global positions of the bottom, middle and space points std::array spGlobalPositions = {Vector3::Zero(), Vector3::Zero(), Vector3::Zero()}; @@ -142,7 +206,7 @@ std::optional estimateTrackParamsFromSeed( int sign = ia > 0 ? -1 : 1; const ActsScalar R = circleCenter.norm(); ActsScalar invTanTheta = - local2.z() / (2.f * R * std::asin(local2.head<2>().norm() / (2.f * R))); + local2.z() / (2 * R * std::asin(local2.head<2>().norm() / (2 * R))); // The momentum direction in the new frame (the center of the circle has the // coordinate (-1.*A/(2*B), 1./(2*B))) ActsScalar A = -circleCenter(0) / circleCenter(1); @@ -172,9 +236,10 @@ std::optional estimateTrackParamsFromSeed( params[eBoundLoc1] = bottomLocalPos.y(); params[eBoundTime] = spGlobalTimes[0].value_or(0.); + ActsScalar bFieldStrength = bField.norm(); // The estimated q/pt in [GeV/c]^-1 (note that the pt is the projection of // momentum on the transverse plane of the new frame) - ActsScalar qOverPt = sign * (UnitConstants::m) / (0.3 * bFieldInTesla * R); + ActsScalar qOverPt = sign / (bFieldStrength * R); // The estimated q/p in [GeV/c]^-1 params[eBoundQOverP] = qOverPt / fastHypot(1., invTanTheta); diff --git a/Core/include/Acts/TrackFitting/GlobalChiSquareFitter.hpp b/Core/include/Acts/TrackFitting/GlobalChiSquareFitter.hpp index 8cd67c38c2b..8442071a23f 100644 --- a/Core/include/Acts/TrackFitting/GlobalChiSquareFitter.hpp +++ b/Core/include/Acts/TrackFitting/GlobalChiSquareFitter.hpp @@ -694,6 +694,20 @@ std::size_t countMaterialStates( return nMaterialSurfaces; } +/// @brief Update parameters (and scattering angles if applicable) +/// +/// @param params Parameters to be updated +/// @param deltaParamsExtended Delta parameters for bound parameter and scattering angles +/// @param nMaterialSurfaces Number of material surfaces in the track +/// @param scatteringMap Map of geometry identifiers to scattering properties, +/// containing all scattering angles and covariances +/// @param geoIdVector Vector of geometry identifiers corresponding to material surfaces +void updateGx2fParams( + BoundTrackParameters& params, const Eigen::VectorXd& deltaParamsExtended, + const std::size_t nMaterialSurfaces, + std::unordered_map& scatteringMap, + const std::vector& geoIdVector); + /// @brief Calculate and update the covariance of the fitted parameters /// /// This function calculates the covariance of the fitted parameters using @@ -704,8 +718,6 @@ std::size_t countMaterialStates( /// /// @param fullCovariancePredicted The covariance matrix to update /// @param extendedSystem All parameters of the current equation system -/// -/// @return deltaParams The calculated delta parameters. void updateGx2fCovarianceParams(BoundMatrix& fullCovariancePredicted, Gx2fSystem& extendedSystem); @@ -1234,7 +1246,6 @@ class Gx2Fitter { using PropagatorOptions = typename propagator_t::template Options; start_parameters_t params = sParameters; - BoundVector deltaParams = BoundVector::Zero(); double chi2sum = 0; double oldChi2sum = std::numeric_limits::max(); @@ -1272,10 +1283,6 @@ class Gx2Fitter { for (nUpdate = 0; nUpdate < gx2fOptions.nUpdateMax; nUpdate++) { ACTS_DEBUG("nUpdate = " << nUpdate + 1 << "/" << gx2fOptions.nUpdateMax); - // update params - params.parameters() += deltaParams; - ACTS_VERBOSE("Updated parameters: " << params.parameters().transpose()); - // set up propagator and co Acts::GeometryContext geoCtx = gx2fOptions.geoContext; Acts::MagneticFieldContext magCtx = gx2fOptions.magFieldContext; @@ -1290,7 +1297,7 @@ class Gx2Fitter { auto& gx2fActor = propagatorOptions.actorList.template get(); gx2fActor.inputMeasurements = &inputMeasurements; - gx2fActor.multipleScattering = multipleScattering; + gx2fActor.multipleScattering = false; gx2fActor.extensions = gx2fOptions.extensions; gx2fActor.calibrationContext = &gx2fOptions.calibrationContext.get(); gx2fActor.actorLogger = m_actorLogger.get(); @@ -1347,10 +1354,7 @@ class Gx2Fitter { // Count the material surfaces, to set up the system. In the multiple // scattering case, we need to extend our system. - const std::size_t nMaterialSurfaces = - multipleScattering - ? countMaterialStates(track, scatteringMap, *m_addToSumLogger) - : 0u; + const std::size_t nMaterialSurfaces = 0u; // We need 6 dimensions for the bound parameters and 2 * nMaterialSurfaces // dimensions for the scattering angles. @@ -1366,8 +1370,8 @@ class Gx2Fitter { // all stored material in each propagation. std::vector geoIdVector; - fillGx2fSystem(track, extendedSystem, multipleScattering, scatteringMap, - geoIdVector, *m_addToSumLogger); + fillGx2fSystem(track, extendedSystem, false, scatteringMap, geoIdVector, + *m_addToSumLogger); chi2sum = extendedSystem.chi2(); @@ -1392,14 +1396,10 @@ class Gx2Fitter { extendedSystem.aMatrix().colPivHouseholderQr().solve( extendedSystem.bVector()); - deltaParams = deltaParamsExtended.topLeftCorner().eval(); - ACTS_VERBOSE("aMatrix:\n" << extendedSystem.aMatrix() << "\n" << "bVector:\n" << extendedSystem.bVector() << "\n" - << "deltaParams:\n" - << deltaParams << "\n" << "deltaParamsExtended:\n" << deltaParamsExtended << "\n" << "oldChi2sum = " << oldChi2sum << "\n" @@ -1416,10 +1416,7 @@ class Gx2Fitter { } if (extendedSystem.chi2() > oldChi2sum + 1e-5) { - ACTS_DEBUG("chi2 not converging monotonically"); - - updateGx2fCovarianceParams(fullCovariancePredicted, extendedSystem); - break; + ACTS_DEBUG("chi2 not converging monotonically in update " << nUpdate); } // If this is the final iteration, update the covariance and break. @@ -1440,19 +1437,9 @@ class Gx2Fitter { break; } - if (multipleScattering) { - // update the scattering angles - for (std::size_t matSurface = 0; matSurface < nMaterialSurfaces; - matSurface++) { - const std::size_t deltaPosition = eBoundSize + 2 * matSurface; - const GeometryIdentifier geoId = geoIdVector[matSurface]; - const auto scatteringMapId = scatteringMap.find(geoId); - assert(scatteringMapId != scatteringMap.end() && - "No scattering angles found for material surface."); - scatteringMapId->second.scatteringAngles().block<2, 1>(2, 0) += - deltaParamsExtended.block<2, 1>(deltaPosition, 0).eval(); - } - } + updateGx2fParams(params, deltaParamsExtended, nMaterialSurfaces, + scatteringMap, geoIdVector); + ACTS_VERBOSE("Updated parameters: " << params.parameters().transpose()); oldChi2sum = extendedSystem.chi2(); } @@ -1460,6 +1447,144 @@ class Gx2Fitter { ACTS_VERBOSE("Final parameters: " << params.parameters().transpose()); /// Finish Fitting ///////////////////////////////////////////////////////// + /// Actual MATERIAL Fitting //////////////////////////////////////////////// + ACTS_DEBUG("Start to evaluate material"); + if (multipleScattering) { + // set up propagator and co + Acts::GeometryContext geoCtx = gx2fOptions.geoContext; + Acts::MagneticFieldContext magCtx = gx2fOptions.magFieldContext; + // Set options for propagator + PropagatorOptions propagatorOptions(geoCtx, magCtx); + + // Add the measurement surface as external surface to the navigator. + // We will try to hit those surface by ignoring boundary checks. + for (const auto& [surfaceId, _] : inputMeasurements) { + propagatorOptions.navigation.insertExternalSurface(surfaceId); + } + + auto& gx2fActor = propagatorOptions.actorList.template get(); + gx2fActor.inputMeasurements = &inputMeasurements; + gx2fActor.multipleScattering = true; + gx2fActor.extensions = gx2fOptions.extensions; + gx2fActor.calibrationContext = &gx2fOptions.calibrationContext.get(); + gx2fActor.actorLogger = m_actorLogger.get(); + gx2fActor.scatteringMap = &scatteringMap; + gx2fActor.parametersWithHypothesis = ¶ms; + + auto propagatorState = m_propagator.makeState(params, propagatorOptions); + + auto& r = propagatorState.template get>(); + r.fittedStates = &trajectoryTempBackend; + + // Clear the track container. It could be more performant to update the + // existing states, but this needs some more thinking. + trackContainerTemp.clear(); + + auto propagationResult = m_propagator.propagate(propagatorState); + + // Run the fitter + auto result = + m_propagator.makeResult(std::move(propagatorState), propagationResult, + propagatorOptions, false); + + if (!result.ok()) { + ACTS_ERROR("Propagation failed: " << result.error()); + return result.error(); + } + + // TODO Improve Propagator + Actor [allocate before loop], rewrite + // makeMeasurements + auto& propRes = *result; + GX2FResult gx2fResult = std::move(propRes.template get()); + + if (!gx2fResult.result.ok()) { + ACTS_INFO("GlobalChiSquareFitter failed in actor: " + << gx2fResult.result.error() << ", " + << gx2fResult.result.error().message()); + return gx2fResult.result.error(); + } + + auto track = trackContainerTemp.makeTrack(); + tipIndex = gx2fResult.lastMeasurementIndex; + + // It could happen, that no measurements were found. Then the track would + // be empty and the following operations would be invalid. Usually, this + // only happens during the first iteration, due to bad initial parameters. + if (tipIndex == Acts::MultiTrajectoryTraits::kInvalid) { + ACTS_INFO("Did not find any measurements in material fit."); + return Experimental::GlobalChiSquareFitterError::NotEnoughMeasurements; + } + + track.tipIndex() = tipIndex; + track.linkForward(); + + // Count the material surfaces, to set up the system. In the multiple + // scattering case, we need to extend our system. + const std::size_t nMaterialSurfaces = + countMaterialStates(track, scatteringMap, *m_addToSumLogger); + + // We need 6 dimensions for the bound parameters and 2 * nMaterialSurfaces + // dimensions for the scattering angles. + const std::size_t dimsExtendedParams = eBoundSize + 2 * nMaterialSurfaces; + + // System that we fill with the information gathered by the actor and + // evaluate later + Gx2fSystem extendedSystem{dimsExtendedParams}; + + // This vector stores the IDs for each visited material in order. We use + // it later for updating the scattering angles. We cannot use + // scatteringMap directly, since we cannot guarantee, that we will visit + // all stored material in each propagation. + std::vector geoIdVector; + + fillGx2fSystem(track, extendedSystem, true, scatteringMap, geoIdVector, + *m_addToSumLogger); + + chi2sum = extendedSystem.chi2(); + + // This check takes into account the evaluated dimensions of the + // measurements. To fit, we need at least NDF+1 measurements. However, we + // count n-dimensional measurements for n measurements, reducing the + // effective number of needed measurements. We might encounter the case, + // where we cannot use some (parts of a) measurements, maybe if we do not + // support that kind of measurement. This is also taken into account here. + // We skip the check during the first iteration, since we cannot guarantee + // to hit all/enough measurement surfaces with the initial parameter + // guess. + if ((nUpdate > 0) && !extendedSystem.isWellDefined()) { + ACTS_INFO("Not enough measurements. Require " + << extendedSystem.findRequiredNdf() + 1 << ", but only " + << extendedSystem.ndf() << " could be used."); + return Experimental::GlobalChiSquareFitterError::NotEnoughMeasurements; + } + + // calculate delta params [a] * delta = b + Eigen::VectorXd deltaParamsExtended = + extendedSystem.aMatrix().colPivHouseholderQr().solve( + extendedSystem.bVector()); + + ACTS_VERBOSE("aMatrix:\n" + << extendedSystem.aMatrix() << "\n" + << "bVector:\n" + << extendedSystem.bVector() << "\n" + << "deltaParamsExtended:\n" + << deltaParamsExtended << "\n" + << "oldChi2sum = " << oldChi2sum << "\n" + << "chi2sum = " << extendedSystem.chi2()); + + chi2sum = extendedSystem.chi2(); + + updateGx2fParams(params, deltaParamsExtended, nMaterialSurfaces, + scatteringMap, geoIdVector); + ACTS_VERBOSE("Updated parameters: " << params.parameters().transpose()); + + updateGx2fCovarianceParams(fullCovariancePredicted, extendedSystem); + } + ACTS_DEBUG("Finished to evaluate material"); + ACTS_VERBOSE( + "Final parameters after material: " << params.parameters().transpose()); + /// Finish MATERIAL Fitting //////////////////////////////////////////////// + ACTS_VERBOSE("Final scattering angles:"); for (const auto& [key, value] : scatteringMap) { if (!value.materialIsValid()) { @@ -1478,7 +1603,6 @@ class Gx2Fitter { // step, we will not ignore the boundary checks for measurement surfaces. We // want to create trackstates only on surfaces, that we actually hit. if (gx2fOptions.nUpdateMax > 0) { - ACTS_VERBOSE("Final delta parameters: " << deltaParams.transpose()); ACTS_VERBOSE("Propagate with the final covariance."); // update covariance params.covariance() = fullCovariancePredicted; diff --git a/Core/include/Acts/Utilities/HashedString.hpp b/Core/include/Acts/Utilities/HashedString.hpp index 6cdbe9d21e6..88b50a34d05 100644 --- a/Core/include/Acts/Utilities/HashedString.hpp +++ b/Core/include/Acts/Utilities/HashedString.hpp @@ -8,9 +8,11 @@ #pragma once +#include #include #include #include +#include #include namespace Acts { @@ -35,7 +37,11 @@ constexpr int length(const char* str) { } } // namespace detail -constexpr HashedString hashString(std::string_view s) { +consteval HashedString hashString(std::string_view s) { + return detail::fnv1a_32(s); +} + +constexpr HashedString hashStringDynamic(std::string_view s) { return detail::fnv1a_32(s); } diff --git a/Core/include/Acts/Utilities/Logger.hpp b/Core/include/Acts/Utilities/Logger.hpp index 48cadb49ec4..83dc989ca85 100644 --- a/Core/include/Acts/Utilities/Logger.hpp +++ b/Core/include/Acts/Utilities/Logger.hpp @@ -482,7 +482,9 @@ class TimedOutputDecorator final : public OutputDecorator { char buffer[20]; time_t t{}; std::time(&t); - std::strftime(buffer, sizeof(buffer), m_format.c_str(), localtime(&t)); + struct tm tbuf {}; + std::strftime(buffer, sizeof(buffer), m_format.c_str(), + localtime_r(&t, &tbuf)); return buffer; } diff --git a/Core/include/Acts/Utilities/detail/ContextType.hpp b/Core/include/Acts/Utilities/detail/ContextType.hpp index 143e8b2d521..8ccadd77c4d 100644 --- a/Core/include/Acts/Utilities/detail/ContextType.hpp +++ b/Core/include/Acts/Utilities/detail/ContextType.hpp @@ -79,6 +79,28 @@ class ContextType { return std::any_cast&>(m_data); } + /// Retrieve a pointer to the contained type + /// + /// @note Returns `nullptr` if @p is not the contained type. + /// + /// @tparam T The type to attempt to retrieve the value as + /// @return Pointer to the contained value, may be null + template + std::decay_t* maybeGet() { + return std::any_cast>(&m_data); + } + + /// Retrieve a pointer to the contained type + /// + /// @note Returns `nullptr` if @p is not the contained type. + /// + /// @tparam T The type to attempt to retrieve the value as + /// @return Pointer to the contained value, may be null + template + const std::decay_t* maybeGet() const { + return std::any_cast>(&m_data); + } + /// Check if the contained type is initialized. /// @return Boolean indicating whether a type is present bool hasValue() const { return m_data.has_value(); } diff --git a/Core/src/AmbiguityResolution/ScoreBasedAmbiguityResolution.cpp b/Core/src/AmbiguityResolution/ScoreBasedAmbiguityResolution.cpp index 4dcbb5071d4..c7e47f41046 100644 --- a/Core/src/AmbiguityResolution/ScoreBasedAmbiguityResolution.cpp +++ b/Core/src/AmbiguityResolution/ScoreBasedAmbiguityResolution.cpp @@ -7,186 +7,3 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. #include "Acts/AmbiguityResolution/ScoreBasedAmbiguityResolution.hpp" - -#include "Acts/EventData/SourceLink.hpp" - -#include - -std::vector Acts::ScoreBasedAmbiguityResolution::getCleanedOutTracks( - const std::vector& trackScore, - const std::vector>& trackFeaturesVectors, - const std::vector>& measurementsPerTrack) - const { - std::vector cleanTracks(measurementsPerTrack.size(), false); - - ACTS_VERBOSE("Cleaning tracks"); - - if (trackScore.size() != measurementsPerTrack.size()) { - throw std::invalid_argument( - "Track score and measurementsPerTrack size mismatch"); - } - - std::size_t numberOfTracks = measurementsPerTrack.size(); - ACTS_DEBUG("Number of tracks: " << numberOfTracks); - - boost::container::flat_map> - tracksPerMeasurement; - - // Removes bad tracks and counts computes the vector of tracks per - // measurement. - for (std::size_t iTrack = 0; iTrack < numberOfTracks; ++iTrack) { - if (trackScore[iTrack] <= 0) { - continue; - } - for (auto measurementObjects : measurementsPerTrack[iTrack]) { - auto iMeasurement = measurementObjects.iMeasurement; - tracksPerMeasurement[iMeasurement].insert(iTrack); - } - } - - enum TrackStateTypes { - // A measurement not yet used in any other track - UnsharedHit = 1, - // A measurement shared with another track - SharedHit = 2, - // A hit that needs to be removed from the track - RejectedHit = 3, - // an outlier, to be copied in case - Outlier = 4, - // other trackstate types to be copied in case - OtherTrackStateType = 5 - }; - - std::vector> newMeasurements; - // Loop over all tracks in the track container - for (std::size_t iTrack = 0; iTrack < numberOfTracks; ++iTrack) { - double track_score = trackScore[iTrack]; - ACTS_DEBUG("Track score: " << track_score); - - if (track_score <= 0) { - ACTS_DEBUG("Track " << iTrack << " could not be accepted - low score"); - continue; - } - - const auto& trackFeaturesVector = trackFeaturesVectors.at(iTrack); - - bool trkCouldBeAccepted = true; - - // For tracks with shared hits, we need to check and remove bad hits - - std::vector trackStateTypes(measurementsPerTrack[iTrack].size(), - OtherTrackStateType); - int index = 0; - - // Loop over all measurements of the track and for each hit a - // trackStateTypes is assigned. - for (const auto& measurementObjects : measurementsPerTrack[iTrack]) { - auto iMeasurement = measurementObjects.iMeasurement; - auto isoutliner = measurementObjects.isOutlier; - auto detectorId = measurementObjects.detectorId; - - auto detector = m_cfg.detectorConfigs.at(detectorId); - if (isoutliner) { - ACTS_VERBOSE("Measurement is outlier on a fitter track, copy it over"); - trackStateTypes[index] = Outlier; - index++; - continue; - } - if (tracksPerMeasurement[iMeasurement].size() == 1) { - ACTS_VERBOSE("Measurement is not shared, copy it over"); - - trackStateTypes[index] = UnsharedHit; - - index++; - continue; - } - if (tracksPerMeasurement[iMeasurement].size() > 1) { - ACTS_VERBOSE("Measurement is shared, copy it over"); - - if (detector.sharedHitsFlag == true) { - ACTS_VERBOSE("Measurement is shared, Reject it"); - trackStateTypes[index] = RejectedHit; - index++; - continue; - } - - trackStateTypes[index] = SharedHit; - - index++; - continue; - } - } - - std::vector newMeasurementsPerTrack; - std::size_t measurement = 0; - std::size_t nshared = 0; - - // Loop over all measurements of the track and process them according to the - // trackStateTypes and other conditions. - // Good measurements are copied to the newMeasurementsPerTrack vector. - for (std::size_t i = 0; i < trackStateTypes.size(); i++) { - auto& measurementObjects = measurementsPerTrack[iTrack][i]; - measurement = measurementObjects.iMeasurement; - - if (trackStateTypes[i] == RejectedHit) { - ACTS_DEBUG("Dropping rejected hit"); - } else if (trackStateTypes[i] != SharedHit) { - ACTS_DEBUG("Good TSOS, copy hit"); - newMeasurementsPerTrack.push_back(measurement); - - // a counter called nshared is used to keep track of the number of - // shared hits accepted. - } else if (nshared >= m_cfg.maxShared) { - ACTS_DEBUG("Too many shared hit, drop it"); - } - // If the track is shared, the hit is only accepted if the track has score - // higher than the minimum score for shared tracks. - else { - ACTS_DEBUG("Try to recover shared hit "); - if (tracksPerMeasurement[measurement].size() < - m_cfg.maxSharedTracksPerMeasurement && - track_score > m_cfg.minScoreSharedTracks) { - ACTS_DEBUG("Accepted hit shared with " - << tracksPerMeasurement[measurement].size() << " tracks"); - newMeasurementsPerTrack.push_back(measurement); - nshared++; - } else { - ACTS_DEBUG("Rejected hit shared with " - << tracksPerMeasurement[measurement].size() << " tracks"); - } - } - } - - // Check if the track has enough hits to be accepted. - if (newMeasurementsPerTrack.size() < 3) { - trkCouldBeAccepted = false; - ACTS_DEBUG(std::endl - << "Track " << iTrack - << " could not be accepted - not enough hits"); - ACTS_DEBUG("Number of hits: " << measurementsPerTrack[iTrack].size()); - ACTS_DEBUG("Number of good hits: " << newMeasurementsPerTrack.size()); - continue; - } - - // Check if the track has too many shared hits to be accepted. - for (std::size_t detectorId = 0; detectorId < m_cfg.detectorConfigs.size(); - detectorId++) { - auto detector = m_cfg.detectorConfigs.at(detectorId); - if (trackFeaturesVector[detectorId].nSharedHits > - detector.maxSharedHits) { - trkCouldBeAccepted = false; - break; - } - } - - if (trkCouldBeAccepted) { - cleanTracks[iTrack] = true; - newMeasurements.push_back(newMeasurementsPerTrack); - ACTS_VERBOSE("Track " << iTrack << " is accepted"); - continue; - } - } - - return cleanTracks; -} diff --git a/Core/src/Geometry/TrackingVolume.cpp b/Core/src/Geometry/TrackingVolume.cpp index bbe9b60fc98..6d3880bd4db 100644 --- a/Core/src/Geometry/TrackingVolume.cpp +++ b/Core/src/Geometry/TrackingVolume.cpp @@ -96,6 +96,13 @@ const TrackingVolume* TrackingVolume::lowestTrackingVolume( } } + // @TODO: Abstract this into an accelerateable structure + for (const auto& volume : volumes()) { + if (volume.inside(position, tol)) { + return volume.lowestTrackingVolume(gctx, position, tol); + } + } + // there is no lower sub structure return this; } diff --git a/Core/src/Navigation/TryAllNavigationPolicy.cpp b/Core/src/Navigation/TryAllNavigationPolicy.cpp index 40ca70c4079..4423c7d62a8 100644 --- a/Core/src/Navigation/TryAllNavigationPolicy.cpp +++ b/Core/src/Navigation/TryAllNavigationPolicy.cpp @@ -13,10 +13,10 @@ namespace Acts { -TryAllNavigationPolicy::TryAllNavigationPolicy(const Config& config, - const GeometryContext& /*gctx*/, +TryAllNavigationPolicy::TryAllNavigationPolicy(const GeometryContext& /*gctx*/, const TrackingVolume& volume, - const Logger& logger) + const Logger& logger, + const Config& config) : m_cfg{config}, m_volume(&volume) { assert(m_volume != nullptr); ACTS_VERBOSE("TryAllNavigationPolicy created for volume " @@ -26,7 +26,7 @@ TryAllNavigationPolicy::TryAllNavigationPolicy(const Config& config, TryAllNavigationPolicy::TryAllNavigationPolicy(const GeometryContext& gctx, const TrackingVolume& volume, const Logger& logger) - : TryAllNavigationPolicy({}, gctx, volume, logger) {} + : TryAllNavigationPolicy(gctx, volume, logger, {}) {} void TryAllNavigationPolicy::initializeCandidates( const NavigationArguments& args, AppendOnlyNavigationStream& stream, diff --git a/Core/src/Seeding/EstimateTrackParamsFromSeed.cpp b/Core/src/Seeding/EstimateTrackParamsFromSeed.cpp index eebcd1c5760..055691bbb2f 100644 --- a/Core/src/Seeding/EstimateTrackParamsFromSeed.cpp +++ b/Core/src/Seeding/EstimateTrackParamsFromSeed.cpp @@ -12,6 +12,84 @@ #include +Acts::FreeVector Acts::estimateTrackParamsFromSeed(const Vector3& sp0, + const Vector3& sp1, + const Vector3& sp2, + const Vector3& bField) { + // Define a new coordinate frame with its origin at the bottom space point, z + // axis long the magnetic field direction and y axis perpendicular to vector + // from the bottom to middle space point. Hence, the projection of the middle + // space point on the transverse plane will be located at the x axis of the + // new frame. + Vector3 relVec = sp1 - sp0; + Vector3 newZAxis = bField.normalized(); + Vector3 newYAxis = newZAxis.cross(relVec).normalized(); + Vector3 newXAxis = newYAxis.cross(newZAxis); + RotationMatrix3 rotation; + rotation.col(0) = newXAxis; + rotation.col(1) = newYAxis; + rotation.col(2) = newZAxis; + // The center of the new frame is at the bottom space point + Translation3 trans(sp0); + // The transform which constructs the new frame + Transform3 transform(trans * rotation); + + // The coordinate of the middle and top space point in the new frame + Vector3 local1 = transform.inverse() * sp1; + Vector3 local2 = transform.inverse() * sp2; + + // In the new frame the bottom sp is at the origin, while the middle + // sp in along the x axis. As such, the x-coordinate of the circle is + // at: x-middle / 2. + // The y coordinate can be found by using the straight line passing + // between the mid point between the middle and top sp and perpendicular to + // the line connecting them + Vector2 circleCenter; + circleCenter(0) = 0.5 * local1(0); + + ActsScalar deltaX21 = local2(0) - local1(0); + ActsScalar sumX21 = local2(0) + local1(0); + // straight line connecting the two points + // y = a * x + c (we don't care about c right now) + // we simply need the slope + // we compute 1./a since this is what we need for the following computation + ActsScalar ia = deltaX21 / local2(1); + // Perpendicular line is then y = -1/a *x + b + // we can evaluate b given we know a already by imposing + // the line passes through P = (0.5 * (x2 + x1), 0.5 * y2) + ActsScalar b = 0.5 * (local2(1) + ia * sumX21); + circleCenter(1) = -ia * circleCenter(0) + b; + // Radius is a signed distance between circleCenter and first sp, which is at + // (0, 0) in the new frame. Sign depends on the slope a (positive vs negative) + int sign = ia > 0 ? -1 : 1; + const ActsScalar R = circleCenter.norm(); + ActsScalar invTanTheta = + local2.z() / (2 * R * std::asin(local2.head<2>().norm() / (2 * R))); + // The momentum direction in the new frame (the center of the circle has the + // coordinate (-1.*A/(2*B), 1./(2*B))) + ActsScalar A = -circleCenter(0) / circleCenter(1); + Vector3 transDirection(1., A, fastHypot(1, A) * invTanTheta); + // Transform it back to the original frame + Vector3 direction = rotation * transDirection.normalized(); + + // Initialize the free parameters vector + FreeVector params = FreeVector::Zero(); + + // The bottom space point position + params.segment<3>(eFreePos0) = sp0; + + // The estimated direction + params.segment<3>(eFreeDir0) = direction; + + // The estimated q/pt in [GeV/c]^-1 (note that the pt is the projection of + // momentum on the transverse plane of the new frame) + ActsScalar qOverPt = sign / (bField.norm() * R); + // The estimated q/p in [GeV/c]^-1 + params[eFreeQOverP] = qOverPt / fastHypot(1., invTanTheta); + + return params; +} + Acts::BoundMatrix Acts::estimateTrackParamCovariance( const EstimateTrackParamCovarianceConfig& config, const BoundVector& params, bool hasTime) { diff --git a/Core/src/TrackFitting/GlobalChiSquareFitter.cpp b/Core/src/TrackFitting/GlobalChiSquareFitter.cpp index de61ee090d4..50b8b4cab8c 100644 --- a/Core/src/TrackFitting/GlobalChiSquareFitter.cpp +++ b/Core/src/TrackFitting/GlobalChiSquareFitter.cpp @@ -10,6 +10,30 @@ #include "Acts/Definitions/TrackParametrization.hpp" +void Acts::Experimental::updateGx2fParams( + BoundTrackParameters& params, const Eigen::VectorXd& deltaParamsExtended, + const std::size_t nMaterialSurfaces, + std::unordered_map& scatteringMap, + const std::vector& geoIdVector) { + // update params + params.parameters() += + deltaParamsExtended.topLeftCorner().eval(); + + // update the scattering angles. + for (std::size_t matSurface = 0; matSurface < nMaterialSurfaces; + matSurface++) { + const std::size_t deltaPosition = eBoundSize + 2 * matSurface; + const GeometryIdentifier geoId = geoIdVector[matSurface]; + const auto scatteringMapId = scatteringMap.find(geoId); + assert(scatteringMapId != scatteringMap.end() && + "No scattering angles found for material surface."); + scatteringMapId->second.scatteringAngles().block<2, 1>(2, 0) += + deltaParamsExtended.block<2, 1>(deltaPosition, 0).eval(); + } + + return; +} + void Acts::Experimental::updateGx2fCovarianceParams( BoundMatrix& fullCovariancePredicted, Gx2fSystem& extendedSystem) { // make invertible diff --git a/Examples/Algorithms/AmbiguityResolution/src/ScoreBasedAmbiguityResolutionAlgorithm.cpp b/Examples/Algorithms/AmbiguityResolution/src/ScoreBasedAmbiguityResolutionAlgorithm.cpp index bd3584fa4b2..b1a6e251dba 100644 --- a/Examples/Algorithms/AmbiguityResolution/src/ScoreBasedAmbiguityResolutionAlgorithm.cpp +++ b/Examples/Algorithms/AmbiguityResolution/src/ScoreBasedAmbiguityResolutionAlgorithm.cpp @@ -116,19 +116,11 @@ ActsExamples::ScoreBasedAmbiguityResolutionAlgorithm::execute( const auto& tracks = m_inputTracks(ctx); // Read input data ACTS_VERBOSE("Number of input tracks: " << tracks.size()); - std::vector> - measurementsPerTracks; - - std::vector> - trackFeaturesVectors; - measurementsPerTracks = m_ambi.computeInitialState( - tracks, &sourceLinkHash, &sourceLinkEquality, trackFeaturesVectors); - Acts::ScoreBasedAmbiguityResolution::OptionalCuts optionalCuts; optionalCuts.cuts.push_back(doubleHolesFilter); std::vector goodTracks = m_ambi.solveAmbiguity( - tracks, measurementsPerTracks, trackFeaturesVectors, optionalCuts); + tracks, &sourceLinkHash, &sourceLinkEquality, optionalCuts); // Prepare the output track collection from the IDs TrackContainer solvedTracks{std::make_shared(), std::make_shared()}; diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationAlgorithm.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationAlgorithm.hpp index fd8937bd300..331408faa9a 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationAlgorithm.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationAlgorithm.hpp @@ -8,18 +8,14 @@ #pragma once -#include "Acts/Definitions/Algebra.hpp" -#include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/Geometry/GeometryContext.hpp" #include "Acts/Geometry/GeometryHierarchyMap.hpp" #include "Acts/Utilities/Logger.hpp" #include "ActsExamples/Digitization/DigitizationConfig.hpp" #include "ActsExamples/Digitization/MeasurementCreation.hpp" -#include "ActsExamples/Digitization/SmearingConfig.hpp" #include "ActsExamples/EventData/Cluster.hpp" -#include "ActsExamples/EventData/Index.hpp" #include "ActsExamples/EventData/Measurement.hpp" #include "ActsExamples/EventData/SimHit.hpp" +#include "ActsExamples/EventData/SimParticle.hpp" #include "ActsExamples/Framework/DataHandle.hpp" #include "ActsExamples/Framework/IAlgorithm.hpp" #include "ActsExamples/Framework/ProcessCode.hpp" @@ -29,28 +25,62 @@ #include "ActsFatras/Digitization/UncorrelatedHitSmearer.hpp" #include -#include #include -#include -#include #include #include -namespace ActsFatras { -class Barcode; -} // namespace ActsFatras - namespace ActsExamples { -struct AlgorithmContext; /// Algorithm that turns simulated hits into measurements by truth smearing. class DigitizationAlgorithm final : public IAlgorithm { public: + class Config { + public: + /// Input collection of simulated hits. + std::string inputSimHits = "simhits"; + /// Output measurements collection. + std::string outputMeasurements = "measurements"; + /// Output cells map (geoID -> collection of cells). + std::string outputCells = "cells"; + /// Output cluster collection. + std::string outputClusters = "clusters"; + /// Output collection to map measured hits to contributing particles. + std::string outputMeasurementParticlesMap = "measurement_particles_map"; + /// Output collection to map measured hits to simulated hits. + std::string outputMeasurementSimHitsMap = "measurement_simhits_map"; + + /// Map of surface by identifier to allow local - to global + std::unordered_map + surfaceByIdentifier; + /// Random numbers tool. + std::shared_ptr randomNumbers = nullptr; + /// Flag to determine whether cell data should be written to the + /// `outputCells` collection; if true, writes (rather voluminous) cell data. + bool doOutputCells = false; + /// Flag to determine whether or not to run the clusterization; if true, + /// clusters, measurements, and sim-hit-maps are output. + bool doClusterization = true; + /// Do we merge hits or not + bool doMerge = false; + /// How close do parameters have to be to consider merged + double mergeNsigma = 1.0; + /// Consider clusters that share a corner as merged (8-cell connectivity) + bool mergeCommonCorner = false; + /// Energy deposit threshold for accepting a hit + /// For a generic readout frontend we assume 1000 e/h pairs, in Si each + /// e/h-pair requiers on average an energy of 3.65 eV (PDG review 2023, + /// Table 35.10) + /// @NOTE The default is set to 0 because this works only well with Geant4 + double minEnergyDeposit = 0.0; // 1000 * 3.65 * Acts::UnitConstants::eV; + /// The digitizers per GeometryIdentifiers + Acts::GeometryHierarchyMap digitizationConfigs; + }; + /// Construct the smearing algorithm. /// /// @param config is the algorithm configuration /// @param level is the logging level - DigitizationAlgorithm(DigitizationConfig config, Acts::Logging::Level level); + DigitizationAlgorithm(Config config, Acts::Logging::Level level); /// Build measurement from simulation hits at input. /// @@ -59,7 +89,7 @@ class DigitizationAlgorithm final : public IAlgorithm { ProcessCode execute(const AlgorithmContext& ctx) const override; /// Get const access to the config - const DigitizationConfig& config() const { return m_cfg; } + const Config& config() const { return m_cfg; } private: /// Helper method for creating digitized parameters from clusters @@ -89,7 +119,7 @@ class DigitizationAlgorithm final : public IAlgorithm { CombinedDigitizer<4>>; /// Configuration of the Algorithm - DigitizationConfig m_cfg; + Config m_cfg; /// Digitizers within geometry hierarchy Acts::GeometryHierarchyMap m_digitizers; /// Geometric digtizer @@ -98,17 +128,17 @@ class DigitizationAlgorithm final : public IAlgorithm { using CellsMap = std::map>; - ReadDataHandle m_simContainerReadHandle{this, - "SimHitContainer"}; - - WriteDataHandle m_measurementWriteHandle{ - this, "Measurements"}; - WriteDataHandle m_cellsWriteHandle{this, "Cells"}; - WriteDataHandle m_clusterWriteHandle{this, "Clusters"}; - WriteDataHandle> - m_measurementParticlesMapWriteHandle{this, "MeasurementParticlesMap"}; - WriteDataHandle> m_measurementSimHitsMapWriteHandle{ - this, "MeasurementSimHitsMap"}; + ReadDataHandle m_inputHits{this, "InputHits"}; + + WriteDataHandle m_outputMeasurements{ + this, "OutputMeasurements"}; + WriteDataHandle m_outputCells{this, "OutputCells"}; + WriteDataHandle m_outputClusters{this, "OutputClusters"}; + + WriteDataHandle> m_outputMeasurementParticlesMap{ + this, "OutputMeasurementParticlesMap"}; + WriteDataHandle> m_outputMeasurementSimHitsMap{ + this, "OutputMeasurementSimHitsMap"}; /// Construct a fixed-size smearer from a configuration. /// diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfig.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfig.hpp index 6a933f50075..213abe4d322 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfig.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfig.hpp @@ -8,107 +8,12 @@ #pragma once -#include "Acts/Definitions/Algebra.hpp" -#include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/Definitions/Units.hpp" #include "Acts/Geometry/GeometryHierarchyMap.hpp" -#include "Acts/Utilities/BinUtility.hpp" -#include "Acts/Utilities/BinningType.hpp" -#include "Acts/Utilities/Logger.hpp" -#include "Acts/Utilities/Result.hpp" -#include "ActsExamples/Digitization/DigitizationConfig.hpp" -#include "ActsExamples/Digitization/Smearers.hpp" +#include "ActsExamples/Digitization/GeometricConfig.hpp" #include "ActsExamples/Digitization/SmearingConfig.hpp" -#include "ActsExamples/Framework/RandomNumbers.hpp" -#include "ActsFatras/Digitization/UncorrelatedHitSmearer.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Acts { -class GeometryIdentifier; -} // namespace Acts namespace ActsExamples { -/// Configuration struct for geometric digitization -/// -/// If this is defined, then the geometric digitization -/// will create clusters with cells. -/// The BinUtility defines the segmentation and which parameters -/// are defined by this. -/// -struct GeometricConfig { - // The dimensions of the measurement - std::vector indices = {}; - - // The (multidimensional) binning definition for the segmentation of the - // sensor - Acts::BinUtility segmentation; - - // The thickness of the sensor - double thickness = 0.; - - /// The charge smearer - ActsFatras::SingleParameterSmearFunction - chargeSmearer = Digitization::Exact(0); - - // The threshold below a cell activation is ignored - double threshold = 0.; - - // Whether to assume digital readout (activation is either 0 or 1) - bool digital = false; - - // Flag as strip - bool strip = false; - - /// The variances for this digitization - std::map> varianceMap = {}; - - /// Charge generation (configurable via the chargeSmearer) - Acts::ActsScalar charge(Acts::ActsScalar path, RandomEngine &rng) const { - if (!chargeSmearer) { - return path; - } - auto res = chargeSmearer(path, rng); - if (res.ok()) { - return std::max(0.0, res->first); - } else { - throw std::runtime_error(res.error().message()); - } - } - - /// This generates the variances for a given cluster - /// - /// @note either the variances are directly taken from a pre-read - /// variance map, or they are generated from the pitch size - /// - /// @param csizes is the cluster size in the different dimensions - /// @param cmins is the cluster minimum in the different dimensions - /// - /// @return a vector of variances for the cluster - std::vector variances( - const std::array &csizes, - const std::array &cmins) const; - - /// Drift generation (currently not implemented) - /// Takes as an argument the position, and a random engine - /// @return drift direction in local 3D coordinates - Acts::Vector3 drift(const Acts::Vector3 & /*position*/, - RandomEngine & /*rng*/) const { - return Acts::Vector3(0., 0., 0.); - }; -}; - /// Configuration struct for the Digitization algorithm /// /// It contains: @@ -116,63 +21,9 @@ struct GeometricConfig { /// - optional SmearingConfig struct DigiComponentsConfig { GeometricConfig geometricDigiConfig; - SmearingConfig smearingDigiConfig = {}; + SmearingConfig smearingDigiConfig; }; -class DigitizationConfig { - public: - DigitizationConfig(bool merge, double sigma, bool commonCorner) - : DigitizationConfig(merge, sigma, commonCorner, - Acts::GeometryHierarchyMap()) { - } - - DigitizationConfig( - bool doMerge, double mergeNsigma, bool mergeCommonCorner, - Acts::GeometryHierarchyMap &&digiCfgs); - - explicit DigitizationConfig( - Acts::GeometryHierarchyMap &&digiCfgs); +using DigiConfigContainer = Acts::GeometryHierarchyMap; - /// Input collection of simulated hits. - std::string inputSimHits = "simhits"; - /// Output measurements collection. - std::string outputMeasurements = "measurements"; - /// Output cells map (geoID -> collection of cells). - std::string outputCells = "cells"; - /// Output cluster collection. - std::string outputClusters = "clusters"; - /// Output collection to map measured hits to contributing particles. - std::string outputMeasurementParticlesMap = "measurement_particles_map"; - /// Output collection to map measured hits to simulated hits. - std::string outputMeasurementSimHitsMap = "measurement_simhits_map"; - /// Map of surface by identifier to allow local - to global - std::unordered_map - surfaceByIdentifier; - /// Random numbers tool. - std::shared_ptr randomNumbers = nullptr; - /// Flag to determine whether cell data should be written to the - /// `outputCells` collection; if true, writes (rather voluminous) cell data. - bool doOutputCells = false; - /// Flag to determine whether or not to run the clusterization; if true, - /// clusters, measurements, and sim-hit-maps are output. - bool doClusterization = true; - /// Do we merge hits or not - bool doMerge; - /// How close do parameters have to be to consider merged - const double mergeNsigma; - /// Consider clusters that share a corner as merged (8-cell connectivity) - const bool mergeCommonCorner; - /// Energy deposit threshold for accepting a hit - /// For a generic readout frontend we assume 1000 e/h pairs, in Si each - /// e/h-pair requiers on average an energy of 3.65 eV (PDG review 2023, - /// Table 35.10) - /// @NOTE The default is set to 0 because this works only well with Geant4 - double minEnergyDeposit = 0.0; // 1000 * 3.65 * Acts::UnitConstants::eV; - /// The digitizers per GeometryIdentifiers - Acts::GeometryHierarchyMap digitizationConfigs; - - std::vector< - std::pair>> - getBoundIndices() const; -}; } // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfigurator.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfigurator.hpp index 55754eb79f7..3e6d01dea0f 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfigurator.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfigurator.hpp @@ -11,21 +11,9 @@ #include "Acts/Geometry/GeometryHierarchyMap.hpp" #include "Acts/Geometry/GeometryIdentifier.hpp" #include "Acts/Geometry/TrackingGeometry.hpp" -#include "Acts/Surfaces/AnnulusBounds.hpp" -#include "Acts/Surfaces/DiscTrapezoidBounds.hpp" -#include "Acts/Surfaces/RadialBounds.hpp" -#include "Acts/Surfaces/RectangleBounds.hpp" -#include "Acts/Surfaces/SurfaceBounds.hpp" -#include "Acts/Surfaces/TrapezoidBounds.hpp" -#include "Acts/Utilities/BinUtility.hpp" -#include "Acts/Utilities/BinningData.hpp" -#include "ActsExamples/Digitization/DigitizationAlgorithm.hpp" #include "ActsExamples/Digitization/DigitizationConfig.hpp" #include -#include -#include -#include namespace Acts { class Surface; @@ -66,4 +54,5 @@ struct DigitizationConfigurator { /// it adds an appropriate entry into the digitisation configuration void operator()(const Acts::Surface* surface); }; + } // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationCoordinatesConverter.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationCoordinatesConverter.hpp index 21c4f619b8a..382e113844f 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationCoordinatesConverter.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationCoordinatesConverter.hpp @@ -8,6 +8,7 @@ #pragma once +#include "ActsExamples/Digitization/DigitizationAlgorithm.hpp" #include "ActsExamples/Digitization/DigitizationConfig.hpp" namespace ActsExamples { @@ -18,10 +19,11 @@ class DigitizationCoordinatesConverter final { /// Construct the converter /// /// @param config is the configuration - explicit DigitizationCoordinatesConverter(DigitizationConfig config); + explicit DigitizationCoordinatesConverter( + DigitizationAlgorithm::Config config); /// Get const access to the config - const DigitizationConfig& config() const { return m_cfg; } + const DigitizationAlgorithm::Config& config() const { return m_cfg; } /// Convert the hit coordinates to the local frame. std::tuple globalToLocal(std::uint64_t moduleId, double x, @@ -33,7 +35,7 @@ class DigitizationCoordinatesConverter final { private: /// Configuration - DigitizationConfig m_cfg; + DigitizationAlgorithm::Config m_cfg; }; } // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/GeometricConfig.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/GeometricConfig.hpp new file mode 100644 index 00000000000..6b4348e20f6 --- /dev/null +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/GeometricConfig.hpp @@ -0,0 +1,98 @@ +// 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/Definitions/Algebra.hpp" +#include "Acts/Definitions/TrackParametrization.hpp" +#include "Acts/Utilities/BinUtility.hpp" +#include "Acts/Utilities/Result.hpp" +#include "ActsExamples/Digitization/Smearers.hpp" +#include "ActsExamples/Framework/RandomNumbers.hpp" +#include "ActsFatras/Digitization/UncorrelatedHitSmearer.hpp" + +#include +#include +#include +#include +#include +#include +#include + +namespace ActsExamples { + +/// Configuration struct for geometric digitization +/// +/// If this is defined, then the geometric digitization +/// will create clusters with cells. +/// The BinUtility defines the segmentation and which parameters +/// are defined by this. +/// +struct GeometricConfig { + // The dimensions of the measurement + std::vector indices = {}; + + // The (multidimensional) binning definition for the segmentation of the + // sensor + Acts::BinUtility segmentation; + + // The thickness of the sensor + double thickness = 0.; + + /// The charge smearer + ActsFatras::SingleParameterSmearFunction + chargeSmearer = Digitization::Exact(0); + + // The threshold below a cell activation is ignored + double threshold = 0.; + + // Whether to assume digital readout (activation is either 0 or 1) + bool digital = false; + + // Flag as strip + bool strip = false; + + /// The variances for this digitization + std::map> varianceMap = {}; + + /// Charge generation (configurable via the chargeSmearer) + Acts::ActsScalar charge(Acts::ActsScalar path, RandomEngine &rng) const { + if (!chargeSmearer) { + return path; + } + auto res = chargeSmearer(path, rng); + if (res.ok()) { + return std::max(0.0, res->first); + } else { + throw std::runtime_error(res.error().message()); + } + } + + /// This generates the variances for a given cluster + /// + /// @note either the variances are directly taken from a pre-read + /// variance map, or they are generated from the pitch size + /// + /// @param csizes is the cluster size in the different dimensions + /// @param cmins is the cluster minimum in the different dimensions + /// + /// @return a vector of variances for the cluster + std::vector variances( + const std::array &csizes, + const std::array &cmins) const; + + /// Drift generation (currently not implemented) + /// Takes as an argument the position, and a random engine + /// @return drift direction in local 3D coordinates + Acts::Vector3 drift(const Acts::Vector3 & /*position*/, + RandomEngine & /*rng*/) const { + return Acts::Vector3(0., 0., 0.); + }; +}; + +} // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/ModuleClusters.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/ModuleClusters.hpp index 675f86af07d..452111db2eb 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/ModuleClusters.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/ModuleClusters.hpp @@ -16,10 +16,8 @@ #include "ActsExamples/EventData/Cluster.hpp" #include "ActsExamples/EventData/SimHit.hpp" -#include #include #include -#include #include #include #include @@ -69,4 +67,5 @@ class ModuleClusters { std::vector> mergeParameters( std::vector values); }; + } // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/Smearers.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/Smearers.hpp index c51b8e26b64..8d0130831ae 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/Smearers.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/Smearers.hpp @@ -12,13 +12,10 @@ #include "Acts/Utilities/Result.hpp" #include "ActsExamples/Framework/RandomNumbers.hpp" #include "ActsFatras/Digitization/DigitizationError.hpp" -#include "ActsFatras/Digitization/UncorrelatedHitSmearer.hpp" #include #include #include -#include -#include #include namespace ActsExamples::Digitization { diff --git a/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp b/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp index 72f3905ab57..07019be74ca 100644 --- a/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp +++ b/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp @@ -11,35 +11,24 @@ #include "Acts/Definitions/Algebra.hpp" #include "Acts/Definitions/TrackParametrization.hpp" #include "Acts/Geometry/GeometryIdentifier.hpp" -#include "Acts/Geometry/TrackingGeometry.hpp" -#include "Acts/Surfaces/Surface.hpp" #include "Acts/Utilities/BinUtility.hpp" -#include "Acts/Utilities/Result.hpp" #include "ActsExamples/Digitization/ModuleClusters.hpp" -#include "ActsExamples/EventData/GeometryContainers.hpp" -#include "ActsExamples/EventData/Index.hpp" -#include "ActsExamples/EventData/SimHit.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" -#include "ActsExamples/Utilities/GroupBy.hpp" -#include "ActsExamples/Utilities/Range.hpp" #include "ActsFatras/EventData/Barcode.hpp" -#include "ActsFatras/EventData/Hit.hpp" #include #include -#include -#include #include #include -#include #include #include #include -ActsExamples::DigitizationAlgorithm::DigitizationAlgorithm( - DigitizationConfig config, Acts::Logging::Level level) - : ActsExamples::IAlgorithm("DigitizationAlgorithm", level), - m_cfg(std::move(config)) { +namespace ActsExamples { + +DigitizationAlgorithm::DigitizationAlgorithm(Config config, + Acts::Logging::Level level) + : IAlgorithm("DigitizationAlgorithm", level), m_cfg(std::move(config)) { if (m_cfg.inputSimHits.empty()) { throw std::invalid_argument("Missing simulated hits input collection"); } @@ -69,12 +58,11 @@ ActsExamples::DigitizationAlgorithm::DigitizationAlgorithm( "Missing hit-to-simulated-hits map output collection"); } - m_measurementWriteHandle.initialize(m_cfg.outputMeasurements); - m_clusterWriteHandle.initialize(m_cfg.outputClusters); - m_measurementParticlesMapWriteHandle.initialize( + m_outputMeasurements.initialize(m_cfg.outputMeasurements); + m_outputClusters.initialize(m_cfg.outputClusters); + m_outputMeasurementParticlesMap.initialize( m_cfg.outputMeasurementParticlesMap); - m_measurementSimHitsMapWriteHandle.initialize( - m_cfg.outputMeasurementSimHitsMap); + m_outputMeasurementSimHitsMap.initialize(m_cfg.outputMeasurementSimHitsMap); } if (m_cfg.doOutputCells) { @@ -82,10 +70,10 @@ ActsExamples::DigitizationAlgorithm::DigitizationAlgorithm( throw std::invalid_argument("Missing cell output collection"); } - m_cellsWriteHandle.initialize(m_cfg.outputCells); + m_outputCells.initialize(m_cfg.outputCells); } - m_simContainerReadHandle.initialize(m_cfg.inputSimHits); + m_inputHits.initialize(m_cfg.inputSimHits); // Create the digitizers from the configuration std::vector> digitizerInput; @@ -139,16 +127,16 @@ ActsExamples::DigitizationAlgorithm::DigitizationAlgorithm( m_digitizers = Acts::GeometryHierarchyMap(digitizerInput); } -ActsExamples::ProcessCode ActsExamples::DigitizationAlgorithm::execute( - const AlgorithmContext& ctx) const { +ProcessCode DigitizationAlgorithm::execute(const AlgorithmContext& ctx) const { // Retrieve input - const auto& simHits = m_simContainerReadHandle(ctx); + const auto& simHits = m_inputHits(ctx); ACTS_DEBUG("Loaded " << simHits.size() << " sim hits"); // Prepare output containers // need list here for stable addresses MeasurementContainer measurements; ClusterContainer clusters; + IndexMultimap measurementParticlesMap; IndexMultimap measurementSimHitsMap; measurements.reserve(simHits.size()); @@ -271,7 +259,7 @@ ActsExamples::ProcessCode ActsExamples::DigitizationAlgorithm::execute( // Store the cell data into a map. if (m_cfg.doOutputCells) { std::vector cells; - for (const auto& [dParameters, simhits] : + for (const auto& [dParameters, simHitsIdxs] : digitizeParametersResult) { for (const auto& cell : dParameters.cluster.channels) { cells.push_back(cell); @@ -281,21 +269,18 @@ ActsExamples::ProcessCode ActsExamples::DigitizationAlgorithm::execute( } if (m_cfg.doClusterization) { - for (auto& [dParameters, simhits] : digitizeParametersResult) { - // The measurement container is unordered and the index under - // which the measurement will be stored is known before adding it. - Index measurementIdx = measurements.size(); - - createMeasurement(measurements, moduleGeoId, dParameters); + for (auto& [dParameters, simHitsIdxs] : digitizeParametersResult) { + auto measurement = + createMeasurement(measurements, moduleGeoId, dParameters); clusters.emplace_back(std::move(dParameters.cluster)); - // this digitization does hit merging so there can be more than - // one mapping entry for each digitized hit. - for (auto simHitIdx : simhits) { + + for (auto [i, simHitIdx] : Acts::enumerate(simHitsIdxs)) { measurementParticlesMap.emplace_hint( - measurementParticlesMap.end(), measurementIdx, + measurementParticlesMap.end(), measurement.index(), simHits.nth(simHitIdx)->particleId()); measurementSimHitsMap.emplace_hint(measurementSimHitsMap.end(), - measurementIdx, simHitIdx); + measurement.index(), + simHitIdx); } } } @@ -309,23 +294,22 @@ ActsExamples::ProcessCode ActsExamples::DigitizationAlgorithm::execute( << " skipped in Digitization. Enable DEBUG mode to see more details."); } - if (m_cfg.doOutputCells) { - m_cellsWriteHandle(ctx, std::move(cellsMap)); + if (m_cfg.doClusterization) { + m_outputMeasurements(ctx, std::move(measurements)); + m_outputClusters(ctx, std::move(clusters)); + + m_outputMeasurementParticlesMap(ctx, std::move(measurementParticlesMap)); + m_outputMeasurementSimHitsMap(ctx, std::move(measurementSimHitsMap)); } - if (m_cfg.doClusterization) { - m_measurementWriteHandle(ctx, std::move(measurements)); - m_clusterWriteHandle(ctx, std::move(clusters)); - m_measurementParticlesMapWriteHandle(ctx, - std::move(measurementParticlesMap)); - m_measurementSimHitsMapWriteHandle(ctx, std::move(measurementSimHitsMap)); + if (m_cfg.doOutputCells) { + m_outputCells(ctx, std::move(cellsMap)); } return ProcessCode::SUCCESS; } -ActsExamples::DigitizedParameters -ActsExamples::DigitizationAlgorithm::localParameters( +DigitizedParameters DigitizationAlgorithm::localParameters( const GeometricConfig& geoCfg, const std::vector& channels, RandomEngine& rng) const { @@ -377,3 +361,5 @@ ActsExamples::DigitizationAlgorithm::localParameters( return dParameters; } + +} // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/src/DigitizationConfig.cpp b/Examples/Algorithms/Digitization/src/DigitizationConfig.cpp index e19452d1e7a..8c23ba729d1 100644 --- a/Examples/Algorithms/Digitization/src/DigitizationConfig.cpp +++ b/Examples/Algorithms/Digitization/src/DigitizationConfig.cpp @@ -8,59 +8,9 @@ #include "ActsExamples/Digitization/DigitizationConfig.hpp" -#include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/Geometry/GeometryIdentifier.hpp" -#include "ActsExamples/Digitization/SmearingConfig.hpp" +namespace ActsExamples { -namespace { - -enum SmearingTypes : int { - eGauss = 0, - eGaussTruncated = 1, - eGaussClipped = 2, - eUniform = 3, - eDigital = 4, -}; - -} // namespace - -ActsExamples::DigitizationConfig::DigitizationConfig( - bool merge, double sigma, bool commonCorner, - Acts::GeometryHierarchyMap&& digiCfgs) - : doMerge(merge), mergeNsigma(sigma), mergeCommonCorner(commonCorner) { - digitizationConfigs = std::move(digiCfgs); -} - -ActsExamples::DigitizationConfig::DigitizationConfig( - Acts::GeometryHierarchyMap&& digiCfgs) - : doMerge(false), mergeNsigma(1.0), mergeCommonCorner(false) { - digitizationConfigs = std::move(digiCfgs); -} - -std::vector< - std::pair>> -ActsExamples::DigitizationConfig::getBoundIndices() const { - std::vector< - std::pair>> - bIndexInput; - - for (std::size_t ibi = 0; ibi < digitizationConfigs.size(); ++ibi) { - Acts::GeometryIdentifier geoID = digitizationConfigs.idAt(ibi); - const auto dCfg = digitizationConfigs.valueAt(ibi); - std::vector boundIndices; - boundIndices.insert(boundIndices.end(), - dCfg.geometricDigiConfig.indices.begin(), - dCfg.geometricDigiConfig.indices.end()); - // we assume nobody will add multiple smearers to a single bound index - for (const auto& c : dCfg.smearingDigiConfig) { - boundIndices.push_back(c.index); - } - bIndexInput.push_back({geoID, boundIndices}); - } - return bIndexInput; -} - -std::vector ActsExamples::GeometricConfig::variances( +std::vector GeometricConfig::variances( const std::array& csizes, const std::array& cmins) const { std::vector rVariances; @@ -80,3 +30,5 @@ std::vector ActsExamples::GeometricConfig::variances( } return rVariances; } + +} // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/src/DigitizationConfigurator.cpp b/Examples/Algorithms/Digitization/src/DigitizationConfigurator.cpp index e7bd2ddfa09..bbf6ec7583b 100644 --- a/Examples/Algorithms/Digitization/src/DigitizationConfigurator.cpp +++ b/Examples/Algorithms/Digitization/src/DigitizationConfigurator.cpp @@ -9,7 +9,6 @@ #include "ActsExamples/Digitization/DigitizationConfigurator.hpp" #include "Acts/Definitions/Algebra.hpp" -#include "Acts/Definitions/TrackParametrization.hpp" #include "Acts/Surfaces/AnnulusBounds.hpp" #include "Acts/Surfaces/DiscTrapezoidBounds.hpp" #include "Acts/Surfaces/RadialBounds.hpp" @@ -25,9 +24,9 @@ #include #include -#include namespace { + /// @note This does not really compare if the configs are equal, therefore /// it is no operator==. The contained std::function types cannot really /// be checked for equality. @@ -47,6 +46,7 @@ bool digiConfigMaybeEqual(ActsExamples::DigiComponentsConfig &a, ag.thickness == bg.thickness && ag.threshold == bg.threshold && ag.digital == bg.digital); } + } // namespace void ActsExamples::DigitizationConfigurator::operator()( diff --git a/Examples/Algorithms/Digitization/src/DigitizationCoordinatesConverter.cpp b/Examples/Algorithms/Digitization/src/DigitizationCoordinatesConverter.cpp index e83e7be995b..b996306fb13 100644 --- a/Examples/Algorithms/Digitization/src/DigitizationCoordinatesConverter.cpp +++ b/Examples/Algorithms/Digitization/src/DigitizationCoordinatesConverter.cpp @@ -10,21 +10,22 @@ #include "Acts/Definitions/Algebra.hpp" #include "Acts/Geometry/GeometryContext.hpp" +#include "ActsExamples/Digitization/DigitizationAlgorithm.hpp" -#include #include #include -ActsExamples::DigitizationCoordinatesConverter:: - DigitizationCoordinatesConverter(DigitizationConfig config) +namespace ActsExamples { + +DigitizationCoordinatesConverter::DigitizationCoordinatesConverter( + DigitizationAlgorithm::Config config) : m_cfg(std::move(config)) { if (m_cfg.surfaceByIdentifier.empty()) { throw std::invalid_argument("Missing Surface-GeometryID association map"); } } -std::tuple -ActsExamples::DigitizationCoordinatesConverter::globalToLocal( +std::tuple DigitizationCoordinatesConverter::globalToLocal( std::uint64_t moduleId, double x, double y, double z) const { const Acts::GeometryIdentifier moduleGeoId = moduleId; auto surfaceItr = m_cfg.surfaceByIdentifier.find(moduleGeoId); @@ -44,8 +45,8 @@ ActsExamples::DigitizationCoordinatesConverter::globalToLocal( } std::tuple -ActsExamples::DigitizationCoordinatesConverter::localToGlobal( - std::uint64_t moduleId, double x, double y) const { +DigitizationCoordinatesConverter::localToGlobal(std::uint64_t moduleId, + double x, double y) const { const Acts::GeometryIdentifier moduleGeoId = moduleId; auto surfaceItr = m_cfg.surfaceByIdentifier.find(moduleGeoId); if (surfaceItr == m_cfg.surfaceByIdentifier.end()) { @@ -61,3 +62,5 @@ ActsExamples::DigitizationCoordinatesConverter::localToGlobal( return {pos2Global.x(), pos2Global.y(), pos2Global.z()}; } + +} // namespace ActsExamples diff --git a/Examples/Algorithms/TrackFinding/src/TrackParamsEstimationAlgorithm.cpp b/Examples/Algorithms/TrackFinding/src/TrackParamsEstimationAlgorithm.cpp index c8a30c7147d..dfb0269a56d 100644 --- a/Examples/Algorithms/TrackFinding/src/TrackParamsEstimationAlgorithm.cpp +++ b/Examples/Algorithms/TrackFinding/src/TrackParamsEstimationAlgorithm.cpp @@ -112,10 +112,16 @@ ProcessCode TrackParamsEstimationAlgorithm::execute( } Acts::Vector3 field = *fieldRes; + if (field.norm() < m_cfg.bFieldMin) { + ACTS_WARNING("Magnetic field at seed " << iseed << " is too small " + << field.norm()); + continue; + } + // Estimate the track parameters from seed auto optParams = Acts::estimateTrackParamsFromSeed( ctx.geoContext, seed.sp().begin(), seed.sp().end(), *surface, field, - m_cfg.bFieldMin, logger()); + logger()); if (!optParams.has_value()) { ACTS_WARNING("Estimation of track parameters for seed " << iseed << " failed."); diff --git a/Examples/Algorithms/TrackFindingExaTrkX/src/PrototracksToParameters.cpp b/Examples/Algorithms/TrackFindingExaTrkX/src/PrototracksToParameters.cpp index c8d34f71bd2..9ffe49ae460 100644 --- a/Examples/Algorithms/TrackFindingExaTrkX/src/PrototracksToParameters.cpp +++ b/Examples/Algorithms/TrackFindingExaTrkX/src/PrototracksToParameters.cpp @@ -154,16 +154,21 @@ ProcessCode PrototracksToParameters::execute( .geometryId(); const auto &surface = *m_cfg.geometry->findSurface(geoId); - auto field = m_cfg.magneticField->getField( + auto fieldRes = m_cfg.magneticField->getField( {bottomSP->x(), bottomSP->y(), bottomSP->z()}, bCache); - if (!field.ok()) { - ACTS_ERROR("Field lookup error: " << field.error()); + if (!fieldRes.ok()) { + ACTS_ERROR("Field lookup error: " << fieldRes.error()); return ProcessCode::ABORT; } + Acts::Vector3 field = *fieldRes; + + if (field.norm() < m_cfg.bFieldMin) { + ACTS_WARNING("Magnetic field at seed is too small " << field.norm()); + continue; + } auto pars = Acts::estimateTrackParamsFromSeed( - ctx.geoContext, seed.sp().begin(), seed.sp().end(), surface, *field, - m_cfg.bFieldMin); + ctx.geoContext, seed.sp().begin(), seed.sp().end(), surface, field); if (not pars) { ACTS_WARNING("Skip track because of bad params"); diff --git a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp index cfc62ab9da9..4c09134ef20 100644 --- a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp +++ b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp @@ -10,21 +10,15 @@ #include "Acts/Definitions/Algebra.hpp" #include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/EventData/ParticleHypothesis.hpp" #include "Acts/Seeding/EstimateTrackParamsFromSeed.hpp" #include "Acts/Surfaces/PerigeeSurface.hpp" #include "Acts/Surfaces/Surface.hpp" -#include "Acts/Utilities/Helpers.hpp" #include "Acts/Utilities/detail/periodic.hpp" #include "ActsExamples/EventData/SimParticle.hpp" #include "ActsExamples/EventData/Track.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" #include "ActsExamples/Framework/RandomNumbers.hpp" -#include "ActsExamples/Utilities/GroupBy.hpp" -#include "ActsExamples/Utilities/Range.hpp" -#include "ActsFatras/EventData/Particle.hpp" -#include #include #include #include diff --git a/Examples/Framework/include/ActsExamples/EventData/Cluster.hpp b/Examples/Framework/include/ActsExamples/EventData/Cluster.hpp index 3eb850b1214..bfd81c9f130 100644 --- a/Examples/Framework/include/ActsExamples/EventData/Cluster.hpp +++ b/Examples/Framework/include/ActsExamples/EventData/Cluster.hpp @@ -8,10 +8,10 @@ #pragma once +#include "Acts/Definitions/Algebra.hpp" #include "ActsFatras/Digitization/Segmentizer.hpp" #include -#include #include namespace ActsExamples { diff --git a/Examples/Framework/include/ActsExamples/Framework/RandomNumbers.hpp b/Examples/Framework/include/ActsExamples/Framework/RandomNumbers.hpp index 6f9f9abbcd6..a94bac778f6 100644 --- a/Examples/Framework/include/ActsExamples/Framework/RandomNumbers.hpp +++ b/Examples/Framework/include/ActsExamples/Framework/RandomNumbers.hpp @@ -6,18 +6,8 @@ // 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/. -// -// RandomNumbers.hpp -// ActsExamples -// -// Created by Andreas Salzburger on 17/05/16. -// -// - #pragma once -#include "ActsExamples/Framework/AlgorithmContext.hpp" - #include #include @@ -27,6 +17,9 @@ struct AlgorithmContext; /// The random number generator used in the framework. using RandomEngine = std::mt19937; ///< Mersenne Twister +/// The seed type used in the framework. +using RandomSeed = std::uint32_t; + /// Provide event and algorithm specific random number generator.s /// /// This provides local random number generators, allowing for @@ -41,7 +34,7 @@ using RandomEngine = std::mt19937; ///< Mersenne Twister class RandomNumbers { public: struct Config { - std::uint64_t seed = 1234567890u; ///< random seed + RandomSeed seed = 1234567890u; ///< random seed }; explicit RandomNumbers(const Config& cfg); @@ -59,7 +52,7 @@ class RandomNumbers { /// /// This should only be used in special cases e.g. where a custom /// random engine is used and `spawnGenerator` can not be used. - std::uint64_t generateSeed(const AlgorithmContext& context) const; + RandomSeed generateSeed(const AlgorithmContext& context) const; private: Config m_cfg; diff --git a/Examples/Framework/src/Framework/RandomNumbers.cpp b/Examples/Framework/src/Framework/RandomNumbers.cpp index 5fd0cdcf7d7..4313a5cce77 100644 --- a/Examples/Framework/src/Framework/RandomNumbers.cpp +++ b/Examples/Framework/src/Framework/RandomNumbers.cpp @@ -6,26 +6,21 @@ // 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/. -// -// RandomNumbers.cpp -// ActsExamples -// -// Created by Andreas Salzburger on 17/05/16. -// -// - #include "ActsExamples/Framework/RandomNumbers.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" -ActsExamples::RandomNumbers::RandomNumbers(const Config& cfg) : m_cfg(cfg) {} +namespace ActsExamples { + +RandomNumbers::RandomNumbers(const Config& cfg) : m_cfg(cfg) {} -ActsExamples::RandomEngine ActsExamples::RandomNumbers::spawnGenerator( +RandomEngine RandomNumbers::spawnGenerator( const AlgorithmContext& context) const { return RandomEngine(generateSeed(context)); } -std::uint64_t ActsExamples::RandomNumbers::generateSeed( - const AlgorithmContext& context) const { +RandomSeed RandomNumbers::generateSeed(const AlgorithmContext& context) const { return m_cfg.seed + context.eventNumber; } + +} // namespace ActsExamples diff --git a/Examples/Io/Json/include/ActsExamples/Io/Json/JsonDigitizationConfig.hpp b/Examples/Io/Json/include/ActsExamples/Io/Json/JsonDigitizationConfig.hpp index 11e063acaa8..a67756b1dbc 100644 --- a/Examples/Io/Json/include/ActsExamples/Io/Json/JsonDigitizationConfig.hpp +++ b/Examples/Io/Json/include/ActsExamples/Io/Json/JsonDigitizationConfig.hpp @@ -9,12 +9,10 @@ #pragma once #include "Acts/Geometry/GeometryHierarchyMap.hpp" -#include "Acts/Plugins/Json/ActsJson.hpp" #include "Acts/Plugins/Json/GeometryHierarchyMapJsonConverter.hpp" #include "ActsExamples/Digitization/DigitizationConfig.hpp" #include "ActsExamples/Digitization/SmearingConfig.hpp" -#include #include #include @@ -44,7 +42,6 @@ void writeDigiConfigToJson( const Acts::GeometryHierarchyMap& cfg, const std::string& path); -using DigiConfigContainer = Acts::GeometryHierarchyMap; using DigiConfigConverter = Acts::GeometryHierarchyMapJsonConverter; diff --git a/Examples/Io/Root/include/ActsExamples/Io/Root/RootMeasurementWriter.hpp b/Examples/Io/Root/include/ActsExamples/Io/Root/RootMeasurementWriter.hpp index 3958e845fb2..a578295e530 100644 --- a/Examples/Io/Root/include/ActsExamples/Io/Root/RootMeasurementWriter.hpp +++ b/Examples/Io/Root/include/ActsExamples/Io/Root/RootMeasurementWriter.hpp @@ -8,9 +8,6 @@ #pragma once -#include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/Geometry/GeometryContext.hpp" -#include "Acts/Geometry/GeometryHierarchyMap.hpp" #include "Acts/Geometry/GeometryIdentifier.hpp" #include "Acts/Utilities/Logger.hpp" #include "ActsExamples/EventData/Cluster.hpp" @@ -24,7 +21,6 @@ #include #include #include -#include class TFile; class TTree; @@ -34,7 +30,6 @@ class TrackingGeometry; } // namespace Acts namespace ActsExamples { -struct AlgorithmContext; /// @class RootMeasurementWriter /// @@ -64,8 +59,6 @@ class RootMeasurementWriter final : public WriterT { /// file access mode std::string fileMode = "RECREATE"; - /// The indices for this digitization configurations - Acts::GeometryHierarchyMap> boundIndices; /// Map of the geometry identifier to the surface std::unordered_map surfaceByIdentifier; diff --git a/Examples/Io/Root/src/RootMaterialTrackReader.cpp b/Examples/Io/Root/src/RootMaterialTrackReader.cpp index 8781b134559..70b2ab8d997 100644 --- a/Examples/Io/Root/src/RootMaterialTrackReader.cpp +++ b/Examples/Io/Root/src/RootMaterialTrackReader.cpp @@ -89,6 +89,10 @@ RootMaterialTrackReader::RootMaterialTrackReader(const Config& config, // Sort the entry numbers of the events { + // necessary to guarantee that m_inputChain->GetV1() is valid for the + // entire range + m_inputChain->SetEstimate(nentries + 1); + m_entryNumbers.resize(nentries); m_inputChain->Draw("event_id", "", "goff"); RootUtility::stableSort(m_inputChain->GetEntries(), m_inputChain->GetV1(), diff --git a/Examples/Io/Root/src/RootMeasurementWriter.cpp b/Examples/Io/Root/src/RootMeasurementWriter.cpp index b7ab332fdea..df095557664 100644 --- a/Examples/Io/Root/src/RootMeasurementWriter.cpp +++ b/Examples/Io/Root/src/RootMeasurementWriter.cpp @@ -9,20 +9,17 @@ #include "ActsExamples/Io/Root/RootMeasurementWriter.hpp" #include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/Utilities/Enumerate.hpp" #include "ActsExamples/EventData/AverageSimHits.hpp" #include "ActsExamples/EventData/Index.hpp" #include "ActsExamples/EventData/Measurement.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" #include "ActsExamples/Utilities/Range.hpp" -#include #include #include #include #include #include -#include #include #include diff --git a/Examples/Io/Root/src/RootParticleReader.cpp b/Examples/Io/Root/src/RootParticleReader.cpp index a76255dbb4a..631fc25ef3e 100644 --- a/Examples/Io/Root/src/RootParticleReader.cpp +++ b/Examples/Io/Root/src/RootParticleReader.cpp @@ -80,6 +80,10 @@ RootParticleReader::RootParticleReader(const RootParticleReader::Config& config, // Sort the entry numbers of the events { + // necessary to guarantee that m_inputChain->GetV1() is valid for the + // entire range + m_inputChain->SetEstimate(m_events + 1); + m_entryNumbers.resize(m_events); m_inputChain->Draw("event_id", "", "goff"); RootUtility::stableSort(m_inputChain->GetEntries(), m_inputChain->GetV1(), diff --git a/Examples/Io/Root/src/RootTrackSummaryReader.cpp b/Examples/Io/Root/src/RootTrackSummaryReader.cpp index 1827c26ad30..9ff3590271a 100644 --- a/Examples/Io/Root/src/RootTrackSummaryReader.cpp +++ b/Examples/Io/Root/src/RootTrackSummaryReader.cpp @@ -99,6 +99,10 @@ RootTrackSummaryReader::RootTrackSummaryReader( // Sort the entry numbers of the events { + // necessary to guarantee that m_inputChain->GetV1() is valid for the + // entire range + m_inputChain->SetEstimate(m_events + 1); + m_entryNumbers.resize(m_events); m_inputChain->Draw("event_nr", "", "goff"); RootUtility::stableSort(m_inputChain->GetEntries(), m_inputChain->GetV1(), diff --git a/Examples/Io/Root/src/RootVertexReader.cpp b/Examples/Io/Root/src/RootVertexReader.cpp index 336e0364f9b..31a8e6d5bec 100644 --- a/Examples/Io/Root/src/RootVertexReader.cpp +++ b/Examples/Io/Root/src/RootVertexReader.cpp @@ -8,13 +8,12 @@ #include "ActsExamples/Io/Root/RootVertexReader.hpp" -#include "Acts/Definitions/PdgParticle.hpp" #include "Acts/Utilities/Logger.hpp" #include "ActsExamples/EventData/SimParticle.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" +#include "ActsExamples/Io/Root/RootUtility.hpp" #include "ActsFatras/EventData/ProcessType.hpp" -#include #include #include #include @@ -64,11 +63,14 @@ RootVertexReader::RootVertexReader(const RootVertexReader::Config& config, // Sort the entry numbers of the events { + // necessary to guarantee that m_inputChain->GetV1() is valid for the + // entire range + m_inputChain->SetEstimate(m_events + 1); + m_entryNumbers.resize(m_events); m_inputChain->Draw("event_id", "", "goff"); - // Sort to get the entry numbers of the ordered events - TMath::Sort(m_inputChain->GetEntries(), m_inputChain->GetV1(), - m_entryNumbers.data(), false); + RootUtility::stableSort(m_inputChain->GetEntries(), m_inputChain->GetV1(), + m_entryNumbers.data(), false); } } diff --git a/Examples/Python/python/acts/examples/simulation.py b/Examples/Python/python/acts/examples/simulation.py index 21c4149661f..65b6820d8b8 100644 --- a/Examples/Python/python/acts/examples/simulation.py +++ b/Examples/Python/python/acts/examples/simulation.py @@ -778,8 +778,8 @@ def addDigitization( rnd = rnd or acts.examples.RandomNumbers() # Digitization - digiCfg = acts.examples.DigitizationConfig( - acts.examples.readDigiConfigFromJson( + digiCfg = acts.examples.DigitizationAlgorithm.Config( + digitizationConfigs=acts.examples.readDigiConfigFromJson( str(digiConfigFile), ), surfaceByIdentifier=trackingGeometry.geoIdSurfaceMap(), @@ -788,7 +788,9 @@ def addDigitization( outputMeasurements="measurements", outputMeasurementParticlesMap="measurement_particles_map", outputMeasurementSimHitsMap="measurement_simhits_map", - doMerge=doMerge, + **acts.examples.defaultKWArgs( + doMerge=doMerge, + ), ) # Not sure how to do this in our style @@ -811,7 +813,6 @@ def addDigitization( filePath=str(outputDirRoot / f"{digiAlg.config.outputMeasurements}.root"), surfaceByIdentifier=trackingGeometry.geoIdSurfaceMap(), ) - rmwConfig.addBoundIndicesFromDigiConfig(digiAlg.config) s.addWriter(acts.examples.RootMeasurementWriter(rmwConfig, customLogLevel())) if outputDirCsv is not None: diff --git a/Examples/Python/src/Digitization.cpp b/Examples/Python/src/Digitization.cpp index 948bcc9593b..5bcce4b74ca 100644 --- a/Examples/Python/src/Digitization.cpp +++ b/Examples/Python/src/Digitization.cpp @@ -6,33 +6,22 @@ // 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 "Acts/Definitions/Algebra.hpp" -#include "Acts/Geometry/GeometryHierarchyMap.hpp" #include "Acts/Plugins/Python/Utilities.hpp" #include "Acts/Utilities/Logger.hpp" #include "ActsExamples/Digitization/DigitizationAlgorithm.hpp" #include "ActsExamples/Digitization/DigitizationConfig.hpp" #include "ActsExamples/Digitization/DigitizationConfigurator.hpp" #include "ActsExamples/Digitization/DigitizationCoordinatesConverter.hpp" -#include "ActsExamples/Framework/AlgorithmContext.hpp" #include "ActsExamples/Io/Json/JsonDigitizationConfig.hpp" #include #include #include #include -#include #include #include -namespace Acts { -class GeometryIdentifier; -} // namespace Acts -namespace ActsExamples { -class IAlgorithm; -} // namespace ActsExamples - namespace py = pybind11; using namespace ActsExamples; @@ -47,19 +36,18 @@ void addDigitization(Context& ctx) { mex.def("writeDigiConfigToJson", ActsExamples::writeDigiConfigToJson); { - using Config = ActsExamples::DigitizationConfig; + using Config = ActsExamples::DigitizationAlgorithm::Config; - py::class_>( - mex, "DigitizationAlgorithm") - .def(py::init(), py::arg("config"), - py::arg("level")) - .def_property_readonly("config", - &ActsExamples::DigitizationAlgorithm::config); + auto a = py::class_>( + mex, "DigitizationAlgorithm") + .def(py::init(), + py::arg("config"), py::arg("level")) + .def_property_readonly( + "config", &ActsExamples::DigitizationAlgorithm::config); - auto c = py::class_(mex, "DigitizationConfig") - .def(py::init>()); + auto c = py::class_(a, "Config").def(py::init<>()); ACTS_PYTHON_STRUCT_BEGIN(c, Config); ACTS_PYTHON_MEMBER(inputSimHits); @@ -81,10 +69,15 @@ void addDigitization(Context& ctx) { patchKwargsConstructor(c); - py::class_(mex, "DigiComponentsConfig"); + auto cc = py::class_(mex, "DigiComponentsConfig") + .def(py::init<>()); + + ACTS_PYTHON_STRUCT_BEGIN(cc, DigiComponentsConfig); + ACTS_PYTHON_MEMBER(geometricDigiConfig); + ACTS_PYTHON_MEMBER(smearingDigiConfig); + ACTS_PYTHON_STRUCT_END(); - py::class_>( - mex, "GeometryHierarchyMap_DigiComponentsConfig") + py::class_(mex, "DigiConfigContainer") .def(py::init>>()); } @@ -107,7 +100,8 @@ void addDigitization(Context& ctx) { py::class_>( mex, "DigitizationCoordinatesConverter") - .def(py::init(), py::arg("config")) + .def(py::init(), + py::arg("config")) .def_property_readonly( "config", &ActsExamples::DigitizationCoordinatesConverter::config) .def("globalToLocal", diff --git a/Examples/Python/src/Navigation.cpp b/Examples/Python/src/Navigation.cpp index 733bbe1a151..a4f55a532ac 100644 --- a/Examples/Python/src/Navigation.cpp +++ b/Examples/Python/src/Navigation.cpp @@ -37,6 +37,10 @@ struct AnyNavigationPolicyFactory : public Acts::NavigationPolicyFactory { virtual std::unique_ptr add( TypeTag /*type*/, SurfaceArrayNavigationPolicy::Config config) = 0; + + virtual std::unique_ptr add( + TypeTag /*type*/, + TryAllNavigationPolicy::Config config) = 0; }; template , @@ -61,6 +65,12 @@ struct NavigationPolicyFactoryT : public AnyNavigationPolicyFactory { return add(std::move(config)); } + std::unique_ptr add( + TypeTag /*type*/, + TryAllNavigationPolicy::Config config) override { + return add(config); + } + std::unique_ptr build( const GeometryContext& gctx, const TrackingVolume& volume, const Logger& logger) const override { @@ -108,6 +118,12 @@ class NavigationPolicyFactory : public Acts::NavigationPolicyFactory { return *this; } + NavigationPolicyFactory& addTryAll( + const py::object& /*cls*/, const TryAllNavigationPolicy::Config& config) { + m_impl = m_impl->add(Type, config); + return *this; + } + std::unique_ptr build( const GeometryContext& gctx, const TrackingVolume& volume, const Logger& logger) const override { @@ -153,7 +169,16 @@ void addNavigation(Context& ctx) { std::shared_ptr>( m, "_NavigationPolicyFactory"); - py::class_(m, "TryAllNavigationPolicy"); + { + auto tryAll = + py::class_(m, "TryAllNavigationPolicy"); + using Config = TryAllNavigationPolicy::Config; + auto c = py::class_(tryAll, "Config").def(py::init<>()); + ACTS_PYTHON_STRUCT_BEGIN(c, Config); + ACTS_PYTHON_MEMBER(portals); + ACTS_PYTHON_MEMBER(sensitives); + ACTS_PYTHON_STRUCT_END(); + } py::class_>( @@ -162,6 +187,7 @@ void addNavigation(Context& ctx) { .def_static("make", []() { return NavigationPolicyFactory{}; }) .def("add", &NavigationPolicyFactory::addNoArguments) .def("add", &NavigationPolicyFactory::addSurfaceArray) + .def("add", &NavigationPolicyFactory::addTryAll) .def("_buildTest", [](NavigationPolicyFactory& self) { auto vol1 = std::make_shared( Transform3::Identity(), diff --git a/Examples/Python/src/Output.cpp b/Examples/Python/src/Output.cpp index 5adead2a9b4..5f174777429 100644 --- a/Examples/Python/src/Output.cpp +++ b/Examples/Python/src/Output.cpp @@ -12,8 +12,7 @@ #include "Acts/Utilities/Logger.hpp" #include "Acts/Visualization/IVisualization3D.hpp" #include "Acts/Visualization/ViewConfig.hpp" -#include "ActsExamples/Digitization/DigitizationConfig.hpp" -#include "ActsExamples/Framework/ProcessCode.hpp" +#include "ActsExamples/Digitization/DigitizationAlgorithm.hpp" #include "ActsExamples/Io/Csv/CsvBFieldWriter.hpp" #include "ActsExamples/Io/Csv/CsvExaTrkXGraphWriter.hpp" #include "ActsExamples/Io/Csv/CsvMeasurementWriter.hpp" @@ -50,10 +49,8 @@ #include "ActsExamples/Plugins/Obj/ObjPropagationStepsWriter.hpp" #include "ActsExamples/Plugins/Obj/ObjTrackingGeometryWriter.hpp" -#include #include #include -#include #include #include @@ -268,13 +265,6 @@ void addOutput(Context& ctx) { auto c = py::class_(w, "Config").def(py::init<>()); - c.def("addBoundIndicesFromDigiConfig", - [](Writer::Config& self, const DigitizationConfig& digiCfg) { - self.boundIndices = - Acts::GeometryHierarchyMap>( - digiCfg.getBoundIndices()); - }); - ACTS_PYTHON_STRUCT_BEGIN(c, Writer::Config); ACTS_PYTHON_MEMBER(inputMeasurements); ACTS_PYTHON_MEMBER(inputClusters); @@ -282,7 +272,6 @@ void addOutput(Context& ctx) { ACTS_PYTHON_MEMBER(inputMeasurementSimHitsMap); ACTS_PYTHON_MEMBER(filePath); ACTS_PYTHON_MEMBER(fileMode); - ACTS_PYTHON_MEMBER(boundIndices); ACTS_PYTHON_MEMBER(surfaceByIdentifier); ACTS_PYTHON_STRUCT_END(); } diff --git a/Examples/Python/tests/conftest.py b/Examples/Python/tests/conftest.py index b2015c3f6a0..71c0899fe3f 100644 --- a/Examples/Python/tests/conftest.py +++ b/Examples/Python/tests/conftest.py @@ -357,8 +357,8 @@ def _factory(s): s.addAlgorithm(simAlg) # Digitization - digiCfg = acts.examples.DigitizationConfig( - acts.examples.readDigiConfigFromJson( + digiCfg = acts.examples.DigitizationAlgorithm.Config( + digitizationConfigs=acts.examples.readDigiConfigFromJson( str( Path(__file__).parent.parent.parent.parent / "Examples/Algorithms/Digitization/share/default-smearing-config-generic.json" diff --git a/Examples/Python/tests/root_file_hashes.txt b/Examples/Python/tests/root_file_hashes.txt index c6ed65f4564..45337b2f762 100644 --- a/Examples/Python/tests/root_file_hashes.txt +++ b/Examples/Python/tests/root_file_hashes.txt @@ -3,16 +3,16 @@ test_fatras__particles_simulation.root: bc970873fef0c2efd86ed5413623802353d2cd04 test_fatras__hits.root: 6e4beb045fa1712c4d14c280ba33c3fa13e4aff9de88d55c3e32f62ad226f724 test_geant4__particles_simulation.root: 49926c71a9b54e13aa1cc7596d3302baf3c87d8e2c1d0267cb4523f6abdc0ac2 test_geant4__hits.root: 4c9e704a75f47ed2e61652679a1d6f18fa4d9cf53faa8f8f5bbf7995634207aa -test_seeding__estimatedparams.root: 69c0e268f9025a0991a212ea2a7f26f53112fecf614b475605bd1cb08415ba56 +test_seeding__estimatedparams.root: 6759004f945cabe03098c94b3eea7e3323acd9f37edfa71641797007336643c8 test_seeding__performance_seeding.root: 992f9c611d30dde0d3f3ab676bab19ada61ab6a4442828e27b65ec5e5b7a2880 test_seeding__particles.root: c423bc666df3674f1a1140dec68ea13f44173232b8057e8a02572aee4f3e7d5b test_seeding__particles_simulation.root: f937a4cc474e80cfbb6eac4384e42e9c5c7ac981fcd6870d624cc898d1a0c006 -test_hashing_seeding__estimatedparams.root: 8daa3f04342c265f32f1608ccc921ab0041686a6280b956f811638ad4328330e -test_seeding_orthogonal__estimatedparams.root: ca5896ec325daf5c8012291bc454269c61c32fe3d7e33bd1fa3b812826930299 +test_hashing_seeding__estimatedparams.root: 6b52f27b2feac2fa46a8ed52abacfe6dc8e6319f86e031cdc2f9ba28a0393cb2 +test_seeding_orthogonal__estimatedparams.root: 6cb69ee239e11ff112dd50c2bcfe945a6f7b00e43e13b2cba4e08f1bfcf6a583 test_seeding_orthogonal__performance_seeding.root: 60fbedcf5cb2b37cd8e526251940564432890d3a159d231ed819e915a904682c test_seeding_orthogonal__particles.root: c423bc666df3674f1a1140dec68ea13f44173232b8057e8a02572aee4f3e7d5b test_seeding_orthogonal__particles_simulation.root: f937a4cc474e80cfbb6eac4384e42e9c5c7ac981fcd6870d624cc898d1a0c006 -test_itk_seeding__estimatedparams.root: 1cc05f9f2aefb5f71a85b31e97bc4e5845fedfcef6c53199495a6340c6b6210b +test_itk_seeding__estimatedparams.root: fc042037f12a434f2236df7d225b8ca24209b6910f04a4496ae3a06516a6ff8c test_itk_seeding__performance_seeding.root: 78ebda54cd0f026ba4b7f316724ffd946de56a932735914baf1b7bba9505c29d test_itk_seeding__particles.root: 907ff693262c0db14b12c74b16586cb20d79caf5f03f93b178943e41ed35a1b6 test_itk_seeding__particles_simulation.root: ef0246069aa697019f28a8b270a68de95312cae5f2f2c74848566c3ce4f70363 @@ -33,19 +33,19 @@ test_digitization_example_input[smeared]__particles.root: 669d0304eb8bcf244aa627 test_digitization_example_input[smeared]__measurements.root: 243c2f69b7b0db9dbeaa7494d4ea0f3dd1691dc90f16e10df6c0491ff4dc7d62 test_digitization_example_input[geometric]__particles.root: 669d0304eb8bcf244aa627809a117944e5e3b994fdfcfb8710f2b9a8f9a62d3b test_digitization_example_input[geometric]__measurements.root: 63ec81635979058fb8976f94455bf490cf92b7b142c4a05cc39de6225f5de2fb -test_ckf_tracks_example[generic-full_seeding]__trackstates_ckf.root: 7c48ec32a2cb1723416a9791a8067ef09825fcf71a6cf561c1f6d2ab9dc1c1ad -test_ckf_tracks_example[generic-full_seeding]__tracksummary_ckf.root: e6b9e539998ba007e9b7d2c8d9d022c47726a39e8ab9b1724c52b1d78234be03 +test_ckf_tracks_example[generic-full_seeding]__trackstates_ckf.root: ec6487dfca5f944cfacfef903eb4b9a97f8f6a668d07f77d0c3ec45c68054824 +test_ckf_tracks_example[generic-full_seeding]__tracksummary_ckf.root: 84085bcc63562cfb1b4c70d2665bf06938ac559bb40c2b01c076e1d8b5c7b43b test_ckf_tracks_example[generic-full_seeding]__performance_seeding_trees.root: 0e0676ffafdb27112fbda50d1cf627859fa745760f98073261dcf6db3f2f991e -test_ckf_tracks_example[generic-truth_estimated]__trackstates_ckf.root: df730fd00a7e6a0941f5f94c07ea9cffdb763853272d284d25bec0eb2072bb2e -test_ckf_tracks_example[generic-truth_estimated]__tracksummary_ckf.root: 417f7326e1e1bb4519f1378145ac733bdda6653eb9871fd69e455e0269d996a6 +test_ckf_tracks_example[generic-truth_estimated]__trackstates_ckf.root: 8e15cceeef4b115708596702988925b7506d39e0531dc5534636ec411a9b4ca2 +test_ckf_tracks_example[generic-truth_estimated]__tracksummary_ckf.root: 8e0116c656e1cc67446d54a5205c4a3e2f4c1fc90fa551bb608c881877dfa0ab test_ckf_tracks_example[generic-truth_estimated]__performance_seeding.root: 1facb05c066221f6361b61f015cdf0918e94d9f3fce2269ec7b6a4dffeb2bc7e test_ckf_tracks_example[generic-truth_smeared]__trackstates_ckf.root: 82a6744980553e6274df78eea15f0dec22676b1c04e14afc3828bff9bbf5e1b1 test_ckf_tracks_example[generic-truth_smeared]__tracksummary_ckf.root: 06d6ae1d05cb611b19df3c59531997c9b0108f5ef6027d76c4827bd2d9edb921 -test_ckf_tracks_example[odd-full_seeding]__trackstates_ckf.root: 0fb43661cc3a7973c28940a283dc168ceb13bc60badf1f520096edaa5982a039 -test_ckf_tracks_example[odd-full_seeding]__tracksummary_ckf.root: c2e029e462d4ca77df2c7f8963093da43be66c8279ca2cc9aee8c0bc35259eec +test_ckf_tracks_example[odd-full_seeding]__trackstates_ckf.root: 17c48c5a61b1a5495d91336cdf06f9c24e50d81349c1f31d7c70ffff5810a376 +test_ckf_tracks_example[odd-full_seeding]__tracksummary_ckf.root: b5805e54030ab8ac80a8c0a764700c65433dc659783fc8ff3b2c96e512a1d045 test_ckf_tracks_example[odd-full_seeding]__performance_seeding_trees.root: 43c58577aafe07645e5660c4f43904efadf91d8cda45c5c04c248bbe0f59814f -test_ckf_tracks_example[odd-truth_estimated]__trackstates_ckf.root: 39ac67c47f371c576d7094bca987a04e0315bd286dc79503a63a5f568b58ac97 -test_ckf_tracks_example[odd-truth_estimated]__tracksummary_ckf.root: 59e2c75e9524653a80a9fd62fe99e958f73f80aa09240dcbb4ea469372e4811d +test_ckf_tracks_example[odd-truth_estimated]__trackstates_ckf.root: 86be5a086d2a87dfde9320bb880bd0788d733ea9727cb5ee6dc0282ec4be39f4 +test_ckf_tracks_example[odd-truth_estimated]__tracksummary_ckf.root: ffce6a73f16986cb3f0386d4a8c1e0ff6f0b4130b9bb12d1af0eb905d000e3e9 test_ckf_tracks_example[odd-truth_estimated]__performance_seeding.root: 1a36b7017e59f1c08602ef3c2cb0483c51df248f112e3780c66594110719c575 test_ckf_tracks_example[odd-truth_smeared]__trackstates_ckf.root: 35a65e15a6f479f628a96f56ee78e1ac371d71a686ee0c974944d681499fe6bd test_ckf_tracks_example[odd-truth_smeared]__tracksummary_ckf.root: 3e257de624674fa9a19dcc72598c78c29a52633821acaa56dc2aa39a1395f1b5 diff --git a/Examples/Python/tests/test_detectors.py b/Examples/Python/tests/test_detectors.py index c4d2c6ea9ed..3de27524db9 100644 --- a/Examples/Python/tests/test_detectors.py +++ b/Examples/Python/tests/test_detectors.py @@ -161,8 +161,8 @@ def eq(self, other): def test_coordinate_converter(trk_geo): - digiCfg = acts.examples.DigitizationConfig( - acts.examples.readDigiConfigFromJson( + digiCfg = acts.examples.DigitizationAlgorithm.Config( + digitizationConfigs=acts.examples.readDigiConfigFromJson( str( Path(__file__).parent.parent.parent.parent / "Examples/Algorithms/Digitization/share/default-smearing-config-generic.json" diff --git a/Examples/Python/tests/test_navigation.py b/Examples/Python/tests/test_navigation.py index 55ec8ac9540..56c908f7911 100644 --- a/Examples/Python/tests/test_navigation.py +++ b/Examples/Python/tests/test_navigation.py @@ -40,3 +40,9 @@ def test_navigation_policy_factory_add_multiple(): .add(acts.TryAllNavigationPolicy) .add(acts.TryAllNavigationPolicy) ) + + +def test_try_all_arguments(): + acts.NavigationPolicyFactory.make().add( + acts.TryAllNavigationPolicy, acts.TryAllNavigationPolicy.Config(sensitives=True) + ) diff --git a/Examples/Python/tests/test_writer.py b/Examples/Python/tests/test_writer.py index 95cd67decd1..4c9e220f899 100644 --- a/Examples/Python/tests/test_writer.py +++ b/Examples/Python/tests/test_writer.py @@ -165,7 +165,6 @@ def test_root_meas_writer(tmp_path, fatras, trk_geo, assert_root_hash): filePath=str(out), surfaceByIdentifier=trk_geo.geoIdSurfaceMap(), ) - config.addBoundIndicesFromDigiConfig(digiAlg.config) s.addWriter(RootMeasurementWriter(level=acts.logging.INFO, config=config)) s.run() diff --git a/Examples/Scripts/Python/digitization_config.py b/Examples/Scripts/Python/digitization_config.py index dfad1913fd6..1b6de07f477 100755 --- a/Examples/Scripts/Python/digitization_config.py +++ b/Examples/Scripts/Python/digitization_config.py @@ -7,7 +7,7 @@ DigitizationConfigurator, writeDigiConfigToJson, GenericDetector, - GeometryHierarchyMap_DigiComponentsConfig, + DigiConfigContainer, ) @@ -27,9 +27,7 @@ def runDigitizationConfig( trackingGeometry.visitSurfaces(digiConfigurator) - outputConfig = GeometryHierarchyMap_DigiComponentsConfig( - digiConfigurator.outputDigiComponents - ) + outputConfig = DigiConfigContainer(digiConfigurator.outputDigiComponents) writeDigiConfigToJson(outputConfig, str(output)) diff --git a/Examples/Scripts/TrackingPerformance/TreeReader.h b/Examples/Scripts/TrackingPerformance/TreeReader.h index 4ab47746dc0..b12ce19d373 100644 --- a/Examples/Scripts/TrackingPerformance/TreeReader.h +++ b/Examples/Scripts/TrackingPerformance/TreeReader.h @@ -145,6 +145,7 @@ struct TrackStatesReader : public TreeReader { // It's not necessary if you just need to read one file, but please do it to // synchronize events if multiple root files are read if (sortEvents) { + tree->SetEstimate(tree->GetEntries() + 1); entryNumbers.resize(tree->GetEntries()); tree->Draw("event_nr", "", "goff"); // Sort to get the entry numbers of the ordered events @@ -338,6 +339,7 @@ struct TrackSummaryReader : public TreeReader { // It's not necessary if you just need to read one file, but please do it to // synchronize events if multiple root files are read if (sortEvents) { + tree->SetEstimate(tree->GetEntries() + 1); entryNumbers.resize(tree->GetEntries()); tree->Draw("event_nr", "", "goff"); // Sort to get the entry numbers of the ordered events @@ -368,7 +370,8 @@ struct TrackSummaryReader : public TreeReader { std::vector>* outlierLayer = new std::vector>; std::vector* nMajorityHits = new std::vector; - std::vector* majorityParticleId = new std::vector; + std::vector* majorityParticleId = + new std::vector; std::vector* hasFittedParams = new std::vector; @@ -427,6 +430,7 @@ struct ParticleReader : public TreeReader { // It's not necessary if you just need to read one file, but please do it to // synchronize events if multiple root files are read if (sortEvents) { + tree->SetEstimate(tree->GetEntries() + 1); entryNumbers.resize(tree->GetEntries()); tree->Draw("event_id", "", "goff"); // Sort to get the entry numbers of the ordered events @@ -436,7 +440,8 @@ struct ParticleReader : public TreeReader { } // Get all the particles with requested event id - std::vector getParticles(const std::uint32_t& eventNumber) const { + std::vector getParticles( + const std::uint32_t& eventNumber) const { // Find the start entry and the batch size for this event std::string eventNumberStr = std::to_string(eventNumber); std::string findStartEntry = "event_id<" + eventNumberStr; diff --git a/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackContainer.hpp b/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackContainer.hpp index b6cba524a8e..79ccf2249a1 100644 --- a/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackContainer.hpp +++ b/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackContainer.hpp @@ -238,7 +238,7 @@ class MutablePodioTrackContainer : public PodioTrackContainerBase { template constexpr void addColumn_impl(std::string_view key) { - Acts::HashedString hashedKey = hashString(key); + Acts::HashedString hashedKey = hashStringDynamic(key); m_dynamic.insert( {hashedKey, std::make_unique>(key)}); } diff --git a/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackStateContainer.hpp b/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackStateContainer.hpp index 8322249a654..e503f3ca2f3 100644 --- a/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackStateContainer.hpp +++ b/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackStateContainer.hpp @@ -610,7 +610,7 @@ class MutablePodioTrackStateContainer final template constexpr void addColumn_impl(std::string_view key) { - HashedString hashedKey = hashString(key); + HashedString hashedKey = hashStringDynamic(key); m_dynamic.insert( {hashedKey, std::make_unique>(key)}); } diff --git a/Plugins/Podio/src/PodioUtil.cpp b/Plugins/Podio/src/PodioUtil.cpp index 6518fcdff07..7b2fc0668a3 100644 --- a/Plugins/Podio/src/PodioUtil.cpp +++ b/Plugins/Podio/src/PodioUtil.cpp @@ -261,7 +261,7 @@ void recoverDynamicColumns( "' is not of allowed type"}; } - HashedString hashedKey = hashString(dynName); + HashedString hashedKey = hashStringDynamic(dynName); dynamic.insert({hashedKey, std::move(up)}); } } diff --git a/Tests/UnitTests/Core/AmbiguityResolution/ScoreBasedAmbiguityResolutionTest.cpp b/Tests/UnitTests/Core/AmbiguityResolution/ScoreBasedAmbiguityResolutionTest.cpp index 568e817031a..55beab4ca2f 100644 --- a/Tests/UnitTests/Core/AmbiguityResolution/ScoreBasedAmbiguityResolutionTest.cpp +++ b/Tests/UnitTests/Core/AmbiguityResolution/ScoreBasedAmbiguityResolutionTest.cpp @@ -18,10 +18,7 @@ #include "Acts/EventData/VectorTrackContainer.hpp" #include "Acts/EventData/detail/TestSourceLink.hpp" #include "Acts/EventData/detail/TestTrackState.hpp" -#include "Acts/Geometry/GeometryContext.hpp" -#include "Acts/Surfaces/PerigeeSurface.hpp" -#include "Acts/TrackFinding/TrackSelector.hpp" -#include "Acts/Utilities/CalibrationContext.hpp" +#include "Acts/Utilities/TrackHelpers.hpp" #include @@ -30,7 +27,6 @@ using Acts::MultiTrajectoryTraits::IndexType; namespace Acts::Test { BOOST_AUTO_TEST_SUITE(ScoreBasedAmbiguityResolutionTest) -using MeasurementInfo = ScoreBasedAmbiguityResolution::MeasurementInfo; // Test fixture for ScoreBasedAmbiguityResolution struct Fixture { @@ -65,64 +61,137 @@ struct Fixture { ~Fixture() = default; }; -// Helper function to create a sample input for getCleanedOutTracks -std::vector> createSampleInput() { - Fixture fixture; - std::vector>> trackVolumes = { - {0, {19, 18, 18, 18, 10, 10, 10, 10, 10, 10, 10, 10, 10}}, - {1, {19, 18, 18, 18, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}}, - {2, {13, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}}, - {3, {13, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}}, - {4, {19, 18, 18, 18, 10, 10, 10, 10, 10, 10, 10, 10, 10}}}; - - std::vector> measurementsPerTrack; - // Add sample measurements for each track - - for (const auto& trackVolume : trackVolumes) { - std::vector measurements; - for (std::size_t i = 0; i < trackVolume.second.size(); ++i) { - std::size_t detectorID = fixture.config.volumeMap[trackVolume.second[i]]; - measurements.push_back({i + 2, detectorID, false}); +template +auto createTestTrack(TrackContainer& tc, const FlagsPerState& flagsPerState) { + auto t = tc.makeTrack(); + for (const auto& flags : flagsPerState) { + auto ts = t.appendTrackState(); + for (auto f : flags) { + ts.typeFlags().set(f); } - measurementsPerTrack.push_back(measurements); } - return measurementsPerTrack; + calculateTrackQuantities(t); + + return t; } -BOOST_FIXTURE_TEST_CASE(GetCleanedOutTracksTest, Fixture) { +BOOST_FIXTURE_TEST_CASE(ComputeInitialStateTest, Fixture) { Fixture fixture; // Create an instance of ScoreBasedAmbiguityResolution ScoreBasedAmbiguityResolution tester(fixture.config); - // Create sample input - std::vector> measurementsPerTrack = - createSampleInput(); + VectorTrackContainer mutVtc; + VectorMultiTrajectory mutMtj; - std::vector TrackSore; - for (std::size_t i = 0; i < measurementsPerTrack.size(); i++) { - TrackSore.push_back(60 + 40 * i); - } - std::vector> trackFeaturesVectors = { - {{0, 14, 0, 0}, {0, 2, 0, 0}}, - {{0, 15, 0, 0}, {0, 2, 0, 0}}, - {{0, 17, 0, 0}, {0, 2, 0, 0}}, - {{0, 18, 0, 0}, {0, 2, 0, 0}}, - {{0, 14, 0, 0}, {0, 3, 0, 0}}}; + TrackContainer mutTc{mutVtc, mutMtj}; + static_assert(!mutTc.ReadOnly, "Unexpectedly read only"); + + auto t = createTestTrack(mutTc, std::vector>{ + {MeasurementFlag}, + {OutlierFlag}, + {MeasurementFlag, SharedHitFlag}, + {HoleFlag}, + {OutlierFlag}, + {HoleFlag}, + {MeasurementFlag, SharedHitFlag}, + {OutlierFlag}, + }); + + BOOST_CHECK_EQUAL(t.nHoles(), 2); + BOOST_CHECK_EQUAL(t.nMeasurements(), 3); + BOOST_CHECK_EQUAL(t.nOutliers(), 3); + BOOST_CHECK_EQUAL(t.nSharedHits(), 2); + + ConstVectorTrackContainer vtc{std::move(mutVtc)}; + ConstVectorMultiTrajectory mtj{std::move(mutMtj)}; + + TrackContainer ctc{vtc, mtj}; + + std::vector> trackFeaturesVectors; + trackFeaturesVectors = tester.computeInitialState(ctc); + + BOOST_CHECK_EQUAL(trackFeaturesVectors.size(), ctc.size()); + + std::vector trackScores; + trackScores = tester.simpleScore(ctc, trackFeaturesVectors); - // Call the function under testBOOST_FIXTURE_TEST_CASE - std::vector cleanTracks = tester.getCleanedOutTracks( - TrackSore, trackFeaturesVectors, measurementsPerTrack); + BOOST_CHECK_EQUAL(trackScores.size(), ctc.size()); + + trackScores = tester.ambiguityScore(ctc, trackFeaturesVectors); + + BOOST_CHECK_EQUAL(trackScores.size(), ctc.size()); // Assert the expected results - BOOST_CHECK_EQUAL(measurementsPerTrack.size(), 5); +} - for (std::size_t i = 0; i < cleanTracks.size(); i++) { - auto score = TrackSore[i]; - if (cleanTracks[i]) { - BOOST_CHECK_GT(score, fixture.config.minScoreSharedTracks); +BOOST_FIXTURE_TEST_CASE(GetCleanedOutTracksTest, Fixture) { + Fixture fixture; + // Create an instance of ScoreBasedAmbiguityResolution + ScoreBasedAmbiguityResolution tester(fixture.config); + + VectorTrackContainer mutVtc; + VectorMultiTrajectory mutMtj; + + TrackContainer mutTc{mutVtc, mutMtj}; + static_assert(!mutTc.ReadOnly, "Unexpectedly read only"); + + auto t = createTestTrack(mutTc, std::vector>{ + {MeasurementFlag}, + {OutlierFlag}, + {MeasurementFlag, SharedHitFlag}, + {HoleFlag}, + {OutlierFlag}, + {HoleFlag}, + {MeasurementFlag, SharedHitFlag}, + {OutlierFlag}, + }); + + BOOST_CHECK_EQUAL(t.nHoles(), 2); + BOOST_CHECK_EQUAL(t.nMeasurements(), 3); + BOOST_CHECK_EQUAL(t.nOutliers(), 3); + BOOST_CHECK_EQUAL(t.nSharedHits(), 2); + + ConstVectorTrackContainer vtc{std::move(mutVtc)}; + ConstVectorMultiTrajectory mtj{std::move(mutMtj)}; + + TrackContainer ctc{vtc, mtj}; + + std::vector> trackFeaturesVectors; + std::vector> measurementsPerTrackVector; + std::map nTracksPerMeasurement; + + trackFeaturesVectors = tester.computeInitialState(ctc); + + BOOST_CHECK_EQUAL(trackFeaturesVectors.size(), ctc.size()); + + for (std::size_t iMeasurement = 1; const auto& track : ctc) { + std::vector measurementsPerTrack; + for (auto ts : track.trackStatesReversed()) { + if (ts.typeFlags().test(Acts::TrackStateFlag::OutlierFlag) || + ts.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) { + measurementsPerTrack.push_back(iMeasurement); + if (nTracksPerMeasurement.find(iMeasurement) == + nTracksPerMeasurement.end()) { + nTracksPerMeasurement[iMeasurement] = 0; + } + nTracksPerMeasurement[iMeasurement]++; + } + + iMeasurement++; } + measurementsPerTrackVector.push_back(std::move(measurementsPerTrack)); } + + auto trackScore = tester.ambiguityScore(ctc, trackFeaturesVectors); + + const auto& track = ctc.getTrack(0); + std::size_t iTrack = track.index(); + bool accepted = tester.getCleanedOutTracks(track, trackScore[iTrack], + measurementsPerTrackVector[iTrack], + nTracksPerMeasurement); + + BOOST_CHECK_EQUAL(accepted, false); } BOOST_AUTO_TEST_SUITE_END() diff --git a/Tests/UnitTests/Core/Seeding/EstimateTrackParamsFromSeedTest.cpp b/Tests/UnitTests/Core/Seeding/EstimateTrackParamsFromSeedTest.cpp index 6161a8bdd33..9aab6c1c70b 100644 --- a/Tests/UnitTests/Core/Seeding/EstimateTrackParamsFromSeedTest.cpp +++ b/Tests/UnitTests/Core/Seeding/EstimateTrackParamsFromSeedTest.cpp @@ -9,10 +9,8 @@ #include #include "Acts/Definitions/Algebra.hpp" -#include "Acts/Definitions/Direction.hpp" #include "Acts/Definitions/TrackParametrization.hpp" #include "Acts/Definitions/Units.hpp" -#include "Acts/EventData/GenericCurvilinearTrackParameters.hpp" #include "Acts/EventData/TrackParameters.hpp" #include "Acts/EventData/detail/TestSourceLink.hpp" #include "Acts/Geometry/GeometryContext.hpp" @@ -29,7 +27,6 @@ #include "Acts/Tests/CommonHelpers/CylindricalTrackingGeometry.hpp" #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp" #include "Acts/Tests/CommonHelpers/MeasurementsCreator.hpp" -#include "Acts/Utilities/CalibrationContext.hpp" #include "Acts/Utilities/Logger.hpp" #include @@ -39,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -99,8 +95,8 @@ BOOST_AUTO_TEST_CASE(trackparameters_estimation_test) { true, // material false // passive }); - auto field = - std::make_shared(Acts::Vector3(0.0, 0.0, 2._T)); + const Vector3 bField(0, 0, 2._T); + auto field = std::make_shared(bField); ConstantFieldStepper stepper(std::move(field)); ConstantFieldPropagator propagator(std::move(stepper), std::move(navigator)); @@ -172,10 +168,15 @@ BOOST_AUTO_TEST_CASE(trackparameters_estimation_test) { spacePointPtrs.begin(), [](const auto& sp) { return &sp.second; }); - // Test the full track parameters estimator + // Test the free track parameters estimator + FreeVector estFreeParams = + estimateTrackParamsFromSeed(spacePointPtrs, bField); + BOOST_CHECK(!estFreeParams.hasNaN()); + + // Test the bound track parameters estimator auto fullParamsOpt = estimateTrackParamsFromSeed( geoCtx, spacePointPtrs.begin(), spacePointPtrs.end(), - *bottomSurface, Vector3(0, 0, 2._T), 0.1_T, *logger); + *bottomSurface, bField, *logger); BOOST_REQUIRE(fullParamsOpt.has_value()); const auto& estFullParams = fullParamsOpt.value(); BOOST_TEST_INFO( diff --git a/Tests/UnitTests/Core/TrackFitting/Gx2fTests.cpp b/Tests/UnitTests/Core/TrackFitting/Gx2fTests.cpp index e3dbe1d4cde..71b2bf2b1f8 100644 --- a/Tests/UnitTests/Core/TrackFitting/Gx2fTests.cpp +++ b/Tests/UnitTests/Core/TrackFitting/Gx2fTests.cpp @@ -1108,15 +1108,15 @@ BOOST_AUTO_TEST_CASE(Material) { // Parameters // We need quite coarse checks here, since on different builds // the created measurements differ in the randomness - BOOST_CHECK_CLOSE(track.parameters()[eBoundLoc0], -11., 7e0); - BOOST_CHECK_CLOSE(track.parameters()[eBoundLoc1], -15., 6e0); - BOOST_CHECK_CLOSE(track.parameters()[eBoundPhi], 1e-5, 1e3); + BOOST_CHECK_CLOSE(track.parameters()[eBoundLoc0], -11., 26e0); + BOOST_CHECK_CLOSE(track.parameters()[eBoundLoc1], -15., 15e0); + BOOST_CHECK_CLOSE(track.parameters()[eBoundPhi], 1e-5, 1.1e3); BOOST_CHECK_CLOSE(track.parameters()[eBoundTheta], std::numbers::pi / 2, - 1e-3); + 2e-2); BOOST_CHECK_EQUAL(track.parameters()[eBoundQOverP], 1); BOOST_CHECK_CLOSE(track.parameters()[eBoundTime], startParametersFit.parameters()[eBoundTime], 1e-6); - // BOOST_CHECK_CLOSE(track.covariance().determinant(), 1e-27, 4e0); + BOOST_CHECK_CLOSE(track.covariance().determinant(), 3.5e-27, 1e1); // Convergence BOOST_CHECK_EQUAL( diff --git a/Tests/UnitTests/Core/Utilities/CMakeLists.txt b/Tests/UnitTests/Core/Utilities/CMakeLists.txt index cb5249b6be9..955b58b31c9 100644 --- a/Tests/UnitTests/Core/Utilities/CMakeLists.txt +++ b/Tests/UnitTests/Core/Utilities/CMakeLists.txt @@ -61,3 +61,4 @@ add_unittest(VectorHelpers VectorHelpersTests.cpp) add_unittest(TrackHelpers TrackHelpersTests.cpp) add_unittest(GraphViz GraphVizTests.cpp) +add_unittest(ContextType ContextTypeTests.cpp) diff --git a/Tests/UnitTests/Core/Utilities/ContextTypeTests.cpp b/Tests/UnitTests/Core/Utilities/ContextTypeTests.cpp new file mode 100644 index 00000000000..2bd67ee1e5f --- /dev/null +++ b/Tests/UnitTests/Core/Utilities/ContextTypeTests.cpp @@ -0,0 +1,38 @@ +// 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 +#include + +#include "Acts/Utilities/detail/ContextType.hpp" + +using namespace Acts; + +BOOST_AUTO_TEST_SUITE(ContextTypeTests) + +BOOST_AUTO_TEST_CASE(PackUnpack) { + ContextType ctx; + + int v = 42; + ctx = v; + + BOOST_CHECK_EQUAL(ctx.get(), 42); + BOOST_CHECK_THROW(ctx.get(), std::bad_any_cast); +} + +BOOST_AUTO_TEST_CASE(MaybeUnpack) { + ContextType ctx; + + int v = 42; + ctx = v; + + BOOST_CHECK_EQUAL(*ctx.maybeGet(), 42); + BOOST_CHECK_EQUAL(ctx.maybeGet(), nullptr); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/Tests/UnitTests/Core/Utilities/HashedStringTests.cpp b/Tests/UnitTests/Core/Utilities/HashedStringTests.cpp index f38a71cbe89..0045ec4a6dc 100644 --- a/Tests/UnitTests/Core/Utilities/HashedStringTests.cpp +++ b/Tests/UnitTests/Core/Utilities/HashedStringTests.cpp @@ -28,7 +28,7 @@ BOOST_AUTO_TEST_CASE(string_hashes) { BOOST_CHECK_EQUAL("abc"_hash, 440920331); std::string s = "abc"; - BOOST_CHECK_EQUAL(hashString(s), 440920331); + BOOST_CHECK_EQUAL(hashStringDynamic(s), 440920331); constexpr std::string_view sv{"abc"}; BOOST_CHECK_EQUAL(hashString(sv), 440920331); static_assert(hashString(sv) == 440920331, "Invalid");