diff --git a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_ckf.root b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_ckf.root index f7fb66f24ab..b02aa3773ac 100644 Binary files a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_ckf.root and b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_ckf.root differ diff --git a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_ckf_ambi.root b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_ckf_ambi.root index 8fbd66c0abb..35c6a2c8519 100644 Binary files a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_ckf_ambi.root and b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_ckf_ambi.root differ diff --git a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_vertexing_amvf_gauss_notime_hist.root b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_vertexing_amvf_gauss_notime_hist.root index cb71ba79000..4cd67bc9bec 100644 Binary files a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_vertexing_amvf_gauss_notime_hist.root and b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_vertexing_amvf_gauss_notime_hist.root differ diff --git a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_vertexing_amvf_grid_time_hist.root b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_vertexing_amvf_grid_time_hist.root index 0980823e57c..3ee1d6b2e89 100644 Binary files a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_vertexing_amvf_grid_time_hist.root and b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_vertexing_amvf_grid_time_hist.root differ diff --git a/CI/test_coverage.py b/CI/test_coverage.py index 06b13a06abb..0488a71d85d 100755 --- a/CI/test_coverage.py +++ b/CI/test_coverage.py @@ -41,7 +41,7 @@ def call(cmd): ret, gcovr_version_text = check_output(["gcovr", "--version"]) gcovr_version = tuple( - map(int, re.match("gcovr (\d+\.\d+)", gcovr_version_text).group(1).split(".")) + map(int, re.match(r"gcovr (\d+\.\d+)", gcovr_version_text).group(1).split(".")) ) extra_flags = [] @@ -63,7 +63,7 @@ def call(cmd): if not os.path.exists(coverage_dir): os.makedirs(coverage_dir) -excludes = ["-e", "../Tests/", "-e", ".*json\.hpp"] +excludes = ["-e", "../Tests/", "-e", r".*json\.hpp"] # create the html report call( diff --git a/Core/include/Acts/Clusterization/Clusterization.hpp b/Core/include/Acts/Clusterization/Clusterization.hpp index 3ebfd8d562d..a7b4d853b20 100644 --- a/Core/include/Acts/Clusterization/Clusterization.hpp +++ b/Core/include/Acts/Clusterization/Clusterization.hpp @@ -13,6 +13,26 @@ namespace Acts::Ccl { +template +concept HasRetrievableColumnInfo = requires(Cell cell) { + { getCellColumn(cell) } -> std::same_as; +}; + +template +concept HasRetrievableRowInfo = requires(Cell cell) { + { getCellRow(cell) } -> std::same_as; +}; + +template +concept HasRetrievableLabelInfo = requires(Cell cell) { + { getCellLabel(cell) } -> std::same_as; +}; + +template +concept CanAcceptCell = requires(Cell cell, Cluster cluster) { + { clusterAddCell(cluster, cell) } -> std::same_as; +}; + using Label = int; constexpr Label NO_LABEL = 0; @@ -28,17 +48,21 @@ enum class ConnectResult { // Default connection type for 2-D grids: 4- or 8-cell connectivity template + requires(Acts::Ccl::HasRetrievableColumnInfo && + Acts::Ccl::HasRetrievableRowInfo) struct Connect2D { - bool conn8; - Connect2D() : conn8{true} {} + bool conn8{true}; + Connect2D() = default; explicit Connect2D(bool commonCorner) : conn8{commonCorner} {} - ConnectResult operator()(const Cell& ref, const Cell& iter) const; + virtual ConnectResult operator()(const Cell& ref, const Cell& iter) const; + virtual ~Connect2D() = default; }; // Default connection type for 1-D grids: 2-cell connectivity -template +template struct Connect1D { - ConnectResult operator()(const Cell& ref, const Cell& iter) const; + virtual ConnectResult operator()(const Cell& ref, const Cell& iter) const; + virtual ~Connect1D() = default; }; // Default connection type based on GridDim @@ -49,13 +73,16 @@ struct DefaultConnect { }; template -struct DefaultConnect : public Connect2D { - explicit DefaultConnect(bool commonCorner) : Connect2D(commonCorner) {} - DefaultConnect() : DefaultConnect(true) {} +struct DefaultConnect : public Connect1D { + ~DefaultConnect() override = default; }; template -struct DefaultConnect : public Connect1D {}; +struct DefaultConnect : public Connect2D { + explicit DefaultConnect(bool commonCorner) : Connect2D(commonCorner) {} + DefaultConnect() = default; + ~DefaultConnect() override = default; +}; /// @brief labelClusters /// @@ -70,6 +97,8 @@ struct DefaultConnect : public Connect1D {}; template > + requires( + Acts::Ccl::HasRetrievableLabelInfo) void labelClusters(CellCollection& cells, Connect connect = Connect()); /// @brief mergeClusters @@ -82,6 +111,9 @@ void labelClusters(CellCollection& cells, Connect connect = Connect()); /// @return nothing template + requires(GridDim == 1 || GridDim == 2) && + Acts::Ccl::HasRetrievableLabelInfo< + typename CellCollection::value_type> ClusterCollection mergeClusters(CellCollection& /*cells*/); /// @brief createClusters diff --git a/Core/include/Acts/Clusterization/Clusterization.ipp b/Core/include/Acts/Clusterization/Clusterization.ipp index 0aa79b53981..90a69930ce1 100644 --- a/Core/include/Acts/Clusterization/Clusterization.ipp +++ b/Core/include/Acts/Clusterization/Clusterization.ipp @@ -14,60 +14,6 @@ namespace Acts::Ccl::internal { -// Machinery for validating generic Cell/Cluster types at compile-time - -template -struct cellTypeHasRequiredFunctions : std::false_type {}; - -template -struct cellTypeHasRequiredFunctions< - T, 2, - std::void_t())), - decltype(getCellColumn(std::declval())), - decltype(getCellLabel(std::declval()))>> : std::true_type { -}; - -template -struct cellTypeHasRequiredFunctions< - T, 1, - std::void_t())), - decltype(getCellLabel(std::declval()))>> : std::true_type { -}; - -template -struct clusterTypeHasRequiredFunctions : std::false_type {}; - -template -struct clusterTypeHasRequiredFunctions< - T, U, - std::void_t(), std::declval()))>> - : std::true_type {}; - -template -constexpr void staticCheckGridDim() { - static_assert( - GridDim == 1 || GridDim == 2, - "mergeClusters is only defined for grid dimensions of 1 or 2. "); -} - -template -constexpr void staticCheckCellType() { - constexpr bool hasFns = cellTypeHasRequiredFunctions(); - static_assert(hasFns, - "Cell type should have the following functions: " - "'int getCellRow(const Cell&)', " - "'int getCellColumn(const Cell&)', " - "'Label& getCellLabel(Cell&)'"); -} - -template -constexpr void staticCheckClusterType() { - constexpr bool hasFns = clusterTypeHasRequiredFunctions(); - static_assert(hasFns, - "Cluster type should have the following function: " - "'void clusterAddCell(Cluster&, const Cell&)'"); -} - template struct Compare { static_assert(GridDim != 1 && GridDim != 2, @@ -75,25 +21,27 @@ struct Compare { }; // Comparator function object for cells, column-wise ordering -// Specialization for 2-D grid -template -struct Compare { +// Specialization for 1-D grids +template +struct Compare { bool operator()(const Cell& c0, const Cell& c1) const { - int row0 = getCellRow(c0); - int row1 = getCellRow(c1); int col0 = getCellColumn(c0); int col1 = getCellColumn(c1); - return (col0 == col1) ? row0 < row1 : col0 < col1; + return col0 < col1; } }; -// Specialization for 1-D grids +// Specialization for 2-D grid template -struct Compare { + requires(Acts::Ccl::HasRetrievableColumnInfo && + Acts::Ccl::HasRetrievableRowInfo) +struct Compare { bool operator()(const Cell& c0, const Cell& c1) const { + int row0 = getCellRow(c0); + int row1 = getCellRow(c1); int col0 = getCellColumn(c0); int col1 = getCellColumn(c1); - return col0 < col1; + return (col0 == col1) ? row0 < row1 : col0 < col1; } }; @@ -184,6 +132,10 @@ Connections getConnections(typename std::vector::iterator it, } template + requires( + Acts::Ccl::HasRetrievableLabelInfo && + Acts::Ccl::CanAcceptCell) ClusterCollection mergeClustersImpl(CellCollection& cells) { using Cluster = typename ClusterCollection::value_type; @@ -215,6 +167,8 @@ ClusterCollection mergeClustersImpl(CellCollection& cells) { namespace Acts::Ccl { template + requires(Acts::Ccl::HasRetrievableColumnInfo && + Acts::Ccl::HasRetrievableRowInfo) ConnectResult Connect2D::operator()(const Cell& ref, const Cell& iter) const { int deltaRow = std::abs(getCellRow(ref) - getCellRow(iter)); @@ -237,7 +191,7 @@ ConnectResult Connect2D::operator()(const Cell& ref, return ConnectResult::eNoConn; } -template +template ConnectResult Connect1D::operator()(const Cell& ref, const Cell& iter) const { int deltaCol = std::abs(getCellColumn(ref) - getCellColumn(iter)); @@ -267,9 +221,10 @@ void recordEquivalences(const internal::Connections seen, } template + requires( + Acts::Ccl::HasRetrievableLabelInfo) void labelClusters(CellCollection& cells, Connect connect) { using Cell = typename CellCollection::value_type; - internal::staticCheckCellType(); internal::DisjointSets ds{}; @@ -277,7 +232,8 @@ void labelClusters(CellCollection& cells, Connect connect) { std::ranges::sort(cells, internal::Compare()); // First pass: Allocate labels and record equivalences - for (auto it = cells.begin(); it != cells.end(); ++it) { + for (auto it = std::ranges::begin(cells); it != std::ranges::end(cells); + ++it) { const internal::Connections seen = internal::getConnections(it, cells, connect); if (seen.nconn == 0) { @@ -299,13 +255,11 @@ void labelClusters(CellCollection& cells, Connect connect) { template + requires(GridDim == 1 || GridDim == 2) && + Acts::Ccl::HasRetrievableLabelInfo< + typename CellCollection::value_type> ClusterCollection mergeClusters(CellCollection& cells) { using Cell = typename CellCollection::value_type; - using Cluster = typename ClusterCollection::value_type; - internal::staticCheckGridDim(); - internal::staticCheckCellType(); - internal::staticCheckClusterType(); - if constexpr (GridDim > 1) { // Sort the cells by their cluster label, only needed if more than // one spatial dimension @@ -318,10 +272,6 @@ ClusterCollection mergeClusters(CellCollection& cells) { template ClusterCollection createClusters(CellCollection& cells, Connect connect) { - using Cell = typename CellCollection::value_type; - using Cluster = typename ClusterCollection::value_type; - internal::staticCheckCellType(); - internal::staticCheckClusterType(); labelClusters(cells, connect); return mergeClusters(cells); } diff --git a/Core/include/Acts/Clusterization/TimedClusterization.hpp b/Core/include/Acts/Clusterization/TimedClusterization.hpp new file mode 100644 index 00000000000..e92ebce44e2 --- /dev/null +++ b/Core/include/Acts/Clusterization/TimedClusterization.hpp @@ -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/. + +#pragma once + +#include "Acts/Clusterization/Clusterization.hpp" +#include "Acts/Definitions/Algebra.hpp" + +#include + +namespace Acts::Ccl { + +template +concept HasRetrievableTimeInfo = requires(Cell cell) { + { getCellTime(cell) } -> std::same_as; +}; + +template +struct TimedConnect : public Acts::Ccl::DefaultConnect { + Acts::ActsScalar timeTolerance{std::numeric_limits::max()}; + + TimedConnect() = default; + TimedConnect(Acts::ActsScalar time); + TimedConnect(Acts::ActsScalar time, bool commonCorner) + requires(N == 2); + ~TimedConnect() override = default; + + ConnectResult operator()(const Cell& ref, const Cell& iter) const override; +}; + +} // namespace Acts::Ccl + +#include "Acts/Clusterization/TimedClusterization.ipp" diff --git a/Core/include/Acts/Clusterization/TimedClusterization.ipp b/Core/include/Acts/Clusterization/TimedClusterization.ipp new file mode 100644 index 00000000000..0e7b3e5bda8 --- /dev/null +++ b/Core/include/Acts/Clusterization/TimedClusterization.ipp @@ -0,0 +1,36 @@ +// 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/. + +namespace Acts::Ccl { + +template +TimedConnect::TimedConnect(Acts::ActsScalar time) + : timeTolerance(time) {} + +template +TimedConnect::TimedConnect(Acts::ActsScalar time, bool commonCorner) + requires(N == 2) + : Acts::Ccl::DefaultConnect(commonCorner), timeTolerance(time) {} + +template +Acts::Ccl::ConnectResult TimedConnect::operator()( + const Cell& ref, const Cell& iter) const { + Acts::Ccl::ConnectResult spaceCompatibility = + Acts::Ccl::DefaultConnect::operator()(ref, iter); + if (spaceCompatibility != Acts::Ccl::ConnectResult::eConn) { + return spaceCompatibility; + } + + if (std::abs(getCellTime(ref) - getCellTime(iter)) < timeTolerance) { + return Acts::Ccl::ConnectResult::eConn; + } + + return Acts::Ccl::ConnectResult::eNoConn; +} + +} // namespace Acts::Ccl diff --git a/Core/include/Acts/Detector/LayerStructureBuilder.hpp b/Core/include/Acts/Detector/LayerStructureBuilder.hpp index 9dd0e0a8e8e..02fd726824e 100644 --- a/Core/include/Acts/Detector/LayerStructureBuilder.hpp +++ b/Core/include/Acts/Detector/LayerStructureBuilder.hpp @@ -91,8 +91,9 @@ class LayerStructureBuilder : public IInternalStructureBuilder { /// Minimum number of surfaces to build an internal structure /// - otherwise the tryAll options is used unsigned int nMinimalSurfaces = 4u; - /// Polyhedron approximations - unsigned int nSegments = 1u; + /// Polyhedron approximations: number of segments to be used + /// to approximate a quarter of a circle + unsigned int quarterSegments = 1u; /// Extra information, mainly for screen output std::string auxiliary = ""; }; diff --git a/Core/include/Acts/EventData/SpacePointContainer.hpp b/Core/include/Acts/EventData/SpacePointContainer.hpp index 32e43645d82..619a1393ecc 100644 --- a/Core/include/Acts/EventData/SpacePointContainer.hpp +++ b/Core/include/Acts/EventData/SpacePointContainer.hpp @@ -12,15 +12,13 @@ #include "Acts/Definitions/Units.hpp" #include "Acts/EventData/SpacePointData.hpp" #include "Acts/EventData/SpacePointProxy.hpp" -#include "Acts/EventData/SpacePointProxyIterator.hpp" #include "Acts/EventData/Utils.hpp" #include "Acts/Utilities/HashedString.hpp" +#include "Acts/Utilities/Iterator.hpp" #include #include -#include - namespace Acts { struct SpacePointContainerConfig { @@ -67,19 +65,22 @@ class SpacePointContainer { public: friend class Acts::SpacePointProxy< Acts::SpacePointContainer>; - friend class Acts::SpacePointProxyIterator< - Acts::SpacePointContainer>; public: - using iterator = Acts::SpacePointProxyIterator< - Acts::SpacePointContainer>; - using const_iterator = iterator; - using SpacePointProxyType = Acts::SpacePointProxy>; + + using iterator = + ContainerIndexIterator, + SpacePointProxyType&, false>; + using const_iterator = + ContainerIndexIterator, + const SpacePointProxyType&, true>; + using ValueType = typename container_t::ValueType; using ProxyType = SpacePointProxyType; using value_type = ProxyType; + using size_type = std::size_t; public: // Constructors @@ -118,9 +119,15 @@ class SpacePointContainer { std::size_t size() const; - iterator begin() const; - iterator end() const; + iterator begin(); + iterator end(); + const_iterator cbegin() const; + const_iterator cend() const; + const_iterator begin() const; + const_iterator end() const; + ProxyType& at(const std::size_t n); + const ProxyType& at(const std::size_t n) const; const ValueType& sp(const std::size_t n) const; private: @@ -128,6 +135,7 @@ class SpacePointContainer { const container_t& container() const; const ProxyType& proxy(const std::size_t n) const; + std::vector& proxies(); const std::vector& proxies() const; float x(const std::size_t n) const; diff --git a/Core/include/Acts/EventData/SpacePointContainer.ipp b/Core/include/Acts/EventData/SpacePointContainer.ipp index abcab8ab5a2..e0c381e4a50 100644 --- a/Core/include/Acts/EventData/SpacePointContainer.ipp +++ b/Core/include/Acts/EventData/SpacePointContainer.ipp @@ -6,7 +6,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -#include +#include namespace Acts { @@ -44,7 +44,7 @@ void SpacePointContainer::initialize() { m_data.setZ(i, external_container.z_impl(i)); m_data.setRadius( i, std::sqrt(m_data.x(i) * m_data.x(i) + m_data.y(i) * m_data.y(i))); - m_data.setPhi(i, atan2f(m_data.y(i), m_data.x(i))); + m_data.setPhi(i, std::atan2(m_data.y(i), m_data.x(i))); m_data.setVarianceR(i, external_container.varianceR_impl(i)); m_data.setVarianceZ(i, external_container.varianceZ_impl(i)); @@ -105,22 +105,58 @@ std::size_t SpacePointContainer::size() const { template class holder_t> typename SpacePointContainer::iterator -SpacePointContainer::begin() const { +SpacePointContainer::begin() { return {*this, 0}; } template class holder_t> typename SpacePointContainer::iterator +SpacePointContainer::end() { + return {*this, size()}; +} + +template class holder_t> +typename SpacePointContainer::const_iterator +SpacePointContainer::begin() const { + return {*this, 0}; +} + +template class holder_t> +typename SpacePointContainer::const_iterator SpacePointContainer::end() const { return {*this, size()}; } +template class holder_t> +typename SpacePointContainer::const_iterator +SpacePointContainer::cbegin() const { + return {*this, 0}; +} + +template class holder_t> +typename SpacePointContainer::const_iterator +SpacePointContainer::cend() const { + return {*this, size()}; +} + template class holder_t> const container_t& SpacePointContainer::container() const { return *m_container; } +template class holder_t> +typename SpacePointContainer::ProxyType& +SpacePointContainer::at(const std::size_t n) { + return proxies().at(n); +} + +template class holder_t> +const typename SpacePointContainer::ProxyType& +SpacePointContainer::at(const std::size_t n) const { + return proxies().at(n); +} + template class holder_t> const typename SpacePointContainer::ValueType& SpacePointContainer::sp(const std::size_t n) const { @@ -173,6 +209,12 @@ SpacePointContainer::proxy(const std::size_t n) const { return proxies()[n]; } +template class holder_t> +std::vector::ProxyType>& +SpacePointContainer::proxies() { + return m_proxies; +} + template class holder_t> const std::vector< typename SpacePointContainer::ProxyType>& diff --git a/Core/include/Acts/EventData/SpacePointProxyIterator.hpp b/Core/include/Acts/EventData/SpacePointProxyIterator.hpp deleted file mode 100644 index c8b91d3c052..00000000000 --- a/Core/include/Acts/EventData/SpacePointProxyIterator.hpp +++ /dev/null @@ -1,58 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 CERN for the benefit of the ACTS project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -#pragma once - -#include "Acts/EventData/SpacePointProxy.hpp" -#include "Acts/Utilities/Holders.hpp" - -namespace Acts { - -template -class SpacePointProxyIterator { - public: - using ContainerType = container_t; - using ProxyType = typename container_t::SpacePointProxyType; - - using iterator_category = std::random_access_iterator_tag; - using value_type = ProxyType; - using difference_type = std::ptrdiff_t; - using pointer = value_type*; - using reference = value_type&; - - public: - // Constructors - SpacePointProxyIterator(container_t&& container, std::size_t index) = delete; - SpacePointProxyIterator(const container_t& container, std::size_t index); - - SpacePointProxyIterator& operator++(); - SpacePointProxyIterator& operator--(); - SpacePointProxyIterator operator++(int); - SpacePointProxyIterator operator--(int); - - bool operator==(const SpacePointProxyIterator& other) const; - auto operator<=>(const SpacePointProxyIterator& other) const; - - SpacePointProxyIterator& operator+=(const std::size_t offset); - SpacePointProxyIterator& operator-=(const std::size_t offset); - - SpacePointProxyIterator operator+(const std::size_t offset) const; - SpacePointProxyIterator operator-(const std::size_t offset) const; - - difference_type operator-(const SpacePointProxyIterator& other) const; - - const value_type& operator*() const; - - private: - const container_t* m_container{nullptr}; - std::size_t m_index{0ul}; -}; - -} // namespace Acts - -#include "Acts/EventData/SpacePointProxyIterator.ipp" diff --git a/Core/include/Acts/EventData/SpacePointProxyIterator.ipp b/Core/include/Acts/EventData/SpacePointProxyIterator.ipp deleted file mode 100644 index 5759e0416a1..00000000000 --- a/Core/include/Acts/EventData/SpacePointProxyIterator.ipp +++ /dev/null @@ -1,100 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 CERN for the benefit of the ACTS project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -namespace Acts { - -// Implementation -template -SpacePointProxyIterator::SpacePointProxyIterator( - const container_t& container, std::size_t index) - : m_container(&container), m_index(index) {} - -template -SpacePointProxyIterator& -SpacePointProxyIterator::operator++() { - ++m_index; - return *this; -} - -template -SpacePointProxyIterator& -SpacePointProxyIterator::operator--() { - --m_index; - return *this; -} - -template -SpacePointProxyIterator -SpacePointProxyIterator::operator++(int) { - SpacePointProxyIterator other(*this); - ++m_index; - return other; -} - -template -SpacePointProxyIterator -SpacePointProxyIterator::operator--(int) { - SpacePointProxyIterator other(*this); - --m_index; - return other; -} - -template -bool SpacePointProxyIterator::operator==( - const SpacePointProxyIterator& other) const { - return m_container == other.m_container && m_index == other.m_index; -} - -template -auto SpacePointProxyIterator::operator<=>( - const SpacePointProxyIterator& other) const { - return m_index <=> other.m_index; -} - -template -SpacePointProxyIterator& -SpacePointProxyIterator::operator+=(const std::size_t offset) { - m_index += offset; - return *this; -} - -template -SpacePointProxyIterator& -SpacePointProxyIterator::operator-=(const std::size_t offset) { - m_index -= offset; - return *this; -} - -template -SpacePointProxyIterator -SpacePointProxyIterator::operator+( - const std::size_t offset) const { - return SpacePointProxyIterator(*m_container, m_index + offset); -} - -template -SpacePointProxyIterator -SpacePointProxyIterator::operator-( - const std::size_t offset) const { - return SpacePointProxyIterator(*m_container, m_index - offset); -} - -template -typename SpacePointProxyIterator::difference_type -SpacePointProxyIterator::operator-( - const SpacePointProxyIterator& other) const { - return m_index - other.m_index; -} - -template -const typename SpacePointProxyIterator::value_type& -SpacePointProxyIterator::operator*() const { - return m_container->proxy(m_index); -} - -} // namespace Acts diff --git a/Core/include/Acts/EventData/TrackContainer.hpp b/Core/include/Acts/EventData/TrackContainer.hpp index 9591a66c6a4..f70c430f002 100644 --- a/Core/include/Acts/EventData/TrackContainer.hpp +++ b/Core/include/Acts/EventData/TrackContainer.hpp @@ -19,6 +19,8 @@ #include "Acts/EventData/Utils.hpp" #include "Acts/Utilities/HashedString.hpp" #include "Acts/Utilities/Holders.hpp" +#include "Acts/Utilities/Iterator.hpp" +#include "Acts/Utilities/TypeTraits.hpp" #include "Acts/Utilities/UnitVectors.hpp" #include @@ -78,6 +80,12 @@ class TrackContainer { using ConstTrackStateProxy = typename MultiTrajectory::ConstTrackStateProxy; + using size_type = IndexType; + using iterator = + Acts::ContainerIndexIterator; + using const_iterator = + Acts::ContainerIndexIterator; + #ifndef DOXYGEN friend TrackProxy; friend ConstTrackProxy; @@ -148,6 +156,21 @@ class TrackContainer { return {*this, itrack}; } + /// Get a const track proxy for a track index + /// @param itrack the track index in the container + /// @return A const track proxy for the index + ConstTrackProxy at(IndexType itrack) const { return getTrack(itrack); } + + /// Get a mutable track proxy for a track index + /// @note Only available if the track container is not read-only + /// @param itrack the track index in the container + /// @return A mutable track proxy for the index + TrackProxy at(IndexType itrack) + requires(!ReadOnly) + { + return {*this, itrack}; + } + /// Add a track to the container. Note this only creates the logical track and /// allocates memory. You can combine this with @c getTrack to obtain a track proxy /// @note Only available if the track container is not read-only @@ -184,36 +207,28 @@ class TrackContainer { /// Get a mutable iterator to the first track in the container /// @note Only available if the track container is not read-only /// @return a mutable iterator to the first track - auto begin() + iterator begin() requires(!ReadOnly) { - return detail_tc::TrackProxyIterator, - TrackProxy, false>{*this, 0}; + return iterator{*this, 0}; } /// Get a past-the-end iterator for this container /// @note Only available if the track container is not read-only /// @return a past-the-end iterator - auto end() + iterator end() requires(!ReadOnly) { - return detail_tc::TrackProxyIterator, - TrackProxy, false>{*this, size()}; + return iterator{*this, size()}; } /// Get an const iterator to the first track in the container /// @return a const iterator to the first track - auto begin() const { - return detail_tc::TrackProxyIterator, - ConstTrackProxy, true>{*this, 0}; - } + const_iterator begin() const { return const_iterator{*this, 0}; } /// Get a past-the-end iterator for this container /// @return a past-the-end iterator - auto end() const { - return detail_tc::TrackProxyIterator, - ConstTrackProxy, true>{*this, size()}; - } + const_iterator end() const { return const_iterator{*this, size()}; } /// @} @@ -411,8 +426,8 @@ class TrackContainer { } } - detail_tc::ConstIf, ReadOnly> m_container; - detail_tc::ConstIf, ReadOnly> m_traj; + const_if_t> m_container; + const_if_t> m_traj; }; template diff --git a/Core/include/Acts/EventData/TrackProxy.hpp b/Core/include/Acts/EventData/TrackProxy.hpp index f5a5aeca6d2..ce674e9cfa4 100644 --- a/Core/include/Acts/EventData/TrackProxy.hpp +++ b/Core/include/Acts/EventData/TrackProxy.hpp @@ -17,6 +17,7 @@ #include "Acts/EventData/TrackProxyConcept.hpp" #include "Acts/EventData/TrackStatePropMask.hpp" #include "Acts/Utilities/HashedString.hpp" +#include "Acts/Utilities/TypeTraits.hpp" #include "Acts/Utilities/UnitVectors.hpp" #include @@ -29,108 +30,6 @@ template class holder_t> class TrackContainer; -namespace detail_tc { -template -using ConstIf = std::conditional_t; - -/// Helper iterator to allow iteration over tracks via track proxies. -template -class TrackProxyIterator { - using ProxyType = proxy_t; - using IndexType = typename ProxyType::IndexType; - using ContainerType = container_t; - - public: - using iterator_category = std::random_access_iterator_tag; - using value_type = ProxyType; - using difference_type = std::ptrdiff_t; - using pointer = void; - using reference = void; - - TrackProxyIterator(container_t& container, IndexType itrack) - requires(!ReadOnly) - : m_container(&container), m_itrack(itrack) {} - - TrackProxyIterator(const container_t& container, IndexType itrack) - requires ReadOnly - : m_container(&container), m_itrack(itrack) {} - - TrackProxyIterator& operator++() { - m_itrack++; - return *this; - } - TrackProxyIterator& operator--() { - m_itrack--; - return *this; - } - - bool operator==(const TrackProxyIterator& other) const { - return m_container == other.m_container && m_itrack == other.m_itrack; - } - - auto operator<=>(const TrackProxyIterator& other) const { - return m_itrack <=> other.m_itrack; - } - - ProxyType operator*() const { return m_container->getTrack(m_itrack); } - - ProxyType operator*() - requires(!ReadOnly) - { - return m_container->getTrack(m_itrack); - } - - TrackProxyIterator operator[](difference_type n) const { - TrackProxyIterator copy = *this; - copy += n; - return copy; - }; - - TrackProxyIterator& operator+=(difference_type n) { - m_itrack += n; - return *this; - } - - TrackProxyIterator operator-=(difference_type n) { - m_itrack -= n; - return *this; - } - - friend difference_type operator-(const TrackProxyIterator& lhs, - const TrackProxyIterator& rhs) { - return lhs.m_itrack - rhs.m_itrack; - } - - friend TrackProxyIterator operator+(const TrackProxyIterator& lhs, - difference_type rhs) { - TrackProxyIterator copy = lhs; - copy += rhs; - return copy; - } - - friend TrackProxyIterator operator+(difference_type lhs, - const TrackProxyIterator& rhs) { - return rhs + lhs; - } - - friend TrackProxyIterator operator-(const TrackProxyIterator& lhs, - difference_type rhs) { - return lhs + (-rhs); - } - - friend TrackProxyIterator operator-(difference_type lhs, - const TrackProxyIterator& rhs) { - return rhs + (-lhs); - } - - private: - detail_lt::TransitiveConstPointer> - m_container; - IndexType m_itrack; -}; - -} // namespace detail_tc - /// Proxy class representing a single track. /// This class provides a **view** into an associated @ref TrackContainer, and /// has **reference semantics**. You can think of it as a pointer to a vector @@ -876,13 +775,14 @@ class TrackProxy { const auto& container() const { return *m_container; } private: - TrackProxy(detail_tc::ConstIf, - ReadOnly>& container, - IndexType itrack) + TrackProxy( + const_if_t>& + container, + IndexType itrack) : m_container{&container}, m_index{itrack} {} - detail_lt::TransitiveConstPointer, ReadOnly>> + detail_lt::TransitiveConstPointer< + const_if_t>> m_container; IndexType m_index; }; diff --git a/Core/include/Acts/Geometry/Extent.hpp b/Core/include/Acts/Geometry/Extent.hpp index 698477744c0..8728728996b 100644 --- a/Core/include/Acts/Geometry/Extent.hpp +++ b/Core/include/Acts/Geometry/Extent.hpp @@ -52,12 +52,6 @@ struct ExtentEnvelope { } } - /// Constructor from an array of envelopes - /// @param values the array of envelopes - constexpr explicit ExtentEnvelope( - const std::array& values) - : m_values(values) {} - /// Static factory for a zero envelope /// @return the zero envelope constexpr static ExtentEnvelope Zero() { @@ -74,6 +68,33 @@ struct ExtentEnvelope { }}; } + /// Helper struct for designated initializer construction + struct Arguments { + Envelope x = zeroEnvelope; + Envelope y = zeroEnvelope; + Envelope z = zeroEnvelope; + Envelope r = zeroEnvelope; + Envelope phi = zeroEnvelope; + Envelope rPhi = zeroEnvelope; + Envelope h = zeroEnvelope; + Envelope eta = zeroEnvelope; + Envelope mag = zeroEnvelope; + }; + + /// Constructor using a helper struct for designated initializaion + /// @param args the arguments + constexpr explicit ExtentEnvelope(Arguments&& args) { + using enum BinningValue; + m_values[toUnderlying(binX)] = args.x; + m_values[toUnderlying(binY)] = args.y; + m_values[toUnderlying(binZ)] = args.z; + m_values[toUnderlying(binR)] = args.r; + m_values[toUnderlying(binPhi)] = args.phi; + m_values[toUnderlying(binH)] = args.h; + m_values[toUnderlying(binEta)] = args.eta; + m_values[toUnderlying(binMag)] = args.mag; + } + /// Comparison operator between envelope sets /// @param lhs the left hand side /// @param rhs the right hand side diff --git a/Core/include/Acts/Geometry/Polyhedron.hpp b/Core/include/Acts/Geometry/Polyhedron.hpp index 2a6eb47d765..00ccaaab4c5 100644 --- a/Core/include/Acts/Geometry/Polyhedron.hpp +++ b/Core/include/Acts/Geometry/Polyhedron.hpp @@ -39,6 +39,7 @@ struct Polyhedron { /// @param facesIn List of lists of indices for faces. /// @param triangularMeshIn List of lists of indices for a triangular mesh /// @param isExact A dedicated flag if this is exact or not + /// /// @note This creates copies of the input vectors Polyhedron(const std::vector& verticesIn, const std::vector& facesIn, diff --git a/Core/include/Acts/Geometry/PortalShell.hpp b/Core/include/Acts/Geometry/PortalShell.hpp new file mode 100644 index 00000000000..39e60b8774b --- /dev/null +++ b/Core/include/Acts/Geometry/PortalShell.hpp @@ -0,0 +1,225 @@ +// 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/Geometry/BoundarySurfaceFace.hpp" +#include "Acts/Utilities/BinningType.hpp" +#include "Acts/Utilities/Logger.hpp" + +#include +#include + +namespace Acts { + +class Portal; +class TrackingVolume; +class GeometryContext; + +/// @class PortalShellBase +/// The portal shell of a volume is the set of portals that describes +/// connections "outside" of the volume. Which boundary surfaces of a volume are +/// included in the shell depends on the volume. Portal shells are only used +/// during geometry construction, and are not part of the final geometry +/// description. +/// +/// This class is the base class for all portal shells +class PortalShellBase { + public: + /// Virtusl destructor + virtual ~PortalShellBase() = default; + + /// Connect a volume to the outer side of all portal shells. Which "side" is + /// "outer" depends on the volume type. + /// This method essentially creates a @c TrivialPortalLink on the unconnected + /// side of each portal that is part of the chell + /// @param volume The volume to connect + virtual void connectOuter(TrackingVolume& volume) = 0; + + /// Get the number of portals in the shell. This number depends on the volume + /// type + /// @return The number of portals in the shell + virtual std::size_t size() const = 0; + + /// Instruct the shell to register the portals with the volume, handing over + /// shared ownership in the process. + /// @note The target volume depends on the shell type, e.g. composite shells + /// like the @c CylinerStackPortalShell register portals to the *correct* + /// volumes. + virtual void applyToVolume() = 0; + + /// Check if a portal is *valid*, e.g. if non of the portals has two + /// unconnected sides. + /// @return True if the shell is valid, false otherwise + virtual bool isValid() const = 0; + + /// Get a label for the portal shell for debugging purposes + /// @return A label for the portal shell + virtual std::string label() const = 0; +}; + +/// @class CylinderPortalShell +/// Base class for cylinder shaped portal shells, e.g. shells for cylinder +/// volumes +class CylinderPortalShell : public PortalShellBase { + public: + /// Enum describing the possible faces of a cylinder portal shell + /// @note These values are synchronized with the BoundarySurfaceFace enum. + /// Once Gen1 is removed, this can be changed. + enum class Face : unsigned int { + PositiveDisc = BoundarySurfaceFace::positiveFaceXY, + NegativeDisc = BoundarySurfaceFace::negativeFaceXY, + OuterCylinder = BoundarySurfaceFace::tubeOuterCover, + InnerCylinder = BoundarySurfaceFace::tubeInnerCover, + NegativePhiPlane = BoundarySurfaceFace::tubeSectorNegativePhi, + PositivePhiPlane = BoundarySurfaceFace::tubeSectorPositivePhi + }; + + using enum Face; + + /// Retrieve the portal associated to the given face. Can be nullptr if unset. + /// @param face The face to retrieve the portal for + /// @return The portal associated to the face + virtual Portal* portal(Face face) = 0; + + /// Retrieve a shared_ptr for the portal associated to the given face. Can be + /// nullptr if unset. + /// @param face The face to retrieve the portal for + /// @return The portal associated to the face + virtual std::shared_ptr portalPtr(Face face) = 0; + + /// Set the portal associated to the given face. + /// @param portal The portal to set + /// @param face The face to set the portal + virtual void setPortal(std::shared_ptr portal, Face face) = 0; + + /// @copydoc PortalShellBase::connectOuter + void connectOuter(TrackingVolume& volume) override; +}; + +/// Output stream operator for the CylinderPortalShell::Face enum +/// @param os The output stream +/// @param face The face to output +/// @return The output stream +std::ostream& operator<<(std::ostream& os, CylinderPortalShell::Face face); + +/// @class SingleCylinderPortalShell +/// This class describes a cylinder shell containing a single volume. The +/// available faces depend on the configuration of the cylinder volume bounds. +/// If a phi sector is configured, the shell will have corresponding portal +/// slots. If the inner radius is non-zero, the shell will have an inner +/// cylinder portal slot. +class SingleCylinderPortalShell : public CylinderPortalShell { + public: + /// Construct a single cylinder portal shell for the given volume + /// @param volume The volume to create the shell for + explicit SingleCylinderPortalShell(TrackingVolume& volume); + + /// @copydoc PortalShellBase::size + std::size_t size() const final; + + /// @copydoc CylinderPortalShell::portal + Portal* portal(Face face) final; + + /// @copydoc CylinderPortalShell::portalPtr + std::shared_ptr portalPtr(Face face) final; + + /// @copydoc CylinderPortalShell::setPortal + void setPortal(std::shared_ptr portal, Face face) final; + + /// @copydoc PortalShellBase::applyToVolume + void applyToVolume() override; + + /// @copydoc PortalShellBase::isValid + bool isValid() const override; + + /// @copydoc PortalShellBase::label + std::string label() const override; + + private: + std::array, 6> m_portals{}; + + TrackingVolume* m_volume; +}; + +/// @class CylinderStackPortalShell +/// This class describes a cylinder shell containing multiple volumes. The +/// available faces depend on the configuration of the cylinder volume bounds. +/// @note The stack shell currently does not support phi sectors +/// The stack can be oriented along the (local) z or r direction, which drives +/// the stacking. Depending on the direction, portals on the shells of children +/// are merged or fused. Subsequently, portal access respects shared portals +/// between shells. Below is an illustration of a stack in the r direction: +/// +/// Fused +-----------------+ +/// portals ----+ | | +/// | | v OuterCylinder +/// | +------+------+ +/// | | | | +/// | | | |<--+ +/// +--+---+ v | | +/// +---+---------+ | +/// | | | | Shared portal +/// | | |<--+--- (grid) +/// | v | | PositiveDisc +/// +-------------+ | +/// r ^ | | | +/// | | |<--+ +/// | | | +/// | +-------------+ InnerCylinder +/// +-----> ^ (if rMin>0) +/// z | | +/// +-----------------+ +/// +/// @note The shells must be ordered in the given direction +/// Depending on the stack direction, the portal lookup will return different +/// portals. In the illustration above, the `PositiveDisc` portal is shared +/// among all shells, while the `OuterCylinder` and `InnerCylinder` portals are +/// looked up from the innermost and outermost shell in the r direction. +class CylinderStackPortalShell : public CylinderPortalShell { + public: + /// Construct the portal shell stack from the given shells + /// @param gctx The geometry context + /// @param shells The shells to stack + /// @note The shells must be ordered in the given direction + /// @param direction The stacking direction + /// @param logger A logging instance for debugging + CylinderStackPortalShell(const GeometryContext& gctx, + std::vector shells, + BinningValue direction, + const Logger& logger = getDummyLogger()); + + /// @copydoc PortalShellBase::size + std::size_t size() const final; + + /// @copydoc CylinderPortalShell::portal + Portal* portal(Face face) final; + + /// @copydoc CylinderPortalShell::portalPtr + std::shared_ptr portalPtr(Face face) final; + + /// @copydoc CylinderPortalShell::setPortal + void setPortal(std::shared_ptr portal, Face face) final; + + void applyToVolume() override { + // No-op, because it's a composite portal shell + } + + /// @copydoc PortalShellBase::isValid + bool isValid() const override; + + /// @copydoc PortalShellBase::label + std::string label() const override; + + private: + BinningValue m_direction; + std::vector m_shells; + bool m_hasInnerCylinder{true}; +}; + +} // namespace Acts diff --git a/Core/include/Acts/Geometry/ProtoLayer.hpp b/Core/include/Acts/Geometry/ProtoLayer.hpp index d12e674918d..1e5d95dc025 100644 --- a/Core/include/Acts/Geometry/ProtoLayer.hpp +++ b/Core/include/Acts/Geometry/ProtoLayer.hpp @@ -33,6 +33,9 @@ struct ProtoLayer { /// The envelope parameters ExtentEnvelope envelope = ExtentEnvelope::Zero(); + /// The local transform + Transform3 transform = Transform3::Identity(); + /// Constructor /// /// Loops over a provided vector of surface and calculates the various @@ -41,8 +44,10 @@ struct ProtoLayer { /// /// @param gctx The current geometry context object, e.g. alignment /// @param surfaces The vector of surfaces to consider + /// @param transformIn The local transform to evaluate the sizing in ProtoLayer(const GeometryContext& gctx, - const std::vector& surfaces); + const std::vector& surfaces, + const Transform3& transformIn = Transform3::Identity()); /// Constructor /// @@ -52,8 +57,23 @@ struct ProtoLayer { /// /// @param gctx The current geometry context object, e.g. alignment /// @param surfaces The vector of surfaces to consider + /// @param transformIn The local transform to evaluate the sizing in ProtoLayer(const GeometryContext& gctx, - const std::vector>& surfaces); + const std::vector>& surfaces, + const Transform3& transformIn = Transform3::Identity()); + + /// Constructor + /// + /// Loops over a provided vector of surface and calculates the various + /// min/max values in one go. Also takes into account the thickness + /// of an associated DetectorElement, if it exists. + /// + /// @param gctx The current geometry context object, e.g. alignment + /// @param surfaces The vector of surfaces to consider + /// @param transformIn The local transform to evaluate the sizing in + ProtoLayer(const GeometryContext& gctx, + const std::vector>& surfaces, + const Transform3& transformIn = Transform3::Identity()); ProtoLayer() = default; @@ -81,6 +101,14 @@ struct ProtoLayer { /// @param sl the input ostream std::ostream& toStream(std::ostream& sl) const; + /// Output stream operator + /// @param sl the input ostream + /// @param pl the ProtoLayer to be printed + /// @return the output ostream + friend std::ostream& operator<<(std::ostream& sl, const ProtoLayer& pl) { + return pl.toStream(sl); + } + /// Give access to the surfaces used/assigned to the ProtoLayer const std::vector& surfaces() const; diff --git a/Core/include/Acts/Geometry/TrackingGeometry.hpp b/Core/include/Acts/Geometry/TrackingGeometry.hpp index b0ac658eecd..e8d48c5ae5e 100644 --- a/Core/include/Acts/Geometry/TrackingGeometry.hpp +++ b/Core/include/Acts/Geometry/TrackingGeometry.hpp @@ -145,6 +145,17 @@ class TrackingGeometry { const std::unordered_map& geoIdSurfaceMap() const; + /// Visualize a tracking geometry including substructure + /// @param helper The visualization helper that implement the output + /// @param gctx The geometry context + /// @param viewConfig Global view config + /// @param portalViewConfig View config for portals + /// @param sensitiveViewConfig View configuration for sensitive surfaces + void visualize(IVisualization3D& helper, const GeometryContext& gctx, + const ViewConfig& viewConfig = s_viewVolume, + const ViewConfig& portalViewConfig = s_viewPortal, + const ViewConfig& sensitiveViewConfig = s_viewSensitive) const; + private: // the known world std::shared_ptr m_world; diff --git a/Core/include/Acts/Geometry/TrackingVolume.hpp b/Core/include/Acts/Geometry/TrackingVolume.hpp index 290e5c21425..c980314fa6d 100644 --- a/Core/include/Acts/Geometry/TrackingVolume.hpp +++ b/Core/include/Acts/Geometry/TrackingVolume.hpp @@ -15,6 +15,7 @@ #include "Acts/Geometry/GeometryIdentifier.hpp" #include "Acts/Geometry/GlueVolumesDescriptor.hpp" #include "Acts/Geometry/Layer.hpp" +#include "Acts/Geometry/Portal.hpp" #include "Acts/Geometry/TrackingVolumeVisitorConcept.hpp" #include "Acts/Geometry/Volume.hpp" #include "Acts/Material/IVolumeMaterial.hpp" @@ -25,6 +26,7 @@ #include "Acts/Utilities/BinnedArray.hpp" #include "Acts/Utilities/Logger.hpp" #include "Acts/Utilities/TransformRange.hpp" +#include "Acts/Visualization/ViewConfig.hpp" #include #include @@ -181,6 +183,10 @@ class TrackingVolume : public Volume { for (const auto& bs : m_boundarySurfaces) { visitor(&(bs->surfaceRepresentation())); } + + for (const auto& portal : portals()) { + visitor(&portal.surface()); + } } // Internal structure @@ -214,6 +220,14 @@ class TrackingVolume : public Volume { volume->visitSurfaces(visitor, restrictToSensitives); } } + + for (const auto& surface : surfaces()) { + visitor(&surface); + } + + for (const auto& volume : volumes()) { + volume.visitSurfaces(visitor, restrictToSensitives); + } } /// @brief Visit all sensitive surfaces @@ -322,6 +336,25 @@ class TrackingVolume : public Volume { /// @param portal The portal to add void addPortal(std::shared_ptr portal); + using MutableSurfaceRange = + detail::TransformRange>>; + using SurfaceRange = + detail::TransformRange>>; + + /// Return all surfaces registered under this tracking volume + /// @return the range of surfaces + SurfaceRange surfaces() const; + + /// Return mutable view of the registered surfaces under this tracking volume + /// @return the range of surfaces + MutableSurfaceRange surfaces(); + + /// Add a surface to this tracking volume + /// @param surface The surface to add + void addSurface(std::shared_ptr surface); + /// Add a child volume to this tracking volume /// @param volume The volume to add /// @note The @p volume will have its mother volume assigned to @p this. @@ -454,6 +487,17 @@ class TrackingVolume : public Volume { /// - positiveFaceXY GlueVolumesDescriptor& glueVolumesDescriptor(); + /// Produces a 3D visualization of this tracking volume + /// @param helper The visualization helper describing the output format + /// @param gctx The geometry context + /// @param viewConfig The view configuration + /// @param portalViewConfig View configuration for portals + /// @param sensitiveViewConfig View configuration for sensitive surfaces + void visualize(IVisualization3D& helper, const GeometryContext& gctx, + const ViewConfig& viewConfig, + const ViewConfig& portalViewConfig, + const ViewConfig& sensitiveViewConfig) const; + private: void connectDenseBoundarySurfaces( MutableTrackingVolumeVector& confinedDenseVolumes); @@ -516,6 +560,7 @@ class TrackingVolume : public Volume { std::vector> m_volumes; std::vector> m_portals; + std::vector> m_surfaces; }; } // namespace Acts diff --git a/Core/include/Acts/Geometry/Volume.hpp b/Core/include/Acts/Geometry/Volume.hpp index a59451efe09..9217e758444 100644 --- a/Core/include/Acts/Geometry/Volume.hpp +++ b/Core/include/Acts/Geometry/Volume.hpp @@ -122,7 +122,7 @@ class Volume : public GeometryObject { /// @param gctx The geometry context /// @param viewConfig The view configuration void visualize(IVisualization3D& helper, const GeometryContext& gctx, - const ViewConfig& viewConfig = {}) const; + const ViewConfig& viewConfig) const; protected: Transform3 m_transform; diff --git a/Core/include/Acts/Propagator/PropagatorOptions.hpp b/Core/include/Acts/Propagator/PropagatorOptions.hpp index 039aed013a5..78e7edab2fe 100644 --- a/Core/include/Acts/Propagator/PropagatorOptions.hpp +++ b/Core/include/Acts/Propagator/PropagatorOptions.hpp @@ -33,13 +33,22 @@ struct PurePropagatorPlainOptions { /// Absolute maximum path length double pathLimit = std::numeric_limits::max(); - /// Required tolerance to reach surface - double surfaceTolerance = s_onSurfaceTolerance; - /// Loop protection step, it adapts the pathLimit bool loopProtection = true; /// Allowed loop fraction, 1 is a full loop double loopFraction = 0.5; + + /// Required tolerance to reach surface + double surfaceTolerance = s_onSurfaceTolerance; + + /// Constrain the propagation to selected volumes + /// @note ignored if empty + /// @note requires `VolumeConstraintAborter` aborter + std::vector constrainToVolumeIds; + /// Additional volumes to be considered as end of world + /// @note ignored if empty + /// @note requires `VolumeConstraintAborter` aborter + std::vector endOfWorldVolumeIds; }; } // namespace detail diff --git a/Core/include/Acts/Propagator/StandardAborters.hpp b/Core/include/Acts/Propagator/StandardAborters.hpp index ce460a945d7..706b0ce0697 100644 --- a/Core/include/Acts/Propagator/StandardAborters.hpp +++ b/Core/include/Acts/Propagator/StandardAborters.hpp @@ -161,7 +161,7 @@ struct ForcedSurfaceReached : SurfaceReached { : SurfaceReached(std::numeric_limits::lowest()) {} }; -/// This is the condition that the end of World has been reached +/// This is the condition that the end of world has been reached /// it then triggers an propagation abort struct EndOfWorldReached { /// boolean operator for abort condition without using the result @@ -181,6 +181,60 @@ struct EndOfWorldReached { } }; +/// This is the condition that the end of world has been reached +/// it then triggers a propagation abort +struct VolumeConstraintAborter { + /// boolean operator for abort condition without using the result + /// + /// @tparam propagator_state_t Type of the propagator state + /// @tparam navigator_t Type of the navigator + /// + /// @param [in,out] state The propagation state object + /// @param [in] navigator The navigator object + /// @param logger a logger instance + template + bool checkAbort(propagator_state_t& state, const stepper_t& /*stepper*/, + const navigator_t& navigator, const Logger& logger) const { + const auto& constrainToVolumeIds = state.options.constrainToVolumeIds; + const auto& endOfWorldVolumeIds = state.options.endOfWorldVolumeIds; + + if (constrainToVolumeIds.empty() && endOfWorldVolumeIds.empty()) { + return false; + } + const auto* currentVolume = navigator.currentVolume(state.navigation); + + // We need a volume to check its ID + if (currentVolume == nullptr) { + return false; + } + + const auto currentVolumeId = + static_cast(currentVolume->geometryId().volume()); + + if (!constrainToVolumeIds.empty() && + std::find(constrainToVolumeIds.begin(), constrainToVolumeIds.end(), + currentVolumeId) == constrainToVolumeIds.end()) { + ACTS_VERBOSE( + "VolumeConstraintAborter aborter | Abort with volume constrain " + << currentVolumeId); + return true; + } + + if (!endOfWorldVolumeIds.empty() && + std::find(endOfWorldVolumeIds.begin(), endOfWorldVolumeIds.end(), + currentVolumeId) != endOfWorldVolumeIds.end()) { + ACTS_VERBOSE( + "VolumeConstraintAborter aborter | Abort with additional end of " + "world volume " + << currentVolumeId); + return true; + } + + return false; + } +}; + /// Aborter that checks if the propagation has reached any surface struct AnySurfaceReached { template using CylindricalSpacePointGrid = Acts::Grid< std::vector, Acts::Axis, + Acts::Axis, Acts::Axis>; /// Cylindrical Binned Group @@ -36,22 +36,25 @@ using CylindricalBinnedGroupIterator = Acts::BinnedGroupIterator< struct CylindricalSpacePointGridConfig { // minimum pT to be found by seedFinder - float minPt = 0; + float minPt = 0 * Acts::UnitConstants::MeV; // maximum extension of sensitive detector layer relevant for seeding as // distance from x=y=0 (i.e. in r) - float rMax = 0; + float rMax = 320 * Acts::UnitConstants::mm; + // maximum extension of sensitive detector layer relevant for seeding as + // distance from x=y=0 (i.e. in r) + float rMin = 0 * Acts::UnitConstants::mm; // maximum extension of sensitive detector layer relevant for seeding in // positive direction in z - float zMax = 0; + float zMax = 0 * Acts::UnitConstants::mm; // maximum extension of sensitive detector layer relevant for seeding in // negative direction in z - float zMin = 0; + float zMin = 0 * Acts::UnitConstants::mm; // maximum distance in r from middle space point to bottom or top spacepoint - float deltaRMax = 0; + float deltaRMax = 0 * Acts::UnitConstants::mm; // maximum forward direction expressed as cot(theta) float cotThetaMax = 0; // maximum impact parameter in mm - float impactMax = 0; + float impactMax = 0 * Acts::UnitConstants::mm; // minimum phi value for phiAxis construction float phiMin = -M_PI; // maximum phi value for phiAxis construction @@ -66,7 +69,8 @@ struct CylindricalSpacePointGridConfig { // maximum number of phi bins int maxPhiBins = 10000; // enable non equidistant binning in z - std::vector zBinEdges; + std::vector zBinEdges{}; + std::vector rBinEdges{}; bool isInInternalUnits = false; CylindricalSpacePointGridConfig toInternalUnits() const { if (isInInternalUnits) { @@ -78,6 +82,7 @@ struct CylindricalSpacePointGridConfig { CylindricalSpacePointGridConfig config = *this; config.isInInternalUnits = true; config.minPt /= 1_MeV; + config.rMin /= 1_mm; config.rMax /= 1_mm; config.zMax /= 1_mm; config.zMin /= 1_mm; @@ -121,7 +126,7 @@ class CylindricalSpacePointGridCreator { const Acts::SeedFinderOptions& options, Acts::CylindricalSpacePointGrid& grid, external_spacepoint_iterator_t spBegin, - external_spacepoint_iterator_t spEnd, Acts::Extent& rRangeSPExtent); + external_spacepoint_iterator_t spEnd); }; } // namespace Acts diff --git a/Core/include/Acts/Seeding/detail/CylindricalSpacePointGrid.ipp b/Core/include/Acts/Seeding/detail/CylindricalSpacePointGrid.ipp index ad23beeaf77..5d8c886f980 100644 --- a/Core/include/Acts/Seeding/detail/CylindricalSpacePointGrid.ipp +++ b/Core/include/Acts/Seeding/detail/CylindricalSpacePointGrid.ipp @@ -103,7 +103,7 @@ Acts::CylindricalSpacePointGridCreator::createGrid( config.phiMin, config.phiMax, phiBins); // vector that will store the edges of the bins of z - std::vector zValues; + std::vector zValues{}; // If zBinEdges is not defined, calculate the edges as zMin + bin * zBinSize if (config.zBinEdges.empty()) { @@ -130,9 +130,19 @@ Acts::CylindricalSpacePointGridCreator::createGrid( } } + std::vector rValues{}; + rValues.reserve(std::max(2ul, config.rBinEdges.size())); + if (config.rBinEdges.empty()) { + rValues = {config.rMin, config.rMax}; + } else { + rValues.insert(rValues.end(), config.rBinEdges.begin(), + config.rBinEdges.end()); + } + Axis zAxis(std::move(zValues)); + Axis rAxis(std::move(rValues)); return Acts::CylindricalSpacePointGrid( - std::make_tuple(std::move(phiAxis), std::move(zAxis))); + std::make_tuple(std::move(phiAxis), std::move(zAxis), std::move(rAxis))); } template & grid, external_spacepoint_iterator_t spBegin, - external_spacepoint_iterator_t spEnd, Acts::Extent& rRangeSPExtent) { - using iterated_value_t = - typename std::iter_value_t; - using iterated_t = typename std::remove_const_t< - typename std::remove_pointer_t>; - static_assert(!std::is_pointer_v, - "Iterator must contain pointers to space points"); - static_assert(std::same_as, - "Iterator does not contain type this class was templated with"); - + external_spacepoint_iterator_t spEnd) { if (!config.isInInternalUnits) { throw std::runtime_error( "SeedFinderConfig not in ACTS internal units in BinnedSPGroup"); @@ -164,13 +165,13 @@ void Acts::CylindricalSpacePointGridCreator::fillGrid( "SeedFinderOptions not in ACTS internal units in BinnedSPGroup"); } - // sort by radius - // add magnitude of beamPos to rMax to avoid excluding measurements - // create number of bins equal to number of millimeters rMax - // (worst case minR: configured minR + 1mm) - // binSizeR allows to increase or reduce numRBins if needed - std::size_t numRBins = static_cast( - (config.rMax + options.beamPos.norm()) / config.binSizeR); + // Space points are assumed to be ALREADY CORRECTED for beamspot position + // phi, z and r space point selection comes naturally from the + // grid axis definition. No need to explicitly cut on those values. + // If a space point is outside the validity range of these quantities + // it goes in an over- or under-flow bin. + // Additional cuts can be applied by customizing the space point selector + // in the config object. // keep track of changed bins while sorting std::vector usedBinIndex(grid.size(), false); @@ -181,40 +182,15 @@ void Acts::CylindricalSpacePointGridCreator::fillGrid( for (external_spacepoint_iterator_t it = spBegin; it != spEnd; it++, ++counter) { const external_spacepoint_t& sp = *it; - float spX = sp.x(); - float spY = sp.y(); - float spZ = sp.z(); - - // store x,y,z values in extent - rRangeSPExtent.extend({spX, spY, spZ}); // remove SPs according to experiment specific cuts if (!config.spacePointSelector(sp)) { continue; } - // remove SPs outside z and phi region - if (spZ > config.zMax || spZ < config.zMin) { - continue; - } - - float spPhi = std::atan2(spY, spX); - if (spPhi > config.phiMax || spPhi < config.phiMin) { - continue; - } - - // calculate r-Bin index and protect against overflow (underflow not - // possible) - std::size_t rIndex = - static_cast(sp.radius() / config.binSizeR); - // if index out of bounds, the SP is outside the region of interest - if (rIndex >= numRBins) { - continue; - } - // fill rbins into grid - std::size_t globIndex = - grid.globalBinFromPosition(Acts::Vector2{sp.phi(), sp.z()}); + std::size_t globIndex = grid.globalBinFromPosition( + Acts::Vector3{sp.phi(), sp.z(), sp.radius()}); auto& rbin = grid.at(globIndex); rbin.push_back(&sp); diff --git a/Core/include/Acts/Surfaces/AnnulusBounds.hpp b/Core/include/Acts/Surfaces/AnnulusBounds.hpp index 17e64f2a505..f1283ec63b8 100644 --- a/Core/include/Acts/Surfaces/AnnulusBounds.hpp +++ b/Core/include/Acts/Surfaces/AnnulusBounds.hpp @@ -133,19 +133,20 @@ class AnnulusBounds : public DiscBounds { std::vector corners() const; /// This method returns the xy coordinates of the four corners of the - /// bounds in module coordinates (in x/y) + /// bounds in module coordinates (in x/y), and if quarterSegments is bigger or + /// equal to 0, the curved part of the segment is included and approximated + /// by the corresponding number of segments. + /// /// Starting from the upper right (max R, pos locX) and proceeding clock-wise /// i.e. (max R; pos locX), (min R; pos locX), (min R; neg loc X), (max R: neg /// locX) /// - /// @param lseg the number of segments used to approximate - /// and eventually curved line - /// - /// @note that that if @c lseg > 0, the extrema points are given, - /// which may slightly alter the number of segments returned + /// @param quarterSegments the number of segments used to approximate + /// a quarter of a circle /// /// @return vector for vertices in 2D - std::vector vertices(unsigned int lseg) const override; + std::vector vertices( + unsigned int quarterSegments = 2u) const override; /// This method returns inner radius double rMin() const final; diff --git a/Core/include/Acts/Surfaces/ConeSurface.hpp b/Core/include/Acts/Surfaces/ConeSurface.hpp index c15d84d1c23..a2b2572bba8 100644 --- a/Core/include/Acts/Surfaces/ConeSurface.hpp +++ b/Core/include/Acts/Surfaces/ConeSurface.hpp @@ -200,15 +200,16 @@ class ConeSurface : public RegularSurface { /// Return a Polyhedron for the surfaces /// /// @param gctx The current geometry context object, e.g. alignment - /// @param lseg Number of segments along curved lines, it represents - /// the full 2*M_PI coverange, if lseg is set to 1 only the extrema - /// are given - /// @note that a surface transform can invalidate the extrema - /// in the transformed space + /// @param quarterSegments Number of segments used to approximate a quarter + /// + /// @note The phi extrema points at (-pi, -1/2 pi, 0, 1/2 pi) that fall within + /// the surface will be inserted to guarantee an appropriate extent + /// measurement in x and y /// /// @return A list of vertices and a face/facett description of it - Polyhedron polyhedronRepresentation(const GeometryContext& gctx, - std::size_t lseg) const override; + Polyhedron polyhedronRepresentation( + const GeometryContext& gctx, + unsigned int quarterSegments = 2u) const override; /// Return properly formatted class name for screen output std::string name() const override; diff --git a/Core/include/Acts/Surfaces/ConvexPolygonBounds.hpp b/Core/include/Acts/Surfaces/ConvexPolygonBounds.hpp index 2f116ddcee5..e802056e7fd 100644 --- a/Core/include/Acts/Surfaces/ConvexPolygonBounds.hpp +++ b/Core/include/Acts/Surfaces/ConvexPolygonBounds.hpp @@ -114,13 +114,13 @@ class ConvexPolygonBounds : public ConvexPolygonBoundsBase { /// Return the vertices /// - /// @param lseg the number of segments used to approximate + /// @param ignoredSegments the number of segments used to approximate /// and eventually curved line /// /// @note the number of segments is ignored in this representation /// /// @return vector for vertices in 2D - std::vector vertices(unsigned int lseg = 1) const final; + std::vector vertices(unsigned int ignoredSegments = 0u) const final; /// Return a rectangle bounds object that encloses this polygon. /// @return The rectangular bounds diff --git a/Core/include/Acts/Surfaces/ConvexPolygonBounds.ipp b/Core/include/Acts/Surfaces/ConvexPolygonBounds.ipp index 505d9f95d82..9f1a61955ae 100644 --- a/Core/include/Acts/Surfaces/ConvexPolygonBounds.ipp +++ b/Core/include/Acts/Surfaces/ConvexPolygonBounds.ipp @@ -111,7 +111,7 @@ bool Acts::ConvexPolygonBounds::inside( template std::vector Acts::ConvexPolygonBounds::vertices( - unsigned int /*lseg*/) const { + unsigned int /*ignoredSegments*/) const { return {m_vertices.begin(), m_vertices.end()}; } diff --git a/Core/include/Acts/Surfaces/CylinderBounds.hpp b/Core/include/Acts/Surfaces/CylinderBounds.hpp index 7453029c213..51508055e06 100644 --- a/Core/include/Acts/Surfaces/CylinderBounds.hpp +++ b/Core/include/Acts/Surfaces/CylinderBounds.hpp @@ -112,12 +112,18 @@ class CylinderBounds : public SurfaceBounds { /// Returns true for full phi coverage bool coversFullAzimuth() const; - /// Create the bows/circles on either side of the cylinder + /// Create the bow/circle vertices on either side of the cylinder /// - /// @param trans is the global transform - /// @param lseg are the numbero if phi segments - std::vector createCircles(const Transform3 trans, - std::size_t lseg) const; + /// @param transform is the global transform + /// @param quarterSegments is the number of segments to approximate a quarter + /// of a circle. In order to symmetrize fully closed and sectoral cylinders, + /// also in the first case the two end points are given (albeit they overlap) + /// in -pi / pi + /// + /// @return a singlevector containing the vertices from one side and then + /// from the other side consecutively + std::vector circleVertices(const Transform3 transform, + unsigned int quarterSegments) const; /// Output Method for std::ostream std::ostream& toStream(std::ostream& sl) const final; diff --git a/Core/include/Acts/Surfaces/CylinderSurface.hpp b/Core/include/Acts/Surfaces/CylinderSurface.hpp index 82bc1c68bc2..09b953afce1 100644 --- a/Core/include/Acts/Surfaces/CylinderSurface.hpp +++ b/Core/include/Acts/Surfaces/CylinderSurface.hpp @@ -214,14 +214,20 @@ class CylinderSurface : public RegularSurface { /// Return a Polyhedron for a cylinder /// + /// This method represents the cylinder as a polyhedron with a given number + /// of segments to represent a quarter of a full circle. The polyedron will + /// consist of the vertices of the cylinder on both sides, and faces between + /// them, both as rectangular faces and as triangular faces. + /// /// @param gctx The current geometry context object, e.g. alignment - /// @param lseg Number of segments along curved lines, it represents - /// the full 2*M_PI coverange, if lseg is set to 1 only the extrema - /// are given + /// @param quarterSegments The number of segments to approximate a quarter of the + /// full circle; it's chosen to be 1, only the extrema points (-pi, -0.5pi, + /// 0., 0.5pi) are inserted to capture the correct extent in the x-y plane /// /// @return A list of vertices and a face/facett description of it - Polyhedron polyhedronRepresentation(const GeometryContext& gctx, - std::size_t lseg) const override; + Polyhedron polyhedronRepresentation( + const GeometryContext& gctx, + unsigned int quarterSegments = 2u) const override; /// Calculate the derivative of path length at the geometry constraint or /// point-of-closest-approach w.r.t. alignment parameters of the surface (i.e. diff --git a/Core/include/Acts/Surfaces/DiamondBounds.hpp b/Core/include/Acts/Surfaces/DiamondBounds.hpp index ddaf727a3e9..7497bd22309 100644 --- a/Core/include/Acts/Surfaces/DiamondBounds.hpp +++ b/Core/include/Acts/Surfaces/DiamondBounds.hpp @@ -90,15 +90,13 @@ class DiamondBounds : public PlanarBounds { bool inside(const Vector2& lposition, const BoundaryTolerance& boundaryTolerance) const final; - /// Return the vertices + /// Return the vertices that describe this shape /// - /// @param lseg the number of segments used to approximate - /// and eventually curved line - /// - /// @note the number of segments is ignored for this representation + /// @param ignoredSegments is an ignored parameter only used for + /// curved bound segments /// /// @return vector for vertices in 2D - std::vector vertices(unsigned int lseg = 1) const final; + std::vector vertices(unsigned int ignoredSegments = 0u) const final; // Bounding box representation const RectangleBounds& boundingBox() const final; @@ -128,8 +126,7 @@ inline std::vector DiamondBounds::values() const { } inline void DiamondBounds::checkConsistency() noexcept(false) { - if (std::any_of(m_values.begin(), m_values.end(), - [](auto v) { return v <= 0.; })) { + if (std::ranges::any_of(m_values, [](auto v) { return v <= 0.; })) { throw std::invalid_argument("DiamondBounds: negative half length."); } if (get(eHalfLengthXnegY) > get(eHalfLengthXzeroY) || diff --git a/Core/include/Acts/Surfaces/DiscBounds.hpp b/Core/include/Acts/Surfaces/DiscBounds.hpp index 22bcce3f960..626f8e2405c 100644 --- a/Core/include/Acts/Surfaces/DiscBounds.hpp +++ b/Core/include/Acts/Surfaces/DiscBounds.hpp @@ -29,14 +29,13 @@ class DiscBounds : public SurfaceBounds { /// Return the vertices /// - /// @param lseg the number of segments used to approximate - /// and eventually curved line, the number refers to full 2*PI - /// - /// @note that the extremas are given, which may slightly alter the - /// number of segments returned + /// @param quarterSegments The number of segments used to describe a quarter + /// of a circle, if it is 1, then only the extrema points in phi are inserted + /// next to the segment corners /// /// @return vector for vertices in 2D - virtual std::vector vertices(unsigned int lseg) const = 0; + virtual std::vector vertices( + unsigned int quarterSegments = 2u) const = 0; /// Returns a reference radius for binning virtual double binningValueR() const = 0; diff --git a/Core/include/Acts/Surfaces/DiscSurface.hpp b/Core/include/Acts/Surfaces/DiscSurface.hpp index 112ec0b30d2..e2c10df4023 100644 --- a/Core/include/Acts/Surfaces/DiscSurface.hpp +++ b/Core/include/Acts/Surfaces/DiscSurface.hpp @@ -312,13 +312,12 @@ class DiscSurface : public RegularSurface { /// Return a Polyhedron for the surfaces /// /// @param gctx The current geometry context object, e.g. alignment - /// @param lseg Number of segments along curved lines, it represents - /// the full 2*M_PI coverange, if lseg is set to 1 only the extrema - /// are given + /// @param quarterSegments Number of segments used to describe the + /// quarter of a full circle /// /// @return A list of vertices and a face/facett description of it - Polyhedron polyhedronRepresentation(const GeometryContext& gctx, - std::size_t lseg) const override; + Polyhedron polyhedronRepresentation( + const GeometryContext& gctx, unsigned int quarterSegments) const override; /// Calculate the derivative of bound track parameters local position w.r.t. /// position in local 3D Cartesian coordinates diff --git a/Core/include/Acts/Surfaces/DiscTrapezoidBounds.hpp b/Core/include/Acts/Surfaces/DiscTrapezoidBounds.hpp index 1e4d9d7706a..a3e4e5ea28f 100644 --- a/Core/include/Acts/Surfaces/DiscTrapezoidBounds.hpp +++ b/Core/include/Acts/Surfaces/DiscTrapezoidBounds.hpp @@ -123,13 +123,11 @@ class DiscTrapezoidBounds : public DiscBounds { /// This method returns the xy coordinates of the four corners of the /// bounds in module coorindates (in xy) /// - /// @param lseg the number of segments used to approximate - /// and eventually curved line - /// - /// @note that the number of segments are ignored for this surface + /// @param ignoredSegments is an ignored parameter only used for + /// curved bound segments /// /// @return vector for vertices in 2D - std::vector vertices(unsigned int lseg) const final; + std::vector vertices(unsigned int ignoredSegments = 0u) const final; private: std::array m_values; diff --git a/Core/include/Acts/Surfaces/EllipseBounds.hpp b/Core/include/Acts/Surfaces/EllipseBounds.hpp index dc6983b86bb..aec08d10381 100644 --- a/Core/include/Acts/Surfaces/EllipseBounds.hpp +++ b/Core/include/Acts/Surfaces/EllipseBounds.hpp @@ -92,14 +92,13 @@ class EllipseBounds : public PlanarBounds { /// Return the vertices /// - /// @param lseg the number of segments used to approximate - /// and eventually curved line, here it refers to the full 2PI Ellipse - /// - /// @note the number of segments to may be altered by also providing - /// the extremas in all direction + /// @param quarterSegments is the number of segments to approximate a quarter + /// of a circle. In order to symmetrize fully closed and sectoral cylinders, + /// also in the first case the two end points are given (albeit they overlap) + /// in -pi / pi /// /// @return vector for vertices in 2D - std::vector vertices(unsigned int lseg) const final; + std::vector vertices(unsigned int quarterSegments) const final; // Bounding box representation const RectangleBounds& boundingBox() const final; diff --git a/Core/include/Acts/Surfaces/PerigeeSurface.hpp b/Core/include/Acts/Surfaces/PerigeeSurface.hpp index 37b1044f0ce..1d913ecc43e 100644 --- a/Core/include/Acts/Surfaces/PerigeeSurface.hpp +++ b/Core/include/Acts/Surfaces/PerigeeSurface.hpp @@ -76,11 +76,11 @@ class PerigeeSurface : public LineSurface { /// Return a Polyhedron for the surfaces /// /// @param gctx The current geometry context object, e.g. alignment - /// @param lseg is ignored for a perigee @note ignored + /// @param ingoreSegments is an ignored parameter /// /// @return A list of vertices and a face/facett description of it Polyhedron polyhedronRepresentation(const GeometryContext& gctx, - std::size_t lseg) const final; + unsigned int ingoreSegments) const final; protected: /// Output Method for std::ostream diff --git a/Core/include/Acts/Surfaces/PlanarBounds.hpp b/Core/include/Acts/Surfaces/PlanarBounds.hpp index 8c4363dbbc3..28bc0e42b60 100644 --- a/Core/include/Acts/Surfaces/PlanarBounds.hpp +++ b/Core/include/Acts/Surfaces/PlanarBounds.hpp @@ -26,14 +26,15 @@ class PlanarBounds : public SurfaceBounds { public: /// Return the vertices /// - /// @param lseg the number of segments used to approximate - /// and eventually curved line + /// @param quarterSegments is the number of segments used to describe curved + /// segments in a quarter of the phi range. If it is 1, then only the extrema + /// points in phi are inserted next to the segment corners. /// - /// @note that the extremas are given, which may slightly alter the - /// number of segments returned + /// @note for planar bounds without curved segments @c quarterSegments is ignored /// /// @return vector for vertices in 2D - virtual std::vector vertices(unsigned int lseg = 1) const = 0; + virtual std::vector vertices( + unsigned int quarterSegments = 2u) const = 0; /// Bounding box parameters /// diff --git a/Core/include/Acts/Surfaces/PlaneSurface.hpp b/Core/include/Acts/Surfaces/PlaneSurface.hpp index 866cb4d4585..2bc65398f8d 100644 --- a/Core/include/Acts/Surfaces/PlaneSurface.hpp +++ b/Core/include/Acts/Surfaces/PlaneSurface.hpp @@ -198,13 +198,15 @@ class PlaneSurface : public RegularSurface { /// Return a Polyhedron for the surfaces /// /// @param gctx The current geometry context object, e.g. alignment - /// @param lseg Number of segments along curved lines, it represents - /// the full 2*M_PI coverange, if lseg is set to 1 only the extrema - /// are given + /// @param quarterSegments is the number of segments used to describe curved + /// segments in a quarter of the phi range. If it is 1, then only the extrema + /// points in phi are inserted next to the segment corners. + /// + /// @note for planar surfaces without curved segments @c quarterSegments is ignored /// /// @return A list of vertices and a face/facett description of it - Polyhedron polyhedronRepresentation(const GeometryContext& gctx, - std::size_t lseg) const override; + Polyhedron polyhedronRepresentation( + const GeometryContext& gctx, unsigned int quarterSegments) const override; /// Return properly formatted class name for screen output std::string name() const override; diff --git a/Core/include/Acts/Surfaces/RectangleBounds.hpp b/Core/include/Acts/Surfaces/RectangleBounds.hpp index 7ad67f3aafb..aba1743fa74 100644 --- a/Core/include/Acts/Surfaces/RectangleBounds.hpp +++ b/Core/include/Acts/Surfaces/RectangleBounds.hpp @@ -86,13 +86,12 @@ class RectangleBounds : public PlanarBounds { /// Return the vertices /// - /// @param lseg the number of segments used to approximate - /// and eventually curved line - /// + /// @param quarterSegments is the number of segments used to describe curved + /// segments in a quarter of the phi range. /// @note the number of segments is ignored in this representation /// /// @return vector for vertices in 2D - std::vector vertices(unsigned int lseg = 1) const final; + std::vector vertices(unsigned int quarterSegments = 0u) const final; // Bounding box representation const RectangleBounds& boundingBox() const final; diff --git a/Core/include/Acts/Surfaces/StrawSurface.hpp b/Core/include/Acts/Surfaces/StrawSurface.hpp index 88fd8423525..706bb7d9823 100644 --- a/Core/include/Acts/Surfaces/StrawSurface.hpp +++ b/Core/include/Acts/Surfaces/StrawSurface.hpp @@ -92,13 +92,13 @@ class StrawSurface : public LineSurface { /// Return a Polyhedron for the surfaces /// /// @param gctx The current geometry context object, e.g. alignment - /// @param lseg Number of segments along curved lines, it represents - /// the full 2*M_PI coverange, if lseg is set to 1 only the extrema - /// are given @note if lseg is set to 1 then only the straw is created + /// @param quarterSegments is the number of segments used to describe curved + /// segments in a quarter of the phi range. If it is 1, then only the extrema + /// points in phi are inserted next to the segment corners. /// /// @return A list of vertices and a face/facett description of it Polyhedron polyhedronRepresentation(const GeometryContext& gctx, - std::size_t lseg) const final; + unsigned int quarterSegments) const final; }; inline Surface::SurfaceType StrawSurface::type() const { diff --git a/Core/include/Acts/Surfaces/Surface.hpp b/Core/include/Acts/Surfaces/Surface.hpp index c93e7d3c9aa..79153e8c98e 100644 --- a/Core/include/Acts/Surfaces/Surface.hpp +++ b/Core/include/Acts/Surfaces/Surface.hpp @@ -418,20 +418,21 @@ class Surface : public virtual GeometryObject, /// Return properly formatted class name virtual std::string name() const = 0; - /// Return a Polyhedron for this object + /// Return a Polyhedron for surface objects /// /// @param gctx The current geometry context object, e.g. alignment - /// @param lseg Number of segments along curved lines, if the lseg - /// is set to one, only the corners and the extrema are given, - /// otherwise it represents the number of segments for a full 2*M_PI - /// circle and is scaled to the relevant sector + /// @param quarterSegments The number of segemtns to approximate a 0.5*pi sector, + /// which represents a quarter of the full circle + /// + /// @note In order to symmetrize the code between sectoral and closed cylinders + /// in case of closed cylinders, both (-pi, pi) are given as separate vertices /// /// @note An internal surface transform can invalidate the extrema /// in the transformed space /// /// @return A list of vertices and a face/facett description of it - virtual Polyhedron polyhedronRepresentation(const GeometryContext& gctx, - std::size_t lseg) const = 0; + virtual Polyhedron polyhedronRepresentation( + const GeometryContext& gctx, unsigned int quarterSegments = 2u) const = 0; /// The derivative of bound track parameters w.r.t. alignment /// parameters of its reference surface (i.e. local frame origin in @@ -481,7 +482,7 @@ class Surface : public virtual GeometryObject, const GeometryContext& gctx, const Vector3& position) const = 0; void visualize(IVisualization3D& helper, const GeometryContext& gctx, - const ViewConfig& viewConfig = {}) const; + const ViewConfig& viewConfig = s_viewSurface) const; protected: /// Output Method for std::ostream, to be overloaded by child classes diff --git a/Core/include/Acts/Surfaces/SurfaceConcept.hpp b/Core/include/Acts/Surfaces/SurfaceConcept.hpp index e09b420ee9f..2abcda1d5d7 100644 --- a/Core/include/Acts/Surfaces/SurfaceConcept.hpp +++ b/Core/include/Acts/Surfaces/SurfaceConcept.hpp @@ -87,7 +87,7 @@ concept SurfaceConcept = requires(S s, const S cs, S s2, const S cs2, { cs.name() } -> std::same_as; { - cs.polyhedronRepresentation(gctx, std::declval()) + cs.polyhedronRepresentation(gctx, std::declval()) } -> std::same_as; { diff --git a/Core/include/Acts/Surfaces/TrapezoidBounds.hpp b/Core/include/Acts/Surfaces/TrapezoidBounds.hpp index 3f116dc4110..8ccd3a5c928 100644 --- a/Core/include/Acts/Surfaces/TrapezoidBounds.hpp +++ b/Core/include/Acts/Surfaces/TrapezoidBounds.hpp @@ -108,13 +108,13 @@ class TrapezoidBounds : public PlanarBounds { /// Return the vertices /// - /// @param lseg the number of segments used to approximate - /// and eventually curved line + /// @param ignoredSegments is and ignored parameter used to describe + /// the number of segments to approximate curved sectors. /// /// @note the number of segments is ignored in this representation /// /// @return vector for vertices in 2D - std::vector vertices(unsigned int lseg = 1) const final; + std::vector vertices(unsigned int ignoredSegments = 0u) const final; // Bounding box representation const RectangleBounds& boundingBox() const final; diff --git a/Core/include/Acts/Surfaces/detail/FacesHelper.hpp b/Core/include/Acts/Surfaces/detail/FacesHelper.hpp index 260f7ce3b01..ca2922c325e 100644 --- a/Core/include/Acts/Surfaces/detail/FacesHelper.hpp +++ b/Core/include/Acts/Surfaces/detail/FacesHelper.hpp @@ -21,7 +21,7 @@ namespace Acts::detail { struct FacesHelper { using FaceVector = std::vector; - /// @brief This method words for all convex type surface setups + /// @brief This method works for all convex type surface setups /// It includes: /// /// Rectangle / Triangle / Polygon @@ -60,14 +60,12 @@ struct FacesHelper { /// vector is splittable in half into the two bows. /// /// @param vertices The vector of vertices - /// @param fullTwoPi The indicator if the concentric face is closed static std::pair cylindricalFaceMesh( - const std::vector& vertices, bool fullTwoPi = true) { + const std::vector& vertices) { FaceVector faces; FaceVector triangularMesh; std::size_t nqfaces = static_cast(0.5 * vertices.size()); - std::size_t reduce = (!fullTwoPi) ? 1 : 0; - for (std::size_t iface = 0; iface < nqfaces - reduce; ++iface) { + for (std::size_t iface = 0; iface < nqfaces - 1; ++iface) { std::size_t p2 = (iface + 1 == nqfaces) ? 0 : iface + 1; std::vector face = {iface, p2, p2 + nqfaces, nqfaces + iface}; diff --git a/Core/include/Acts/Surfaces/detail/VerticesHelper.hpp b/Core/include/Acts/Surfaces/detail/VerticesHelper.hpp index 71938626eaf..3e63c7189e6 100644 --- a/Core/include/Acts/Surfaces/detail/VerticesHelper.hpp +++ b/Core/include/Acts/Surfaces/detail/VerticesHelper.hpp @@ -22,51 +22,53 @@ namespace Acts::detail::VerticesHelper { /// A method that inserts the cartesian extrema points and segments /// a curved segment into sub segments /// -/// @param phiMin the minimum Phi of the bounds object -/// @param phiMax the maximum Phi of the bounds object +/// @param phiMin the minimum phi value +/// @param phiMax The second phi value /// @param phiRef is a vector of reference phi values to be included as well -/// @param phiTolerance is the tolerance for reference phi insertion -/// @return a vector +/// @param quarterSegments number of segments used to approximate a segment quarter +/// +/// @return a vector of generated phi values std::vector phiSegments(ActsScalar phiMin = -M_PI, ActsScalar phiMax = M_PI, const std::vector& phiRefs = {}, - ActsScalar phiTolerance = 1e-6); + unsigned int quarterSegments = 2u); /// Helper method to create a regular 2 or 3 D segment -/// between two phi values +/// between two phi values with a given number of segments +/// +/// It will insert the phi at extrema points and reference points, it uses +/// a minimum approximation of a circle with 8 segments /// /// @tparam vertex_t Type of vertex to be applied /// @tparam transform_t Optional transform /// -/// @param vertices [in,out] The 3D vertices to be filled -/// @param rxy The radius description if first +/= second: ellipse -/// @param phi1 The first phi value -/// @param phi2 The second phi value -/// @param lseg The number of segments for full 2*PI -/// @param addon The additional segments to be built +/// @param rXY The radius description if first +/= second: ellipse +/// @param phiMin the minimum phi value +/// @param phiMax the second phi value +/// @param phiRef is a vector of reference phi values to be included as well +/// @param quarterSegments number of segments used to approximate a segment quarter /// @param offset The out of plane offset position of the bow /// @param transform The transform applied (optional) +/// +/// @return a vector of vertices template -void createSegment(std::vector& vertices, - std::pair rxy, ActsScalar phi1, - ActsScalar phi2, unsigned int lseg, int addon = 0, - const vertex_t& offset = vertex_t::Zero(), - const transform_t& transform = transform_t::Identity()) { - // Calculate the number of segments - 1 is the minimum - unsigned int segs = - static_cast(std::abs(phi2 - phi1) / (2 * M_PI) * lseg); - segs = segs > 0 ? segs : 1; - ActsScalar phistep = (phi2 - phi1) / segs; - // Create the segments - for (unsigned int iphi = 0; iphi < segs + addon; ++iphi) { - ActsScalar phi = phi1 + iphi * phistep; +std::vector segmentVertices( + std::pair rXY, ActsScalar phiMin, ActsScalar phiMax, + const std::vector& phiRefs = {}, + unsigned int quarterSegments = 2u, + const vertex_t& offset = vertex_t::Zero(), + const transform_t& transform = transform_t::Identity()) { + std::vector vertices; + std::vector phis = + phiSegments(phiMin, phiMax, phiRefs, quarterSegments); + for (ActsScalar phi : phis) { vertex_t vertex = vertex_t::Zero(); - vertex(0) = rxy.first * std::cos(phi); - vertex(1) = rxy.second * std::sin(phi); - + vertex(0) = rXY.first * std::cos(phi); + vertex(1) = rXY.second * std::sin(phi); vertex = vertex + offset; vertices.push_back(transform * vertex); } + return vertices; } /// Construct vertices on an ellipse-like bound object. @@ -76,14 +78,15 @@ void createSegment(std::vector& vertices, /// @param outerRx The radius of the outer ellipse (in x) /// @param outerRy The radius of the outer ellipse (in y) /// @param avgPhi The phi direction of the center if sector -/// @param halfPhi The half phi sector if sector -/// @param lseg The number of segments for for a full 2*pi segment +/// @param halfPhi The half phi sector of the ellipse +/// @param quarterSegments number of segments used to approximate a segment quarter +/// /// @return a vector of 2d-vectors std::vector ellipsoidVertices(ActsScalar innerRx, ActsScalar innerRy, ActsScalar outerRx, ActsScalar outerRy, ActsScalar avgPhi = 0., ActsScalar halfPhi = M_PI, - unsigned int lseg = 1); + unsigned int quarterSegments = 2u); /// Construct vertices on an disc/wheel-like bound object. /// @@ -91,12 +94,14 @@ std::vector ellipsoidVertices(ActsScalar innerRx, ActsScalar innerRy, /// @param outerR The radius of the outer circle (sector) /// @param avgPhi The phi direction of the center if sector /// @param halfPhi The half phi sector if sector -/// @param lseg The number of segments for for a full 2*pi segment +/// @param quarterSegments number of segments used to approximate a segment quarter +/// /// @return a vector of 2d-vectors std::vector circularVertices(ActsScalar innerR, ActsScalar outerR, ActsScalar avgPhi = 0., ActsScalar halfPhi = M_PI, - unsigned int lseg = 1); + unsigned int quarterSegments = 2u); + /// Check if the point is inside the polygon w/o any tolerances. /// /// @tparam vertex_container_t is an iterable container diff --git a/Core/include/Acts/TrackFinding/CombinatorialKalmanFilter.hpp b/Core/include/Acts/TrackFinding/CombinatorialKalmanFilter.hpp index 4878724f99e..b28b7372252 100644 --- a/Core/include/Acts/TrackFinding/CombinatorialKalmanFilter.hpp +++ b/Core/include/Acts/TrackFinding/CombinatorialKalmanFilter.hpp @@ -596,15 +596,19 @@ class CombinatorialKalmanFilter { const bool isEndOfWorldReached = endOfWorldReached.checkAbort(state, stepper, navigator, logger()); + const bool isVolumeConstraintReached = volumeConstraintAborter.checkAbort( + state, stepper, navigator, logger()); const bool isPathLimitReached = result.pathLimitReached.checkAbort( state, stepper, navigator, logger()); const bool isTargetReached = targetReached.checkAbort(state, stepper, navigator, logger()); const bool allBranchesStopped = result.activeBranches.empty(); if (isEndOfWorldReached || isPathLimitReached || isTargetReached || - allBranchesStopped) { + allBranchesStopped || isVolumeConstraintReached) { if (isEndOfWorldReached) { ACTS_VERBOSE("End of world reached"); + } else if (isVolumeConstraintReached) { + ACTS_VERBOSE("Volume constraint reached"); } else if (isPathLimitReached) { ACTS_VERBOSE("Path limit reached"); } else if (isTargetReached) { @@ -1173,6 +1177,9 @@ class CombinatorialKalmanFilter { /// End of world aborter EndOfWorldReached endOfWorldReached; + /// Volume constraint aborter + VolumeConstraintAborter volumeConstraintAborter; + /// Actor logger instance const Logger* actorLogger{nullptr}; /// Updater logger instance diff --git a/Core/include/Acts/TrackFitting/GlobalChiSquareFitter.hpp b/Core/include/Acts/TrackFitting/GlobalChiSquareFitter.hpp index 2de65a78a07..92a6a4f76ba 100644 --- a/Core/include/Acts/TrackFitting/GlobalChiSquareFitter.hpp +++ b/Core/include/Acts/TrackFitting/GlobalChiSquareFitter.hpp @@ -610,10 +610,10 @@ class Gx2Fitter { // Check if we can stop to propagate if (result.measurementStates == inputMeasurements->size()) { - ACTS_INFO("Actor: finish: All measurements have been found."); + ACTS_DEBUG("Actor: finish: All measurements have been found."); result.finished = true; } else if (state.navigation.navigationBreak) { - ACTS_INFO("Actor: finish: navigationBreak."); + ACTS_DEBUG("Actor: finish: navigationBreak."); result.finished = true; } @@ -1218,7 +1218,7 @@ class Gx2Fitter { // We only consider states with a measurement (and/or material) if (!stateHasMeasurement && !doMaterial) { - ACTS_INFO(" Skip state."); + ACTS_DEBUG(" Skip state."); continue; } @@ -1388,6 +1388,9 @@ class Gx2Fitter { // Propagate again with the final covariance matrix. This is necessary to // obtain the propagated covariance for each state. + // We also need to recheck the result and find the tipIndex, because at this + // 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 deltaParams:\n" << deltaParams); ACTS_VERBOSE("Propagate with the final covariance."); @@ -1413,7 +1416,33 @@ class Gx2Fitter { auto& r = propagatorState.template get>(); r.fittedStates = &trackContainer.trackStateContainer(); - m_propagator.template propagate(propagatorState); + auto propagationResult = m_propagator.template propagate(propagatorState); + + // Run the fitter + auto result = m_propagator.template makeResult(std::move(propagatorState), + propagationResult, + propagatorOptions, false); + + if (!result.ok()) { + ACTS_ERROR("Propagation failed: " << result.error()); + return result.error(); + } + + 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(); + } + + if (tipIndex != gx2fResult.lastMeasurementIndex) { + ACTS_INFO("Final fit used unreachable measurements."); + return Experimental::GlobalChiSquareFitterError:: + UsedUnreachableMeasurements; + } } if (!trackContainer.hasColumn( diff --git a/Core/include/Acts/TrackFitting/GlobalChiSquareFitterError.hpp b/Core/include/Acts/TrackFitting/GlobalChiSquareFitterError.hpp index 7c95750a3f6..5bc4c55b3e2 100644 --- a/Core/include/Acts/TrackFitting/GlobalChiSquareFitterError.hpp +++ b/Core/include/Acts/TrackFitting/GlobalChiSquareFitterError.hpp @@ -19,6 +19,7 @@ enum class GlobalChiSquareFitterError { DidNotConverge = 2, NotEnoughMeasurements = 3, UpdatePushedToNewVolume = 4, + UsedUnreachableMeasurements = 5, }; std::error_code make_error_code( diff --git a/Core/include/Acts/TrackFitting/KalmanFitter.hpp b/Core/include/Acts/TrackFitting/KalmanFitter.hpp index f55b0fac1cf..b0fe848c17b 100644 --- a/Core/include/Acts/TrackFitting/KalmanFitter.hpp +++ b/Core/include/Acts/TrackFitting/KalmanFitter.hpp @@ -484,11 +484,8 @@ class KalmanFitter { result.fittedStates->applyBackwards( result.lastMeasurementIndex, [&](auto trackState) { auto fSurface = &trackState.referenceSurface(); - auto surface_it = std::find_if( - result.passedAgainSurfaces.begin(), - result.passedAgainSurfaces.end(), - [=](const Surface* s) { return s == fSurface; }); - if (surface_it == result.passedAgainSurfaces.end()) { + if (!rangeContainsValue(result.passedAgainSurfaces, + fSurface)) { // If reversed filtering missed this surface, then there is // no smoothed parameter trackState.unset(TrackStatePropMask::Smoothed); diff --git a/Core/include/Acts/Utilities/BinUtility.hpp b/Core/include/Acts/Utilities/BinUtility.hpp index b01c8d27158..a1213ddd8ec 100644 --- a/Core/include/Acts/Utilities/BinUtility.hpp +++ b/Core/include/Acts/Utilities/BinUtility.hpp @@ -47,7 +47,7 @@ class BinUtility { /// Constructor with only a Transform3 /// /// @param tForm is the local to global transform - BinUtility(const Transform3& tForm) + explicit BinUtility(const Transform3& tForm) : m_binningData(), m_transform(tForm), m_itransform(tForm.inverse()) { m_binningData.reserve(3); } @@ -317,13 +317,15 @@ class BinUtility { return ss.str(); } + /// Overload of << operator for std::ostream for debug output + friend std::ostream& operator<<(std::ostream& sl, const BinUtility& bgen) { + return bgen.toStream(sl); + } + private: std::vector m_binningData; /// vector of BinningData Transform3 m_transform; /// shared transform Transform3 m_itransform; /// unique inverse transform }; -/// Overload of << operator for std::ostream for debug output -std::ostream& operator<<(std::ostream& sl, const BinUtility& bgen); - } // namespace Acts diff --git a/Core/include/Acts/Utilities/Iterator.hpp b/Core/include/Acts/Utilities/Iterator.hpp new file mode 100644 index 00000000000..a69e6c77faa --- /dev/null +++ b/Core/include/Acts/Utilities/Iterator.hpp @@ -0,0 +1,132 @@ +// 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 +#include +#include +#include + +namespace Acts { +template +class ContainerIndexIterator { + public: + using value_type = Value; + using iterator_category = std::random_access_iterator_tag; + using container_type = + std::conditional_t; + using difference_type = std::ptrdiff_t; + using pointer = void; + using reference = void; + + ContainerIndexIterator() : m_container(nullptr), m_index(0) {} + + ContainerIndexIterator(container_type& container, std::size_t index) + : m_container(&container), m_index(index) {} + + template + explicit ContainerIndexIterator( + const ContainerIndexIterator<_Container, OtherValue, OtherConst>& o) + requires(!OtherConst || Const) + : m_container(o.m_container), m_index(o.m_index) {} + + value_type operator*() const { + assert(m_container != nullptr); + return m_container->at(m_index); + } + + template + ContainerIndexIterator& operator=( + const ContainerIndexIterator<_Container, OtherValue, OtherConst>& o) + requires(!OtherConst || Const) + { + m_container = o.m_container; + m_index = o.m_index; + return *this; + } + + ContainerIndexIterator& operator++() { + ++m_index; + return *this; + } + + ContainerIndexIterator operator++(int) { + auto copy = *this; + ++*this; + return copy; + } + + ContainerIndexIterator& operator+=(const difference_type& i) { + m_index += i; + return *this; + } + + friend ContainerIndexIterator operator+(const ContainerIndexIterator& t, + const difference_type& i) { + return ContainerIndexIterator(*t.m_container, t.m_index + i); + } + + friend ContainerIndexIterator operator+(const difference_type& i, + const ContainerIndexIterator& t) { + return t + i; + } + + ContainerIndexIterator& operator--() { + --m_index; + return *this; + } + + ContainerIndexIterator operator--(int) { + auto copy = *this; + --*this; + return copy; + } + + ContainerIndexIterator& operator-=(const difference_type& i) { + m_index -= i; + return *this; + } + + friend ContainerIndexIterator operator-(const ContainerIndexIterator& t, + const difference_type& i) { + return ContainerIndexIterator(*t.m_container, t.m_index - i); + } + + template + friend difference_type operator-( + const ContainerIndexIterator& t, + const ContainerIndexIterator<_Container, OtherValue, OtherConst>& o) { + assert(t.m_container == o.m_container); + return t.m_index - o.m_index; + } + + value_type operator[](const difference_type& i) const { return *(*this + i); } + + template + std::strong_ordering operator<=>( + const ContainerIndexIterator<_Container, OtherValue, OtherConst>& o) + const { + if (m_container == o.m_container) { + return m_index <=> o.m_index; + } else { + return m_container <=> o.m_container; + } + } + + template + bool operator==(const ContainerIndexIterator<_Container, OtherValue, + OtherConst>& other) const { + return m_container == other.m_container && m_index == other.m_index; + } + + private: + container_type* m_container; + typename container_type::size_type m_index; +}; +} // namespace Acts diff --git a/Core/src/Utilities/BinUtility.cpp b/Core/include/Acts/Utilities/TypeTraits.hpp similarity index 65% rename from Core/src/Utilities/BinUtility.cpp rename to Core/include/Acts/Utilities/TypeTraits.hpp index 707f6dce1a0..a3c4aaccdcb 100644 --- a/Core/src/Utilities/BinUtility.cpp +++ b/Core/include/Acts/Utilities/TypeTraits.hpp @@ -6,10 +6,11 @@ // 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/Utilities/BinUtility.hpp" +#pragma once -#include +#include -std::ostream& Acts::operator<<(std::ostream& sl, const BinUtility& bgen) { - return bgen.toStream(sl); -} +namespace Acts { +template +using const_if_t = std::conditional_t; +} // namespace Acts diff --git a/Core/include/Acts/Vertexing/AdaptiveMultiVertexFitter.hpp b/Core/include/Acts/Vertexing/AdaptiveMultiVertexFitter.hpp index 73884fd31f3..91f18618673 100644 --- a/Core/include/Acts/Vertexing/AdaptiveMultiVertexFitter.hpp +++ b/Core/include/Acts/Vertexing/AdaptiveMultiVertexFitter.hpp @@ -22,6 +22,7 @@ #include "Acts/Vertexing/VertexingError.hpp" #include "Acts/Vertexing/VertexingOptions.hpp" +#include #include namespace Acts { @@ -81,8 +82,7 @@ class AdaptiveMultiVertexFitter { Result removeVertexFromCollection(Vertex& vtxToRemove, const Logger& logger) { - auto it = std::find(vertexCollection.begin(), vertexCollection.end(), - &vtxToRemove); + auto it = std::ranges::find(vertexCollection, &vtxToRemove); // Check if the value was found before erasing if (it == vertexCollection.end()) { ACTS_ERROR("vtxToRemove is not part of vertexCollection."); diff --git a/Core/include/Acts/Visualization/GeometryView3D.hpp b/Core/include/Acts/Visualization/GeometryView3D.hpp index 05053de31ef..fed07697a87 100644 --- a/Core/include/Acts/Visualization/GeometryView3D.hpp +++ b/Core/include/Acts/Visualization/GeometryView3D.hpp @@ -31,12 +31,6 @@ class DetectorVolume; class Portal; } // namespace Experimental -static const ViewConfig s_viewSensitive; -static const ViewConfig s_viewPassive; -static const ViewConfig s_viewVolume; -static const ViewConfig s_viewGrid; -static const ViewConfig s_viewLine; - struct GeometryView3D { /// Helper method to draw Polyhedron objects /// diff --git a/Core/include/Acts/Visualization/IVisualization3D.hpp b/Core/include/Acts/Visualization/IVisualization3D.hpp index 734ab3fe129..be8c5b96226 100644 --- a/Core/include/Acts/Visualization/IVisualization3D.hpp +++ b/Core/include/Acts/Visualization/IVisualization3D.hpp @@ -72,6 +72,12 @@ class IVisualization3D { /// Remove all contents of this helper /// virtual void clear() = 0; + + virtual ~IVisualization3D() = default; + + /// Start a new object context + /// @param name The name of the object + virtual void object(const std::string& name) = 0; }; /// Overload of the << operator to facilitate writing to streams. diff --git a/Core/include/Acts/Visualization/ObjVisualization3D.hpp b/Core/include/Acts/Visualization/ObjVisualization3D.hpp index 941e719f870..a9f496ce304 100644 --- a/Core/include/Acts/Visualization/ObjVisualization3D.hpp +++ b/Core/include/Acts/Visualization/ObjVisualization3D.hpp @@ -12,12 +12,8 @@ #include "Acts/Visualization/IVisualization3D.hpp" #include "Acts/Visualization/ViewConfig.hpp" -#include #include -#include -#include #include -#include #include #include @@ -26,14 +22,10 @@ namespace Acts { /// This helper produces output in the OBJ format. Note that colors are not /// supported in this implementation. /// -template class ObjVisualization3D : public IVisualization3D { public: - static_assert(std::is_same_v || std::is_same_v, - "Use either double or float"); - /// Stored value type, should be double or float - using ValueType = T; + using ValueType = double; /// Type of a vertex based on the value type using VertexType = Eigen::Matrix; @@ -77,22 +69,32 @@ class ObjVisualization3D : public IVisualization3D { /// @copydoc Acts::IVisualization3D::clear() void clear() final; + /// Start a new object context with a name + /// @param name The name of the object + void object(const std::string& name) final; + private: + struct Object { + std::string name; + std::vector vertices{}; + std::vector faces{}; + std::vector lines{}; + + /// The object data to be written + /// Map of colors to be written at given index position + std::map lineColors{}; + std::map vertexColors{}; + std::map faceColors{}; + }; + + Object& object(); + const Object& object() const; + /// The output parameters unsigned int m_outputPrecision = 4; double m_outputScalor = 1.; - /// The object data to be written - std::vector m_vertices; - std::vector m_faces; - std::vector m_lines; - /// Map of colors to be written at given index position - std::map m_lineColors; - std::map m_vertexColors; - std::map m_faceColors; -}; -#ifndef DOXYGEN -#include "detail/ObjVisualization3D.ipp" -#endif + std::vector m_objects; +}; } // namespace Acts diff --git a/Core/include/Acts/Visualization/PlyVisualization3D.hpp b/Core/include/Acts/Visualization/PlyVisualization3D.hpp index e2c94481b9c..a4367dc7e02 100644 --- a/Core/include/Acts/Visualization/PlyVisualization3D.hpp +++ b/Core/include/Acts/Visualization/PlyVisualization3D.hpp @@ -60,6 +60,10 @@ class PlyVisualization3D : public IVisualization3D { /// @copydoc Acts::IVisualization3D::clear() void clear() final; + void object(const std::string& /*name*/) final { + // Unimplemented + } + private: std::vector> m_vertices; std::vector m_faces; diff --git a/Core/include/Acts/Visualization/ViewConfig.hpp b/Core/include/Acts/Visualization/ViewConfig.hpp index 6fcf1b47984..e2cf7b80618 100644 --- a/Core/include/Acts/Visualization/ViewConfig.hpp +++ b/Core/include/Acts/Visualization/ViewConfig.hpp @@ -10,7 +10,7 @@ #include #include -#include +#include namespace Acts { @@ -49,17 +49,31 @@ struct Color { constexpr Color(double r, double g, double b) : Color{std::array{r, g, b}} {} + private: + constexpr static int hexToInt(std::string_view hex) { + constexpr auto hexCharToInt = [](char c) { + if (c >= '0' && c <= '9') { + return c - '0'; + } else if (c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } else if (c >= 'A' && c <= 'F') { + return c - 'A' + 10; + } else { + throw std::invalid_argument("Invalid hex character"); + } + }; + + int value = 0; + for (char c : hex) { + value = (value << 4) + hexCharToInt(c); + } + return value; + }; + + public: /// Constructor from hex string. The expected format is `#RRGGBB` /// @param hex The hex string constexpr explicit Color(std::string_view hex) { - auto hexToInt = [](std::string_view hexStr) { - int value = 0; - std::stringstream ss; - ss << std::hex << hexStr; - ss >> value; - return value; - }; - if (hex[0] == '#' && hex.size() == 7) { rgb[0] = hexToInt(hex.substr(1, 2)); // Extract R component rgb[1] = hexToInt(hex.substr(3, 2)); // Extract G component @@ -85,7 +99,6 @@ struct Color { /// @param rhs The second color /// @return True if the colors are equal friend bool operator==(const Color& lhs, const Color& rhs) = default; - /// Output stream operator /// @param os The output stream /// @param color The color to be printed @@ -99,6 +112,10 @@ struct Color { std::array rgb{}; }; +constexpr Color s_defaultSurfaceColor{"#0000aa"}; +constexpr Color s_defaultPortalColor{"#308c48"}; +constexpr Color s_defaultVolumColor{"#ffaa00"}; + /// @brief Struct to concentrate all visualization configurations /// in order to harmonize visualization interfaces struct ViewConfig { @@ -112,12 +129,20 @@ struct ViewConfig { double lineThickness = 0.15; /// The visual surface thickness for this object double surfaceThickness = 0.15; - /// The number of segments to approximate full 2pi - unsigned int nSegments = 72; + /// The number of segments to approximate a quarter of the circle + unsigned int quarterSegments = 72; /// Whether to triangulate or not bool triangulate = false; /// Write name - non-empty string indicates writing std::filesystem::path outputName = std::filesystem::path(""); }; +static const ViewConfig s_viewSurface = {.color = {170, 170, 170}}; +static const ViewConfig s_viewPortal = {.color = Color{"#308c48"}}; +static const ViewConfig s_viewSensitive = {.color = {0, 180, 240}}; +static const ViewConfig s_viewPassive = {.color = {240, 280, 0}}; +static const ViewConfig s_viewVolume = {.color = {220, 220, 0}}; +static const ViewConfig s_viewGrid = {.color = {220, 0, 0}}; +static const ViewConfig s_viewLine = {.color = {0, 0, 220}}; + } // namespace Acts diff --git a/Core/include/Acts/Visualization/detail/ObjVisualization3D.ipp b/Core/include/Acts/Visualization/detail/ObjVisualization3D.ipp deleted file mode 100644 index 2419ef8c546..00000000000 --- a/Core/include/Acts/Visualization/detail/ObjVisualization3D.ipp +++ /dev/null @@ -1,179 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 CERN for the benefit of the ACTS project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -template -void ObjVisualization3D::vertex(const Vector3& vtx, Color color) { - m_vertexColors[m_vertices.size()] = color; - m_vertices.push_back(vtx.template cast()); -} - -template -void ObjVisualization3D::line(const Vector3& a, const Vector3& b, - Color color) { - if (color != Color{0, 0, 0}) { - m_lineColors[m_lines.size()] = color; - } - // not implemented - vertex(a, color); - vertex(b, color); - m_lines.push_back({m_vertices.size() - 2, m_vertices.size() - 1}); -} - -template -void ObjVisualization3D::face(const std::vector& vtxs, - Color color) { - if (color != Color{0, 0, 0}) { - m_faceColors[m_faces.size()] = color; - } - FaceType idxs; - idxs.reserve(vtxs.size()); - for (const auto& vtx : vtxs) { - vertex(vtx, color); - idxs.push_back(m_vertices.size() - 1); - } - m_faces.push_back(std::move(idxs)); -} - -template -void ObjVisualization3D::faces(const std::vector& vtxs, - const std::vector& faces, - Color color) { - // No faces given - call the face() method - if (faces.empty()) { - face(vtxs, color); - } else { - if (color != Color{0, 0, 0}) { - m_faceColors[m_faces.size()] = color; - } - auto vtxoffs = m_vertices.size(); - if (color != Color{0, 0, 0}) { - m_vertexColors[m_vertices.size()] = color; - } - m_vertices.insert(m_vertices.end(), vtxs.begin(), vtxs.end()); - for (const auto& face : faces) { - if (face.size() == 2) { - m_lines.push_back({face[0] + vtxoffs, face[2] + vtxoffs}); - } else { - FaceType rawFace = face; - std::transform(rawFace.begin(), rawFace.end(), rawFace.begin(), - [&](std::size_t& iv) { return (iv + vtxoffs); }); - m_faces.push_back(rawFace); - } - } - } -} - -template -void ObjVisualization3D::write(const std::filesystem::path& path) const { - std::ofstream os; - std::filesystem::path objectpath = path; - if (!objectpath.has_extension()) { - objectpath.replace_extension(std::filesystem::path("obj")); - } - os.open(std::filesystem::absolute(objectpath).string()); - std::filesystem::path mtlpath = objectpath; - mtlpath.replace_extension(std::filesystem::path("mtl")); - - const std::string mtlpathString = std::filesystem::absolute(mtlpath).string(); - os << "mtllib " << mtlpathString << "\n"; - std::ofstream mtlos; - mtlos.open(mtlpathString); - - write(os, mtlos); - os.close(); - mtlos.close(); -} - -template -void ObjVisualization3D::write(std::ostream& os) const { - std::stringstream sterile; - write(os, sterile); -} - -template -void ObjVisualization3D::write(std::ostream& os, std::ostream& mos) const { - std::map materials; - - auto mixColor = [&](const Color& color) -> std::string { - std::string materialName; - materialName = "material_"; - materialName += std::to_string(color[0]) + std::string("_"); - materialName += std::to_string(color[1]) + std::string("_"); - materialName += std::to_string(color[2]); - - if (!materials.contains(materialName)) { - mos << "newmtl " << materialName << "\n"; - std::vector shadings = {"Ka", "Kd", "Ks"}; - for (const auto& shd : shadings) { - mos << shd << " " << std::to_string(color[0] / 256.) << " "; - mos << std::to_string(color[1] / 256.) << " "; - mos << std::to_string(color[2] / 256.) << " " - << "\n"; - } - mos << "\n"; - } - return std::string("usemtl ") + materialName; - }; - - std::size_t iv = 0; - Color lastVertexColor = {0, 0, 0}; - for (const VertexType& vtx : m_vertices) { - if (m_vertexColors.contains(iv)) { - auto color = m_vertexColors.find(iv)->second; - if (color != lastVertexColor) { - os << mixColor(color) << "\n"; - lastVertexColor = color; - } - } - - os << "v " << std::setprecision(m_outputPrecision) - << m_outputScalor * vtx.x() << " " << m_outputScalor * vtx.y() << " " - << m_outputScalor * vtx.z() << "\n"; - ++iv; - } - std::size_t il = 0; - Color lastLineColor = {0, 0, 0}; - for (const LineType& ln : m_lines) { - if (m_lineColors.contains(il)) { - auto color = m_lineColors.find(il)->second; - if (color != lastLineColor) { - os << mixColor(color) << "\n"; - lastLineColor = color; - } - } - os << "l " << ln.first + 1 << " " << ln.second + 1 << "\n"; - ++il; - } - std::size_t is = 0; - Color lastFaceColor = {0, 0, 0}; - for (const FaceType& fc : m_faces) { - if (m_faceColors.contains(is)) { - auto color = m_faceColors.find(is)->second; - if (color != lastFaceColor) { - os << mixColor(color) << "\n"; - lastFaceColor = color; - } - } - os << "f"; - for (std::size_t i = 0; i < fc.size(); i++) { - os << " " << fc[i] + 1; - } - os << "\n"; - ++is; - } -} - -template -void ObjVisualization3D::clear() { - m_vertices.clear(); - m_faces.clear(); - m_lines.clear(); - m_lineColors.clear(); - m_vertexColors.clear(); - m_faceColors.clear(); -} diff --git a/Core/src/Detector/LayerStructureBuilder.cpp b/Core/src/Detector/LayerStructureBuilder.cpp index d936b27398a..94766a80d0d 100644 --- a/Core/src/Detector/LayerStructureBuilder.cpp +++ b/Core/src/Detector/LayerStructureBuilder.cpp @@ -256,7 +256,8 @@ Acts::Experimental::LayerStructureBuilder::construct( if (!support.internalConstraints.empty()) { // Estimate the extent from the surfaces for (const auto& s : internalSurfaces) { - auto sPolyhedron = s->polyhedronRepresentation(gctx, m_cfg.nSegments); + auto sPolyhedron = + s->polyhedronRepresentation(gctx, m_cfg.quarterSegments); supportExtent.extend(sPolyhedron.extent(), support.internalConstraints); } diff --git a/Core/src/Geometry/CMakeLists.txt b/Core/src/Geometry/CMakeLists.txt index fa5d70c1c02..74f6e0e126d 100644 --- a/Core/src/Geometry/CMakeLists.txt +++ b/Core/src/Geometry/CMakeLists.txt @@ -42,4 +42,5 @@ target_sources( CompositePortalLink.cpp PortalLinkBase.cpp PortalError.cpp + PortalShell.cpp ) diff --git a/Core/src/Geometry/CylinderVolumeBuilder.cpp b/Core/src/Geometry/CylinderVolumeBuilder.cpp index bb741167519..47de379d9be 100644 --- a/Core/src/Geometry/CylinderVolumeBuilder.cpp +++ b/Core/src/Geometry/CylinderVolumeBuilder.cpp @@ -274,19 +274,17 @@ Acts::CylinderVolumeBuilder::trackingVolume( double tolerance = m_cfg.ringTolerance; // Search for the rmin value - and insert if necessary double rMin = discBounds->rMin(); - auto innerSearch = std::find_if( - innerRadii.begin(), innerRadii.end(), [&](double reference) { - return std::abs(rMin - reference) < tolerance; - }); + auto innerSearch = std::ranges::find_if(innerRadii, [&](double r) { + return std::abs(rMin - r) < tolerance; + }); if (innerSearch == innerRadii.end()) { innerRadii.push_back(rMin); } // Search for the rmax value - and insert if necessary double rMax = discBounds->rMax(); - auto outerSearch = std::find_if( - outerRadii.begin(), outerRadii.end(), [&](double reference) { - return std::abs(rMax - reference) < tolerance; - }); + auto outerSearch = std::ranges::find_if(outerRadii, [&](double r) { + return std::abs(rMax - r) < tolerance; + }); if (outerSearch == outerRadii.end()) { outerRadii.push_back(rMax); } @@ -356,10 +354,9 @@ Acts::CylinderVolumeBuilder::trackingVolume( double test = elay->surfaceRepresentation().binningPositionValue( gctx, BinningValue::binR); // Find the right bin - auto ringVolume = std::find_if( - volumeRminRmax.begin(), volumeRminRmax.end(), - [&](const auto& reference) { - return (test > reference.first && test < reference.second); + auto ringVolume = + std::ranges::find_if(volumeRminRmax, [&](const auto& vrr) { + return (test > vrr.first && test < vrr.second); }); if (ringVolume != volumeRminRmax.end()) { unsigned int ringBin = diff --git a/Core/src/Geometry/Extent.cpp b/Core/src/Geometry/Extent.cpp index 9e520d171a3..2f07f6358bc 100644 --- a/Core/src/Geometry/Extent.cpp +++ b/Core/src/Geometry/Extent.cpp @@ -144,8 +144,7 @@ bool Acts::Extent::contains(const Extent& rhs, // Check all if (!bValue.has_value()) { - return std::all_of(allBinningValues().begin(), allBinningValues().end(), - checkContainment); + return std::ranges::all_of(allBinningValues(), checkContainment); } // Check specific return checkContainment(bValue.value()); @@ -163,8 +162,7 @@ bool Acts::Extent::intersects(const Extent& rhs, // Check all if (!bValue.has_value()) { - return std::any_of(allBinningValues().begin(), allBinningValues().end(), - checkIntersect); + return std::ranges::any_of(allBinningValues(), checkIntersect); } // Check specific return checkIntersect(bValue.value()); diff --git a/Core/src/Geometry/Layer.cpp b/Core/src/Geometry/Layer.cpp index dca511b3978..024f99e9c42 100644 --- a/Core/src/Geometry/Layer.cpp +++ b/Core/src/Geometry/Layer.cpp @@ -126,11 +126,9 @@ Acts::Layer::compatibleSurfaces( double farLimit = options.farLimit; auto isUnique = [&](const SurfaceIntersection& b) { - auto find_it = std::find_if( - sIntersections.begin(), sIntersections.end(), [&b](const auto& a) { - return a.object() == b.object() && a.index() == b.index(); - }); - return find_it == sIntersections.end(); + return std::ranges::none_of(sIntersections, [&b](const auto& a) { + return a.object() == b.object() && a.index() == b.index(); + }); }; // lemma 0 : accept the surface @@ -140,7 +138,7 @@ Acts::Layer::compatibleSurfaces( if (sensitive && options.resolveSensitive) { return true; } - // next option: it's a material surface and you want to have it + // next option: it's a material surface, and you want to have it if (options.resolveMaterial && sf.surfaceMaterial() != nullptr) { return true; } diff --git a/Core/src/Geometry/PortalShell.cpp b/Core/src/Geometry/PortalShell.cpp new file mode 100644 index 00000000000..59c83c1529f --- /dev/null +++ b/Core/src/Geometry/PortalShell.cpp @@ -0,0 +1,388 @@ +// 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 "Acts/Geometry/PortalShell.hpp" + +#include "Acts/Geometry/BoundarySurfaceFace.hpp" +#include "Acts/Geometry/CylinderVolumeBounds.hpp" +#include "Acts/Geometry/Portal.hpp" +#include "Acts/Geometry/PortalLinkBase.hpp" +#include "Acts/Geometry/TrackingVolume.hpp" + +#include +#include +#include + +#include + +namespace Acts { + +void CylinderPortalShell::connectOuter(TrackingVolume& volume) { + for (Face face : {PositiveDisc, NegativeDisc, OuterCylinder, InnerCylinder, + NegativePhiPlane, PositivePhiPlane}) { + const auto& portalAtFace = portalPtr(face); + if (portalAtFace != nullptr) { + portalAtFace->fill(volume); + volume.addPortal(portalAtFace); + } + } +} + +SingleCylinderPortalShell::SingleCylinderPortalShell(TrackingVolume& volume) + : m_volume{&volume} { + if (m_volume->volumeBounds().type() != VolumeBounds::BoundsType::eCylinder) { + throw std::invalid_argument("Invalid volume bounds type"); + } + + const auto& bounds = + dynamic_cast(m_volume->volumeBounds()); + + std::vector orientedSurfaces = + bounds.orientedSurfaces(m_volume->transform()); + + auto handle = [&](Face face, std::size_t from) { + const auto& source = orientedSurfaces.at(from); + m_portals.at(toUnderlying(face)) = + std::make_shared(source.direction, source.surface, *m_volume); + }; + + if (orientedSurfaces.size() == 6) { + // Fully equipped cylinder + handle(PositiveDisc, positiveFaceXY); + handle(NegativeDisc, negativeFaceXY); + handle(OuterCylinder, tubeOuterCover); + handle(InnerCylinder, tubeInnerCover); + handle(NegativePhiPlane, tubeSectorNegativePhi); + handle(PositivePhiPlane, tubeSectorPositivePhi); + } else if (orientedSurfaces.size() == 5) { + // Phi sector but no inner cylinder (rMin == 0) + handle(PositiveDisc, positiveFaceXY); + handle(NegativeDisc, negativeFaceXY); + handle(OuterCylinder, tubeOuterCover); + // Skip inner tube cover, requires offsetting + handle(NegativePhiPlane, tubeSectorNegativePhi - 1); + handle(PositivePhiPlane, tubeSectorPositivePhi - 1); + } else if (orientedSurfaces.size() == 4) { + // No phi sector but rMin > 0 + handle(PositiveDisc, positiveFaceXY); + handle(NegativeDisc, negativeFaceXY); + handle(OuterCylinder, tubeOuterCover); + handle(InnerCylinder, tubeInnerCover); + } else if (orientedSurfaces.size() == 3) { + // No phi sector and rMin == 0 + handle(PositiveDisc, positiveFaceXY); + handle(NegativeDisc, negativeFaceXY); + handle(OuterCylinder, tubeOuterCover); + } else { + throw std::invalid_argument("Invalid number of oriented surfaces"); + } +} + +Portal* SingleCylinderPortalShell::portal(Face face) { + return portalPtr(face).get(); +} + +std::shared_ptr SingleCylinderPortalShell::portalPtr(Face face) { + return m_portals.at(toUnderlying(face)); +} + +void SingleCylinderPortalShell::setPortal(std::shared_ptr portal, + Face face) { + assert(portal != nullptr); + assert(portal->isValid()); + m_portals.at(toUnderlying(face)) = std::move(portal); +} + +std::size_t SingleCylinderPortalShell::size() const { + std::size_t count = 0; + std::ranges::for_each( + m_portals, [&count](const auto& portal) { count += portal ? 1 : 0; }); + return count; +} + +void SingleCylinderPortalShell::applyToVolume() { + for (std::size_t i = 0; i < m_portals.size(); i++) { + const auto& portal = m_portals.at(i); + if (portal != nullptr) { + if (!portal->isValid()) { + std::stringstream ss; + ss << static_cast(i); + throw std::runtime_error{"Invalid portal found in shell at " + + ss.str()}; + } + m_volume->addPortal(portal); + } + } +} + +bool SingleCylinderPortalShell::isValid() const { + return std::ranges::all_of(m_portals, [](const auto& portal) { + return portal == nullptr || portal->isValid(); + }); +}; + +std::string SingleCylinderPortalShell::label() const { + std::stringstream ss; + ss << "CylinderShell(vol=" << m_volume->volumeName() << ")"; + return ss.str(); +} + +CylinderStackPortalShell::CylinderStackPortalShell( + const GeometryContext& gctx, std::vector shells, + BinningValue direction, const Logger& logger) + : m_direction{direction}, m_shells{std::move(shells)} { + ACTS_VERBOSE("Making cylinder stack shell in " << m_direction + << " direction"); + if (std::ranges::any_of(m_shells, + [](const auto* shell) { return shell == nullptr; })) { + ACTS_ERROR("Invalid shell pointer"); + throw std::invalid_argument("Invalid shell pointer"); + } + + ACTS_VERBOSE(" ~> " << label()); + + if (!std::ranges::all_of( + m_shells, [](const auto* shell) { return shell->isValid(); })) { + ACTS_ERROR("Invalid shell"); + throw std::invalid_argument("Invalid shell"); + } + + auto merge = [&](Face face) { + std::vector> portals; + std::ranges::transform( + m_shells, std::back_inserter(portals), + [face](auto* shell) { return shell->portalPtr(face); }); + + auto merged = std::accumulate( + std::next(portals.begin()), portals.end(), portals.front(), + [&](const auto& aPortal, + const auto& bPortal) -> std::shared_ptr { + assert(aPortal != nullptr); + assert(bPortal != nullptr); + + return std::make_shared( + Portal::merge(gctx, *aPortal, *bPortal, direction, logger)); + }); + + assert(merged != nullptr); + assert(merged->isValid()); + + // reset merged portal on all shells + for (auto& shell : m_shells) { + shell->setPortal(merged, face); + } + }; + + auto fuse = [&](Face faceA, Face faceB) { + for (std::size_t i = 1; i < m_shells.size(); i++) { + auto& shellA = m_shells.at(i - 1); + auto& shellB = m_shells.at(i); + ACTS_VERBOSE("Fusing " << shellA->label() << " and " << shellB->label()); + + auto fused = std::make_shared(Portal::fuse( + gctx, *shellA->portalPtr(faceA), *shellB->portalPtr(faceB), logger)); + + assert(fused != nullptr && "Invalid fused portal"); + assert(fused->isValid() && "Fused portal is invalid"); + + shellA->setPortal(fused, faceA); + shellB->setPortal(fused, faceB); + + assert(shellA->isValid() && "Shell A is not valid after fusing"); + assert(shellB->isValid() && "Shell B is not valid after fusing"); + } + }; + + if (direction == BinningValue::binR) { + ACTS_VERBOSE("Merging portals at positive and negative discs"); + merge(PositiveDisc); + merge(NegativeDisc); + + ACTS_VERBOSE("Fusing portals at outer and inner cylinders"); + fuse(OuterCylinder, InnerCylinder); + + } else if (direction == BinningValue::binZ) { + bool allHaveInnerCylinders = std::ranges::all_of( + m_shells, [](const auto* shell) { return shell->size() == 4; }); + + bool noneHaveInnerCylinders = std::ranges::all_of( + m_shells, [](const auto* shell) { return shell->size() == 3; }); + + if (!allHaveInnerCylinders && !noneHaveInnerCylinders) { + ACTS_ERROR("Invalid inner cylinder configuration"); + throw std::invalid_argument("Invalid inner cylinder configuration"); + } + + m_hasInnerCylinder = allHaveInnerCylinders; + + ACTS_VERBOSE("Merging portals at outer cylinders"); + merge(OuterCylinder); + assert(isValid() && "Shell is not valid after outer merging"); + + if (m_hasInnerCylinder) { + ACTS_VERBOSE("Merging portals at inner cylinders"); + merge(InnerCylinder); + assert(isValid() && "Shell is not valid after inner merging"); + } + + ACTS_VERBOSE("Fusing portals at positive and negative discs"); + fuse(PositiveDisc, NegativeDisc); + assert(isValid() && "Shell is not valid after disc fusing"); + + } else { + throw std::invalid_argument("Invalid direction"); + } + + assert(isValid() && "Shell is not valid after construction"); +} + +std::size_t CylinderStackPortalShell::size() const { + return m_hasInnerCylinder ? 4 : 3; +} + +Portal* CylinderStackPortalShell::portal(Face face) { + return portalPtr(face).get(); +} + +std::shared_ptr CylinderStackPortalShell::portalPtr(Face face) { + if (m_direction == BinningValue::binR) { + switch (face) { + case NegativeDisc: + return m_shells.front()->portalPtr(NegativeDisc); + case PositiveDisc: + return m_shells.front()->portalPtr(PositiveDisc); + case OuterCylinder: + return m_shells.back()->portalPtr(OuterCylinder); + case InnerCylinder: + return m_shells.front()->portalPtr(InnerCylinder); + case NegativePhiPlane: + [[fallthrough]]; + case PositivePhiPlane: + return nullptr; + default: + std::stringstream ss; + ss << "Invalid face: " << face; + throw std::invalid_argument(ss.str()); + } + + } else { + switch (face) { + case NegativeDisc: + return m_shells.front()->portalPtr(NegativeDisc); + case PositiveDisc: + return m_shells.back()->portalPtr(PositiveDisc); + case OuterCylinder: + [[fallthrough]]; + case InnerCylinder: + return m_shells.front()->portalPtr(face); + case NegativePhiPlane: + [[fallthrough]]; + case PositivePhiPlane: + return nullptr; + default: + std::stringstream ss; + ss << "Invalid face: " << face; + throw std::invalid_argument(ss.str()); + } + } +} + +void CylinderStackPortalShell::setPortal(std::shared_ptr portal, + Face face) { + assert(portal != nullptr); + + if (m_direction == BinningValue::binR) { + switch (face) { + case NegativeDisc: + [[fallthrough]]; + case PositiveDisc: + for (auto* shell : m_shells) { + shell->setPortal(portal, face); + } + break; + case OuterCylinder: + m_shells.back()->setPortal(std::move(portal), OuterCylinder); + break; + case InnerCylinder: + if (!m_hasInnerCylinder) { + throw std::invalid_argument("Inner cylinder not available"); + } + m_shells.front()->setPortal(std::move(portal), InnerCylinder); + break; + default: + std::stringstream ss; + ss << "Invalid face: " << face; + throw std::invalid_argument(ss.str()); + } + + } else { + switch (face) { + case NegativeDisc: + m_shells.front()->setPortal(std::move(portal), NegativeDisc); + break; + case PositiveDisc: + m_shells.back()->setPortal(std::move(portal), PositiveDisc); + break; + case InnerCylinder: + if (!m_hasInnerCylinder) { + throw std::invalid_argument("Inner cylinder not available"); + } + [[fallthrough]]; + case OuterCylinder: + for (auto* shell : m_shells) { + shell->setPortal(portal, face); + } + break; + default: + std::stringstream ss; + ss << "Invalid face: " << face; + throw std::invalid_argument(ss.str()); + } + } +} + +bool CylinderStackPortalShell::isValid() const { + return std::ranges::all_of(m_shells, [](const auto* shell) { + assert(shell != nullptr); + return shell->isValid(); + }); +} + +std::string CylinderStackPortalShell::label() const { + std::stringstream ss; + ss << "CylinderStackShell(dir=" << m_direction << ", children="; + + std::vector labels; + std::ranges::transform(m_shells, std::back_inserter(labels), + [](const auto* shell) { return shell->label(); }); + ss << boost::algorithm::join(labels, "|"); + ss << ")"; + return ss.str(); +} + +std::ostream& operator<<(std::ostream& os, CylinderPortalShell::Face face) { + switch (face) { + using enum CylinderPortalShell::Face; + case PositiveDisc: + return os << "PositiveDisc"; + case NegativeDisc: + return os << "NegativeDisc"; + case OuterCylinder: + return os << "OuterCylinder"; + case InnerCylinder: + return os << "InnerCylinder"; + case NegativePhiPlane: + return os << "NegativePhiPlane"; + case PositivePhiPlane: + return os << "PositivePhiPlane"; + default: + return os << "Invalid face"; + } +} + +} // namespace Acts diff --git a/Core/src/Geometry/ProtoLayer.cpp b/Core/src/Geometry/ProtoLayer.cpp index 659b34b1168..c8f190d4293 100644 --- a/Core/src/Geometry/ProtoLayer.cpp +++ b/Core/src/Geometry/ProtoLayer.cpp @@ -13,26 +13,34 @@ #include "Acts/Surfaces/RegularSurface.hpp" #include "Acts/Utilities/Helpers.hpp" -#include -#include -#include -#include - using Acts::VectorHelpers::perp; using Acts::VectorHelpers::phi; namespace Acts { ProtoLayer::ProtoLayer(const GeometryContext& gctx, - const std::vector& surfaces) - : m_surfaces(surfaces) { + const std::vector& surfaces, + const Transform3& transformIn) + : transform(transformIn), m_surfaces(surfaces) { measure(gctx, surfaces); } ProtoLayer::ProtoLayer( const GeometryContext& gctx, - const std::vector>& surfaces) - : m_surfaces(unpack_shared_vector(surfaces)) { + const std::vector>& surfaces, + const Transform3& transformIn) + : transform(transformIn), m_surfaces(unpack_shared_vector(surfaces)) { + measure(gctx, m_surfaces); +} + +ProtoLayer::ProtoLayer(const GeometryContext& gctx, + const std::vector>& surfaces, + const Transform3& transformIn) + : transform(transformIn) { + m_surfaces.reserve(surfaces.size()); + for (const auto& sf : surfaces) { + m_surfaces.push_back(sf.get()); + } measure(gctx, m_surfaces); } @@ -78,15 +86,13 @@ void ProtoLayer::measure(const GeometryContext& gctx, double thickness = element->thickness(); // We need a translation along and opposite half thickness Vector3 sfNormal = regSurface->normal(gctx, sf->center(gctx)); - std::vector deltaT = {-0.5 * thickness, 0.5 * thickness}; - for (const auto& dT : deltaT) { - Transform3 dtransform = Transform3::Identity(); - dtransform.pretranslate(dT * sfNormal); + for (const auto& dT : {-0.5 * thickness, 0.5 * thickness}) { + Transform3 dtransform = transform * Translation3{dT * sfNormal}; extent.extend(sfPolyhedron.extent(dtransform)); } continue; } - extent.extend(sfPolyhedron.extent()); + extent.extend(sfPolyhedron.extent(transform)); } } diff --git a/Core/src/Geometry/TrackingGeometry.cpp b/Core/src/Geometry/TrackingGeometry.cpp index b68d788d08b..f9207afbd18 100644 --- a/Core/src/Geometry/TrackingGeometry.cpp +++ b/Core/src/Geometry/TrackingGeometry.cpp @@ -85,3 +85,11 @@ const std::unordered_map& Acts::TrackingGeometry::geoIdSurfaceMap() const { return m_surfacesById; } + +void Acts::TrackingGeometry::visualize( + IVisualization3D& helper, const GeometryContext& gctx, + const ViewConfig& viewConfig, const ViewConfig& portalViewConfig, + const ViewConfig& sensitiveViewConfig) const { + highestTrackingVolume()->visualize(helper, gctx, viewConfig, portalViewConfig, + sensitiveViewConfig); +} diff --git a/Core/src/Geometry/TrackingVolume.cpp b/Core/src/Geometry/TrackingVolume.cpp index d2c1124a1ae..ad2c939fcbd 100644 --- a/Core/src/Geometry/TrackingVolume.cpp +++ b/Core/src/Geometry/TrackingVolume.cpp @@ -347,6 +347,31 @@ void TrackingVolume::closeGeometry( std::unordered_map& volumeMap, std::size_t& vol, const GeometryIdentifierHook& hook, const Logger& logger) { + if (!boundarySurfaces().empty() && !portals().empty()) { + ACTS_ERROR( + "TrackingVolume::closeGeometry: Volume " + << volumeName() + << " has both boundary surfaces and portals. This is not supported."); + throw std::invalid_argument( + "Volume has both boundary surfaces and portals"); + } + + if (m_confinedVolumes && !volumes().empty()) { + ACTS_ERROR( + "TrackingVolume::closeGeometry: Volume " + << volumeName() + << " has both confined volumes and volumes. This is not supported."); + throw std::invalid_argument("Volume has both confined volumes and volumes"); + } + + if (m_confinedLayers && !surfaces().empty()) { + ACTS_ERROR( + "TrackingVolume::closeGeometry: Volume " + << volumeName() + << " has both confined layers and surfaces. This is not supported."); + throw std::invalid_argument("Volume has both confined layers and surfaces"); + } + // we can construct the volume ID from this auto volumeID = GeometryIdentifier().setVolume(++vol); // assign the Volume ID to the volume itself @@ -379,7 +404,8 @@ void TrackingVolume::closeGeometry( // get the intersection solution auto& bSurface = bSurfIter->surfaceRepresentation(); // create the boundary surface id - auto boundaryID = GeometryIdentifier(volumeID).setBoundary(++iboundary); + iboundary++; + auto boundaryID = GeometryIdentifier(volumeID).setBoundary(iboundary); // now assign to the boundary surface auto& mutableBSurface = *(const_cast(&bSurface)); mutableBSurface.assignGeometryId(boundaryID); @@ -397,7 +423,8 @@ void TrackingVolume::closeGeometry( // loop over the layers for (auto& layerPtr : m_confinedLayers->arrayObjects()) { // create the layer identification - auto layerID = GeometryIdentifier(volumeID).setLayer(++ilayer); + ilayer++; + auto layerID = GeometryIdentifier(volumeID).setLayer(ilayer); // now close the geometry auto mutableLayerPtr = std::const_pointer_cast(layerPtr); mutableLayerPtr->closeGeometry(materialDecorator, layerID, hook, @@ -428,12 +455,24 @@ void TrackingVolume::closeGeometry( GeometryIdentifier::Value iportal = 0; for (auto& portal : portals()) { - auto portalId = GeometryIdentifier(volumeID).setBoundary(++iportal); + iportal++; + auto portalId = GeometryIdentifier(volumeID).setBoundary(iportal); assert(portal.isValid() && "Invalid portal encountered during closing"); portal.surface().assignGeometryId(portalId); } + GeometryIdentifier::Value isensitive = 0; + + for (auto& surface : surfaces()) { + if (surface.associatedDetectorElement() == nullptr) { + continue; + } + isensitive++; + auto sensitiveId = GeometryIdentifier(volumeID).setSensitive(isensitive); + surface.assignGeometryId(sensitiveId); + } + for (auto& volume : volumes()) { volume.closeGeometry(materialDecorator, volumeMap, vol, hook, logger); } @@ -663,7 +702,46 @@ TrackingVolume::MutablePortalRange TrackingVolume::portals() { } void TrackingVolume::addPortal(std::shared_ptr portal) { + if (portal == nullptr) { + throw std::invalid_argument("Portal is nullptr"); + } m_portals.push_back(std::move(portal)); } +TrackingVolume::SurfaceRange TrackingVolume::surfaces() const { + return SurfaceRange{m_surfaces}; +} + +TrackingVolume::MutableSurfaceRange TrackingVolume::surfaces() { + return MutableSurfaceRange{m_surfaces}; +} + +void TrackingVolume::addSurface(std::shared_ptr surface) { + if (surface == nullptr) { + throw std::invalid_argument("Surface is nullptr"); + } + m_surfaces.push_back(std::move(surface)); +} + +void TrackingVolume::visualize(IVisualization3D& helper, + const GeometryContext& gctx, + const ViewConfig& viewConfig, + const ViewConfig& portalViewConfig, + const ViewConfig& sensitiveViewConfig) const { + helper.object(volumeName()); + Volume::visualize(helper, gctx, viewConfig); + + if (!surfaces().empty()) { + helper.object(volumeName() + "_sensitives"); + } + for (const auto& surface : surfaces()) { + surface.visualize(helper, gctx, sensitiveViewConfig); + } + + for (const auto& child : volumes()) { + child.visualize(helper, gctx, viewConfig, portalViewConfig, + sensitiveViewConfig); + } +} + } // namespace Acts diff --git a/Core/src/Surfaces/AnnulusBounds.cpp b/Core/src/Surfaces/AnnulusBounds.cpp index d96b3bc7e80..34c7b5c468b 100644 --- a/Core/src/Surfaces/AnnulusBounds.cpp +++ b/Core/src/Surfaces/AnnulusBounds.cpp @@ -103,33 +103,30 @@ std::vector Acts::AnnulusBounds::corners() const { } std::vector Acts::AnnulusBounds::vertices( - unsigned int lseg) const { - if (lseg > 0) { - // List of vertices counter-clockwise starting with left inner - std::vector rvertices; - + unsigned int quarterSegments) const { + if (quarterSegments > 0u) { using VectorHelpers::phi; - auto phisInner = detail::VerticesHelper::phiSegments( - phi(m_inRightStripXY - m_moduleOrigin), - phi(m_inLeftStripXY - m_moduleOrigin)); - auto phisOuter = detail::VerticesHelper::phiSegments( - phi(m_outLeftStripXY - m_moduleOrigin), - phi(m_outRightStripXY - m_moduleOrigin)); - - // Inner bow from phi_min -> phi_max - for (unsigned int iseg = 0; iseg < phisInner.size() - 1; ++iseg) { - int addon = (iseg == phisInner.size() - 2) ? 1 : 0; - detail::VerticesHelper::createSegment( - rvertices, {get(eMinR), get(eMinR)}, phisInner[iseg], - phisInner[iseg + 1], lseg, addon); - } - // Upper bow from phi_max -> phi_min - for (unsigned int iseg = 0; iseg < phisOuter.size() - 1; ++iseg) { - int addon = (iseg == phisOuter.size() - 2) ? 1 : 0; - detail::VerticesHelper::createSegment( - rvertices, {get(eMaxR), get(eMaxR)}, phisOuter[iseg], - phisOuter[iseg + 1], lseg, addon); - } + + ActsScalar phiMinInner = phi(m_inRightStripXY - m_moduleOrigin); + ActsScalar phiMaxInner = phi(m_inLeftStripXY - m_moduleOrigin); + + ActsScalar phiMinOuter = phi(m_outRightStripXY - m_moduleOrigin); + ActsScalar phiMaxOuter = phi(m_outLeftStripXY - m_moduleOrigin); + + // Inner bow from phi_min -> phi_max (needs to be reversed) + std::vector rvertices = + detail::VerticesHelper::segmentVertices( + {get(eMinR), get(eMinR)}, phiMinInner, phiMaxInner, {}, + quarterSegments); + std::reverse(rvertices.begin(), rvertices.end()); + + // Outer bow from phi_min -> phi_max + auto overtices = + detail::VerticesHelper::segmentVertices( + {get(eMaxR), get(eMaxR)}, phiMinOuter, phiMaxOuter, {}, + quarterSegments); + rvertices.insert(rvertices.end(), overtices.begin(), overtices.end()); + std::for_each(rvertices.begin(), rvertices.end(), [&](Acts::Vector2& rv) { rv += m_moduleOrigin; }); return rvertices; diff --git a/Core/src/Surfaces/CMakeLists.txt b/Core/src/Surfaces/CMakeLists.txt index 2f704f595c6..07cc26cbfcf 100644 --- a/Core/src/Surfaces/CMakeLists.txt +++ b/Core/src/Surfaces/CMakeLists.txt @@ -24,7 +24,7 @@ target_sources( SurfaceArray.cpp SurfaceError.cpp TrapezoidBounds.cpp - VerticesHelper.cpp + detail/VerticesHelper.cpp RegularSurface.cpp CurvilinearSurface.cpp detail/AlignmentHelper.cpp diff --git a/Core/src/Surfaces/ConeSurface.cpp b/Core/src/Surfaces/ConeSurface.cpp index 98f1484609d..ce10c59815f 100644 --- a/Core/src/Surfaces/ConeSurface.cpp +++ b/Core/src/Surfaces/ConeSurface.cpp @@ -183,19 +183,18 @@ const Acts::ConeBounds& Acts::ConeSurface::bounds() const { } Acts::Polyhedron Acts::ConeSurface::polyhedronRepresentation( - const GeometryContext& gctx, std::size_t lseg) const { + const GeometryContext& gctx, unsigned int quarterSegments) const { // Prepare vertices and faces std::vector vertices; std::vector faces; std::vector triangularMesh; - - double minZ = bounds().get(ConeBounds::eMinZ); - double maxZ = bounds().get(ConeBounds::eMaxZ); + ActsScalar minZ = bounds().get(ConeBounds::eMinZ); + ActsScalar maxZ = bounds().get(ConeBounds::eMaxZ); if (minZ == -std::numeric_limits::infinity() || maxZ == std::numeric_limits::infinity()) { throw std::domain_error( - "Polyhedron repr of boundless surface not possible"); + "Polyhedron representation of boundless surface is not possible"); } auto ctransform = transform(gctx); @@ -208,64 +207,53 @@ Acts::Polyhedron Acts::ConeSurface::polyhedronRepresentation( } // Cone parameters - double hPhiSec = bounds().get(ConeBounds::eHalfPhiSector); - double avgPhi = bounds().get(ConeBounds::eAveragePhi); - bool fullCone = (hPhiSec == M_PI); - - // Get the phi segments from the helper - auto phiSegs = fullCone ? detail::VerticesHelper::phiSegments() - : detail::VerticesHelper::phiSegments( - avgPhi - hPhiSec, avgPhi + hPhiSec, - {static_cast(avgPhi)}); - - // Negative cone if exists - std::vector coneSides; + ActsScalar hPhiSec = bounds().get(ConeBounds::eHalfPhiSector); + ActsScalar avgPhi = bounds().get(ConeBounds::eAveragePhi); + std::vector refPhi = {}; + if (bool fullCone = (hPhiSec == M_PI); !fullCone) { + refPhi = {avgPhi}; + } + + // Add the cone sizes + std::vector coneSides; if (std::abs(minZ) > s_onSurfaceTolerance) { coneSides.push_back(minZ); } if (std::abs(maxZ) > s_onSurfaceTolerance) { coneSides.push_back(maxZ); } + for (auto& z : coneSides) { - // Remember the first vertex std::size_t firstIv = vertices.size(); // Radius and z offset double r = std::abs(z) * bounds().tanAlpha(); Vector3 zoffset(0., 0., z); - for (unsigned int iseg = 0; iseg < phiSegs.size() - 1; ++iseg) { - int addon = (iseg == phiSegs.size() - 2 && !fullCone) ? 1 : 0; - detail::VerticesHelper::createSegment(vertices, {r, r}, phiSegs[iseg], - phiSegs[iseg + 1], lseg, addon, - zoffset, ctransform); - } - // Create the faces + auto svertices = detail::VerticesHelper::segmentVertices( + {r, r}, avgPhi - hPhiSec, avgPhi + hPhiSec, refPhi, quarterSegments, + zoffset, ctransform); + vertices.insert(vertices.end(), svertices.begin(), svertices.end()); + // If the tip exists, the faces need to be triangular if (tipExists) { - for (std::size_t iv = firstIv + 2; iv < vertices.size() + 1; ++iv) { - std::size_t one = 0, two = iv - 1, three = iv - 2; + for (std::size_t iv = firstIv + 1; iv < svertices.size() + firstIv; + ++iv) { + std::size_t one = 0, two = iv, three = iv - 1; if (z < 0.) { std::swap(two, three); } faces.push_back({one, two, three}); } - // Complete cone if necessary - if (fullCone) { - if (z > 0.) { - faces.push_back({0, firstIv, vertices.size() - 1}); - } else { - faces.push_back({0, vertices.size() - 1, firstIv}); - } - } } } + // if no tip exists, connect the two bows if (tipExists) { triangularMesh = faces; } else { - auto facesMesh = - detail::FacesHelper::cylindricalFaceMesh(vertices, fullCone); + auto facesMesh = detail::FacesHelper::cylindricalFaceMesh(vertices); faces = facesMesh.first; triangularMesh = facesMesh.second; } + return Polyhedron(vertices, faces, triangularMesh, false); } diff --git a/Core/src/Surfaces/CylinderBounds.cpp b/Core/src/Surfaces/CylinderBounds.cpp index 76e3e902ea7..e7d5032c993 100644 --- a/Core/src/Surfaces/CylinderBounds.cpp +++ b/Core/src/Surfaces/CylinderBounds.cpp @@ -104,45 +104,40 @@ std::ostream& Acts::CylinderBounds::toStream(std::ostream& sl) const { return sl; } -std::vector Acts::CylinderBounds::createCircles( - const Transform3 ctrans, std::size_t lseg) const { +std::vector Acts::CylinderBounds::circleVertices( + const Transform3 transform, unsigned int quarterSegments) const { std::vector vertices; double avgPhi = get(eAveragePhi); double halfPhi = get(eHalfPhiSector); - bool fullCylinder = coversFullAzimuth(); - - // Get the phi segments from the helper - ensures extra points - auto phiSegs = fullCylinder ? detail::VerticesHelper::phiSegments() - : detail::VerticesHelper::phiSegments( - avgPhi - halfPhi, avgPhi + halfPhi, - {static_cast(avgPhi)}); + std::vector phiRef = {}; + if (bool fullCylinder = coversFullAzimuth(); fullCylinder) { + phiRef = {static_cast(avgPhi)}; + } // Write the two bows/circles on either side std::vector sides = {-1, 1}; for (auto& side : sides) { - for (std::size_t iseg = 0; iseg < phiSegs.size() - 1; ++iseg) { - int addon = (iseg == phiSegs.size() - 2 && !fullCylinder) ? 1 : 0; - /// Helper method to create the segment - detail::VerticesHelper::createSegment( - vertices, {get(eR), get(eR)}, phiSegs[iseg], phiSegs[iseg + 1], lseg, - addon, Vector3(0., 0., side * get(eHalfLengthZ)), ctrans); - } + /// Helper method to create the segment + auto svertices = detail::VerticesHelper::segmentVertices( + {get(eR), get(eR)}, avgPhi - halfPhi, avgPhi + halfPhi, phiRef, + quarterSegments, Vector3(0., 0., side * get(eHalfLengthZ)), transform); + vertices.insert(vertices.end(), svertices.begin(), svertices.end()); } - double bevelMinZ = get(eBevelMinZ); - double bevelMaxZ = get(eBevelMaxZ); + ActsScalar bevelMinZ = get(eBevelMinZ); + ActsScalar bevelMaxZ = get(eBevelMaxZ); // Modify the vertices position if bevel is defined if ((bevelMinZ != 0. || bevelMaxZ != 0.) && vertices.size() % 2 == 0) { auto halfWay = vertices.end() - vertices.size() / 2; - double mult{1}; - auto invCtrans = ctrans.inverse(); - auto func = [&mult, &ctrans, &invCtrans](Vector3& v) { - v = invCtrans * v; + ActsScalar mult{1}; + auto invTransform = transform.inverse(); + auto func = [&mult, &transform, &invTransform](Vector3& v) { + v = invTransform * v; v(2) += v(1) * mult; - v = ctrans * v; + v = transform * v; }; if (bevelMinZ != 0.) { mult = std::tan(-bevelMinZ); diff --git a/Core/src/Surfaces/CylinderSurface.cpp b/Core/src/Surfaces/CylinderSurface.cpp index 29ca1edf150..a39dce4a4fa 100644 --- a/Core/src/Surfaces/CylinderSurface.cpp +++ b/Core/src/Surfaces/CylinderSurface.cpp @@ -188,19 +188,15 @@ const Acts::CylinderBounds& Acts::CylinderSurface::bounds() const { } Acts::Polyhedron Acts::CylinderSurface::polyhedronRepresentation( - const GeometryContext& gctx, std::size_t lseg) const { + const GeometryContext& gctx, unsigned int quarterSegments) const { auto ctrans = transform(gctx); // Prepare vertices and faces - std::vector vertices = bounds().createCircles(ctrans, lseg); - std::vector faces; - std::vector triangularMesh; - - bool fullCylinder = bounds().coversFullAzimuth(); - - auto facesMesh = - detail::FacesHelper::cylindricalFaceMesh(vertices, fullCylinder); - return Polyhedron(vertices, facesMesh.first, facesMesh.second, false); + std::vector vertices = + bounds().circleVertices(ctrans, quarterSegments); + auto [faces, triangularMesh] = + detail::FacesHelper::cylindricalFaceMesh(vertices); + return Polyhedron(vertices, faces, triangularMesh, false); } Acts::Vector3 Acts::CylinderSurface::rotSymmetryAxis( diff --git a/Core/src/Surfaces/DiamondBounds.cpp b/Core/src/Surfaces/DiamondBounds.cpp index b0239eca3f3..7febf8e7f2d 100644 --- a/Core/src/Surfaces/DiamondBounds.cpp +++ b/Core/src/Surfaces/DiamondBounds.cpp @@ -27,7 +27,7 @@ bool Acts::DiamondBounds::inside( } std::vector Acts::DiamondBounds::vertices( - unsigned int /*lseg*/) const { + unsigned int /*ignoredSegments*/) const { // Vertices starting at lower left (min rel. phi) // counter-clockwise double x1 = get(DiamondBounds::eHalfLengthXnegY); diff --git a/Core/src/Surfaces/DiscSurface.cpp b/Core/src/Surfaces/DiscSurface.cpp index c46390ff1c9..aa2f3f7036f 100644 --- a/Core/src/Surfaces/DiscSurface.cpp +++ b/Core/src/Surfaces/DiscSurface.cpp @@ -154,12 +154,9 @@ const Acts::SurfaceBounds& Acts::DiscSurface::bounds() const { } Acts::Polyhedron Acts::DiscSurface::polyhedronRepresentation( - const GeometryContext& gctx, std::size_t lseg) const { + const GeometryContext& gctx, unsigned int quarterSegments) const { // Prepare vertices and faces std::vector vertices; - std::vector faces; - std::vector triangularMesh; - // Understand the disc bool fullDisc = m_bounds->coversFullAzimuth(); bool toCenter = m_bounds->rMin() < s_onSurfaceTolerance; @@ -167,7 +164,7 @@ Acts::Polyhedron Acts::DiscSurface::polyhedronRepresentation( bool exactPolyhedron = (m_bounds->type() == SurfaceBounds::eDiscTrapezoid); bool addCentreFromConvexFace = (m_bounds->type() != SurfaceBounds::eAnnulus); if (m_bounds) { - auto vertices2D = m_bounds->vertices(lseg); + auto vertices2D = m_bounds->vertices(quarterSegments); vertices.reserve(vertices2D.size() + 1); Vector3 wCenter(0., 0., 0); for (const auto& v2D : vertices2D) { @@ -182,22 +179,19 @@ Acts::Polyhedron Acts::DiscSurface::polyhedronRepresentation( if (addCentreFromConvexFace) { vertices.push_back(wCenter); } - auto facesMesh = detail::FacesHelper::convexFaceMesh(vertices, true); - faces = facesMesh.first; - triangularMesh = facesMesh.second; + auto [faces, triangularMesh] = + detail::FacesHelper::convexFaceMesh(vertices, true); + return Polyhedron(vertices, faces, triangularMesh, exactPolyhedron); } else { // Two concentric rings, we use the pure concentric method momentarily, // but that creates too many unneccesarry faces, when only two // are needed to describe the mesh, @todo investigate merging flag - auto facesMesh = detail::FacesHelper::cylindricalFaceMesh(vertices, true); - faces = facesMesh.first; - triangularMesh = facesMesh.second; + auto [faces, triangularMesh] = + detail::FacesHelper::cylindricalFaceMesh(vertices); + return Polyhedron(vertices, faces, triangularMesh, exactPolyhedron); } - } else { - throw std::domain_error( - "Polyhedron repr of boundless surface not possible."); } - return Polyhedron(vertices, faces, triangularMesh, exactPolyhedron); + throw std::domain_error("Polyhedron repr of boundless surface not possible."); } Acts::Vector2 Acts::DiscSurface::localPolarToCartesian( diff --git a/Core/src/Surfaces/DiscTrapezoidBounds.cpp b/Core/src/Surfaces/DiscTrapezoidBounds.cpp index 6cebe5433d5..ed02bac17de 100644 --- a/Core/src/Surfaces/DiscTrapezoidBounds.cpp +++ b/Core/src/Surfaces/DiscTrapezoidBounds.cpp @@ -64,7 +64,7 @@ bool Acts::DiscTrapezoidBounds::inside( } std::vector Acts::DiscTrapezoidBounds::vertices( - unsigned int /*lseg*/) const { + unsigned int /*ignoredSegments*/) const { Vector2 cAxis(std::cos(get(eAveragePhi)), std::sin(get(eAveragePhi))); Vector2 nAxis(cAxis.y(), -cAxis.x()); auto ymin = std::sqrt(get(eMinR) * get(eMinR) - diff --git a/Core/src/Surfaces/EllipseBounds.cpp b/Core/src/Surfaces/EllipseBounds.cpp index d6357eabcc3..485f36736d8 100644 --- a/Core/src/Surfaces/EllipseBounds.cpp +++ b/Core/src/Surfaces/EllipseBounds.cpp @@ -61,10 +61,10 @@ bool Acts::EllipseBounds::inside( } std::vector Acts::EllipseBounds::vertices( - unsigned int lseg) const { + unsigned int quarterSegments) const { return detail::VerticesHelper::ellipsoidVertices( get(eInnerRx), get(eInnerRy), get(eOuterRx), get(eOuterRy), - get(eAveragePhi), get(eHalfPhiSector), lseg); + get(eAveragePhi), get(eHalfPhiSector), quarterSegments); } const Acts::RectangleBounds& Acts::EllipseBounds::boundingBox() const { diff --git a/Core/src/Surfaces/PerigeeSurface.cpp b/Core/src/Surfaces/PerigeeSurface.cpp index 328db94478e..777d061b2b1 100644 --- a/Core/src/Surfaces/PerigeeSurface.cpp +++ b/Core/src/Surfaces/PerigeeSurface.cpp @@ -58,7 +58,7 @@ std::ostream& Acts::PerigeeSurface::toStreamImpl(const GeometryContext& gctx, } Acts::Polyhedron Acts::PerigeeSurface::polyhedronRepresentation( - const GeometryContext& gctx, std::size_t /*lseg*/) const { + const GeometryContext& gctx, unsigned int /*quarterSegments*/) const { // Prepare vertices and faces std::vector vertices; std::vector faces; diff --git a/Core/src/Surfaces/PlaneSurface.cpp b/Core/src/Surfaces/PlaneSurface.cpp index 414f2611eef..b33ef82eb46 100644 --- a/Core/src/Surfaces/PlaneSurface.cpp +++ b/Core/src/Surfaces/PlaneSurface.cpp @@ -88,16 +88,14 @@ const Acts::SurfaceBounds& Acts::PlaneSurface::bounds() const { } Acts::Polyhedron Acts::PlaneSurface::polyhedronRepresentation( - const GeometryContext& gctx, std::size_t lseg) const { + const GeometryContext& gctx, unsigned int quarterSegments) const { // Prepare vertices and faces std::vector vertices; - std::vector faces; - std::vector triangularMesh; bool exactPolyhedron = true; // If you have bounds you can create a polyhedron representation if (m_bounds) { - auto vertices2D = m_bounds->vertices(lseg); + auto vertices2D = m_bounds->vertices(quarterSegments); vertices.reserve(vertices2D.size() + 1); for (const auto& v2D : vertices2D) { vertices.push_back(transform(gctx) * Vector3(v2D.x(), v2D.y(), 0.)); @@ -116,22 +114,20 @@ Acts::Polyhedron Acts::PlaneSurface::polyhedronRepresentation( // @todo same as for Discs: coversFull is not the right criterium // for triangulation if (!isEllipse || !innerExists || !coversFull) { - auto facesMesh = detail::FacesHelper::convexFaceMesh(vertices); - faces = facesMesh.first; - triangularMesh = facesMesh.second; + auto [faces, triangularMesh] = + detail::FacesHelper::convexFaceMesh(vertices); + return Polyhedron(vertices, faces, triangularMesh, exactPolyhedron); } else { // Two concentric rings, we use the pure concentric method momentarily, // but that creates too many unneccesarry faces, when only two // are needed to describe the mesh, @todo investigate merging flag - auto facesMesh = detail::FacesHelper::cylindricalFaceMesh(vertices, true); - faces = facesMesh.first; - triangularMesh = facesMesh.second; + auto [faces, triangularMesh] = + detail::FacesHelper::cylindricalFaceMesh(vertices); + return Polyhedron(vertices, faces, triangularMesh, exactPolyhedron); } - } else { - throw std::domain_error( - "Polyhedron repr of boundless surface not possible."); } - return Polyhedron(vertices, faces, triangularMesh, exactPolyhedron); + throw std::domain_error( + "Polyhedron representation of boundless surface not possible."); } Acts::Vector3 Acts::PlaneSurface::normal(const GeometryContext& gctx, diff --git a/Core/src/Surfaces/StrawSurface.cpp b/Core/src/Surfaces/StrawSurface.cpp index 1ac8f8eb264..2ce1ef74b42 100644 --- a/Core/src/Surfaces/StrawSurface.cpp +++ b/Core/src/Surfaces/StrawSurface.cpp @@ -48,7 +48,7 @@ Acts::StrawSurface& Acts::StrawSurface::operator=(const StrawSurface& other) { } Acts::Polyhedron Acts::StrawSurface::polyhedronRepresentation( - const GeometryContext& gctx, std::size_t lseg) const { + const GeometryContext& gctx, unsigned int quarterSegments) const { // Prepare vertices and faces std::vector vertices; std::vector faces; @@ -56,20 +56,17 @@ Acts::Polyhedron Acts::StrawSurface::polyhedronRepresentation( const Transform3& ctransform = transform(gctx); // Draw the bounds if more than one segment are chosen - if (lseg > 1) { + if (quarterSegments > 0u) { double r = m_bounds->get(LineBounds::eR); - auto phiSegs = detail::VerticesHelper::phiSegments(); // Write the two bows/circles on either side std::vector sides = {-1, 1}; for (auto& side : sides) { - for (std::size_t iseg = 0; iseg < phiSegs.size() - 1; ++iseg) { - int addon = (iseg == phiSegs.size() - 2) ? 1 : 0; - /// Helper method to create the segment - detail::VerticesHelper::createSegment( - vertices, {r, r}, phiSegs[iseg], phiSegs[iseg + 1], lseg, addon, - Vector3(0., 0., side * m_bounds->get(LineBounds::eHalfLengthZ)), - ctransform); - } + /// Helper method to create the segment + auto svertices = detail::VerticesHelper::segmentVertices( + {r, r}, -M_PI, M_PI, {}, quarterSegments, + Vector3(0., 0., side * m_bounds->get(LineBounds::eHalfLengthZ)), + ctransform); + vertices.insert(vertices.end(), svertices.begin(), svertices.end()); } auto facesMesh = detail::FacesHelper::cylindricalFaceMesh(vertices); faces = facesMesh.first; diff --git a/Core/src/Surfaces/Surface.cpp b/Core/src/Surfaces/Surface.cpp index 3ebf11d8e92..cadef176cda 100644 --- a/Core/src/Surfaces/Surface.cpp +++ b/Core/src/Surfaces/Surface.cpp @@ -359,6 +359,7 @@ void Acts::Surface::associateLayer(const Acts::Layer& lay) { void Acts::Surface::visualize(IVisualization3D& helper, const GeometryContext& gctx, const ViewConfig& viewConfig) const { - Polyhedron polyhedron = polyhedronRepresentation(gctx, viewConfig.nSegments); + Polyhedron polyhedron = + polyhedronRepresentation(gctx, viewConfig.quarterSegments); polyhedron.visualize(helper, viewConfig); } diff --git a/Core/src/Surfaces/TrapezoidBounds.cpp b/Core/src/Surfaces/TrapezoidBounds.cpp index 06da2fa0fef..e74285e445e 100644 --- a/Core/src/Surfaces/TrapezoidBounds.cpp +++ b/Core/src/Surfaces/TrapezoidBounds.cpp @@ -96,7 +96,7 @@ bool Acts::TrapezoidBounds::inside( } std::vector Acts::TrapezoidBounds::vertices( - unsigned int /*lseg*/) const { + unsigned int /*ignoredSegments*/) const { const double hlXnY = get(TrapezoidBounds::eHalfLengthXnegY); const double hlXpY = get(TrapezoidBounds::eHalfLengthXposY); const double hlY = get(TrapezoidBounds::eHalfLengthY); diff --git a/Core/src/Surfaces/VerticesHelper.cpp b/Core/src/Surfaces/detail/VerticesHelper.cpp similarity index 54% rename from Core/src/Surfaces/VerticesHelper.cpp rename to Core/src/Surfaces/detail/VerticesHelper.cpp index 3ff4785fe37..b8bed1fb50f 100644 --- a/Core/src/Surfaces/VerticesHelper.cpp +++ b/Core/src/Surfaces/detail/VerticesHelper.cpp @@ -14,44 +14,61 @@ std::vector Acts::detail::VerticesHelper::phiSegments( ActsScalar phiMin, ActsScalar phiMax, - const std::vector& phiRefs, ActsScalar phiTolerance) { - // This is to ensure that the extrema are built regardless of number - // of segments - std::vector phiSegments; - std::vector quarters = {-M_PI, -0.5 * M_PI, 0., 0.5 * M_PI, M_PI}; - // It does not cover the full azimuth - if (phiMin != -M_PI || phiMax != M_PI) { - phiSegments.push_back(phiMin); - for (unsigned int iq = 1; iq < 4; ++iq) { - if (phiMin < quarters[iq] && phiMax > quarters[iq]) { - phiSegments.push_back(quarters[iq]); - } + const std::vector& phiRefs, unsigned int quarterSegments) { + // Check that the phi range is valid + if (phiMin > phiMax) { + throw std::invalid_argument( + "VerticesHelper::phiSegments ... Minimum phi must be smaller than " + "maximum phi"); + } + + // First check that no reference phi is outside the range + for (ActsScalar phiRef : phiRefs) { + if (phiRef < phiMin || phiRef > phiMax) { + throw std::invalid_argument( + "VerticesHelper::phiSegments ... Reference phi is outside the range " + "of the segment"); } - phiSegments.push_back(phiMax); - } else { - phiSegments = quarters; } - // Insert the reference phis if - if (!phiRefs.empty()) { - for (const auto& phiRef : phiRefs) { - // Trying to find the right patch - auto match = std::find_if( - phiSegments.begin(), phiSegments.end(), [&](ActsScalar phiSeg) { - return std::abs(phiSeg - phiRef) < phiTolerance; - }); - if (match == phiSegments.end()) { + if (quarterSegments == 0u) { + throw std::invalid_argument( + "VerticesHelper::phiSegments ... Number of segments must be larger " + "than 0."); + } + std::vector phiSegments = {phiMin, phiMax}; + // Minimum approximation for a circle need + // - if the circle is closed the last point is given twice + for (unsigned int i = 0; i < 4 * quarterSegments + 1; ++i) { + ActsScalar phiExt = -M_PI + i * 2 * M_PI / (4 * quarterSegments); + if (phiExt > phiMin && phiExt < phiMax && + std::ranges::none_of(phiSegments, [&phiExt](ActsScalar phi) { + return std::abs(phi - phiExt) < + std::numeric_limits::epsilon(); + })) { + phiSegments.push_back(phiExt); + } + } + // Add the reference phis + for (const auto& phiRef : phiRefs) { + if (phiRef > phiMin && phiRef < phiMax) { + if (std::ranges::none_of(phiSegments, [&phiRef](ActsScalar phi) { + return std::abs(phi - phiRef) < + std::numeric_limits::epsilon(); + })) { phiSegments.push_back(phiRef); } } - std::ranges::sort(phiSegments); } + + // Sort the phis + std::ranges::sort(phiSegments); return phiSegments; } std::vector Acts::detail::VerticesHelper::ellipsoidVertices( ActsScalar innerRx, ActsScalar innerRy, ActsScalar outerRx, ActsScalar outerRy, ActsScalar avgPhi, ActsScalar halfPhi, - unsigned int lseg) { + unsigned int quarterSegments) { // List of vertices counter-clockwise starting at smallest phi w.r.t center, // for both inner/outer ring/segment std::vector rvertices; // return vertices @@ -61,22 +78,20 @@ std::vector Acts::detail::VerticesHelper::ellipsoidVertices( bool innerExists = (innerRx > 0. && innerRy > 0.); bool closed = std::abs(halfPhi - M_PI) < s_onSurfaceTolerance; - // Get the phi segments from the helper method - auto phiSegs = detail::VerticesHelper::phiSegments( - avgPhi - halfPhi, avgPhi + halfPhi, {avgPhi}); + std::vector refPhi = {}; + if (avgPhi != 0.) { + refPhi.push_back(avgPhi); + } // The inner (if exists) and outer bow - for (unsigned int iseg = 0; iseg < phiSegs.size() - 1; ++iseg) { - int addon = (iseg == phiSegs.size() - 2 && !closed) ? 1 : 0; - if (innerExists) { - createSegment(ivertices, {innerRx, innerRy}, - phiSegs[iseg], phiSegs[iseg + 1], lseg, - addon); - } - createSegment(overtices, {outerRx, outerRy}, - phiSegs[iseg], phiSegs[iseg + 1], lseg, - addon); + if (innerExists) { + ivertices = segmentVertices( + {innerRx, innerRy}, avgPhi - halfPhi, avgPhi + halfPhi, refPhi, + quarterSegments); } + overtices = segmentVertices( + {outerRx, outerRy}, avgPhi - halfPhi, avgPhi + halfPhi, refPhi, + quarterSegments); // We want to keep the same counter-clockwise orientation for displaying if (!innerExists) { @@ -97,9 +112,9 @@ std::vector Acts::detail::VerticesHelper::ellipsoidVertices( std::vector Acts::detail::VerticesHelper::circularVertices( ActsScalar innerR, ActsScalar outerR, ActsScalar avgPhi, ActsScalar halfPhi, - unsigned int lseg) { + unsigned int quarterSegments) { return ellipsoidVertices(innerR, innerR, outerR, outerR, avgPhi, halfPhi, - lseg); + quarterSegments); } bool Acts::detail::VerticesHelper::onHyperPlane( diff --git a/Core/src/TrackFinding/MeasurementSelector.cpp b/Core/src/TrackFinding/MeasurementSelector.cpp index cde6670e4ca..130c8381536 100644 --- a/Core/src/TrackFinding/MeasurementSelector.cpp +++ b/Core/src/TrackFinding/MeasurementSelector.cpp @@ -118,10 +118,10 @@ MeasurementSelector::Cuts MeasurementSelector::getCutsByTheta( // look at the positive half of the Z axis const double constrainedTheta = std::min(theta, M_PI - theta); - auto it = std::find_if(config.begin(), config.end(), - [constrainedTheta](const InternalCutBin& cuts) { - return constrainedTheta < cuts.maxTheta; - }); + auto it = std::ranges::find_if( + config, [constrainedTheta](const InternalCutBin& cuts) { + return constrainedTheta < cuts.maxTheta; + }); assert(it != config.end()); return {it->maxNumMeasurements, it->maxChi2Measurement, it->maxChi2Outlier}; } diff --git a/Core/src/TrackFitting/GlobalChiSquareFitterError.cpp b/Core/src/TrackFitting/GlobalChiSquareFitterError.cpp index 98beceb8cb1..3a3cc713173 100644 --- a/Core/src/TrackFitting/GlobalChiSquareFitterError.cpp +++ b/Core/src/TrackFitting/GlobalChiSquareFitterError.cpp @@ -32,6 +32,8 @@ class GlobalChiSquareFitterErrorCategory : public std::error_category { return "Gx2f: Not enough measurements."; case GlobalChiSquareFitterError::UpdatePushedToNewVolume: return "Gx2f: Update pushed the parameters to a new volume."; + case GlobalChiSquareFitterError::UsedUnreachableMeasurements: + return "Gx2f: Final fit used unreachable measurements."; default: return "unknown"; } diff --git a/Core/src/Utilities/BinningType.cpp b/Core/src/Utilities/BinningType.cpp index e1ed3ecea71..8faa7dcd856 100644 --- a/Core/src/Utilities/BinningType.cpp +++ b/Core/src/Utilities/BinningType.cpp @@ -32,8 +32,7 @@ const std::vector& allBinningValues() { } BinningValue binningValueFromName(const std::string& name) { - auto it = - std::find(s_binningValueNames.begin(), s_binningValueNames.end(), name); + auto it = std::ranges::find(s_binningValueNames, name); if (it == s_binningValueNames.end()) { throw std::invalid_argument("Unknown binning value name: " + name); } diff --git a/Core/src/Utilities/CMakeLists.txt b/Core/src/Utilities/CMakeLists.txt index 6c5553387a0..1fb61813cd3 100644 --- a/Core/src/Utilities/CMakeLists.txt +++ b/Core/src/Utilities/CMakeLists.txt @@ -2,7 +2,6 @@ target_sources( ActsCore PRIVATE AnnealingUtility.cpp - BinUtility.cpp Logger.cpp SpacePointUtility.cpp TrackHelpers.cpp diff --git a/Core/src/Vertexing/AdaptiveMultiVertexFinder.cpp b/Core/src/Vertexing/AdaptiveMultiVertexFinder.cpp index 655ee0b218f..34d20e32e0a 100644 --- a/Core/src/Vertexing/AdaptiveMultiVertexFinder.cpp +++ b/Core/src/Vertexing/AdaptiveMultiVertexFinder.cpp @@ -12,6 +12,8 @@ #include "Acts/Vertexing/IVertexFinder.hpp" #include "Acts/Vertexing/VertexingError.hpp" +#include + namespace Acts { Result> AdaptiveMultiVertexFinder::find( @@ -364,10 +366,7 @@ std::pair AdaptiveMultiVertexFinder::checkVertexAndCompatibleTracks( !m_cfg.useFastCompatibility)) { // TODO: Understand why looking for compatible tracks only in seed tracks // and not also in all tracks - auto foundIter = - std::find_if(seedTracks.begin(), seedTracks.end(), - [&trk](auto seedTrk) { return trk == seedTrk; }); - if (foundIter != seedTracks.end()) { + if (rangeContainsValue(seedTracks, trk)) { nCompatibleTracks++; ACTS_DEBUG("Compatible track found."); @@ -399,9 +398,7 @@ auto AdaptiveMultiVertexFinder::removeCompatibleTracksFromSeedTracks( trkAtVtx.chi2Track < m_cfg.maxVertexChi2 && !m_cfg.useFastCompatibility)) { // Find and remove track from seedTracks - auto foundSeedIter = - std::find_if(seedTracks.begin(), seedTracks.end(), - [&trk](auto seedTrk) { return trk == seedTrk; }); + auto foundSeedIter = std::ranges::find(seedTracks, trk); if (foundSeedIter != seedTracks.end()) { seedTracks.erase(foundSeedIter); removedSeedTracks.push_back(trk); @@ -425,9 +422,7 @@ bool AdaptiveMultiVertexFinder::removeTrackIfIncompatible( double compatibility = trkAtVtx.vertexCompatibility; if (compatibility > maxCompatibility) { // Try to find track in seed tracks - auto foundSeedIter = - std::find_if(seedTracks.begin(), seedTracks.end(), - [&trk](auto seedTrk) { return trk == seedTrk; }); + auto foundSeedIter = std::ranges::find(seedTracks, trk); if (foundSeedIter != seedTracks.end()) { maxCompatibility = compatibility; maxCompSeedIt = foundSeedIter; diff --git a/Core/src/Vertexing/IterativeVertexFinder.cpp b/Core/src/Vertexing/IterativeVertexFinder.cpp index e455dca47ec..9c03ba8a8f8 100644 --- a/Core/src/Vertexing/IterativeVertexFinder.cpp +++ b/Core/src/Vertexing/IterativeVertexFinder.cpp @@ -222,10 +222,9 @@ inline void Acts::IterativeVertexFinder::removeTracks( const BoundTrackParameters& params = m_cfg.extractParameters(trk); // Find track in seedTracks auto foundIter = - std::find_if(seedTracks.begin(), seedTracks.end(), - [¶ms, this](const auto seedTrk) { - return params == m_cfg.extractParameters(seedTrk); - }); + std::ranges::find_if(seedTracks, [¶ms, this](const auto seedTrk) { + return params == m_cfg.extractParameters(seedTrk); + }); if (foundIter != seedTracks.end()) { // Remove track from seed tracks seedTracks.erase(foundIter); @@ -284,10 +283,7 @@ Acts::Result Acts::IterativeVertexFinder::removeUsedCompatibleTracks( } // Find and remove track from seedTracks auto foundSeedIter = - std::find_if(seedTracks.begin(), seedTracks.end(), - [&trackAtVtx](const auto& seedTrk) { - return trackAtVtx.originalParams == seedTrk; - }); + std::ranges::find(seedTracks, trackAtVtx.originalParams); if (foundSeedIter != seedTracks.end()) { seedTracks.erase(foundSeedIter); } else { @@ -296,10 +292,7 @@ Acts::Result Acts::IterativeVertexFinder::removeUsedCompatibleTracks( // Find and remove track from tracksToFit auto foundFitIter = - std::find_if(tracksToFit.begin(), tracksToFit.end(), - [&trackAtVtx](const auto& fitTrk) { - return trackAtVtx.originalParams == fitTrk; - }); + std::ranges::find(tracksToFit, trackAtVtx.originalParams); if (foundFitIter != tracksToFit.end()) { tracksToFit.erase(foundFitIter); } else { @@ -334,9 +327,7 @@ Acts::Result Acts::IterativeVertexFinder::removeUsedCompatibleTracks( // check if sufficiently compatible with last fitted vertex // (quite loose constraint) if (chi2 < m_cfg.maximumChi2cutForSeeding) { - auto foundIter = - std::find_if(seedTracks.begin(), seedTracks.end(), - [&trk](const auto& seedTrk) { return trk == seedTrk; }); + auto foundIter = std::ranges::find(seedTracks, trk); if (foundIter != seedTracks.end()) { // Remove track from seed tracks seedTracks.erase(foundIter); @@ -345,8 +336,8 @@ Acts::Result Acts::IterativeVertexFinder::removeUsedCompatibleTracks( } else { // Track not compatible with vertex // Remove track from current vertex - auto foundIter = std::find_if( - tracksAtVertex.begin(), tracksAtVertex.end(), + auto foundIter = std::ranges::find_if( + tracksAtVertex, [&trk](auto trkAtVtx) { return trk == trkAtVtx.originalParams; }); if (foundIter != tracksAtVertex.end()) { // Remove track from seed tracks @@ -495,8 +486,8 @@ Acts::Result Acts::IterativeVertexFinder::reassignTracksToNewVertex( // delete it later // when all tracks used to fit current vertex are deleted seedTracks.push_back(tracksIter->originalParams); - // seedTracks.push_back(*std::find_if( - // origTracks.begin(), origTracks.end(), + // seedTracks.push_back(*std::ranges::find_if( + // origTracks, // [&origParams, this](auto origTrack) { // return origParams == m_extractParameters(*origTrack); // })); diff --git a/Core/src/Visualization/CMakeLists.txt b/Core/src/Visualization/CMakeLists.txt index 5d4f916af1c..567b1e1e236 100644 --- a/Core/src/Visualization/CMakeLists.txt +++ b/Core/src/Visualization/CMakeLists.txt @@ -1 +1,4 @@ -target_sources(ActsCore PRIVATE GeometryView3D.cpp EventDataView3D.cpp) +target_sources( + ActsCore + PRIVATE GeometryView3D.cpp EventDataView3D.cpp ObjVisualization3D.cpp +) diff --git a/Core/src/Visualization/EventDataView3D.cpp b/Core/src/Visualization/EventDataView3D.cpp index 63644d0204f..ac3a62a1e79 100644 --- a/Core/src/Visualization/EventDataView3D.cpp +++ b/Core/src/Visualization/EventDataView3D.cpp @@ -27,12 +27,13 @@ void Acts::EventDataView3D::drawCovarianceCartesian( std::vector ellipse = createEllipse( lambda0 * locErrorScale, lambda1 * locErrorScale, theta, - viewConfig.nSegments, viewConfig.offset, lposition, transform); + viewConfig.quarterSegments, viewConfig.offset, lposition, transform); ellipse.push_back(transform * Vector3(lposition.x(), lposition.y(), viewConfig.offset)); - auto faces = detail::FacesHelper::convexFaceMesh(ellipse, true); - Polyhedron ellipseHedron(ellipse, faces.first, faces.second); + auto [faces, triangularMesh] = + detail::FacesHelper::convexFaceMesh(ellipse, true); + Polyhedron ellipseHedron(ellipse, faces, triangularMesh); Acts::GeometryView3D::drawPolyhedron(helper, ellipseHedron, viewConfig); } @@ -56,12 +57,13 @@ void Acts::EventDataView3D::drawCovarianceAngular( std::vector ellipse = createEllipse(angularErrorScale * directionScale * lambda0 * sin(dtheta), angularErrorScale * directionScale * lambda1, theta, - viewConfig.nSegments, 0., {0., 0.}, eplane); + viewConfig.quarterSegments, 0., {0., 0.}, eplane); std::vector coneTop = ellipse; coneTop.push_back(anker); - auto coneTopFaces = detail::FacesHelper::convexFaceMesh(coneTop, true); - Polyhedron coneTopHedron(coneTop, coneTopFaces.first, coneTopFaces.second); + auto [faces, triangularMesh] = + detail::FacesHelper::convexFaceMesh(coneTop, true); + Polyhedron coneTopHedron(coneTop, faces, triangularMesh); GeometryView3D::drawPolyhedron(helper, coneTopHedron, viewConfig); std::vector cone = ellipse; @@ -69,7 +71,8 @@ void Acts::EventDataView3D::drawCovarianceAngular( // Force triangular ViewConfig coneViewConfig = viewConfig; coneViewConfig.triangulate = true; - auto coneFaces = detail::FacesHelper::convexFaceMesh(cone, true); - Polyhedron coneHedron(cone, coneFaces.first, coneFaces.second); + auto [facesCone, triangularMeshCone] = + detail::FacesHelper::convexFaceMesh(cone, true); + Polyhedron coneHedron(cone, facesCone, triangularMeshCone); GeometryView3D::drawPolyhedron(helper, coneHedron, coneViewConfig); } diff --git a/Core/src/Visualization/GeometryView3D.cpp b/Core/src/Visualization/GeometryView3D.cpp index e0a7c52a5a7..f16d9e809cc 100644 --- a/Core/src/Visualization/GeometryView3D.cpp +++ b/Core/src/Visualization/GeometryView3D.cpp @@ -26,7 +26,6 @@ #include "Acts/Surfaces/RadialBounds.hpp" #include "Acts/Surfaces/Surface.hpp" #include "Acts/Surfaces/SurfaceArray.hpp" -#include "Acts/Utilities/BinnedArray.hpp" #include "Acts/Utilities/BinningType.hpp" #include "Acts/Utilities/IAxis.hpp" #include "Acts/Utilities/UnitVectors.hpp" @@ -36,18 +35,9 @@ #include #include #include -#include #include #include -namespace Acts::Experimental { -ViewConfig s_viewSensitive = {.color = {0, 180, 240}}; -ViewConfig s_viewPassive = {.color = {240, 280, 0}}; -ViewConfig s_viewVolume = {.color = {220, 220, 0}}; -ViewConfig s_viewGrid = {.color = {220, 0, 0}}; -ViewConfig s_viewLine = {.color = {0, 0, 220}}; -} // namespace Acts::Experimental - void Acts::GeometryView3D::drawPolyhedron(IVisualization3D& helper, const Polyhedron& polyhedron, const ViewConfig& viewConfig) { @@ -95,7 +85,6 @@ void Acts::GeometryView3D::drawSurfaceArray( auto phiValues = axes[0]->getBinEdges(); auto zValues = axes[1]->getBinEdges(); ViewConfig gridRadConfig = gridConfig; - gridRadConfig.nSegments = phiValues.size(); // Longitudinal lines for (auto phi : phiValues) { double cphi = std::cos(phi); @@ -120,7 +109,7 @@ void Acts::GeometryView3D::drawSurfaceArray( auto rValues = axes[0]->getBinEdges(); auto phiValues = axes[1]->getBinEdges(); ViewConfig gridRadConfig = gridConfig; - gridRadConfig.nSegments = phiValues.size(); + gridRadConfig.quarterSegments = phiValues.size(); for (auto r : rValues) { CylinderVolumeBounds cvb(r - 0.5 * thickness, r + 0.5 * thickness, 0.5 * thickness); @@ -244,7 +233,7 @@ void Acts::GeometryView3D::drawTrackingVolume( ViewConfig lConfig = layerView; ViewConfig sConfig = sensitiveView; ViewConfig gConfig = gridView; - gConfig.nSegments = 8; + gConfig.quarterSegments = 8; ViewConfig vcConfig = cConfig; std::string vname = tVolume.volumeName(); diff --git a/Core/src/Visualization/ObjVisualization3D.cpp b/Core/src/Visualization/ObjVisualization3D.cpp new file mode 100644 index 00000000000..777e883b3d3 --- /dev/null +++ b/Core/src/Visualization/ObjVisualization3D.cpp @@ -0,0 +1,211 @@ +// 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 "Acts/Visualization/ObjVisualization3D.hpp" + +#include +#include +#include + +namespace Acts { + +void ObjVisualization3D::vertex(const Vector3& vtx, Color color) { + auto& o = object(); + o.vertexColors[o.vertices.size()] = color; + o.vertices.push_back(vtx.template cast()); +} + +void ObjVisualization3D::line(const Vector3& a, const Vector3& b, Color color) { + auto& o = object(); + if (color != Color{0, 0, 0}) { + o.lineColors[o.lines.size()] = color; + } + // not implemented + vertex(a, color); + vertex(b, color); + o.lines.push_back({o.vertices.size() - 2, o.vertices.size() - 1}); +} + +void ObjVisualization3D::face(const std::vector& vtxs, Color color) { + auto& o = object(); + if (color != Color{0, 0, 0}) { + o.faceColors[o.faces.size()] = color; + } + FaceType idxs; + idxs.reserve(vtxs.size()); + for (const auto& vtx : vtxs) { + vertex(vtx, color); + idxs.push_back(o.vertices.size() - 1); + } + o.faces.push_back(std::move(idxs)); +} + +void ObjVisualization3D::faces(const std::vector& vtxs, + const std::vector& faces, + Color color) { + auto& o = object(); + // No faces given - call the face() method + if (faces.empty()) { + face(vtxs, color); + } else { + if (color != Color{0, 0, 0}) { + o.faceColors[o.faces.size()] = color; + } + auto vtxoffs = o.vertices.size(); + if (color != Color{0, 0, 0}) { + o.vertexColors[o.vertices.size()] = color; + } + o.vertices.insert(o.vertices.end(), vtxs.begin(), vtxs.end()); + for (const auto& face : faces) { + if (face.size() == 2) { + o.lines.push_back({face[0] + vtxoffs, face[2] + vtxoffs}); + } else { + FaceType rawFace; + std::ranges::transform( + face, std::back_inserter(rawFace), + [&](unsigned long iv) { return (iv + vtxoffs); }); + o.faces.push_back(rawFace); + } + } + } +} + +void ObjVisualization3D::write(const std::filesystem::path& path) const { + std::ofstream os; + std::filesystem::path objectpath = path; + if (!objectpath.has_extension()) { + objectpath.replace_extension(std::filesystem::path("obj")); + } + os.open(std::filesystem::absolute(objectpath).string()); + std::filesystem::path mtlpath = objectpath; + mtlpath.replace_extension(std::filesystem::path("mtl")); + + const std::string mtlpathString = std::filesystem::absolute(mtlpath).string(); + os << "mtllib " << mtlpathString << "\n"; + std::ofstream mtlos; + mtlos.open(mtlpathString); + + write(os, mtlos); + os.close(); + mtlos.close(); +} + +void ObjVisualization3D::write(std::ostream& os) const { + std::stringstream sterile; + write(os, sterile); +} + +void ObjVisualization3D::write(std::ostream& os, std::ostream& mos) const { + std::map> materials; + + auto mixColor = [&](const Color& color) { + std::string materialName; + materialName = "material_"; + materialName += std::to_string(color[0]) + std::string("_"); + materialName += std::to_string(color[1]) + std::string("_"); + materialName += std::to_string(color[2]); + + if (!materials.contains(materialName)) { + mos << "newmtl " << materialName << "\n"; + std::vector shadings = {"Ka", "Kd", "Ks"}; + for (const auto& shd : shadings) { + mos << shd << " " << std::to_string(color[0] / 256.) << " "; + mos << std::to_string(color[1] / 256.) << " "; + mos << std::to_string(color[2] / 256.) << " " << "\n"; + } + mos << "\n"; + } + return std::string("usemtl ") + materialName; + }; + + std::size_t vertexOffset = 0; + for (const auto& o : m_objects) { + if (!o.name.empty()) { + os << "o " << o.name << "\n"; + } + + std::size_t iv = 0; + Color lastVertexColor = {0, 0, 0}; + for (const VertexType& vtx : o.vertices) { + if (o.vertexColors.contains(iv)) { + auto color = o.vertexColors.find(iv)->second; + if (color != lastVertexColor) { + os << mixColor(color) << "\n"; + lastVertexColor = color; + } + } + + os << "v " << std::setprecision(m_outputPrecision) + << m_outputScalor * vtx.x() << " " << m_outputScalor * vtx.y() << " " + << m_outputScalor * vtx.z() << "\n"; + ++iv; + } + std::size_t il = 0; + Color lastLineColor = {0, 0, 0}; + for (const auto& [start, end] : o.lines) { + if (o.lineColors.contains(il)) { + auto color = o.lineColors.find(il)->second; + if (color != lastLineColor) { + os << mixColor(color) << "\n"; + lastLineColor = color; + } + } + os << "l " << vertexOffset + start + 1 << " " << vertexOffset + end + 1 + << "\n"; + ++il; + } + std::size_t is = 0; + Color lastFaceColor = {0, 0, 0}; + for (const FaceType& fc : o.faces) { + if (o.faceColors.contains(is)) { + auto color = o.faceColors.find(is)->second; + if (color != lastFaceColor) { + os << mixColor(color) << "\n"; + lastFaceColor = color; + } + } + os << "f"; + for (std::size_t fi : fc) { + os << " " << vertexOffset + fi + 1; + } + os << "\n"; + ++is; + } + + vertexOffset += iv; + } +} + +void ObjVisualization3D::clear() { + m_objects.clear(); +} + +void ObjVisualization3D::object(const std::string& name) { + if (name.empty()) { + throw std::invalid_argument{"Object name can not be empty"}; + } + m_objects.push_back(Object{.name = name}); +} + +ObjVisualization3D::Object& ObjVisualization3D::object() { + if (m_objects.empty()) { + m_objects.push_back(Object{.name = ""}); + } + + return m_objects.back(); +} + +const ObjVisualization3D::Object& ObjVisualization3D::object() const { + if (m_objects.empty()) { + throw std::runtime_error{"No objects present"}; + } + + return m_objects.back(); +} + +} // namespace Acts diff --git a/Examples/Algorithms/Geant4/src/SensitiveSteppingAction.cpp b/Examples/Algorithms/Geant4/src/SensitiveSteppingAction.cpp index cb763ecc582..17df42bdb21 100644 --- a/Examples/Algorithms/Geant4/src/SensitiveSteppingAction.cpp +++ b/Examples/Algorithms/Geant4/src/SensitiveSteppingAction.cpp @@ -18,6 +18,7 @@ #include "ActsExamples/Geant4/SensitiveSurfaceMapper.hpp" #include "ActsFatras/EventData/Barcode.hpp" +#include #include #include #include @@ -254,11 +255,10 @@ void ActsExamples::SensitiveSteppingAction::UserSteppingAction( buffer.back().momentum4After(), eventStore().particleHitCount.at(particleId) - 1); - assert(std::all_of(buffer.begin(), buffer.end(), - [&](const auto& h) { return h.geometryId() == geoId; })); - assert(std::all_of(buffer.begin(), buffer.end(), [&](const auto& h) { - return h.particleId() == particleId; - })); + assert(std::ranges::all_of( + buffer, [&](const auto& h) { return h.geometryId() == geoId; })); + assert(std::ranges::all_of( + buffer, [&](const auto& h) { return h.particleId() == particleId; })); eventStore().numberGeantSteps += buffer.size(); eventStore().maxStepsForHit = diff --git a/Examples/Algorithms/Geant4/src/SensitiveSurfaceMapper.cpp b/Examples/Algorithms/Geant4/src/SensitiveSurfaceMapper.cpp index ced44d89e94..2fd1a924d94 100644 --- a/Examples/Algorithms/Geant4/src/SensitiveSurfaceMapper.cpp +++ b/Examples/Algorithms/Geant4/src/SensitiveSurfaceMapper.cpp @@ -331,7 +331,7 @@ bool ActsExamples::SensitiveSurfaceMapper::checkMapping( if (writeMissingSurfacesAsObj) { Acts::ObjVisualization3D visualizer; Acts::ViewConfig vcfg; - vcfg.nSegments = 720; + vcfg.quarterSegments = 720; for (auto srf : missing) { Acts::GeometryView3D::drawSurface(visualizer, *srf, gctx, Acts::Transform3::Identity(), vcfg); diff --git a/Examples/Algorithms/GeneratorsPythia8/ActsExamples/Generators/Pythia8ProcessGenerator.cpp b/Examples/Algorithms/GeneratorsPythia8/ActsExamples/Generators/Pythia8ProcessGenerator.cpp index 91de17b9eef..808bf931c6a 100644 --- a/Examples/Algorithms/GeneratorsPythia8/ActsExamples/Generators/Pythia8ProcessGenerator.cpp +++ b/Examples/Algorithms/GeneratorsPythia8/ActsExamples/Generators/Pythia8ProcessGenerator.cpp @@ -154,11 +154,10 @@ Pythia8Generator::operator()(RandomEngine& rng) { // check if an existing vertex is close enough auto it = - std::find_if(vertices.begin(), vertices.end(), - [&pos4, this](const SimVertex& other) { - return (pos4.head<3>() - other.position()).norm() < - m_cfg.spatialVertexThreshold; - }); + std::ranges::find_if(vertices, [&pos4, this](const SimVertex& v) { + return (pos4.head<3>() - v.position()).norm() < + m_cfg.spatialVertexThreshold; + }); if (it != vertices.end()) { particleId.setVertexSecondary(std::distance(vertices.begin(), it)); diff --git a/Examples/Algorithms/MaterialMapping/include/ActsExamples/MaterialMapping/MappingMaterialDecorator.hpp b/Examples/Algorithms/MaterialMapping/include/ActsExamples/MaterialMapping/MappingMaterialDecorator.hpp index 565b04c9ae3..b06e538885c 100644 --- a/Examples/Algorithms/MaterialMapping/include/ActsExamples/MaterialMapping/MappingMaterialDecorator.hpp +++ b/Examples/Algorithms/MaterialMapping/include/ActsExamples/MaterialMapping/MappingMaterialDecorator.hpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -93,14 +94,10 @@ class MappingMaterialDecorator : public IMaterialDecorator { /// /// @param volume to be looped onto void volumeLoop(const Acts::TrackingVolume* tVolume) { - auto sameId = - [tVolume]( - const std::pair>& pair) { - return (tVolume->geometryId() == pair.first); - }; - if (std::find_if(m_volumeMaterialMap.begin(), m_volumeMaterialMap.end(), - sameId) != m_volumeMaterialMap.end()) { + auto sameId = [tVolume](const auto& pair) { + return (tVolume->geometryId() == pair.first); + }; + if (std::ranges::any_of(m_volumeMaterialMap, sameId)) { // this volume was already visited return; } diff --git a/Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/SeedingAlgorithm.hpp b/Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/SeedingAlgorithm.hpp index 61042cd5d09..73bb81d5d7f 100644 --- a/Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/SeedingAlgorithm.hpp +++ b/Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/SeedingAlgorithm.hpp @@ -100,8 +100,8 @@ class SeedingAlgorithm final : public IAlgorithm { Acts::SeedFinder> m_seedFinder; - std::unique_ptr> m_bottomBinFinder; - std::unique_ptr> m_topBinFinder; + std::unique_ptr> m_bottomBinFinder{nullptr}; + std::unique_ptr> m_topBinFinder{nullptr}; Config m_cfg; diff --git a/Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/SeedingAlgorithmHashing.hpp b/Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/SeedingAlgorithmHashing.hpp index 194ef4944a1..78a0ef2ae89 100644 --- a/Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/SeedingAlgorithmHashing.hpp +++ b/Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/SeedingAlgorithmHashing.hpp @@ -135,8 +135,8 @@ class SeedingAlgorithmHashing final : public IAlgorithm { Acts::SeedFinder> m_seedFinder; - std::unique_ptr> m_bottomBinFinder; - std::unique_ptr> m_topBinFinder; + std::unique_ptr> m_bottomBinFinder{nullptr}; + std::unique_ptr> m_topBinFinder{nullptr}; Config m_cfg; diff --git a/Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/TrackFindingAlgorithm.hpp b/Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/TrackFindingAlgorithm.hpp index 999bf7ef7fe..8a36481fc41 100644 --- a/Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/TrackFindingAlgorithm.hpp +++ b/Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/TrackFindingAlgorithm.hpp @@ -130,12 +130,17 @@ class TrackFindingAlgorithm final : public IAlgorithm { bool trimTracks = true; // Pixel and strip volume ids to be used for maxPixel/StripHoles cuts - std::set pixelVolumes; - std::set stripVolumes; + std::vector pixelVolumeIds; + std::vector stripVolumeIds; - /// additional track selector settings + // additional track selector settings std::size_t maxPixelHoles = std::numeric_limits::max(); std::size_t maxStripHoles = std::numeric_limits::max(); + + /// The volume ids to constrain the track finding to + std::vector constrainToVolumeIds; + /// The volume ids to stop the track finding at + std::vector endOfWorldVolumeIds; }; /// Constructor of the track finding algorithm diff --git a/Examples/Algorithms/TrackFinding/src/SeedingAlgorithm.cpp b/Examples/Algorithms/TrackFinding/src/SeedingAlgorithm.cpp index 40111376a9c..14b89d848ca 100644 --- a/Examples/Algorithms/TrackFinding/src/SeedingAlgorithm.cpp +++ b/Examples/Algorithms/TrackFinding/src/SeedingAlgorithm.cpp @@ -11,7 +11,6 @@ #include "Acts/Definitions/Algebra.hpp" #include "Acts/EventData/Seed.hpp" #include "Acts/EventData/SpacePointData.hpp" -#include "Acts/Geometry/Extent.hpp" #include "Acts/Seeding/BinnedGroup.hpp" #include "Acts/Seeding/SeedFilter.hpp" #include "Acts/Utilities/BinningType.hpp" @@ -191,10 +190,10 @@ ActsExamples::SeedingAlgorithm::SeedingAlgorithm( ActsExamples::SpacePointContainer>, Acts::detail::RefHolder>::SpacePointProxyType; - m_bottomBinFinder = std::make_unique>( - m_cfg.numPhiNeighbors, cfg.zBinNeighborsBottom); - m_topBinFinder = std::make_unique>( - m_cfg.numPhiNeighbors, m_cfg.zBinNeighborsTop); + m_bottomBinFinder = std::make_unique>( + m_cfg.numPhiNeighbors, cfg.zBinNeighborsBottom, 0); + m_topBinFinder = std::make_unique>( + m_cfg.numPhiNeighbors, m_cfg.zBinNeighborsTop, 0); m_cfg.seedFinderConfig.seedFilter = std::make_unique>( @@ -243,33 +242,40 @@ ActsExamples::ProcessCode ActsExamples::SeedingAlgorithm::execute( using value_type = typename decltype(spContainer)::SpacePointProxyType; using seed_type = Acts::Seed; - // extent used to store r range for middle spacepoint - Acts::Extent rRangeSPExtent; - Acts::CylindricalSpacePointGrid grid = Acts::CylindricalSpacePointGridCreator::createGrid( m_cfg.gridConfig, m_cfg.gridOptions); Acts::CylindricalSpacePointGridCreator::fillGrid( m_cfg.seedFinderConfig, m_cfg.seedFinderOptions, grid, - spContainer.begin(), spContainer.end(), rRangeSPExtent); + spContainer.begin(), spContainer.end()); + + // Compute radius Range + // we rely on the fact the grid is storing the proxies + // with a sorting in the radius + float minRange = std::numeric_limits::max(); + float maxRange = std::numeric_limits::lowest(); + for (const auto& coll : grid) { + if (coll.empty()) { + continue; + } + const auto* firstEl = coll.front(); + const auto* lastEl = coll.back(); + minRange = std::min(firstEl->radius(), minRange); + maxRange = std::max(lastEl->radius(), maxRange); + } - std::array, 2ul> navigation; + std::array, 3ul> navigation; navigation[1ul] = m_cfg.seedFinderConfig.zBinsCustomLooping; auto spacePointsGrouping = Acts::CylindricalBinnedGroup( std::move(grid), *m_bottomBinFinder, *m_topBinFinder, std::move(navigation)); - // safely clamp double to float - float up = Acts::clampValue( - std::floor(rRangeSPExtent.max(Acts::BinningValue::binR) / 2) * 2); - /// variable middle SP radial region of interest const Acts::Range1D rMiddleSPRange( - std::floor(rRangeSPExtent.min(Acts::BinningValue::binR) / 2) * 2 + - m_cfg.seedFinderConfig.deltaRMiddleMinSPRange, - up - m_cfg.seedFinderConfig.deltaRMiddleMaxSPRange); + minRange + m_cfg.seedFinderConfig.deltaRMiddleMinSPRange, + maxRange - m_cfg.seedFinderConfig.deltaRMiddleMaxSPRange); // run the seeding static thread_local std::vector seeds; diff --git a/Examples/Algorithms/TrackFinding/src/SeedingAlgorithmHashing.cpp b/Examples/Algorithms/TrackFinding/src/SeedingAlgorithmHashing.cpp index ec664aef437..c722a9e5a2b 100644 --- a/Examples/Algorithms/TrackFinding/src/SeedingAlgorithmHashing.cpp +++ b/Examples/Algorithms/TrackFinding/src/SeedingAlgorithmHashing.cpp @@ -11,7 +11,6 @@ #include "Acts/Definitions/Algebra.hpp" #include "Acts/EventData/Seed.hpp" #include "Acts/EventData/SpacePointData.hpp" -#include "Acts/Geometry/Extent.hpp" #include "Acts/Plugins/Hashing/HashingAlgorithm.hpp" #include "Acts/Plugins/Hashing/HashingTraining.hpp" #include "Acts/Seeding/BinnedGroup.hpp" @@ -175,10 +174,10 @@ ActsExamples::SeedingAlgorithmHashing::SeedingAlgorithmHashing( m_cfg.seedFinderConfig.experimentCuts.connect(); } - m_bottomBinFinder = std::make_unique>( - m_cfg.numPhiNeighbors, m_cfg.zBinNeighborsBottom); - m_topBinFinder = std::make_unique>( - m_cfg.numPhiNeighbors, m_cfg.zBinNeighborsTop); + m_bottomBinFinder = std::make_unique>( + m_cfg.numPhiNeighbors, m_cfg.zBinNeighborsBottom, 0); + m_topBinFinder = std::make_unique>( + m_cfg.numPhiNeighbors, m_cfg.zBinNeighborsTop, 0); m_cfg.seedFinderConfig.seedFilter = std::make_unique>( @@ -269,17 +268,30 @@ ActsExamples::ProcessCode ActsExamples::SeedingAlgorithmHashing::execute( Acts::SpacePointContainer spContainer(spConfig, spOptions, container); - // extent used to store r range for middle spacepoint - Acts::Extent rRangeSPExtent; // construct the seeding tools Acts::CylindricalSpacePointGrid grid = Acts::CylindricalSpacePointGridCreator::createGrid( m_cfg.gridConfig, m_cfg.gridOptions); Acts::CylindricalSpacePointGridCreator::fillGrid( m_cfg.seedFinderConfig, m_cfg.seedFinderOptions, grid, - spContainer.begin(), spContainer.end(), rRangeSPExtent); + spContainer.begin(), spContainer.end()); + + // Compute radius Range + // we rely on the fact the grid is storing the proxies + // with a sorting in the radius + float minRange = std::numeric_limits::max(); + float maxRange = std::numeric_limits::lowest(); + for (const auto& coll : grid) { + if (coll.empty()) { + continue; + } + const auto* firstEl = coll.front(); + const auto* lastEl = coll.back(); + minRange = std::min(firstEl->radius(), minRange); + maxRange = std::max(lastEl->radius(), maxRange); + } - std::array, 2ul> navigation; + std::array, 3ul> navigation; navigation[1ul] = m_cfg.seedFinderConfig.zBinsCustomLooping; // groups spacepoints @@ -287,15 +299,10 @@ ActsExamples::ProcessCode ActsExamples::SeedingAlgorithmHashing::execute( std::move(grid), *m_bottomBinFinder, *m_topBinFinder, std::move(navigation)); - // safely clamp double to float - float up = Acts::clampValue( - std::floor(rRangeSPExtent.max(Acts::BinningValue::binR) / 2) * 2); - /// variable middle SP radial region of interest const Acts::Range1D rMiddleSPRange( - std::floor(rRangeSPExtent.min(Acts::BinningValue::binR) / 2) * 2 + - m_cfg.seedFinderConfig.deltaRMiddleMinSPRange, - up - m_cfg.seedFinderConfig.deltaRMiddleMaxSPRange); + minRange + m_cfg.seedFinderConfig.deltaRMiddleMinSPRange, + maxRange - m_cfg.seedFinderConfig.deltaRMiddleMaxSPRange); // this creates seeds of proxy, we need to convert it to seed of space // points diff --git a/Examples/Algorithms/TrackFinding/src/TrackFindingAlgorithm.cpp b/Examples/Algorithms/TrackFinding/src/TrackFindingAlgorithm.cpp index 0a5ae601d20..a6d5efc69e6 100644 --- a/Examples/Algorithms/TrackFinding/src/TrackFindingAlgorithm.cpp +++ b/Examples/Algorithms/TrackFinding/src/TrackFindingAlgorithm.cpp @@ -217,16 +217,18 @@ class BranchStopper { } bool tooManyHolesPS = false; - if (!(m_cfg.pixelVolumes.empty() && m_cfg.stripVolumes.empty())) { + if (!(m_cfg.pixelVolumeIds.empty() && m_cfg.stripVolumeIds.empty())) { auto& branchState = branchStateAccessor(track); // count both holes and outliers as holes for pixel/strip counts if (trackState.typeFlags().test(Acts::TrackStateFlag::HoleFlag) || trackState.typeFlags().test(Acts::TrackStateFlag::OutlierFlag)) { - if (m_cfg.pixelVolumes.contains( - trackState.referenceSurface().geometryId().volume())) { + auto volumeId = trackState.referenceSurface().geometryId().volume(); + if (std::find(m_cfg.pixelVolumeIds.begin(), m_cfg.pixelVolumeIds.end(), + volumeId) != m_cfg.pixelVolumeIds.end()) { ++branchState.nPixelHoles; - } else if (m_cfg.stripVolumes.contains( - trackState.referenceSurface().geometryId().volume())) { + } else if (std::find(m_cfg.stripVolumeIds.begin(), + m_cfg.stripVolumeIds.end(), + volumeId) != m_cfg.stripVolumeIds.end()) { ++branchState.nStripHoles; } } @@ -350,11 +352,15 @@ ProcessCode TrackFindingAlgorithm::execute(const AlgorithmContext& ctx) const { firstPropOptions.maxSteps = m_cfg.maxSteps; firstPropOptions.direction = m_cfg.reverseSearch ? Acts::Direction::Backward : Acts::Direction::Forward; + firstPropOptions.constrainToVolumeIds = m_cfg.constrainToVolumeIds; + firstPropOptions.endOfWorldVolumeIds = m_cfg.endOfWorldVolumeIds; Acts::PropagatorPlainOptions secondPropOptions(ctx.geoContext, ctx.magFieldContext); secondPropOptions.maxSteps = m_cfg.maxSteps; secondPropOptions.direction = firstPropOptions.direction.invert(); + secondPropOptions.constrainToVolumeIds = m_cfg.constrainToVolumeIds; + secondPropOptions.endOfWorldVolumeIds = m_cfg.endOfWorldVolumeIds; // Set the CombinatorialKalmanFilter options TrackFinderOptions firstOptions(ctx.geoContext, ctx.magFieldContext, @@ -379,6 +385,8 @@ ProcessCode TrackFindingAlgorithm::execute(const AlgorithmContext& ctx) const { logger().cloneWithSuffix("Propagator")); ExtrapolatorOptions extrapolationOptions(ctx.geoContext, ctx.magFieldContext); + extrapolationOptions.constrainToVolumeIds = m_cfg.constrainToVolumeIds; + extrapolationOptions.endOfWorldVolumeIds = m_cfg.endOfWorldVolumeIds; // Perform the track finding for all initial parameters ACTS_DEBUG("Invoke track finding with " << initialParameters.size() diff --git a/Examples/Algorithms/TrackFinding/src/TrackParamsEstimationAlgorithm.cpp b/Examples/Algorithms/TrackFinding/src/TrackParamsEstimationAlgorithm.cpp index c5dbc8bb625..880e1571517 100644 --- a/Examples/Algorithms/TrackFinding/src/TrackParamsEstimationAlgorithm.cpp +++ b/Examples/Algorithms/TrackFinding/src/TrackParamsEstimationAlgorithm.cpp @@ -56,7 +56,7 @@ Acts::BoundSquareMatrix makeInitialCovariance( // theta contribution variance += - varianceTheta * std::pow(params[Acts::eBoundQOverP] * + varianceTheta * std::pow(params[Acts::eBoundQOverP] / std::tan(params[Acts::eBoundTheta]), 2); } @@ -77,11 +77,9 @@ Acts::BoundSquareMatrix makeInitialCovariance( } // namespace -ActsExamples::TrackParamsEstimationAlgorithm::TrackParamsEstimationAlgorithm( - ActsExamples::TrackParamsEstimationAlgorithm::Config cfg, - Acts::Logging::Level lvl) - : ActsExamples::IAlgorithm("TrackParamsEstimationAlgorithm", lvl), - m_cfg(std::move(cfg)) { +TrackParamsEstimationAlgorithm::TrackParamsEstimationAlgorithm( + TrackParamsEstimationAlgorithm::Config cfg, Acts::Logging::Level lvl) + : IAlgorithm("TrackParamsEstimationAlgorithm", lvl), m_cfg(std::move(cfg)) { if (m_cfg.inputSeeds.empty()) { throw std::invalid_argument("Missing seeds input collection"); } @@ -103,8 +101,8 @@ ActsExamples::TrackParamsEstimationAlgorithm::TrackParamsEstimationAlgorithm( m_outputTracks.maybeInitialize(m_cfg.outputProtoTracks); } -ActsExamples::ProcessCode ActsExamples::TrackParamsEstimationAlgorithm::execute( - const ActsExamples::AlgorithmContext& ctx) const { +ProcessCode TrackParamsEstimationAlgorithm::execute( + const AlgorithmContext& ctx) const { auto const& seeds = m_inputSeeds(ctx); ACTS_VERBOSE("Read " << seeds.size() << " seeds"); @@ -197,4 +195,5 @@ ActsExamples::ProcessCode ActsExamples::TrackParamsEstimationAlgorithm::execute( return ProcessCode::SUCCESS; } + } // namespace ActsExamples diff --git a/Examples/Algorithms/TrackFindingExaTrkX/src/TrackFindingAlgorithmExaTrkX.cpp b/Examples/Algorithms/TrackFindingExaTrkX/src/TrackFindingAlgorithmExaTrkX.cpp index 06fcb1c9438..05fe35a6ea0 100644 --- a/Examples/Algorithms/TrackFindingExaTrkX/src/TrackFindingAlgorithmExaTrkX.cpp +++ b/Examples/Algorithms/TrackFindingExaTrkX/src/TrackFindingAlgorithmExaTrkX.cpp @@ -19,6 +19,7 @@ #include "ActsExamples/EventData/SimSpacePoint.hpp" #include "ActsExamples/Framework/WhiteBoard.hpp" +#include #include using namespace ActsExamples; @@ -97,8 +98,8 @@ ActsExamples::TrackFindingAlgorithmExaTrkX::TrackFindingAlgorithmExaTrkX( NodeFeature::eClusterX, NodeFeature::eClusterY, NodeFeature::eCellCount, NodeFeature::eCellSum, NodeFeature::eCluster1R, NodeFeature::eCluster2R}; - auto wantClFeatures = std::any_of( - m_cfg.nodeFeatures.begin(), m_cfg.nodeFeatures.end(), + auto wantClFeatures = std::ranges::any_of( + m_cfg.nodeFeatures, [&](const auto& f) { return Acts::rangeContainsValue(clFeatures, f); }); if (wantClFeatures && !m_inputClusters.isInitialized()) { diff --git a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp index f0d20f1a370..937a5bc1863 100644 --- a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp +++ b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp @@ -143,7 +143,7 @@ ActsExamples::ProcessCode ActsExamples::ParticleSmearing::execute( // theta contribution variance += varianceTheta * - std::pow(params[Acts::eBoundQOverP] * + std::pow(params[Acts::eBoundQOverP] / std::tan(params[Acts::eBoundTheta]), 2); } diff --git a/Examples/Algorithms/Vertexing/src/VertexingHelpers.hpp b/Examples/Algorithms/Vertexing/src/VertexingHelpers.hpp index 9d3afe19646..3222578a3da 100644 --- a/Examples/Algorithms/Vertexing/src/VertexingHelpers.hpp +++ b/Examples/Algorithms/Vertexing/src/VertexingHelpers.hpp @@ -15,6 +15,7 @@ #include "ActsExamples/Framework/AlgorithmContext.hpp" #include "ActsExamples/Framework/DataHandle.hpp" +#include #include #include @@ -55,8 +56,7 @@ inline ProtoVertexContainer makeProtoVertices( protoVertex.reserve(vertex.tracks().size()); for (const auto& track : vertex.tracks()) { - auto it = std::find(inputTracks.begin(), inputTracks.end(), - track.originalParams); + auto it = std::ranges::find(inputTracks, track.originalParams); if (it != inputTracks.end()) { protoVertex.push_back(std::distance(inputTracks.begin(), it)); } else { diff --git a/Examples/Framework/include/ActsExamples/EventData/Measurement.hpp b/Examples/Framework/include/ActsExamples/EventData/Measurement.hpp index 5d57c82b531..8703806a164 100644 --- a/Examples/Framework/include/ActsExamples/EventData/Measurement.hpp +++ b/Examples/Framework/include/ActsExamples/EventData/Measurement.hpp @@ -17,12 +17,15 @@ #include "Acts/EventData/detail/CalculateResiduals.hpp" #include "Acts/EventData/detail/ParameterTraits.hpp" #include "Acts/EventData/detail/PrintParameters.hpp" +#include "Acts/Utilities/Iterator.hpp" #include "ActsExamples/EventData/MeasurementConcept.hpp" #include +#include #include #include #include +#include #include #include #include @@ -58,7 +61,8 @@ using ConstVariableBoundMeasurementProxy = /// provide access to the individual measurements. class MeasurementContainer { public: - using Index = std::size_t; + using size_type = std::size_t; + using Index = size_type; template using FixedProxy = FixedMeasurementProxy; template @@ -81,6 +85,15 @@ class MeasurementContainer { /// @return The index of the added measurement Index addMeasurement(std::uint8_t size); + /// @brief Get a variable-size measurement proxy + /// @param index The index of the measurement + /// @return The variable-size measurement proxy + VariableProxy at(Index index); + /// @brief Get a const variable-size measurement proxy + /// @param index The index of the measurement + /// @return The const variable-size measurement proxy + ConstVariableProxy at(Index index) const; + /// @brief Get a variable-size measurement proxy /// @param index The index of the measurement /// @return The variable-size measurement proxy @@ -125,48 +138,11 @@ class MeasurementContainer { template FixedProxy emplaceMeasurement(Args&&... args); - template - class IteratorImpl { - public: - using value_type = - std::conditional_t; - using reference = value_type; - using pointer = value_type*; - using difference_type = std::ptrdiff_t; - using iterator_category = std::forward_iterator_tag; - - using Container = std::conditional_t; - - IteratorImpl(Container& container, std::size_t index) - : m_container(container), m_index(index) {} - - reference operator*() const { return m_container.getMeasurement(m_index); } - - pointer operator->() const { return &operator*(); } - - IteratorImpl& operator++() { - ++m_index; - return *this; - } - - IteratorImpl operator++(int) { - auto copy = *this; - ++*this; - return copy; - } - - bool operator==(const IteratorImpl& other) const { - return m_index == other.m_index; - } - - private: - Container& m_container; - Index m_index; - }; - - using iterator = IteratorImpl; - using const_iterator = IteratorImpl; + using iterator = + Acts::ContainerIndexIterator; + using const_iterator = + Acts::ContainerIndexIterator; iterator begin(); iterator end(); @@ -535,4 +511,7 @@ MeasurementContainer::FixedProxy MeasurementContainer::emplaceMeasurement( return meas; } +static_assert( + std::random_access_iterator && + std::random_access_iterator); } // namespace ActsExamples diff --git a/Examples/Framework/src/EventData/Measurement.cpp b/Examples/Framework/src/EventData/Measurement.cpp index 09c1e0a257a..f37661948db 100644 --- a/Examples/Framework/src/EventData/Measurement.cpp +++ b/Examples/Framework/src/EventData/Measurement.cpp @@ -33,6 +33,16 @@ std::size_t MeasurementContainer::addMeasurement(std::uint8_t size) { return m_entries.size() - 1; } +MeasurementContainer::VariableProxy MeasurementContainer::at( + std::size_t index) { + return VariableProxy{*this, index}; +} + +MeasurementContainer::ConstVariableProxy MeasurementContainer::at( + std::size_t index) const { + return ConstVariableProxy{*this, index}; +} + MeasurementContainer::VariableProxy MeasurementContainer::getMeasurement( std::size_t index) { return VariableProxy{*this, index}; diff --git a/Examples/Framework/src/Utilities/EventDataTransforms.cpp b/Examples/Framework/src/Utilities/EventDataTransforms.cpp index 9e0cbbff3fd..79d3d543a05 100644 --- a/Examples/Framework/src/Utilities/EventDataTransforms.cpp +++ b/Examples/Framework/src/Utilities/EventDataTransforms.cpp @@ -32,12 +32,12 @@ const ActsExamples::SimSpacePoint* ActsExamples::findSpacePointForIndex( ActsExamples::Index index, const SimSpacePointContainer& spacepoints) { auto match = [&](const SimSpacePoint& sp) { const auto& sls = sp.sourceLinks(); - return std::any_of(sls.begin(), sls.end(), [&](const auto& sl) { + return std::ranges::any_of(sls, [&](const auto& sl) { return sl.template get().index() == index; }); }; - auto found = std::find_if(spacepoints.begin(), spacepoints.end(), match); + auto found = std::ranges::find_if(spacepoints, match); if (found == spacepoints.end()) { return nullptr; diff --git a/Examples/Framework/src/Validation/TrackClassification.cpp b/Examples/Framework/src/Validation/TrackClassification.cpp index 0341dc09e5a..a89f7c2a07a 100644 --- a/Examples/Framework/src/Validation/TrackClassification.cpp +++ b/Examples/Framework/src/Validation/TrackClassification.cpp @@ -25,10 +25,9 @@ inline void increaseHitCount( std::vector& particleHitCounts, ActsFatras::Barcode particleId) { // linear search since there is no ordering - auto it = std::find_if(particleHitCounts.begin(), particleHitCounts.end(), - [=](const ActsExamples::ParticleHitCount& phc) { - return (phc.particleId == particleId); - }); + auto it = std::ranges::find_if(particleHitCounts, [=](const auto& phc) { + return (phc.particleId == particleId); + }); // either increase count if we saw the particle before or add it if (it != particleHitCounts.end()) { it->hitCount += 1u; diff --git a/Examples/Io/Csv/include/ActsExamples/Io/Csv/CsvInputOutput.hpp b/Examples/Io/Csv/include/ActsExamples/Io/Csv/CsvInputOutput.hpp index 3cdbe789e3c..7f4e7b894c3 100644 --- a/Examples/Io/Csv/include/ActsExamples/Io/Csv/CsvInputOutput.hpp +++ b/Examples/Io/Csv/include/ActsExamples/Io/Csv/CsvInputOutput.hpp @@ -38,6 +38,7 @@ #include "Acts/Utilities/Concepts.hpp" #include "Acts/Utilities/Helpers.hpp" +#include #include #include #include @@ -605,7 +606,7 @@ inline void NamedTupleDsvReader::parse_header( m_extra_columns.clear(); for (std::size_t i = 0; i < m_columns.size(); ++i) { // find the position of the column in the tuple. - auto it = std::find(names.begin(), names.end(), m_columns[i]); + auto it = std::ranges::find(names, m_columns[i]); if (it != names.end()) { // establish mapping between column and tuple item position m_tuple_column_map[std::distance(names.begin(), it)] = i; diff --git a/Examples/Io/EDM4hep/src/EDM4hepReader.cpp b/Examples/Io/EDM4hep/src/EDM4hepReader.cpp index ec84083f2aa..dfb11c84c9e 100644 --- a/Examples/Io/EDM4hep/src/EDM4hepReader.cpp +++ b/Examples/Io/EDM4hep/src/EDM4hepReader.cpp @@ -181,11 +181,9 @@ ProcessCode EDM4hepReader::read(const AlgorithmContext& ctx) { vtxPos /= Acts::UnitConstants::mm; // linear search for vector - auto it = std::find_if( - primaryVertices.begin(), primaryVertices.end(), - [&vtxPos]( - const std::pair>& - pair) { return pair.first == vtxPos; }); + auto it = std::ranges::find_if(primaryVertices, [&vtxPos](const auto& v) { + return v.first == vtxPos; + }); if (it == primaryVertices.end()) { ACTS_DEBUG("Found primary vertex at " << vtx.x << ", " << vtx.y << ", " diff --git a/Examples/Io/Root/src/RootMaterialDecorator.cpp b/Examples/Io/Root/src/RootMaterialDecorator.cpp index b8f49c53ea1..37f396bb86c 100644 --- a/Examples/Io/Root/src/RootMaterialDecorator.cpp +++ b/Examples/Io/Root/src/RootMaterialDecorator.cpp @@ -148,8 +148,8 @@ ActsExamples::RootMaterialDecorator::RootMaterialDecorator( std::vector hists{n, v, o, min, max, t, x0, l0, A, Z, rho}; // Only go on when you have all histograms - if (std::all_of(hists.begin(), hists.end(), - [](const auto* hist) { return hist != nullptr; })) { + if (std::ranges::all_of( + hists, [](const auto* hist) { return hist != nullptr; })) { // Get the number of bins int nbins0 = t->GetNbinsX(); int nbins1 = t->GetNbinsY(); diff --git a/Examples/Io/Root/src/RootSimHitReader.cpp b/Examples/Io/Root/src/RootSimHitReader.cpp index 1e503d8711c..4f0d805dc7e 100644 --- a/Examples/Io/Root/src/RootSimHitReader.cpp +++ b/Examples/Io/Root/src/RootSimHitReader.cpp @@ -108,9 +108,9 @@ std::pair RootSimHitReader::availableEvents() const { } ProcessCode RootSimHitReader::read(const AlgorithmContext& context) { - auto it = std::find_if( - m_eventMap.begin(), m_eventMap.end(), - [&](const auto& a) { return std::get<0>(a) == context.eventNumber; }); + auto it = std::ranges::find_if(m_eventMap, [&](const auto& a) { + return std::get<0>(a) == context.eventNumber; + }); if (it == m_eventMap.end()) { // explicitly warn if it happens for the first or last event as that might diff --git a/Examples/Io/Svg/include/ActsExamples/Io/Svg/SvgDefaults.hpp b/Examples/Io/Svg/include/ActsExamples/Io/Svg/SvgDefaults.hpp index 14d0474776e..b4e6c4f8178 100644 --- a/Examples/Io/Svg/include/ActsExamples/Io/Svg/SvgDefaults.hpp +++ b/Examples/Io/Svg/include/ActsExamples/Io/Svg/SvgDefaults.hpp @@ -22,7 +22,7 @@ static inline Acts::Svg::Style layerStyle() { lStyle.highlights = {"mouseover", "mouseout"}; lStyle.strokeColor = {25, 25, 25}; lStyle.strokeWidth = 0.5; - lStyle.nSegments = 72u; + lStyle.quarterSegments = 72u; return lStyle; } @@ -43,7 +43,7 @@ static inline Acts::Svg::Style backgroundStyle() { bgStyle.highlights = {}; bgStyle.strokeColor = {25, 25, 25}; bgStyle.strokeWidth = 0.5; - bgStyle.nSegments = 72u; + bgStyle.quarterSegments = 72u; return bgStyle; } @@ -55,7 +55,7 @@ static inline Acts::Svg::Style pointStyle() { pStyle.highlights = {"mouseover", "mouseout"}; pStyle.strokeColor = {0, 0, 0}; pStyle.strokeWidth = 0.5; - pStyle.nSegments = 72u; + pStyle.quarterSegments = 72u; return pStyle; } diff --git a/Examples/Python/python/acts/examples/odd.py b/Examples/Python/python/acts/examples/odd.py index 4e1efb1c783..a28058af78b 100644 --- a/Examples/Python/python/acts/examples/odd.py +++ b/Examples/Python/python/acts/examples/odd.py @@ -76,8 +76,9 @@ def getOpenDataDetector( } def geoid_hook(geoid, surface): + gctx = acts.GeometryContext() if geoid.volume() in volumeRadiusCutsMap: - r = math.sqrt(surface.center()[0] ** 2 + surface.center()[1] ** 2) + r = math.sqrt(surface.center(gctx)[0] ** 2 + surface.center(gctx)[1] ** 2) geoid.setExtra(1) for cut in volumeRadiusCutsMap[geoid.volume()]: diff --git a/Examples/Python/python/acts/examples/reconstruction.py b/Examples/Python/python/acts/examples/reconstruction.py index e47b435e72b..ab12005af86 100644 --- a/Examples/Python/python/acts/examples/reconstruction.py +++ b/Examples/Python/python/acts/examples/reconstruction.py @@ -147,8 +147,24 @@ "maxPixelHoles", "maxStripHoles", "trimTracks", + "constrainToVolumes", + "endOfWorldVolumes", + ], + defaults=[ + 15.0, + 25.0, + 10, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, ], - defaults=[15.0, 25.0, 10, None, None, None, None, None, None, None, None], ) AmbiguityResolutionConfig = namedtuple( @@ -1531,11 +1547,13 @@ def addCKFTracks( reverseSearch=reverseSearch, seedDeduplication=ckfConfig.seedDeduplication, stayOnSeed=ckfConfig.stayOnSeed, - pixelVolumes=ckfConfig.pixelVolumes, - stripVolumes=ckfConfig.stripVolumes, + pixelVolumeIds=ckfConfig.pixelVolumes, + stripVolumeIds=ckfConfig.stripVolumes, maxPixelHoles=ckfConfig.maxPixelHoles, maxStripHoles=ckfConfig.maxStripHoles, trimTracks=ckfConfig.trimTracks, + constrainToVolumeIds=ckfConfig.constrainToVolumes, + endOfWorldVolumeIds=ckfConfig.endOfWorldVolumes, ), ) s.addAlgorithm(trackFinder) diff --git a/Examples/Python/src/Geant4Component.cpp b/Examples/Python/src/Geant4Component.cpp index 14e7b138888..ff34da94cc0 100644 --- a/Examples/Python/src/Geant4Component.cpp +++ b/Examples/Python/src/Geant4Component.cpp @@ -334,7 +334,8 @@ PYBIND11_MODULE(ActsPythonBindingsGeant4, mod) { const std::vector& sensitiveMatches, const std::vector& - passiveMatches) { + passiveMatches, + bool convertMaterial) { // Initiate the detector construction & retrieve world ActsExamples::GdmlDetectorConstruction gdmlContruction(gdmlFileName); const auto* world = gdmlContruction.Construct(); @@ -351,6 +352,7 @@ PYBIND11_MODULE(ActsPythonBindingsGeant4, mod) { Acts::Geant4DetectorSurfaceFactory::Options options; options.sensitiveSurfaceSelector = sensitiveSelectors; options.passiveSurfaceSelector = passiveSelectors; + options.convertMaterial = convertMaterial; G4Transform3D nominal; Acts::Geant4DetectorSurfaceFactory factory; diff --git a/Examples/Python/src/Geometry.cpp b/Examples/Python/src/Geometry.cpp index 4fb0f07d07a..05484845465 100644 --- a/Examples/Python/src/Geometry.cpp +++ b/Examples/Python/src/Geometry.cpp @@ -37,6 +37,7 @@ #include "Acts/Surfaces/SurfaceArray.hpp" #include "Acts/Utilities/Helpers.hpp" #include "Acts/Utilities/RangeXD.hpp" +#include "Acts/Visualization/ViewConfig.hpp" #include "ActsExamples/Geometry/VolumeAssociationTest.hpp" #include @@ -109,13 +110,12 @@ void addGeometry(Context& ctx) { { py::class_>(m, "Surface") + // Can't bind directly because GeometryObject is virtual base of Surface .def("geometryId", - [](Acts::Surface& self) { return self.geometryId(); }) - .def("center", - [](Acts::Surface& self) { - return self.center(Acts::GeometryContext{}); - }) - .def("type", [](Acts::Surface& self) { return self.type(); }); + [](const Surface& self) { return self.geometryId(); }) + .def("center", &Surface::center) + .def("type", &Surface::type) + .def("visualize", &Surface::visualize); } { @@ -167,7 +167,11 @@ void addGeometry(Context& ctx) { }) .def_property_readonly( "highestTrackingVolume", - &Acts::TrackingGeometry::highestTrackingVolumePtr); + &Acts::TrackingGeometry::highestTrackingVolumePtr) + .def("visualize", &Acts::TrackingGeometry::visualize, py::arg("helper"), + py::arg("gctx"), py::arg("viewConfig") = s_viewVolume, + py::arg("portalViewConfig") = s_viewPortal, + py::arg("sensitiveViewConfig") = s_viewSensitive); } { @@ -287,7 +291,7 @@ void addExperimentalGeometry(Context& ctx) { for (const auto& surface : smap) { auto gid = surface->geometryId(); // Exclusion criteria - if (sensitiveOnly and gid.sensitive() == 0) { + if (sensitiveOnly && gid.sensitive() == 0) { continue; }; surfaceVolumeLayerMap[gid.volume()][gid.layer()].push_back(surface); @@ -333,7 +337,7 @@ void addExperimentalGeometry(Context& ctx) { ACTS_PYTHON_MEMBER(surfacesProvider); ACTS_PYTHON_MEMBER(supports); ACTS_PYTHON_MEMBER(binnings); - ACTS_PYTHON_MEMBER(nSegments); + ACTS_PYTHON_MEMBER(quarterSegments); ACTS_PYTHON_MEMBER(auxiliary); ACTS_PYTHON_STRUCT_END(); diff --git a/Examples/Python/src/ModuleEntry.cpp b/Examples/Python/src/ModuleEntry.cpp index 77348edaf1c..1a0e27db907 100644 --- a/Examples/Python/src/ModuleEntry.cpp +++ b/Examples/Python/src/ModuleEntry.cpp @@ -120,6 +120,7 @@ PYBIND11_MODULE(ActsPythonBindings, m) { addAlgebra(ctx); addBinning(ctx); addEventData(ctx); + addOutput(ctx); addPropagation(ctx); addGeometryBuildingGen1(ctx); @@ -128,7 +129,6 @@ PYBIND11_MODULE(ActsPythonBindings, m) { addMagneticField(ctx); addMaterial(ctx); - addOutput(ctx); addDetector(ctx); addExampleAlgorithms(ctx); addInput(ctx); diff --git a/Examples/Python/src/Obj.cpp b/Examples/Python/src/Obj.cpp index ce03e60a3fe..09acb0c53b6 100644 --- a/Examples/Python/src/Obj.cpp +++ b/Examples/Python/src/Obj.cpp @@ -6,6 +6,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. +#include "Acts/Visualization/IVisualization3D.hpp" #include #include #include @@ -19,6 +20,7 @@ #include #include +#include namespace py = pybind11; using namespace pybind11::literals; @@ -35,7 +37,7 @@ void addObj(Context& ctx) { /// @param surfaces is the collection of surfaces /// @param viewContext is the geometry context /// @param viewRgb is the color of the surfaces - /// @param viewSegements is the number of segments to approximate a full circle + /// @param viewSegments is the number of segments to approximate a quarter of a circle /// @param fileName is the path to the output file /// mex.def("writeSurfacesObj", @@ -87,5 +89,8 @@ void addObj(Context& ctx) { obj.write(fileName); }); } + + py::class_(m, "ObjVisualization3D") + .def(py::init<>()); } } // namespace Acts::Python diff --git a/Examples/Python/src/Output.cpp b/Examples/Python/src/Output.cpp index 328ae9ecd92..11472d8e203 100644 --- a/Examples/Python/src/Output.cpp +++ b/Examples/Python/src/Output.cpp @@ -10,6 +10,7 @@ #include "Acts/Geometry/GeometryHierarchyMap.hpp" #include "Acts/Plugins/Python/Utilities.hpp" #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" @@ -57,6 +58,7 @@ #include #include +#include namespace Acts { class TrackingGeometry; @@ -119,7 +121,7 @@ void addOutput(Context& ctx) { ACTS_PYTHON_MEMBER(offset); ACTS_PYTHON_MEMBER(lineThickness); ACTS_PYTHON_MEMBER(surfaceThickness); - ACTS_PYTHON_MEMBER(nSegments); + ACTS_PYTHON_MEMBER(quarterSegments); ACTS_PYTHON_MEMBER(triangulate); ACTS_PYTHON_MEMBER(outputName); ACTS_PYTHON_STRUCT_END(); @@ -130,10 +132,14 @@ void addOutput(Context& ctx) { .def(py::init<>()) .def(py::init()) .def(py::init()) - .def(py::init()) + .def(py::init()) .def_readonly("rgb", &Color::rgb); } + py::class_(m, "IVisualization3D") + .def("write", py::overload_cast( + &IVisualization3D::write, py::const_)); + { using Writer = ActsExamples::ObjTrackingGeometryWriter; auto w = py::class_>( diff --git a/Examples/Python/src/Svg.cpp b/Examples/Python/src/Svg.cpp index 2c0219d0466..ee011920947 100644 --- a/Examples/Python/src/Svg.cpp +++ b/Examples/Python/src/Svg.cpp @@ -225,7 +225,7 @@ void addSvg(Context& ctx) { ACTS_PYTHON_MEMBER(highlights); ACTS_PYTHON_MEMBER(strokeWidth); ACTS_PYTHON_MEMBER(strokeColor); - ACTS_PYTHON_MEMBER(nSegments); + ACTS_PYTHON_MEMBER(quarterSegments); ACTS_PYTHON_STRUCT_END(); } @@ -328,6 +328,21 @@ void addSvg(Context& ctx) { }); } + { + auto gco = py::class_(svg, "GridOptions") + .def(py::init<>()); + ACTS_PYTHON_STRUCT_BEGIN(gco, Svg::GridConverter::Options); + ACTS_PYTHON_MEMBER(style); + ACTS_PYTHON_STRUCT_END(); + + auto isco = py::class_( + svg, "IndexedSurfacesOptions") + .def(py::init<>()); + ACTS_PYTHON_STRUCT_BEGIN(isco, Svg::IndexedSurfacesConverter::Options); + ACTS_PYTHON_MEMBER(gridOptions); + ACTS_PYTHON_STRUCT_END(); + } + // How detector volumes are drawn: Svg DetectorVolume options & drawning { auto c = py::class_( @@ -338,12 +353,16 @@ void addSvg(Context& ctx) { ACTS_PYTHON_MEMBER(portalIndices); ACTS_PYTHON_MEMBER(portalOptions); ACTS_PYTHON_MEMBER(surfaceOptions); + ACTS_PYTHON_MEMBER(indexedSurfacesOptions); ACTS_PYTHON_STRUCT_END(); // Define the proto volume & indexed surface grid py::class_(svg, "ProtoVolume"); py::class_(svg, "ProtoIndexedSurfaceGrid"); + // Define the proto grid + py::class_(svg, "ProtoGrid"); + // Convert an Acts::Experimental::DetectorVolume object into an // acts::svg::proto::volume svg.def("convertDetectorVolume", &Svg::DetectorVolumeConverter::convert); @@ -352,6 +371,15 @@ void addSvg(Context& ctx) { svg.def("drawDetectorVolume", &drawDetectorVolume); } + // Draw the ProtoIndexedSurfaceGrid + { + svg.def("drawIndexedSurfaces", + [](const Svg::ProtoIndexedSurfaceGrid& pIndexedSurfaceGrid, + const std::string& identification) { + return Svg::View::xy(pIndexedSurfaceGrid, identification); + }); + } + // How a detector is drawn: Svg Detector options & drawning { svg.def("drawDetector", &drawDetector); } diff --git a/Examples/Python/src/TrackFinding.cpp b/Examples/Python/src/TrackFinding.cpp index 05ebcb3c7a7..4179d58d94a 100644 --- a/Examples/Python/src/TrackFinding.cpp +++ b/Examples/Python/src/TrackFinding.cpp @@ -337,11 +337,13 @@ void addTrackFinding(Context& ctx) { ACTS_PYTHON_MEMBER(reverseSearch); ACTS_PYTHON_MEMBER(seedDeduplication); ACTS_PYTHON_MEMBER(stayOnSeed); - ACTS_PYTHON_MEMBER(pixelVolumes); - ACTS_PYTHON_MEMBER(stripVolumes); + ACTS_PYTHON_MEMBER(pixelVolumeIds); + ACTS_PYTHON_MEMBER(stripVolumeIds); ACTS_PYTHON_MEMBER(maxPixelHoles); ACTS_PYTHON_MEMBER(maxStripHoles); ACTS_PYTHON_MEMBER(trimTracks); + ACTS_PYTHON_MEMBER(constrainToVolumeIds); + ACTS_PYTHON_MEMBER(endOfWorldVolumeIds); ACTS_PYTHON_STRUCT_END(); } diff --git a/Examples/Python/tests/root_file_hashes.txt b/Examples/Python/tests/root_file_hashes.txt index 368a7c45ef3..84f90c6d811 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: 3c9c6265183b04c9d62ed5f2d0709c6dd74e33fbb53ac0aeb3274f6600257fc1 test_geant4__hits.root: adf5dcdf000a580412dc5089e17460897d6535c978eafa021584ba4281d0a1ac -test_seeding__estimatedparams.root: ff9b876f07de7e352c71f11dccdbaed93b6ef0328bba40c4f6c9fdb2090f386e +test_seeding__estimatedparams.root: 69c0e268f9025a0991a212ea2a7f26f53112fecf614b475605bd1cb08415ba56 test_seeding__performance_seeding.root: 992f9c611d30dde0d3f3ab676bab19ada61ab6a4442828e27b65ec5e5b7a2880 test_seeding__particles.root: 7855b021f39ad238bca098e4282667be0666f2d1630e5bcb9d51d3b5ee39fa14 test_seeding__particles_simulation.root: 87d9c6c82422ca381a17735096b36c547eacb5dda2f26d7377614bd97a70ab1a -test_hashing_seeding__estimatedparams.root: 77658e952bbceb5a61b0235c76f4dbb7bb5994a8ef32b769197ddcfe46ade241 -test_seeding_orthogonal__estimatedparams.root: 47718b57d59d9b9686bd7a7bb5958d668c0a953ad6b094601ca7b27f530db786 +test_hashing_seeding__estimatedparams.root: 1f43b760e80089b5674e106d00d962d74be564cbf33ae38222052ebb6f9cbf3a +test_seeding_orthogonal__estimatedparams.root: ca5896ec325daf5c8012291bc454269c61c32fe3d7e33bd1fa3b812826930299 test_seeding_orthogonal__performance_seeding.root: 60fbedcf5cb2b37cd8e526251940564432890d3a159d231ed819e915a904682c test_seeding_orthogonal__particles.root: 7855b021f39ad238bca098e4282667be0666f2d1630e5bcb9d51d3b5ee39fa14 test_seeding_orthogonal__particles_simulation.root: 87d9c6c82422ca381a17735096b36c547eacb5dda2f26d7377614bd97a70ab1a -test_itk_seeding__estimatedparams.root: 1266e99f1885a3c74a58471a4d6e750ad8fd87c7372a9ab929e8b99603b42ac8 +test_itk_seeding__estimatedparams.root: 1cc05f9f2aefb5f71a85b31e97bc4e5845fedfcef6c53199495a6340c6b6210b test_itk_seeding__performance_seeding.root: 78ebda54cd0f026ba4b7f316724ffd946de56a932735914baf1b7bba9505c29d test_itk_seeding__particles.root: 0b6f4ad438010ac48803d48ed98e80b5e87d310bae6c2c02b16cd94d7a4d7d07 test_itk_seeding__particles_simulation.root: ef0246069aa697019f28a8b270a68de95312cae5f2f2c74848566c3ce4f70363 @@ -33,22 +33,22 @@ test_digitization_example_input[smeared]__particles.root: 5fe7dda2933ee6b9615b06 test_digitization_example_input[smeared]__measurements.root: 243c2f69b7b0db9dbeaa7494d4ea0f3dd1691dc90f16e10df6c0491ff4dc7d62 test_digitization_example_input[geometric]__particles.root: 5fe7dda2933ee6b9615b064d192322fe07831133cd998e5ed99a3b992b713a10 test_digitization_example_input[geometric]__measurements.root: 63ec81635979058fb8976f94455bf490cf92b7b142c4a05cc39de6225f5de2fb -test_ckf_tracks_example[generic-full_seeding]__trackstates_ckf.root: e041089f5ddf060580f068a951621882082b4659d935965c118b76f6c3944fd2 -test_ckf_tracks_example[generic-full_seeding]__tracksummary_ckf.root: 4d2e26c352285aed77e46e09ee1977eb34cd82a29b0cb08f162a61ea76f71f17 +test_ckf_tracks_example[generic-full_seeding]__trackstates_ckf.root: f15437e7873a92615e7f967cbcb8c48119e7fa31136817dc275d186552ce8b26 +test_ckf_tracks_example[generic-full_seeding]__tracksummary_ckf.root: d5e8542d2b735cd8ab60774bb5dbe01b1e0b0924dffff1ff719723802a4933e6 test_ckf_tracks_example[generic-full_seeding]__performance_seeding_trees.root: 0e0676ffafdb27112fbda50d1cf627859fa745760f98073261dcf6db3f2f991e -test_ckf_tracks_example[generic-truth_estimated]__trackstates_ckf.root: 71a48e6d22be7f01611394ed7bd5a4a498aade6e20deb7efb0d9bd67dd950970 -test_ckf_tracks_example[generic-truth_estimated]__tracksummary_ckf.root: 5a973ec1c159681361ac069809e364cef4ec3e0efcafb05689f1175764f438b4 +test_ckf_tracks_example[generic-truth_estimated]__trackstates_ckf.root: 2f4d7d5fed66bc2c7d7df6eff2637ab1c34877eb84123bf8e543731fe5d96b91 +test_ckf_tracks_example[generic-truth_estimated]__tracksummary_ckf.root: 1d0931cd08865cf8d69e1d9b4e7b87aaa1dc4337bdd14cb925c45553851b6040 test_ckf_tracks_example[generic-truth_estimated]__performance_seeding.root: 1facb05c066221f6361b61f015cdf0918e94d9f3fce2269ec7b6a4dffeb2bc7e -test_ckf_tracks_example[generic-truth_smeared]__trackstates_ckf.root: b10f61d3b68ecc3d1910a17aeadd01a1e23b31b6418935809d1f12e95eac607a -test_ckf_tracks_example[generic-truth_smeared]__tracksummary_ckf.root: 69733ede1fc08370b5c0d0535f274b59bb51217239bd6645ff62ec9dadaa1f41 -test_ckf_tracks_example[odd-full_seeding]__trackstates_ckf.root: 33a68b20005a92b88bf7d01179a4b4fe3c1476a2019176904356924c0ad68f4b -test_ckf_tracks_example[odd-full_seeding]__tracksummary_ckf.root: 749a53533fed3d550c2e37f504bac5a8ab5c5cdf60d5055dcd545aa44613601a +test_ckf_tracks_example[generic-truth_smeared]__trackstates_ckf.root: 9d5c3d943d3baccacb9969430386b71a6c5570c0d4ee50c09b8ef5471b9a42cd +test_ckf_tracks_example[generic-truth_smeared]__tracksummary_ckf.root: 1f38a7fe0f5ff1d8f054b8120caf55243104f49da6c39a8dd17defaf4547aa07 +test_ckf_tracks_example[odd-full_seeding]__trackstates_ckf.root: f373840f282f113667248d4f63a8cebec4d94d438fcf9508b30c6c4b2f220f23 +test_ckf_tracks_example[odd-full_seeding]__tracksummary_ckf.root: 9e4cf24b0be8e2285c453272a7a0424f75ff4d7d863db2ced4f178da390d9073 test_ckf_tracks_example[odd-full_seeding]__performance_seeding_trees.root: 43c58577aafe07645e5660c4f43904efadf91d8cda45c5c04c248bbe0f59814f -test_ckf_tracks_example[odd-truth_estimated]__trackstates_ckf.root: 7750f58b970c79dc3c937482e2a6e4576bc5d495fd6e4576d63ac2882d8283d4 -test_ckf_tracks_example[odd-truth_estimated]__tracksummary_ckf.root: f5d5d5521e367dd2e26365b896b079279a5a8b97b7e11d38eb0eb317740ad4dd +test_ckf_tracks_example[odd-truth_estimated]__trackstates_ckf.root: 3246e7530ae263d8856e487b8cc5de392dcce54ba807e0299c6a409e139e0910 +test_ckf_tracks_example[odd-truth_estimated]__tracksummary_ckf.root: 1ab5d0271be05e47b5f367ae9f818c8de058ee841ac0b6c62c08521a81e11a9a test_ckf_tracks_example[odd-truth_estimated]__performance_seeding.root: 1a36b7017e59f1c08602ef3c2cb0483c51df248f112e3780c66594110719c575 -test_ckf_tracks_example[odd-truth_smeared]__trackstates_ckf.root: 33398059bf968f7279d4cc706f3b914fcf6f010ae82c43df8875785bda6f7cbe -test_ckf_tracks_example[odd-truth_smeared]__tracksummary_ckf.root: 3d01335a51fb03c78a174c8b11d473b38ba9c4ed3d6cba201b3925f463411708 +test_ckf_tracks_example[odd-truth_smeared]__trackstates_ckf.root: 39f3d17a4f3fb9ba792ccf41b3851b5c690e8a7777e1777f072a3d9aa4aca66b +test_ckf_tracks_example[odd-truth_smeared]__tracksummary_ckf.root: d6a05c8e8522e676d65c5a1cc634938340689b53f057a4d4c75c3b2c8efb1169 test_vertex_fitting_reading[Truth-False-100]__performance_vertexing.root: 76ef6084d758dfdfc0151ddec2170e12d73394424e3dac4ffe46f0f339ec8293 test_vertex_fitting_reading[Iterative-False-100]__performance_vertexing.root: 60372210c830a04f95ceb78c6c68a9b0de217746ff59e8e73053750c837b57eb test_vertex_fitting_reading[Iterative-True-100]__performance_vertexing.root: e34f217d524a5051dbb04a811d3407df3ebe2cc4bb7f54f6bda0847dbd7b52c3 diff --git a/Examples/Scripts/Python/full_chain_itk.py b/Examples/Scripts/Python/full_chain_itk.py index 6231127096c..5e268f87fcb 100755 --- a/Examples/Scripts/Python/full_chain_itk.py +++ b/Examples/Scripts/Python/full_chain_itk.py @@ -126,8 +126,8 @@ seedDeduplication=True, stayOnSeed=True, # ITk volumes from Noemi's plot - pixelVolumes={8, 9, 10, 13, 14, 15, 16, 18, 19, 20}, - stripVolumes={22, 23, 24}, + pixelVolumes=[8, 9, 10, 13, 14, 15, 16, 18, 19, 20], + stripVolumes=[22, 23, 24], maxPixelHoles=1, maxStripHoles=2, ), diff --git a/Examples/Scripts/Python/full_chain_odd.py b/Examples/Scripts/Python/full_chain_odd.py index e76111da7ac..e6da5eee4dd 100755 --- a/Examples/Scripts/Python/full_chain_odd.py +++ b/Examples/Scripts/Python/full_chain_odd.py @@ -363,10 +363,27 @@ numMeasurementsCutOff=10, seedDeduplication=True, stayOnSeed=True, - pixelVolumes={16, 17, 18}, - stripVolumes={23, 24, 25}, + pixelVolumes=[16, 17, 18], + stripVolumes=[23, 24, 25], maxPixelHoles=1, maxStripHoles=2, + constrainToVolumes=[ + 2, # beam pipe + 32, + 4, # beam pip gap + 16, + 17, + 18, # pixel + 20, # PST + 23, + 24, + 25, # short strip + 26, + 8, # long strip gap + 28, + 29, + 30, # long strip + ], ), outputDirRoot=outputDir if args.output_root else None, outputDirCsv=outputDir if args.output_csv else None, diff --git a/Plugins/ActSVG/include/Acts/Plugins/ActSVG/DetectorVolumeSvgConverter.hpp b/Plugins/ActSVG/include/Acts/Plugins/ActSVG/DetectorVolumeSvgConverter.hpp index 6ac84da77ee..f27db472439 100644 --- a/Plugins/ActSVG/include/Acts/Plugins/ActSVG/DetectorVolumeSvgConverter.hpp +++ b/Plugins/ActSVG/include/Acts/Plugins/ActSVG/DetectorVolumeSvgConverter.hpp @@ -41,6 +41,8 @@ struct Options { PortalConverter::Options portalOptions; /// The Surface converter options SurfaceConverter::Options surfaceOptions; + /// The Grid converter options + IndexedSurfacesConverter::Options indexedSurfacesOptions; }; /// Write/create the detector volume diff --git a/Plugins/ActSVG/include/Acts/Plugins/ActSVG/SvgUtils.hpp b/Plugins/ActSVG/include/Acts/Plugins/ActSVG/SvgUtils.hpp index a6faa5ed42c..0b36d7f82c9 100644 --- a/Plugins/ActSVG/include/Acts/Plugins/ActSVG/SvgUtils.hpp +++ b/Plugins/ActSVG/include/Acts/Plugins/ActSVG/SvgUtils.hpp @@ -19,6 +19,7 @@ namespace Acts::Svg { +/// @brief Style struct struct Style { // Fill parameters std::array fillColor = {255, 255, 255}; @@ -38,7 +39,8 @@ struct Style { unsigned int fontSize = 14u; - unsigned int nSegments = 72u; + /// Number of segments to approximate a quarter of a circle + unsigned int quarterSegments = 72u; /// Conversion to fill and stroke object from the base library /// @return a tuple of actsvg digestable objects diff --git a/Plugins/ActSVG/src/DetectorVolumeSvgConverter.cpp b/Plugins/ActSVG/src/DetectorVolumeSvgConverter.cpp index c187e69569b..93527488538 100644 --- a/Plugins/ActSVG/src/DetectorVolumeSvgConverter.cpp +++ b/Plugins/ActSVG/src/DetectorVolumeSvgConverter.cpp @@ -68,7 +68,8 @@ Acts::Svg::DetectorVolumeConverter::convert( // Make dedicated surface grid sheets const auto& internalNavigationDelegate = dVolume.internalNavigation(); - IndexedSurfacesConverter::Options isOptions; + IndexedSurfacesConverter::Options isOptions = + volumeOptions.indexedSurfacesOptions; // Use or transfer the surface style if (isOptions.surfaceStyles.empty()) { std::pair style{ diff --git a/Plugins/ActSVG/src/SurfaceArraySvgConverter.cpp b/Plugins/ActSVG/src/SurfaceArraySvgConverter.cpp index f2acf870864..794bb1d43b5 100644 --- a/Plugins/ActSVG/src/SurfaceArraySvgConverter.cpp +++ b/Plugins/ActSVG/src/SurfaceArraySvgConverter.cpp @@ -13,6 +13,8 @@ #include "Acts/Surfaces/SurfaceArray.hpp" #include "Acts/Surfaces/SurfaceBounds.hpp" +#include + std::tuple, Acts::Svg::ProtoGrid, std::vector > Acts::Svg::SurfaceArrayConverter::convert( @@ -93,11 +95,9 @@ Acts::Svg::SurfaceArrayConverter::convert( auto sameBounds = [&](const SurfaceBounds* test) { return ((*test) == sBounds); }; - // Check if you have this template object already - auto tBounds = - std::find_if(templateBounds.begin(), templateBounds.end(), sameBounds); - // New reference bounds and new reference object - if (tBounds == templateBounds.end()) { + // Check if you have this template object already before creating new + // reference bounds and new reference object + if (std::ranges::none_of(templateBounds, sameBounds)) { // Let's get the right style SurfaceConverter::Options sOptions; sOptions.templateSurface = true; @@ -107,7 +107,7 @@ Acts::Svg::SurfaceArrayConverter::convert( sOptions.style = *sfStyle; } - // Create a referese surface and reference object from it + // Create a reference surface and reference object from it auto referenceSurface = SurfaceConverter::convert(gctx, *sf, sOptions); auto referenceObject = View::xy(referenceSurface, @@ -148,8 +148,7 @@ Acts::Svg::SurfaceArrayConverter::convert( return ((*test) == sBounds); }; // Check if you have this template object already - auto tBounds = std::find_if(templateBounds.begin(), templateBounds.end(), - sameBounds); + auto tBounds = std::ranges::find_if(templateBounds, sameBounds); // New reference bounds and new reference object if (tBounds != templateBounds.end()) { std::size_t tObject = std::distance(templateBounds.begin(), tBounds); @@ -196,7 +195,7 @@ Acts::Svg::SurfaceArrayConverter::convert( auto bSurfaces = surfaceArray.neighbors(bCenter); std::vector binnAssoc; for (const auto& bs : bSurfaces) { - auto candidate = std::find(surfaces.begin(), surfaces.end(), bs); + auto candidate = std::ranges::find(surfaces, bs); if (candidate != surfaces.end()) { binnAssoc.push_back(std::distance(surfaces.begin(), candidate)); } diff --git a/Plugins/ActSVG/src/SurfaceSvgConverter.cpp b/Plugins/ActSVG/src/SurfaceSvgConverter.cpp index c5bf2bba429..d9fb864a1f4 100644 --- a/Plugins/ActSVG/src/SurfaceSvgConverter.cpp +++ b/Plugins/ActSVG/src/SurfaceSvgConverter.cpp @@ -21,7 +21,7 @@ Acts::Svg::ProtoSurface Acts::Svg::SurfaceConverter::convert( if (!cOptions.templateSurface) { // Polyhedron surface for vertices needed anyway Polyhedron surfaceHedron = - surface.polyhedronRepresentation(gctx, cOptions.style.nSegments); + surface.polyhedronRepresentation(gctx, cOptions.style.quarterSegments); auto vertices3D = surfaceHedron.vertices; pSurface._vertices = vertices3D; } else { @@ -30,7 +30,7 @@ Acts::Svg::ProtoSurface Acts::Svg::SurfaceConverter::convert( auto planarBounds = dynamic_cast(&(surface.bounds())); if (planarBounds != nullptr) { - auto vertices2D = planarBounds->vertices(cOptions.style.nSegments); + auto vertices2D = planarBounds->vertices(cOptions.style.quarterSegments); pSurface._vertices.reserve(vertices2D.size()); for (const auto& v2 : vertices2D) { pSurface._vertices.push_back({v2[0], v2[1], 0.}); @@ -40,7 +40,8 @@ Acts::Svg::ProtoSurface Acts::Svg::SurfaceConverter::convert( auto annulusBounds = dynamic_cast(&(surface.bounds())); if (annulusBounds != nullptr) { - auto vertices2D = annulusBounds->vertices(cOptions.style.nSegments); + auto vertices2D = + annulusBounds->vertices(cOptions.style.quarterSegments); pSurface._vertices.reserve(vertices2D.size()); for (const auto& v2 : vertices2D) { pSurface._vertices.push_back({v2[0], v2[1], 0.}); diff --git a/Plugins/DD4hep/include/Acts/Plugins/DD4hep/DD4hepDetectorSurfaceFactory.hpp b/Plugins/DD4hep/include/Acts/Plugins/DD4hep/DD4hepDetectorSurfaceFactory.hpp index 0a283433ab4..d6855443af2 100644 --- a/Plugins/DD4hep/include/Acts/Plugins/DD4hep/DD4hepDetectorSurfaceFactory.hpp +++ b/Plugins/DD4hep/include/Acts/Plugins/DD4hep/DD4hepDetectorSurfaceFactory.hpp @@ -71,8 +71,8 @@ class DD4hepDetectorSurfaceFactory { std::optional pExtent = std::nullopt; /// Optionally provide an Extent constraints to measure the layers std::vector extentConstraints = {}; - /// The approximination for extent measuring - std::size_t nExtentSegments = 1u; + /// The approximination of a circle quarter for extent measuring + std::size_t nExtentQSegments = 1u; }; /// Nested options struct to steer the conversion diff --git a/Plugins/DD4hep/include/Acts/Plugins/DD4hep/DD4hepLayerStructure.hpp b/Plugins/DD4hep/include/Acts/Plugins/DD4hep/DD4hepLayerStructure.hpp index bdf4780fb2f..a44e4341feb 100644 --- a/Plugins/DD4hep/include/Acts/Plugins/DD4hep/DD4hepLayerStructure.hpp +++ b/Plugins/DD4hep/include/Acts/Plugins/DD4hep/DD4hepLayerStructure.hpp @@ -65,8 +65,8 @@ class DD4hepLayerStructure { std::optional extent = std::nullopt; /// The extent constraints - optionally std::vector extentConstraints = {}; - /// Approximation for the polyhedron binning nSegments - unsigned int nSegments = 1u; + /// Approximation for the polyhedron binning + unsigned int quarterSegments = 1u; /// Patch the binning with the extent if possible bool patchBinningWithExtent = true; /// Conversion options diff --git a/Plugins/DD4hep/src/DD4hepDetectorSurfaceFactory.cpp b/Plugins/DD4hep/src/DD4hepDetectorSurfaceFactory.cpp index f3059fbeed5..d628ff76379 100644 --- a/Plugins/DD4hep/src/DD4hepDetectorSurfaceFactory.cpp +++ b/Plugins/DD4hep/src/DD4hepDetectorSurfaceFactory.cpp @@ -108,7 +108,7 @@ Acts::DD4hepDetectorSurfaceFactory::constructSensitiveComponents( // Measure if configured to do so if (cache.sExtent.has_value()) { auto sExtent = - sSurface->polyhedronRepresentation(gctx, cache.nExtentSegments) + sSurface->polyhedronRepresentation(gctx, cache.nExtentQSegments) .extent(); cache.sExtent.value().extend(sExtent, cache.extentConstraints); } @@ -137,7 +137,7 @@ Acts::DD4hepDetectorSurfaceFactory::constructPassiveComponents( // Measure if configured to do so if (cache.pExtent.has_value()) { auto sExtent = - pSurface->polyhedronRepresentation(gctx, cache.nExtentSegments) + pSurface->polyhedronRepresentation(gctx, cache.nExtentQSegments) .extent(); cache.pExtent.value().extend(sExtent, cache.extentConstraints); } diff --git a/Plugins/DD4hep/src/DD4hepLayerStructure.cpp b/Plugins/DD4hep/src/DD4hepLayerStructure.cpp index 64b6e8cf32e..10a4e6eb9f0 100644 --- a/Plugins/DD4hep/src/DD4hepLayerStructure.cpp +++ b/Plugins/DD4hep/src/DD4hepLayerStructure.cpp @@ -38,7 +38,7 @@ Acts::Experimental::DD4hepLayerStructure::builder( fCache.sExtent = options.extent; fCache.pExtent = options.extent; fCache.extentConstraints = options.extentConstraints; - fCache.nExtentSegments = options.nSegments; + fCache.nExtentQSegments = options.quarterSegments; m_surfaceFactory->construct(fCache, gctx, dd4hepElement, options.conversionOptions); diff --git a/Plugins/Detray/src/DetrayGeometryConverter.cpp b/Plugins/Detray/src/DetrayGeometryConverter.cpp index da57d91c2bb..664900841f0 100644 --- a/Plugins/Detray/src/DetrayGeometryConverter.cpp +++ b/Plugins/Detray/src/DetrayGeometryConverter.cpp @@ -21,6 +21,8 @@ #include "Acts/Surfaces/Surface.hpp" #include "Acts/Surfaces/SurfaceBounds.hpp" +#include + #include using namespace detray; @@ -36,7 +38,7 @@ namespace { int findVolume( const Acts::Experimental::DetectorVolume* volume, const std::vector& volumes) { - auto candidate = std::find(volumes.begin(), volumes.end(), volume); + auto candidate = std::ranges::find(volumes, volume); if (candidate != volumes.end()) { return std::distance(volumes.begin(), candidate); } diff --git a/Plugins/ExaTrkX/src/ExaTrkXPipeline.cpp b/Plugins/ExaTrkX/src/ExaTrkXPipeline.cpp index a3d6dfe1148..d53de1d3071 100644 --- a/Plugins/ExaTrkX/src/ExaTrkXPipeline.cpp +++ b/Plugins/ExaTrkX/src/ExaTrkXPipeline.cpp @@ -8,6 +8,8 @@ #include "Acts/Plugins/ExaTrkX/ExaTrkXPipeline.hpp" +#include "Acts/Utilities/Helpers.hpp" + #include namespace Acts { @@ -27,9 +29,8 @@ ExaTrkXPipeline::ExaTrkXPipeline( if (!m_trackBuilder) { throw std::invalid_argument("Missing track building module"); } - if (m_edgeClassifiers.empty() or - not std::all_of(m_edgeClassifiers.begin(), m_edgeClassifiers.end(), - [](const auto &a) { return static_cast(a); })) { + if (m_edgeClassifiers.empty() || + rangeContainsValue(m_edgeClassifiers, nullptr)) { throw std::invalid_argument("Missing graph construction module"); } } diff --git a/Plugins/FpeMonitoring/src/FpeMonitor.cpp b/Plugins/FpeMonitoring/src/FpeMonitor.cpp index 3b08145668e..8b4feb5f1d2 100644 --- a/Plugins/FpeMonitoring/src/FpeMonitor.cpp +++ b/Plugins/FpeMonitoring/src/FpeMonitor.cpp @@ -87,10 +87,9 @@ void FpeMonitor::Result::add(FpeType type, void *stackPtr, auto st = std::make_unique( boost::stacktrace::stacktrace::from_dump(stackPtr, bufferSize)); - auto it = std::find_if( - m_stracktraces.begin(), m_stracktraces.end(), [&](const FpeInfo &el) { - return areFpesEquivalent({el.type, *el.st}, {type, *st}); - }); + auto it = std::ranges::find_if(m_stracktraces, [&](const FpeInfo &el) { + return areFpesEquivalent({el.type, *el.st}, {type, *st}); + }); if (it != m_stracktraces.end()) { it->count += 1; @@ -101,10 +100,9 @@ void FpeMonitor::Result::add(FpeType type, void *stackPtr, bool FpeMonitor::Result::contains( FpeType type, const boost::stacktrace::stacktrace &st) const { - return std::find_if(m_stracktraces.begin(), m_stracktraces.end(), - [&](const FpeInfo &el) { - return areFpesEquivalent({el.type, *el.st}, {type, st}); - }) != m_stracktraces.end(); + return std::ranges::any_of(m_stracktraces, [&](const FpeInfo &el) { + return areFpesEquivalent({el.type, *el.st}, {type, st}); + }); } FpeMonitor::Result &FpeMonitor::result() { @@ -167,11 +165,9 @@ void FpeMonitor::Result::deduplicate() { m_stracktraces.clear(); for (auto &info : copy) { - auto it = std::find_if(m_stracktraces.begin(), m_stracktraces.end(), - [&info](const FpeInfo &el) { - return areFpesEquivalent({el.type, *el.st}, - {info.type, *info.st}); - }); + auto it = std::ranges::find_if(m_stracktraces, [&info](const FpeInfo &el) { + return areFpesEquivalent({el.type, *el.st}, {info.type, *info.st}); + }); if (it != m_stracktraces.end()) { it->count += info.count; continue; diff --git a/Plugins/Geant4/include/Acts/Plugins/Geant4/Geant4DetectorSurfaceFactory.hpp b/Plugins/Geant4/include/Acts/Plugins/Geant4/Geant4DetectorSurfaceFactory.hpp index fae8fc20fea..d06c77412e4 100644 --- a/Plugins/Geant4/include/Acts/Plugins/Geant4/Geant4DetectorSurfaceFactory.hpp +++ b/Plugins/Geant4/include/Acts/Plugins/Geant4/Geant4DetectorSurfaceFactory.hpp @@ -67,7 +67,7 @@ class Geant4DetectorSurfaceFactory { /// Convert the length scale ActsScalar scaleConversion = 1.; /// Convert the material - bool convertMaterial = true; + bool convertMaterial = false; /// Converted material thickness (< 0 indicates keeping original thickness) ActsScalar convertedMaterialThickness = -1; /// A selector for sensitive surfaces diff --git a/Plugins/GeoModel/include/Acts/Plugins/GeoModel/GeoModelBlueprintCreater.hpp b/Plugins/GeoModel/include/Acts/Plugins/GeoModel/GeoModelBlueprintCreater.hpp index f382a49543a..df895eb0741 100644 --- a/Plugins/GeoModel/include/Acts/Plugins/GeoModel/GeoModelBlueprintCreater.hpp +++ b/Plugins/GeoModel/include/Acts/Plugins/GeoModel/GeoModelBlueprintCreater.hpp @@ -40,8 +40,8 @@ class GeoModelBlueprintCreater { std::vector> detectorSurfaces = {}; /// The binning values for the KDTree sorting std::vector kdtBinning = {}; - /// Polyhedron approximations - unsigned int nSegments = 1u; + /// Polyhedron approximation: number of segments per circlequarter + unsigned int quarterSegments = 1u; }; /// The cache struct diff --git a/Plugins/GeoModel/src/GeoModelBlueprintCreater.cpp b/Plugins/GeoModel/src/GeoModelBlueprintCreater.cpp index 9d31eeaaffc..93712d5d911 100644 --- a/Plugins/GeoModel/src/GeoModelBlueprintCreater.cpp +++ b/Plugins/GeoModel/src/GeoModelBlueprintCreater.cpp @@ -354,7 +354,7 @@ Acts::GeoModelBlueprintCreater::createInternalStructureBuilder( // Loop over surfaces and create an internal extent for (auto& sf : surfaces) { auto sfExtent = - sf->polyhedronRepresentation(gctx, m_cfg.nSegments).extent(); + sf->polyhedronRepresentation(gctx, m_cfg.quarterSegments).extent(); internalExtent.extend(sfExtent, internalConstraints); } ACTS_VERBOSE("Found " << surfaces.size() << " surfaces in range " diff --git a/Plugins/GeoModel/src/GeoModelDetectorObjectFactory.cpp b/Plugins/GeoModel/src/GeoModelDetectorObjectFactory.cpp index d6f1d72d614..b68bb585358 100644 --- a/Plugins/GeoModel/src/GeoModelDetectorObjectFactory.cpp +++ b/Plugins/GeoModel/src/GeoModelDetectorObjectFactory.cpp @@ -19,6 +19,7 @@ #include "Acts/Plugins/GeoModel/GeoModelConverters.hpp" #include "Acts/Plugins/GeoModel/IGeoShapeConverter.hpp" +#include #include #include @@ -141,9 +142,9 @@ Acts::GeoModelDetectorObjectFactory::findAllSubVolumes(const PVConstLink &vol) { } bool Acts::GeoModelDetectorObjectFactory::convertBox(std::string name) { - auto convB = std::any_of( - m_cfg.convertBox.begin(), m_cfg.convertBox.end(), - [&](const auto &n) { return name.find(n) != std::string::npos; }); + auto convB = std::ranges::any_of(m_cfg.convertBox, [&](const auto &n) { + return name.find(n) != std::string::npos; + }); return convB; } @@ -199,14 +200,14 @@ bool Acts::GeoModelDetectorObjectFactory::matches(const std::string &name, return true; } - auto matchName = std::any_of( - m_cfg.nameList.begin(), m_cfg.nameList.end(), - [&](const auto &n) { return name.find(n) != std::string::npos; }); + auto matchName = std::ranges::any_of(m_cfg.nameList, [&](const auto &n) { + return name.find(n) != std::string::npos; + }); std::string matStr = physvol->getLogVol()->getMaterial()->getName(); - auto matchMaterial = std::any_of( - m_cfg.materialList.begin(), m_cfg.materialList.end(), + auto matchMaterial = std::ranges::any_of( + m_cfg.materialList, [&](const auto &m) { return matStr.find(m) != std::string::npos; }); bool match = matchMaterial && matchName; diff --git a/Plugins/Json/src/DetectorVolumeJsonConverter.cpp b/Plugins/Json/src/DetectorVolumeJsonConverter.cpp index 19628c078ab..3d5c03c020d 100644 --- a/Plugins/Json/src/DetectorVolumeJsonConverter.cpp +++ b/Plugins/Json/src/DetectorVolumeJsonConverter.cpp @@ -21,6 +21,7 @@ #include "Acts/Plugins/Json/VolumeBoundsJsonConverter.hpp" #include "Acts/Utilities/Enumerate.hpp" +#include #include nlohmann::json Acts::DetectorVolumeJsonConverter::toJson( @@ -59,7 +60,7 @@ nlohmann::json Acts::DetectorVolumeJsonConverter::toJson( nlohmann::json jPortals; if (!portals.empty()) { for (const auto* p : volume.portals()) { - auto it = std::find(portals.begin(), portals.end(), p); + auto it = std::ranges::find(portals, p); if (it != portals.end()) { jPortals.push_back(std::distance(portals.begin(), it)); } else { diff --git a/Plugins/Json/src/MaterialMapJsonConverter.cpp b/Plugins/Json/src/MaterialMapJsonConverter.cpp index e27c069157c..76fc01f8569 100644 --- a/Plugins/Json/src/MaterialMapJsonConverter.cpp +++ b/Plugins/Json/src/MaterialMapJsonConverter.cpp @@ -336,12 +336,10 @@ void Acts::MaterialMapJsonConverter::convertToHierarchy( std::pair>& surfaceHierarchy, const Acts::TrackingVolume* tVolume) { - auto sameId = - [tVolume]( - const std::pair& - pair) { return (tVolume->geometryId() == pair.first); }; - if (std::find_if(volumeHierarchy.begin(), volumeHierarchy.end(), sameId) != - volumeHierarchy.end()) { + auto sameId = [tVolume](const auto& pair) { + return (tVolume->geometryId() == pair.first); + }; + if (std::ranges::any_of(volumeHierarchy, sameId)) { // this volume was already visited return; } diff --git a/Plugins/Json/src/PortalJsonConverter.cpp b/Plugins/Json/src/PortalJsonConverter.cpp index a7044f7b6dd..e39b6efca17 100644 --- a/Plugins/Json/src/PortalJsonConverter.cpp +++ b/Plugins/Json/src/PortalJsonConverter.cpp @@ -40,7 +40,7 @@ namespace { int findVolume( const Acts::Experimental::DetectorVolume* volume, const std::vector& volumes) { - auto candidate = std::find(volumes.begin(), volumes.end(), volume); + auto candidate = std::ranges::find(volumes, volume); if (candidate != volumes.end()) { return std::distance(volumes.begin(), candidate); } diff --git a/Tests/Benchmarks/RayFrustumBenchmark.cpp b/Tests/Benchmarks/RayFrustumBenchmark.cpp index 2d0069da1b1..e4f11e60991 100644 --- a/Tests/Benchmarks/RayFrustumBenchmark.cpp +++ b/Tests/Benchmarks/RayFrustumBenchmark.cpp @@ -187,10 +187,10 @@ int main(int /*argc*/, char** /*argv[]*/) { return {name, func(testBox, ray)}; }); - bool all = std::all_of(results.begin(), results.end(), - [](const auto& r) { return r.second; }); - bool none = std::none_of(results.begin(), results.end(), - [](const auto& r) { return r.second; }); + bool all = + std::ranges::all_of(results, [](const auto& r) { return r.second; }); + bool none = + std::ranges::none_of(results, [](const auto& r) { return r.second; }); if (!all && !none) { std::cerr << "Discrepancy: " << std::endl; @@ -369,10 +369,10 @@ int main(int /*argc*/, char** /*argv[]*/) { return {name, func(testBox, fr)}; }); - bool all = std::all_of(results.begin(), results.end(), - [](const auto& r) { return r.second; }); - bool none = std::none_of(results.begin(), results.end(), - [](const auto& r) { return r.second; }); + bool all = + std::ranges::all_of(results, [](const auto& r) { return r.second; }); + bool none = + std::ranges::none_of(results, [](const auto& r) { return r.second; }); if (!all && !none) { std::cerr << "Discrepancy: " << std::endl; diff --git a/Tests/CommonHelpers/Acts/Tests/CommonHelpers/Assertions.hpp b/Tests/CommonHelpers/Acts/Tests/CommonHelpers/Assertions.hpp index 6bc19dc0431..3fee5af18ae 100644 --- a/Tests/CommonHelpers/Acts/Tests/CommonHelpers/Assertions.hpp +++ b/Tests/CommonHelpers/Acts/Tests/CommonHelpers/Assertions.hpp @@ -10,15 +10,15 @@ #include +#include #include -#define CHECK_NE_COLLECTIONS(col1, col2) \ - do { \ - BOOST_CHECK_EQUAL(col1.size(), col2.size()); \ - std::vector result; \ - for (std::size_t i = 0; i < col1.size(); i++) { \ - result.push_back(col1[i] == col2[i]); \ - } \ - BOOST_CHECK( \ - !std::all_of(result.begin(), result.end(), [](bool r) { return r; })); \ +#define CHECK_NE_COLLECTIONS(col1, col2) \ + do { \ + BOOST_CHECK_EQUAL(col1.size(), col2.size()); \ + std::vector result; \ + for (std::size_t i = 0; i < col1.size(); i++) { \ + result.push_back(col1[i] == col2[i]); \ + } \ + BOOST_CHECK(!std::ranges::all_of(result, [](bool r) { return r; })); \ } while (0) diff --git a/Tests/CommonHelpers/Acts/Tests/CommonHelpers/LineSurfaceStub.hpp b/Tests/CommonHelpers/Acts/Tests/CommonHelpers/LineSurfaceStub.hpp index 848e02cab01..662969bc450 100644 --- a/Tests/CommonHelpers/Acts/Tests/CommonHelpers/LineSurfaceStub.hpp +++ b/Tests/CommonHelpers/Acts/Tests/CommonHelpers/LineSurfaceStub.hpp @@ -52,11 +52,11 @@ class LineSurfaceStub : public LineSurface { /// Return a Polyhedron for the surfaces /// /// @param gctx The current geometry context object, e.g. alignment - /// @param lseg is ignored for a perigee @note ignored + /// @param ingoredSegmeent is ignored for the srub /// /// @return A list of vertices and a face/facett description of it Polyhedron polyhedronRepresentation(const GeometryContext& /*gctx*/, - std::size_t /*lseg*/) const final { + unsigned int /*lseg*/) const final { return Polyhedron({}, {}, {}); } }; diff --git a/Tests/UnitTests/Core/Clusterization/CMakeLists.txt b/Tests/UnitTests/Core/Clusterization/CMakeLists.txt index 38dffefd462..a6c4844bdb9 100644 --- a/Tests/UnitTests/Core/Clusterization/CMakeLists.txt +++ b/Tests/UnitTests/Core/Clusterization/CMakeLists.txt @@ -1,2 +1,3 @@ add_unittest(Clusterization1D ClusterizationTests1D.cpp) add_unittest(Clusterization2D ClusterizationTests2D.cpp) +add_unittest(TimedClusterization TimedClusterizationTests.cpp) diff --git a/Tests/UnitTests/Core/Clusterization/TimedClusterizationTests.cpp b/Tests/UnitTests/Core/Clusterization/TimedClusterizationTests.cpp new file mode 100644 index 00000000000..ac60393d9b6 --- /dev/null +++ b/Tests/UnitTests/Core/Clusterization/TimedClusterizationTests.cpp @@ -0,0 +1,260 @@ +// 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 "Acts/Clusterization/TimedClusterization.hpp" + +namespace Acts::Test { + +// Define objects +using Identifier = std::size_t; +struct Cell { + Cell(Identifier identifier, int c, int r, double t) + : id(identifier), column(c), row(r), time(t) {} + + Identifier id{}; + int column{0}; + int row{0}; + int label{-1}; + double time{0.}; +}; + +struct Cluster { + std::vector ids{}; +}; + +using CellCollection = std::vector; +using ClusterCollection = std::vector; + +// Define functions +static inline int getCellRow(const Cell& cell) { + return cell.row; +} + +static inline int getCellColumn(const Cell& cell) { + return cell.column; +} + +static inline int& getCellLabel(Cell& cell) { + return cell.label; +} + +static inline double getCellTime(const Cell& cell) { + return cell.time; +} + +static void clusterAddCell(Cluster& cl, const Cell& cell) { + cl.ids.push_back(cell.id); +} + +BOOST_AUTO_TEST_CASE(TimedGrid_1D_withtime) { + // 1x10 matrix + /* + X X X Y O X Y Y X X + */ + // 6 + 3 cells -> 3 + 2 clusters in total + + std::vector cells; + // X + cells.emplace_back(0ul, 0, -1, 0); + cells.emplace_back(1ul, 1, -1, 0); + cells.emplace_back(2ul, 2, -1, 0); + cells.emplace_back(3ul, 5, -1, 0); + cells.emplace_back(4ul, 8, -1, 0); + cells.emplace_back(5ul, 9, -1, 0); + // Y + cells.emplace_back(6ul, 3, 0, 1); + cells.emplace_back(7ul, 6, 1, 1); + cells.emplace_back(8ul, 7, 1, 1); + + std::vector> expectedResults; + expectedResults.push_back({0ul, 1ul, 2ul}); + expectedResults.push_back({6ul}); + expectedResults.push_back({3ul}); + expectedResults.push_back({7ul, 8ul}); + expectedResults.push_back({4ul, 5ul}); + + ClusterCollection clusters = + Acts::Ccl::createClusters( + cells, Acts::Ccl::TimedConnect(0.5)); + + BOOST_CHECK_EQUAL(5ul, clusters.size()); + + for (std::size_t i(0); i < clusters.size(); ++i) { + std::vector& timedIds = clusters[i].ids; + const std::vector& expected = expectedResults[i]; + std::sort(timedIds.begin(), timedIds.end()); + BOOST_CHECK_EQUAL(timedIds.size(), expected.size()); + + for (std::size_t j(0); j < timedIds.size(); ++j) { + BOOST_CHECK_EQUAL(timedIds[j], expected[j]); + } + } +} + +BOOST_AUTO_TEST_CASE(TimedGrid_2D_notime) { + // 4x4 matrix + /* + X O O X + O O O X + X X O O + X O O X + */ + // 7 cells -> 4 clusters in total + + std::vector cells; + cells.emplace_back(0ul, 0, 0, 0); + cells.emplace_back(1ul, 3, 0, 0); + cells.emplace_back(2ul, 3, 1, 0); + cells.emplace_back(3ul, 0, 2, 0); + cells.emplace_back(4ul, 1, 2, 0); + cells.emplace_back(5ul, 0, 3, 0); + cells.emplace_back(6ul, 3, 3, 0); + + std::vector> expectedResults; + expectedResults.push_back({0ul}); + expectedResults.push_back({3ul, 4ul, 5ul}); + expectedResults.push_back({1ul, 2ul}); + expectedResults.push_back({6ul}); + + ClusterCollection clusters = + Acts::Ccl::createClusters( + cells, + Acts::Ccl::TimedConnect(std::numeric_limits::max())); + + BOOST_CHECK_EQUAL(4ul, clusters.size()); + + // Compare against default connect (only space) + ClusterCollection defaultClusters = + Acts::Ccl::createClusters( + cells, Acts::Ccl::DefaultConnect()); + + BOOST_CHECK_EQUAL(4ul, defaultClusters.size()); + BOOST_CHECK_EQUAL(defaultClusters.size(), expectedResults.size()); + + std::vector sizes{1, 3, 2, 1}; + for (std::size_t i(0); i < clusters.size(); ++i) { + std::vector& timedIds = clusters[i].ids; + std::vector& defaultIds = defaultClusters[i].ids; + const std::vector& expected = expectedResults[i]; + BOOST_CHECK_EQUAL(timedIds.size(), defaultIds.size()); + BOOST_CHECK_EQUAL(timedIds.size(), sizes[i]); + BOOST_CHECK_EQUAL(timedIds.size(), expected.size()); + + std::sort(timedIds.begin(), timedIds.end()); + std::sort(defaultIds.begin(), defaultIds.end()); + for (std::size_t j(0); j < timedIds.size(); ++j) { + BOOST_CHECK_EQUAL(timedIds[j], defaultIds[j]); + BOOST_CHECK_EQUAL(timedIds[j], expected[j]); + } + } +} + +BOOST_AUTO_TEST_CASE(TimedGrid_2D_withtime) { + // 4x4 matrix + /* + X Y O X + O Y Y X + X X Z Z + X O O X + */ + // 7 + 3 + 2 cells -> 4 + 1 + 1 clusters in total + + std::vector cells; + // X + cells.emplace_back(0ul, 0, 0, 0); + cells.emplace_back(1ul, 3, 0, 0); + cells.emplace_back(2ul, 3, 1, 0); + cells.emplace_back(3ul, 0, 2, 0); + cells.emplace_back(4ul, 1, 2, 0); + cells.emplace_back(5ul, 0, 3, 0); + cells.emplace_back(6ul, 3, 3, 0); + // Y + cells.emplace_back(7ul, 1, 0, 1); + cells.emplace_back(8ul, 1, 1, 1); + cells.emplace_back(9ul, 2, 1, 1); + // Z + cells.emplace_back(10ul, 2, 2, 2); + cells.emplace_back(11ul, 3, 2, 2); + + std::vector> expectedResults; + expectedResults.push_back({0ul}); + expectedResults.push_back({3ul, 4ul, 5ul}); + expectedResults.push_back({7ul, 8ul, 9ul}); + expectedResults.push_back({10ul, 11ul}); + expectedResults.push_back({1ul, 2ul}); + expectedResults.push_back({6ul}); + + ClusterCollection clusters = + Acts::Ccl::createClusters( + cells, Acts::Ccl::TimedConnect(0.5)); + + BOOST_CHECK_EQUAL(6ul, clusters.size()); + + std::vector sizes{1, 3, 3, 2, 2, 1}; + for (std::size_t i(0); i < clusters.size(); ++i) { + std::vector& timedIds = clusters[i].ids; + BOOST_CHECK_EQUAL(timedIds.size(), sizes[i]); + std::sort(timedIds.begin(), timedIds.end()); + + const std::vector& expected = expectedResults[i]; + BOOST_CHECK_EQUAL(timedIds.size(), expected.size()); + + for (std::size_t j(0); j < timedIds.size(); ++j) { + BOOST_CHECK_EQUAL(timedIds[j], expected[j]); + } + } +} + +BOOST_AUTO_TEST_CASE(TimedGrid_2D_noTollerance) { + // 4x4 matrix + /* + X O O X + O O O X + X X O O + X O O X + */ + // 7 cells -> 7 clusters in total + // since time requirement will never be satisfied + + std::vector cells; + cells.emplace_back(0ul, 0, 0, 0); + cells.emplace_back(1ul, 3, 0, 0); + cells.emplace_back(2ul, 3, 1, 0); + cells.emplace_back(3ul, 0, 2, 0); + cells.emplace_back(4ul, 1, 2, 0); + cells.emplace_back(5ul, 0, 3, 0); + cells.emplace_back(6ul, 3, 3, 0); + + std::vector> expectedResults; + expectedResults.push_back({0ul}); + expectedResults.push_back({3ul}); + expectedResults.push_back({5ul}); + expectedResults.push_back({4ul}); + expectedResults.push_back({1ul}); + expectedResults.push_back({2ul}); + expectedResults.push_back({6ul}); + + ClusterCollection clusters = + Acts::Ccl::createClusters( + cells, Acts::Ccl::TimedConnect(0.)); + + BOOST_CHECK_EQUAL(7ul, clusters.size()); + + for (std::size_t i(0); i < clusters.size(); ++i) { + std::vector& timedIds = clusters[i].ids; + const std::vector& expected = expectedResults[i]; + + BOOST_CHECK_EQUAL(timedIds.size(), 1); + BOOST_CHECK_EQUAL(timedIds.size(), expected.size()); + BOOST_CHECK_EQUAL(timedIds[0], expected[0]); + } +} + +} // namespace Acts::Test diff --git a/Tests/UnitTests/Core/EventData/CMakeLists.txt b/Tests/UnitTests/Core/EventData/CMakeLists.txt index 5699dc4527f..61b5079da8e 100644 --- a/Tests/UnitTests/Core/EventData/CMakeLists.txt +++ b/Tests/UnitTests/Core/EventData/CMakeLists.txt @@ -15,5 +15,6 @@ add_unittest(ParticleHypothesis ParticleHypothesisTests.cpp) add_unittest(MultiTrajectoryHelpers MultiTrajectoryHelpersTests.cpp) add_unittest(SubspaceHelpers SubspaceHelpersTests.cpp) add_unittest(SeedEdm SeedEdmTests.cpp) +add_unittest(SpacePointContainerEdm SpacePointContainerEdmTests.cpp) add_non_compile_test(MultiTrajectory TrackContainerComplianceTests.cpp) diff --git a/Tests/UnitTests/Core/EventData/SpacePointContainerEdmTests.cpp b/Tests/UnitTests/Core/EventData/SpacePointContainerEdmTests.cpp new file mode 100644 index 00000000000..7ca20985499 --- /dev/null +++ b/Tests/UnitTests/Core/EventData/SpacePointContainerEdmTests.cpp @@ -0,0 +1,203 @@ +// 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 "Acts/Definitions/Algebra.hpp" +#include "Acts/EventData/SpacePointContainer.hpp" +#include "Acts/Utilities/HashedString.hpp" +#include "Acts/Utilities/Holders.hpp" + +#include +#include +#include +#include +#include + +namespace Acts::Test { + +struct SpacePoint { + SpacePoint() = default; + SpacePoint(float ix, float iy, float iz, float ivarR, float ivarZ) + : x(ix), y(iy), z(iz), varR(ivarR), varZ(ivarZ) {} + float x{}; + float y{}; + float z{}; + float varR{}; + float varZ{}; +}; +using SpacePointCollection = std::vector; + +class Adapter { + public: + friend Acts::SpacePointContainer; + friend Acts::SpacePointContainer; + using value_type = SpacePoint; + using ValueType = value_type; + + Adapter(SpacePointCollection&&) = delete; + Adapter(const SpacePointCollection& externalCollection) + : m_storage(&externalCollection) {} + + private: + std::size_t size_impl() const { return storage().size(); } + + float x_impl(std::size_t idx) const { return storage()[idx].x; }; + float y_impl(std::size_t idx) const { return storage()[idx].y; }; + float z_impl(std::size_t idx) const { return storage()[idx].z; }; + float varianceR_impl(std::size_t idx) const { return storage()[idx].varR; } + float varianceZ_impl(std::size_t idx) const { return storage()[idx].varZ; } + + const SpacePoint& get_impl(std::size_t idx) const { return storage()[idx]; } + + std::any component_impl(Acts::HashedString key, std::size_t /*n*/) const { + using namespace Acts::HashedStringLiteral; + switch (key) { + case "TopStripVector"_hash: + case "BottomStripVector"_hash: + case "StripCenterDistance"_hash: + case "TopStripCenterPosition"_hash: + return Acts::Vector3(0., 0., 0.); + default: + throw std::runtime_error("no such component " + std::to_string(key)); + } + } + + const SpacePointCollection& storage() const { return *m_storage; } + + private: + const SpacePointCollection* m_storage{}; +}; + +BOOST_AUTO_TEST_CASE(spacepoint_container_edm_traits) { + using adapter_t = Acts::Test::Adapter; + using container_t = + Acts::SpacePointContainer; + using proxy_t = Acts::SpacePointProxy; + using iterator_t = Acts::ContainerIndexIterator; + + static_assert(std::ranges::range); + static_assert(std::same_as); + static_assert( + std::same_as::iterator_category, + std::random_access_iterator_tag>); +} + +BOOST_AUTO_TEST_CASE(spacepoint_container_edm_constructors) { + std::size_t nExternalPoints = 10; + SpacePointCollection externalCollection(nExternalPoints); + + Acts::SpacePointContainerConfig spConfig; + Acts::SpacePointContainerOptions spOptions; + + Acts::Test::Adapter adapterForRef(externalCollection); + Acts::SpacePointContainer + spContainerRef(spConfig, spOptions, adapterForRef); + + Acts::SpacePointContainer + spContainerVal(spConfig, spOptions, + Acts::Test::Adapter(externalCollection)); + + BOOST_CHECK_EQUAL(spContainerRef.size(), nExternalPoints); + BOOST_CHECK_EQUAL(spContainerVal.size(), nExternalPoints); +} + +BOOST_AUTO_TEST_CASE(spacepoint_container_edm_functionalities) { + std::size_t nExternalPoints = 100; + SpacePointCollection externalCollection; + externalCollection.reserve(nExternalPoints); + for (std::size_t i = 0; i < nExternalPoints; ++i) { + externalCollection.emplace_back(1.f * i, 1.5f * i, 2.f * i, 2.5f * i, + 3.f * i); + } + + Acts::SpacePointContainerConfig spConfig; + spConfig.useDetailedDoubleMeasurementInfo = true; + Acts::SpacePointContainerOptions spOptions; + + Acts::Test::Adapter adapter(externalCollection); + Acts::SpacePointContainer + spContainer(spConfig, spOptions, adapter); + + BOOST_CHECK_EQUAL(spContainer.size(), nExternalPoints); + BOOST_CHECK_EQUAL(spContainer.size(), externalCollection.size()); + BOOST_CHECK_EQUAL(spContainer.end() - spContainer.begin(), nExternalPoints); + BOOST_CHECK_EQUAL(std::distance(spContainer.begin(), spContainer.end()), + nExternalPoints); + BOOST_CHECK_EQUAL(std::distance(std::ranges::begin(spContainer), + std::ranges::end(spContainer)), + nExternalPoints); + + using proxy_t = Acts::SpacePointProxy< + Acts::SpacePointContainer>; + static_assert(std::same_as); + static_assert( + std::same_as); + static_assert( + std::same_as); + static_assert( + std::same_as); + static_assert( + std::same_as); + + using iterator_t = + Acts::ContainerIndexIterator; + using const_iterator_t = + Acts::ContainerIndexIterator; + static_assert( + std::same_as); + static_assert(std::same_as); + static_assert( + std::same_as); + static_assert(std::same_as); + + std::size_t n = 0ul; + for (const proxy_t& proxy : spContainer) { + float refX = 1.f * n; + float refY = 1.5f * n; + float refZ = 2.f * n; + float refCovR = 2.5f * n; + float refCovZ = 3.f * n; + float refRadius = std::hypot(refX, refY); + float refPhi = std::atan2(refY, refX); + + BOOST_CHECK_EQUAL(proxy.index(), n); + BOOST_CHECK_EQUAL(proxy.x(), refX); + BOOST_CHECK_EQUAL(proxy.y(), refY); + BOOST_CHECK_EQUAL(proxy.z(), refZ); + BOOST_CHECK_EQUAL(proxy.radius(), refRadius); + BOOST_CHECK_EQUAL(proxy.phi(), refPhi); + BOOST_CHECK_EQUAL(proxy.varianceR(), refCovR); + BOOST_CHECK_EQUAL(proxy.varianceZ(), refCovZ); + + const Acts::Vector3& topStripVector = proxy.topStripVector(); + const Acts::Vector3& bottomStripVector = proxy.bottomStripVector(); + const Acts::Vector3& stripCenterDistance = proxy.stripCenterDistance(); + const Acts::Vector3& topStripCenterPosition = + proxy.topStripCenterPosition(); + + for (std::size_t i = 0; i < 3; ++i) { + BOOST_CHECK_EQUAL(topStripVector[i], 0.); + BOOST_CHECK_EQUAL(bottomStripVector[i], 0.); + BOOST_CHECK_EQUAL(stripCenterDistance[i], 0.); + BOOST_CHECK_EQUAL(topStripCenterPosition[i], 0.); + } + + const Acts::Test::SpacePoint& sp = proxy.externalSpacePoint(); + BOOST_CHECK_EQUAL(&sp, &externalCollection[n]); + + ++n; + } + BOOST_CHECK_EQUAL(n, nExternalPoints); +} + +} // namespace Acts::Test diff --git a/Tests/UnitTests/Core/EventData/TrackTests.cpp b/Tests/UnitTests/Core/EventData/TrackTests.cpp index 013132a60b9..432efad6447 100644 --- a/Tests/UnitTests/Core/EventData/TrackTests.cpp +++ b/Tests/UnitTests/Core/EventData/TrackTests.cpp @@ -228,9 +228,9 @@ BOOST_AUTO_TEST_CASE(IteratorConcept) { BOOST_CHECK(*it == tc.getTrack(0)); std::advance(it, 4); BOOST_CHECK(*it == tc.getTrack(4)); - BOOST_CHECK(*(it[-1]) == tc.getTrack(3)); - BOOST_CHECK(*(it[0]) == tc.getTrack(4)); - BOOST_CHECK(*(it[1]) == tc.getTrack(5)); + BOOST_CHECK(*(it + (-1)) == tc.getTrack(3)); + BOOST_CHECK(*(it + 0) == tc.getTrack(4)); + BOOST_CHECK(*(it + 1) == tc.getTrack(5)); BOOST_CHECK(*(it - 2) == tc.getTrack(2)); } diff --git a/Tests/UnitTests/Core/Geometry/CMakeLists.txt b/Tests/UnitTests/Core/Geometry/CMakeLists.txt index 1fa422bb0a6..0226e46d7d0 100644 --- a/Tests/UnitTests/Core/Geometry/CMakeLists.txt +++ b/Tests/UnitTests/Core/Geometry/CMakeLists.txt @@ -34,3 +34,4 @@ add_unittest(Volume VolumeTests.cpp) add_unittest(CylinderVolumeStack CylinderVolumeStackTests.cpp) add_unittest(PortalLink PortalLinkTests.cpp) add_unittest(Portal PortalTests.cpp) +add_unittest(PortalShell PortalShellTests.cpp) diff --git a/Tests/UnitTests/Core/Geometry/ExtentTests.cpp b/Tests/UnitTests/Core/Geometry/ExtentTests.cpp index 80513a1d80b..e0913e273eb 100644 --- a/Tests/UnitTests/Core/Geometry/ExtentTests.cpp +++ b/Tests/UnitTests/Core/Geometry/ExtentTests.cpp @@ -176,6 +176,17 @@ BOOST_AUTO_TEST_CASE(ProtoSupportCaseTests) { BOOST_CHECK(volumeExtent.constrains(BinningValue::binR)); } +BOOST_AUTO_TEST_CASE(DesignatedInitializers) { + using enum BinningValue; + ExtentEnvelope exp; + exp[binX] = {1., 2.}; + exp[binEta] = {-1., 1.}; + + ExtentEnvelope act{{.x = {1., 2.}, .eta = {-1., 1.}}}; + + BOOST_CHECK(exp == act); +} + BOOST_AUTO_TEST_SUITE_END() } // namespace Acts::Test diff --git a/Tests/UnitTests/Core/Geometry/PortalShellTests.cpp b/Tests/UnitTests/Core/Geometry/PortalShellTests.cpp new file mode 100644 index 00000000000..4c44617524a --- /dev/null +++ b/Tests/UnitTests/Core/Geometry/PortalShellTests.cpp @@ -0,0 +1,768 @@ +// 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 +#include + +#include "Acts/Definitions/Units.hpp" +#include "Acts/Geometry/CuboidVolumeBounds.hpp" +#include "Acts/Geometry/CutoutCylinderVolumeBounds.hpp" +#include "Acts/Geometry/CylinderVolumeBounds.hpp" +#include "Acts/Geometry/GridPortalLink.hpp" +#include "Acts/Geometry/Portal.hpp" +#include "Acts/Geometry/PortalShell.hpp" +#include "Acts/Geometry/TrackingVolume.hpp" +#include "Acts/Geometry/TrivialPortalLink.hpp" +#include "Acts/Surfaces/SurfaceMergingException.hpp" + +#include + +using namespace Acts::UnitLiterals; + +namespace Acts::Test { +GeometryContext gctx; + +std::size_t getVolumeIndex() { + static std::size_t i = 1; + return i++; +} + +auto makeVolume(auto&&... pars) { + TrackingVolume vol(Transform3::Identity(), + std::make_shared( + std::forward(pars)...)); + vol.setVolumeName("cyl" + std::to_string(getVolumeIndex())); + return vol; +}; + +auto logger = Acts::getDefaultLogger("UnitTests", Acts::Logging::VERBOSE); + +BOOST_AUTO_TEST_SUITE(PortalShellTests) + +BOOST_AUTO_TEST_CASE(ConstructionFromVolume) { + // - Cylinder + // | | no phi | phi | + // | --------- | ------ | --- | + // | rMin > 0 | 1 | 3 | + // | rMin == 0 | 2 | 4 | + + auto cyl1 = makeVolume(30_mm, 40_mm, 100_mm); + auto cyl2 = makeVolume(0_mm, 40_mm, 100_mm); + auto cyl3 = makeVolume(30_mm, 40_mm, 100_mm, 45_degree); + auto cyl4 = makeVolume(0_mm, 40_mm, 100_mm, 45_degree); + + TrackingVolume boxVolume( + Transform3::Identity(), + std::make_shared(10_mm, 10_mm, 10_mm)); + + BOOST_CHECK_THROW(SingleCylinderPortalShell{boxVolume}, + std::invalid_argument); + + SingleCylinderPortalShell shell1{cyl1}; + BOOST_CHECK_EQUAL(shell1.size(), 4); + + using enum CylinderPortalShell::Face; + + const auto* pDisc = shell1.portal(PositiveDisc); + BOOST_REQUIRE_NE(pDisc, nullptr); + BOOST_CHECK_EQUAL( + pDisc + ->resolveVolume(gctx, Vector3{35_mm, 0_mm, 100_mm}, -Vector3::UnitZ()) + .value(), + &cyl1); + BOOST_CHECK_EQUAL( + pDisc->resolveVolume(gctx, Vector3{35_mm, 0_mm, 100_mm}, Vector3::UnitZ()) + .value(), + nullptr); + + const auto* nDisc = shell1.portal(NegativeDisc); + BOOST_REQUIRE_NE(nDisc, nullptr); + BOOST_CHECK_EQUAL(nDisc + ->resolveVolume(gctx, Vector3{35_mm, 0_mm, -100_mm}, + -Vector3::UnitZ()) + .value(), + nullptr); + BOOST_CHECK_EQUAL( + nDisc + ->resolveVolume(gctx, Vector3{35_mm, 0_mm, -100_mm}, Vector3::UnitZ()) + .value(), + &cyl1); + + const auto* oCyl = shell1.portal(OuterCylinder); + BOOST_REQUIRE_NE(oCyl, nullptr); + BOOST_CHECK_EQUAL( + oCyl->resolveVolume(gctx, Vector3{40_mm, 0_mm, 10_mm}, Vector3::UnitX()) + .value(), + nullptr); + BOOST_CHECK_EQUAL( + oCyl->resolveVolume(gctx, Vector3{40_mm, 0_mm, 10_mm}, -Vector3::UnitX()) + .value(), + &cyl1); + + const auto* iCyl = shell1.portal(InnerCylinder); + BOOST_REQUIRE_NE(iCyl, nullptr); + BOOST_CHECK_EQUAL( + iCyl->resolveVolume(gctx, Vector3{30_mm, 0_mm, 10_mm}, Vector3::UnitX()) + .value(), + &cyl1); + BOOST_CHECK_EQUAL( + iCyl->resolveVolume(gctx, Vector3{30_mm, 0_mm, 10_mm}, -Vector3::UnitX()) + .value(), + nullptr); + + SingleCylinderPortalShell shell2{cyl2}; + BOOST_CHECK_EQUAL(shell2.size(), 3); + + pDisc = shell2.portal(PositiveDisc); + BOOST_REQUIRE_NE(pDisc, nullptr); + BOOST_CHECK_EQUAL( + pDisc + ->resolveVolume(gctx, Vector3{35_mm, 0_mm, 100_mm}, -Vector3::UnitZ()) + .value(), + &cyl2); + BOOST_CHECK_EQUAL( + pDisc->resolveVolume(gctx, Vector3{35_mm, 0_mm, 100_mm}, Vector3::UnitZ()) + .value(), + nullptr); + + nDisc = shell2.portal(NegativeDisc); + BOOST_REQUIRE_NE(nDisc, nullptr); + BOOST_CHECK_EQUAL(nDisc + ->resolveVolume(gctx, Vector3{35_mm, 0_mm, -100_mm}, + -Vector3::UnitZ()) + .value(), + nullptr); + BOOST_CHECK_EQUAL( + nDisc + ->resolveVolume(gctx, Vector3{35_mm, 0_mm, -100_mm}, Vector3::UnitZ()) + .value(), + &cyl2); + + oCyl = shell2.portal(OuterCylinder); + BOOST_REQUIRE_NE(oCyl, nullptr); + BOOST_CHECK_EQUAL( + oCyl->resolveVolume(gctx, Vector3{40_mm, 0_mm, 10_mm}, Vector3::UnitX()) + .value(), + nullptr); + BOOST_CHECK_EQUAL( + oCyl->resolveVolume(gctx, Vector3{40_mm, 0_mm, 10_mm}, -Vector3::UnitX()) + .value(), + &cyl2); + + iCyl = shell2.portal(InnerCylinder); + BOOST_CHECK_EQUAL(iCyl, nullptr); + + SingleCylinderPortalShell shell3{cyl3}; + BOOST_CHECK_EQUAL(shell3.size(), 6); + + pDisc = shell3.portal(PositiveDisc); + BOOST_REQUIRE_NE(pDisc, nullptr); + BOOST_CHECK_EQUAL( + pDisc + ->resolveVolume(gctx, Vector3{35_mm, 0_mm, 100_mm}, -Vector3::UnitZ()) + .value(), + &cyl3); + BOOST_CHECK_EQUAL( + pDisc->resolveVolume(gctx, Vector3{35_mm, 0_mm, 100_mm}, Vector3::UnitZ()) + .value(), + nullptr); + + nDisc = shell3.portal(NegativeDisc); + BOOST_REQUIRE_NE(nDisc, nullptr); + BOOST_CHECK_EQUAL(nDisc + ->resolveVolume(gctx, Vector3{35_mm, 0_mm, -100_mm}, + -Vector3::UnitZ()) + .value(), + nullptr); + BOOST_CHECK_EQUAL( + nDisc + ->resolveVolume(gctx, Vector3{35_mm, 0_mm, -100_mm}, Vector3::UnitZ()) + .value(), + &cyl3); + + oCyl = shell3.portal(OuterCylinder); + BOOST_REQUIRE_NE(oCyl, nullptr); + BOOST_CHECK_EQUAL( + oCyl->resolveVolume(gctx, Vector3{40_mm, 0_mm, 10_mm}, Vector3::UnitX()) + .value(), + nullptr); + BOOST_CHECK_EQUAL( + oCyl->resolveVolume(gctx, Vector3{40_mm, 0_mm, 10_mm}, -Vector3::UnitX()) + .value(), + &cyl3); + + iCyl = shell3.portal(InnerCylinder); + BOOST_REQUIRE_NE(iCyl, nullptr); + BOOST_CHECK_EQUAL( + iCyl->resolveVolume(gctx, Vector3{30_mm, 0_mm, 10_mm}, Vector3::UnitX()) + .value(), + &cyl3); + BOOST_CHECK_EQUAL( + iCyl->resolveVolume(gctx, Vector3{30_mm, 0_mm, 10_mm}, -Vector3::UnitX()) + .value(), + nullptr); + + auto anglePoint = [](double angle, double r, double z) { + return Vector3{r * std::cos(angle), r * std::sin(angle), z}; + }; + + const auto* nPhi = shell3.portal(NegativePhiPlane); + BOOST_REQUIRE_NE(nPhi, nullptr); + Vector3 point = anglePoint(-45_degree, 35_mm, 10_mm); + Vector3 dir = Vector3::UnitZ().cross(point).normalized(); + Vector3 idir = (-Vector3::UnitZ()).cross(point).normalized(); + BOOST_CHECK_EQUAL(nPhi->resolveVolume(gctx, point, dir).value(), nullptr); + BOOST_CHECK_EQUAL(nPhi->resolveVolume(gctx, point, idir).value(), &cyl3); + + const auto* pPhi = shell3.portal(PositivePhiPlane); + BOOST_REQUIRE_NE(pPhi, nullptr); + point = anglePoint(45_degree, 35_mm, 10_mm); + dir = Vector3::UnitZ().cross(point).normalized(); + idir = (-Vector3::UnitZ()).cross(point).normalized(); + BOOST_CHECK_EQUAL(pPhi->resolveVolume(gctx, point, dir).value(), nullptr); + BOOST_CHECK_EQUAL(pPhi->resolveVolume(gctx, point, idir).value(), &cyl3); + + SingleCylinderPortalShell shell4{cyl4}; + BOOST_CHECK_EQUAL(shell4.size(), 5); + + pDisc = shell4.portal(PositiveDisc); + BOOST_REQUIRE_NE(pDisc, nullptr); + BOOST_CHECK_EQUAL( + pDisc + ->resolveVolume(gctx, Vector3{35_mm, 0_mm, 100_mm}, -Vector3::UnitZ()) + .value(), + &cyl4); + BOOST_CHECK_EQUAL( + pDisc->resolveVolume(gctx, Vector3{35_mm, 0_mm, 100_mm}, Vector3::UnitZ()) + .value(), + nullptr); + + nDisc = shell4.portal(NegativeDisc); + BOOST_REQUIRE_NE(nDisc, nullptr); + BOOST_CHECK_EQUAL(nDisc + ->resolveVolume(gctx, Vector3{35_mm, 0_mm, -100_mm}, + -Vector3::UnitZ()) + .value(), + nullptr); + BOOST_CHECK_EQUAL( + nDisc + ->resolveVolume(gctx, Vector3{35_mm, 0_mm, -100_mm}, Vector3::UnitZ()) + .value(), + &cyl4); + + oCyl = shell4.portal(OuterCylinder); + BOOST_REQUIRE_NE(oCyl, nullptr); + BOOST_CHECK_EQUAL( + oCyl->resolveVolume(gctx, Vector3{40_mm, 0_mm, 10_mm}, Vector3::UnitX()) + .value(), + nullptr); + BOOST_CHECK_EQUAL( + oCyl->resolveVolume(gctx, Vector3{40_mm, 0_mm, 10_mm}, -Vector3::UnitX()) + .value(), + &cyl4); + + iCyl = shell4.portal(InnerCylinder); + BOOST_CHECK_EQUAL(iCyl, nullptr); + + nPhi = shell4.portal(NegativePhiPlane); + BOOST_REQUIRE_NE(nPhi, nullptr); + point = anglePoint(-45_degree, 35_mm, 10_mm); + dir = Vector3::UnitZ().cross(point).normalized(); + idir = (-Vector3::UnitZ()).cross(point).normalized(); + BOOST_CHECK_EQUAL(nPhi->resolveVolume(gctx, point, dir).value(), nullptr); + BOOST_CHECK_EQUAL(nPhi->resolveVolume(gctx, point, idir).value(), &cyl4); + + pPhi = shell4.portal(PositivePhiPlane); + BOOST_REQUIRE_NE(pPhi, nullptr); + point = anglePoint(45_degree, 35_mm, 10_mm); + dir = Vector3::UnitZ().cross(point).normalized(); + idir = (-Vector3::UnitZ()).cross(point).normalized(); + BOOST_CHECK_EQUAL(pPhi->resolveVolume(gctx, point, dir).value(), nullptr); + BOOST_CHECK_EQUAL(pPhi->resolveVolume(gctx, point, idir).value(), &cyl4); +} + +// outer cylinder +// +----------+----------+ +// | | | +// negative | v | positive +// disc +--> <--+ disc +// | ^ | +// | | | +// +----------+----------+ +// inner cylinder + +BOOST_AUTO_TEST_CASE(PortalAssignment) { + using enum CylinderPortalShell::Face; + TrackingVolume vol( + Transform3::Identity(), + std::make_shared(30_mm, 100_mm, 100_mm)); + + SingleCylinderPortalShell shell{vol}; + + const auto* iCyl = shell.portal(InnerCylinder); + const auto* pDisc = shell.portal(PositiveDisc); + auto* oCyl = shell.portal(OuterCylinder); + auto* nDisc = shell.portal(NegativeDisc); + + // Setting new outer cylinder + BOOST_REQUIRE_NE(oCyl, nullptr); + auto* oCylLink = dynamic_cast( + oCyl->getLink(Direction::OppositeNormal)); + BOOST_REQUIRE_NE(oCylLink, nullptr); + + auto grid = oCylLink->makeGrid(BinningValue::binZ); + + auto portal2 = + std::make_shared(Direction::OppositeNormal, std::move(grid)); + shell.setPortal(portal2, OuterCylinder); + BOOST_CHECK_EQUAL(shell.portal(OuterCylinder), portal2.get()); + + // Other portals should stay the same + BOOST_CHECK_EQUAL(shell.portal(InnerCylinder), iCyl); + BOOST_CHECK_EQUAL(shell.portal(PositiveDisc), pDisc); + BOOST_CHECK_EQUAL(shell.portal(NegativeDisc), nDisc); + + // Setting new negative disc + BOOST_REQUIRE_NE(nDisc, nullptr); + auto* nDiscLink = dynamic_cast( + nDisc->getLink(Direction::AlongNormal)); + BOOST_REQUIRE_NE(nDiscLink, nullptr); + + grid = nDiscLink->makeGrid(BinningValue::binR); + + auto portal3 = + std::make_shared(Direction::AlongNormal, std::move(grid)); + shell.setPortal(portal3, NegativeDisc); + BOOST_CHECK_EQUAL(shell.portal(NegativeDisc), portal3.get()); + + // Other portals should stay the same + BOOST_CHECK_EQUAL(shell.portal(OuterCylinder), portal2.get()); + BOOST_CHECK_EQUAL(shell.portal(InnerCylinder), iCyl); + BOOST_CHECK_EQUAL(shell.portal(PositiveDisc), pDisc); +} + +BOOST_AUTO_TEST_SUITE(CylinderStack) +BOOST_AUTO_TEST_CASE(ZDirection) { + using enum CylinderPortalShell::Face; + BOOST_TEST_CONTEXT("rMin>0") { + TrackingVolume vol1( + Transform3{Translation3{Vector3::UnitZ() * -100_mm}}, + std::make_shared(30_mm, 100_mm, 100_mm)); + + TrackingVolume vol2( + Transform3{Translation3{Vector3::UnitZ() * 100_mm}}, + std::make_shared(30_mm, 100_mm, 100_mm)); + + SingleCylinderPortalShell shell1{vol1}; + SingleCylinderPortalShell shell2{vol2}; + + BOOST_CHECK_NE(shell1.portal(PositiveDisc), shell2.portal(NegativeDisc)); + + CylinderStackPortalShell stack{ + gctx, {&shell1, &shell2}, BinningValue::binZ}; + BOOST_CHECK_EQUAL(stack.size(), 4); + + const auto* iCyl = stack.portal(InnerCylinder); + BOOST_CHECK_EQUAL(shell1.portal(InnerCylinder), iCyl); + BOOST_CHECK_EQUAL(shell2.portal(InnerCylinder), iCyl); + + const auto* oCyl = stack.portal(OuterCylinder); + BOOST_CHECK_EQUAL(shell1.portal(OuterCylinder), oCyl); + BOOST_CHECK_EQUAL(shell2.portal(OuterCylinder), oCyl); + + BOOST_CHECK_EQUAL(stack.portal(PositiveDisc), shell2.portal(PositiveDisc)); + BOOST_CHECK_EQUAL(stack.portal(NegativeDisc), shell1.portal(NegativeDisc)); + + BOOST_CHECK_EQUAL(stack.portal(NegativePhiPlane), nullptr); + BOOST_CHECK_EQUAL(stack.portalPtr(NegativePhiPlane), nullptr); + + BOOST_CHECK_EQUAL(stack.portal(PositivePhiPlane), nullptr); + BOOST_CHECK_EQUAL(stack.portalPtr(PositivePhiPlane), nullptr); + + // Disc portals have been fused + BOOST_CHECK_EQUAL(shell1.portal(PositiveDisc), shell2.portal(NegativeDisc)); + + shell1 = SingleCylinderPortalShell{vol1}; + shell2 = SingleCylinderPortalShell{vol2}; + + BOOST_CHECK_THROW( + CylinderStackPortalShell(gctx, {&shell1, &shell2}, BinningValue::binR), + SurfaceMergingException); + } + + BOOST_TEST_CONTEXT("rMin==0") { + TrackingVolume vol1( + Transform3{Translation3{Vector3::UnitZ() * -100_mm}}, + std::make_shared(0_mm, 100_mm, 100_mm)); + + TrackingVolume vol2( + Transform3{Translation3{Vector3::UnitZ() * 100_mm}}, + std::make_shared(0_mm, 100_mm, 100_mm)); + + SingleCylinderPortalShell shell1{vol1}; + SingleCylinderPortalShell shell2{vol2}; + + BOOST_CHECK_EQUAL(shell1.portal(InnerCylinder), nullptr); + BOOST_CHECK_EQUAL(shell2.portal(InnerCylinder), nullptr); + + BOOST_CHECK_NE(shell1.portal(PositiveDisc), shell2.portal(NegativeDisc)); + + CylinderStackPortalShell stack{ + gctx, {&shell1, &shell2}, BinningValue::binZ}; + BOOST_CHECK_EQUAL(stack.size(), 3); + + // Disc portals have been fused + BOOST_CHECK_EQUAL(shell1.portal(PositiveDisc), shell2.portal(NegativeDisc)); + + const auto* iCyl = stack.portal(InnerCylinder); + BOOST_CHECK_EQUAL(iCyl, nullptr); + + const auto* oCyl = stack.portal(OuterCylinder); + BOOST_CHECK_EQUAL(shell1.portal(OuterCylinder), oCyl); + BOOST_CHECK_EQUAL(shell2.portal(OuterCylinder), oCyl); + + BOOST_CHECK_EQUAL(stack.portal(PositiveDisc), shell2.portal(PositiveDisc)); + BOOST_CHECK_EQUAL(stack.portal(NegativeDisc), shell1.portal(NegativeDisc)); + + BOOST_CHECK_EQUAL(stack.portal(NegativePhiPlane), nullptr); + BOOST_CHECK_EQUAL(stack.portalPtr(NegativePhiPlane), nullptr); + + BOOST_CHECK_EQUAL(stack.portal(PositivePhiPlane), nullptr); + BOOST_CHECK_EQUAL(stack.portalPtr(PositivePhiPlane), nullptr); + + shell1 = SingleCylinderPortalShell{vol1}; + shell2 = SingleCylinderPortalShell{vol2}; + + BOOST_CHECK_THROW( + CylinderStackPortalShell(gctx, {&shell1, &shell2}, BinningValue::binR), + SurfaceMergingException); + } +} + +BOOST_AUTO_TEST_CASE(RDirection) { + using enum CylinderPortalShell::Face; + BOOST_TEST_CONTEXT("rMin>0") { + TrackingVolume vol1( + Transform3::Identity(), + std::make_shared(30_mm, 100_mm, 100_mm)); + + TrackingVolume vol2( + Transform3::Identity(), + std::make_shared(100_mm, 150_mm, 100_mm)); + + SingleCylinderPortalShell shell1{vol1}; + SingleCylinderPortalShell shell2{vol2}; + + BOOST_CHECK_NE(shell1.portal(OuterCylinder), shell2.portal(InnerCylinder)); + + CylinderStackPortalShell stack{ + gctx, {&shell1, &shell2}, BinningValue::binR}; + BOOST_CHECK_EQUAL(stack.size(), 4); + + // Internal cylinder portals have been fused + BOOST_CHECK_EQUAL(shell1.portal(OuterCylinder), + shell2.portal(InnerCylinder)); + + const auto* nDisc = stack.portal(NegativeDisc); + const auto* pDisc = stack.portal(PositiveDisc); + + BOOST_CHECK_EQUAL(shell1.portal(NegativeDisc), nDisc); + BOOST_CHECK_EQUAL(shell2.portal(NegativeDisc), nDisc); + BOOST_CHECK_EQUAL(shell1.portal(PositiveDisc), pDisc); + BOOST_CHECK_EQUAL(shell2.portal(PositiveDisc), pDisc); + + BOOST_CHECK_EQUAL(stack.portal(InnerCylinder), + shell1.portal(InnerCylinder)); + BOOST_CHECK_EQUAL(stack.portal(OuterCylinder), + shell2.portal(OuterCylinder)); + + BOOST_CHECK_EQUAL(stack.portal(NegativePhiPlane), nullptr); + BOOST_CHECK_EQUAL(stack.portalPtr(NegativePhiPlane), nullptr); + + BOOST_CHECK_EQUAL(stack.portal(PositivePhiPlane), nullptr); + BOOST_CHECK_EQUAL(stack.portalPtr(PositivePhiPlane), nullptr); + + shell1 = SingleCylinderPortalShell{vol1}; + shell2 = SingleCylinderPortalShell{vol2}; + + BOOST_CHECK_THROW( + CylinderStackPortalShell(gctx, {&shell1, &shell2}, BinningValue::binZ), + SurfaceMergingException); + } + + BOOST_TEST_CONTEXT("rMin==0") { + TrackingVolume vol1( + Transform3::Identity(), + std::make_shared(0_mm, 100_mm, 100_mm)); + + TrackingVolume vol2( + Transform3::Identity(), + std::make_shared(100_mm, 150_mm, 100_mm)); + + SingleCylinderPortalShell shell1{vol1}; + SingleCylinderPortalShell shell2{vol2}; + + BOOST_CHECK_EQUAL(shell1.portal(InnerCylinder), nullptr); + BOOST_CHECK_NE(shell1.portal(OuterCylinder), shell2.portal(InnerCylinder)); + + CylinderStackPortalShell stack{ + gctx, {&shell1, &shell2}, BinningValue::binR}; + BOOST_CHECK_EQUAL(stack.size(), 4); + + // Internal cylinder portals have been fused + BOOST_CHECK_EQUAL(shell1.portal(OuterCylinder), + shell2.portal(InnerCylinder)); + + const auto* nDisc = stack.portal(NegativeDisc); + const auto* pDisc = stack.portal(PositiveDisc); + + BOOST_CHECK_EQUAL(shell1.portal(NegativeDisc), nDisc); + BOOST_CHECK_EQUAL(shell2.portal(NegativeDisc), nDisc); + BOOST_CHECK_EQUAL(shell1.portal(PositiveDisc), pDisc); + BOOST_CHECK_EQUAL(shell2.portal(PositiveDisc), pDisc); + + BOOST_CHECK_EQUAL(stack.portal(InnerCylinder), nullptr); + BOOST_CHECK_EQUAL(stack.portal(OuterCylinder), + shell2.portal(OuterCylinder)); + + BOOST_CHECK_EQUAL(stack.portal(NegativePhiPlane), nullptr); + BOOST_CHECK_EQUAL(stack.portalPtr(NegativePhiPlane), nullptr); + + BOOST_CHECK_EQUAL(stack.portal(PositivePhiPlane), nullptr); + BOOST_CHECK_EQUAL(stack.portalPtr(PositivePhiPlane), nullptr); + + shell1 = SingleCylinderPortalShell{vol1}; + shell2 = SingleCylinderPortalShell{vol2}; + + BOOST_CHECK_THROW( + CylinderStackPortalShell(gctx, {&shell1, &shell2}, BinningValue::binZ), + std::invalid_argument); + } +} + +BOOST_AUTO_TEST_CASE(NestedStacks) { + // ^ + // r | +---------------------------------+---------+ + // | | | | + // | | | | + // | | vol2 | | + // | | | | + // | | | | + // | +---------------------------------+ | + // | | | | + // | | | | + // | | gap | vol3 | + // | | | | + // | | | | + // | +---------------------------------+ | + // | | | | + // | | | | + // | | vol1 | | + // | | | | + // | | | | + // | +---------------------------------+---------+ + // | + // +--------------------------------------------------> + // z + + Transform3 base = Transform3::Identity(); + + TrackingVolume vol1( + base, std::make_shared(23_mm, 48_mm, 200_mm), + "PixelLayer0"); + + TrackingVolume gap( + base, std::make_shared(48_mm, 250_mm, 200_mm), + "Gap"); + + TrackingVolume vol2( + base, std::make_shared(250_mm, 400_mm, 200_mm), + "PixelLayer3"); + + TrackingVolume vol3( + base * Translation3{Vector3::UnitZ() * 300_mm}, + std::make_shared(23_mm, 400_mm, 100_mm), + "PixelEcPos"); + + SingleCylinderPortalShell shell1{vol1}; + BOOST_CHECK(shell1.isValid()); + SingleCylinderPortalShell gapShell{gap}; + BOOST_CHECK(gapShell.isValid()); + SingleCylinderPortalShell shell2{vol2}; + BOOST_CHECK(shell2.isValid()); + + CylinderStackPortalShell stack{ + gctx, {&shell1, &gapShell, &shell2}, BinningValue::binR}; + + BOOST_CHECK(stack.isValid()); + + SingleCylinderPortalShell shell3{vol3}; + BOOST_CHECK(shell3.isValid()); + + CylinderStackPortalShell stack2{ + gctx, {&stack, &shell3}, BinningValue::binZ, *logger}; + BOOST_CHECK(stack2.isValid()); + + using enum CylinderPortalShell::Face; + + auto lookup = [](auto& shell, CylinderPortalShell::Face face, + Vector3 position, + Vector3 direction) -> const TrackingVolume* { + const auto* portal = shell.portal(face); + BOOST_REQUIRE_NE(portal, nullptr); + return portal->resolveVolume(gctx, position, direction).value(); + }; + + // Interconnection in the r direction + + BOOST_CHECK_EQUAL(lookup(shell1, InnerCylinder, 23_mm * Vector3::UnitX(), + -Vector3::UnitX()), + nullptr); + BOOST_CHECK_EQUAL( + lookup(shell1, InnerCylinder, 23_mm * Vector3::UnitX(), Vector3::UnitX()), + &vol1); + + BOOST_CHECK_EQUAL( + lookup(shell1, OuterCylinder, 48_mm * Vector3::UnitX(), Vector3::UnitX()), + &gap); + + BOOST_CHECK_EQUAL(lookup(gapShell, InnerCylinder, 48_mm * Vector3::UnitX(), + -Vector3::UnitX()), + &vol1); + + BOOST_CHECK_EQUAL(lookup(gapShell, OuterCylinder, 250_mm * Vector3::UnitX(), + Vector3::UnitX()), + &vol2); + + BOOST_CHECK_EQUAL(lookup(shell2, InnerCylinder, 250_mm * Vector3::UnitX(), + -Vector3::UnitX()), + &gap); + + BOOST_CHECK_EQUAL(lookup(shell2, OuterCylinder, 400_mm * Vector3::UnitX(), + Vector3::UnitX()), + nullptr); + + BOOST_CHECK_EQUAL(lookup(shell2, OuterCylinder, 400_mm * Vector3::UnitX(), + -Vector3::UnitX()), + &vol2); + + BOOST_CHECK_EQUAL(lookup(shell2, OuterCylinder, 400_mm * Vector3::UnitX(), + -Vector3::UnitX()), + &vol2); + + // Left connection + + BOOST_CHECK_EQUAL(lookup(shell1, NegativeDisc, Vector3(30_mm, 0, -200_mm), + -Vector3::UnitZ()), + nullptr); + + BOOST_CHECK_EQUAL(lookup(shell1, NegativeDisc, Vector3(30_mm, 0, -200_mm), + Vector3::UnitZ()), + &vol1); + + BOOST_CHECK_EQUAL(lookup(gapShell, NegativeDisc, Vector3(60_mm, 0, -200_mm), + -Vector3::UnitZ()), + nullptr); + + BOOST_CHECK_EQUAL(lookup(gapShell, NegativeDisc, Vector3(60_mm, 0, -200_mm), + Vector3::UnitZ()), + &gap); + + BOOST_CHECK_EQUAL(lookup(shell2, NegativeDisc, Vector3(300_mm, 0, -200_mm), + -Vector3::UnitZ()), + nullptr); + + BOOST_CHECK_EQUAL(lookup(shell2, NegativeDisc, Vector3(300_mm, 0, -200_mm), + Vector3::UnitZ()), + &vol2); + + // Right connection + + BOOST_CHECK_EQUAL(lookup(shell1, PositiveDisc, Vector3(30_mm, 0, 200_mm), + -Vector3::UnitZ()), + &vol1); + + BOOST_CHECK_EQUAL( + lookup(shell1, PositiveDisc, Vector3(30_mm, 0, 200_mm), Vector3::UnitZ()), + &vol3); + + BOOST_CHECK_EQUAL(lookup(gapShell, PositiveDisc, Vector3(60_mm, 0, 200_mm), + -Vector3::UnitZ()), + &gap); + + BOOST_CHECK_EQUAL(lookup(gapShell, PositiveDisc, Vector3(60_mm, 0, 200_mm), + Vector3::UnitZ()), + &vol3); + + BOOST_CHECK_EQUAL(lookup(shell2, PositiveDisc, Vector3(300_mm, 0, 200_mm), + -Vector3::UnitZ()), + &vol2); + + BOOST_CHECK_EQUAL(lookup(shell2, PositiveDisc, Vector3(300_mm, 0, 200_mm), + Vector3::UnitZ()), + &vol3); + + // Right outer connection + + BOOST_CHECK_EQUAL(lookup(shell3, PositiveDisc, Vector3(300_mm, 0, 400_mm), + -Vector3::UnitZ()), + &vol3); + + BOOST_CHECK_EQUAL(lookup(shell3, PositiveDisc, Vector3(300_mm, 0, 400_mm), + Vector3::UnitZ()), + nullptr); +} + +BOOST_AUTO_TEST_CASE(ConnectOuter) { + auto cyl1 = makeVolume(30_mm, 40_mm, 100_mm); + auto cyl2 = makeVolume(0_mm, 50_mm, 110_mm); + + SingleCylinderPortalShell shell{cyl1}; + + using enum CylinderPortalShell::Face; + BOOST_CHECK_EQUAL( + shell.portal(OuterCylinder)->getLink(Direction::AlongNormal), nullptr); + BOOST_CHECK_EQUAL( + shell.portal(InnerCylinder)->getLink(Direction::OppositeNormal), nullptr); + BOOST_CHECK_EQUAL(shell.portal(PositiveDisc)->getLink(Direction::AlongNormal), + nullptr); + BOOST_CHECK_EQUAL( + shell.portal(NegativeDisc)->getLink(Direction::OppositeNormal), nullptr); + + shell.connectOuter(cyl2); + + BOOST_CHECK_NE(shell.portal(OuterCylinder)->getLink(Direction::AlongNormal), + nullptr); + BOOST_CHECK_NE( + shell.portal(InnerCylinder)->getLink(Direction::OppositeNormal), nullptr); + BOOST_CHECK_NE(shell.portal(PositiveDisc)->getLink(Direction::AlongNormal), + nullptr); + BOOST_CHECK_NE(shell.portal(NegativeDisc)->getLink(Direction::OppositeNormal), + nullptr); +} + +BOOST_AUTO_TEST_CASE(RegisterInto) { + using enum CylinderPortalShell::Face; + TrackingVolume vol1( + Transform3::Identity(), + std::make_shared(0_mm, 100_mm, 100_mm)); + + SingleCylinderPortalShell shell{vol1}; + + BOOST_CHECK_EQUAL(vol1.portals().size(), 0); + + shell.applyToVolume(); + BOOST_CHECK_EQUAL(vol1.portals().size(), 3); +} + +BOOST_AUTO_TEST_SUITE_END() // CylinderStack +BOOST_AUTO_TEST_SUITE_END() + +} // namespace Acts::Test diff --git a/Tests/UnitTests/Core/Geometry/ProtoLayerTests.cpp b/Tests/UnitTests/Core/Geometry/ProtoLayerTests.cpp index cbace6a6559..efde97d9b41 100644 --- a/Tests/UnitTests/Core/Geometry/ProtoLayerTests.cpp +++ b/Tests/UnitTests/Core/Geometry/ProtoLayerTests.cpp @@ -9,30 +9,33 @@ #include #include "Acts/Definitions/Algebra.hpp" +#include "Acts/Definitions/Units.hpp" +#include "Acts/Geometry/DetectorElementBase.hpp" #include "Acts/Geometry/Extent.hpp" #include "Acts/Geometry/GeometryContext.hpp" #include "Acts/Geometry/ProtoLayer.hpp" #include "Acts/Surfaces/PlaneSurface.hpp" #include "Acts/Surfaces/RectangleBounds.hpp" #include "Acts/Surfaces/Surface.hpp" +#include "Acts/Tests/CommonHelpers/DetectorElementStub.hpp" #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp" #include "Acts/Utilities/BinningType.hpp" #include "Acts/Utilities/RangeXD.hpp" -#include #include #include #include #include -#include #include namespace Acts::Test::Layers { +GeometryContext tgContext = GeometryContext(); + BOOST_AUTO_TEST_SUITE(Geometry) BOOST_AUTO_TEST_CASE(ProtoLayerTests) { - GeometryContext tgContext = GeometryContext(); + using enum BinningValue; // Create a proto layer with 4 surfaces on the x/y grid auto recBounds = std::make_shared(3., 6.); @@ -105,20 +108,20 @@ BOOST_AUTO_TEST_CASE(ProtoLayerTests) { // Test 1 - identity transform auto protoLayer = createProtoLayer(Transform3::Identity()); - CHECK_CLOSE_ABS(protoLayer.range(BinningValue::binX), 12., 1e-8); - CHECK_CLOSE_ABS(protoLayer.medium(BinningValue::binX), 0., 1e-8); - CHECK_CLOSE_ABS(protoLayer.min(BinningValue::binX), -6., 1e-8); - CHECK_CLOSE_ABS(protoLayer.max(BinningValue::binX), 6., 1e-8); - CHECK_CLOSE_ABS(protoLayer.range(BinningValue::binY), 6., 1e-8); - CHECK_CLOSE_ABS(protoLayer.medium(BinningValue::binY), 0., 1e-8); - CHECK_CLOSE_ABS(protoLayer.min(BinningValue::binY), -3., 1e-8); - CHECK_CLOSE_ABS(protoLayer.max(BinningValue::binY), 3., 1e-8); - CHECK_CLOSE_ABS(protoLayer.range(BinningValue::binZ), 12., 1e-8); - CHECK_CLOSE_ABS(protoLayer.medium(BinningValue::binZ), 0., 1e-8); - CHECK_CLOSE_ABS(protoLayer.min(BinningValue::binZ), -6., 1e-8); - CHECK_CLOSE_ABS(protoLayer.max(BinningValue::binZ), 6., 1e-8); - CHECK_CLOSE_ABS(protoLayer.max(BinningValue::binR), std::hypot(3, 6), 1e-8); - CHECK_CLOSE_ABS(protoLayer.min(BinningValue::binR), 3., 1e-8); + CHECK_CLOSE_ABS(protoLayer.range(binX), 12., 1e-8); + CHECK_CLOSE_ABS(protoLayer.medium(binX), 0., 1e-8); + CHECK_CLOSE_ABS(protoLayer.min(binX), -6., 1e-8); + CHECK_CLOSE_ABS(protoLayer.max(binX), 6., 1e-8); + CHECK_CLOSE_ABS(protoLayer.range(binY), 6., 1e-8); + CHECK_CLOSE_ABS(protoLayer.medium(binY), 0., 1e-8); + CHECK_CLOSE_ABS(protoLayer.min(binY), -3., 1e-8); + CHECK_CLOSE_ABS(protoLayer.max(binY), 3., 1e-8); + CHECK_CLOSE_ABS(protoLayer.range(binZ), 12., 1e-8); + CHECK_CLOSE_ABS(protoLayer.medium(binZ), 0., 1e-8); + CHECK_CLOSE_ABS(protoLayer.min(binZ), -6., 1e-8); + CHECK_CLOSE_ABS(protoLayer.max(binZ), 6., 1e-8); + CHECK_CLOSE_ABS(protoLayer.max(binR), std::hypot(3, 6), 1e-8); + CHECK_CLOSE_ABS(protoLayer.min(binR), 3., 1e-8); // Test 1a @@ -127,16 +130,15 @@ BOOST_AUTO_TEST_CASE(ProtoLayerTests) { auto protoLayerRot = createProtoLayer(AngleAxis3(-0.345, Vector3::UnitZ()) * Transform3::Identity()); - BOOST_CHECK_NE(protoLayer.min(BinningValue::binX), -6.); - CHECK_CLOSE_ABS(protoLayerRot.medium(BinningValue::binX), 0., 1e-8); - CHECK_CLOSE_ABS(protoLayerRot.medium(BinningValue::binY), 0., 1e-8); - CHECK_CLOSE_ABS(protoLayerRot.range(BinningValue::binZ), 12., 1e-8); - CHECK_CLOSE_ABS(protoLayerRot.medium(BinningValue::binZ), 0., 1e-8); - CHECK_CLOSE_ABS(protoLayerRot.min(BinningValue::binZ), -6., 1e-8); - CHECK_CLOSE_ABS(protoLayerRot.max(BinningValue::binZ), 6., 1e-8); - CHECK_CLOSE_ABS(protoLayerRot.min(BinningValue::binR), 3., 1e-8); - CHECK_CLOSE_ABS(protoLayerRot.max(BinningValue::binR), std::hypot(3, 6), - 1e-8); + BOOST_CHECK_NE(protoLayer.min(binX), -6.); + CHECK_CLOSE_ABS(protoLayerRot.medium(binX), 0., 1e-8); + CHECK_CLOSE_ABS(protoLayerRot.medium(binY), 0., 1e-8); + CHECK_CLOSE_ABS(protoLayerRot.range(binZ), 12., 1e-8); + CHECK_CLOSE_ABS(protoLayerRot.medium(binZ), 0., 1e-8); + CHECK_CLOSE_ABS(protoLayerRot.min(binZ), -6., 1e-8); + CHECK_CLOSE_ABS(protoLayerRot.max(binZ), 6., 1e-8); + CHECK_CLOSE_ABS(protoLayerRot.min(binR), 3., 1e-8); + CHECK_CLOSE_ABS(protoLayerRot.max(binR), std::hypot(3, 6), 1e-8); std::stringstream sstream; protoLayerRot.toStream(sstream); @@ -155,6 +157,111 @@ Extent in space : BOOST_CHECK_EQUAL(sstream.str(), oString); } +BOOST_AUTO_TEST_CASE(OrientedLayer) { + using enum BinningValue; + using namespace Acts::UnitLiterals; + + Transform3 base = Transform3::Identity(); + + auto recBounds = std::make_shared(3_mm, 6_mm); + + std::vector> detectorElements; + + auto makeFan = [&](double yrot, double thickness = 0) { + detectorElements.clear(); + + std::size_t nSensors = 8; + double deltaPhi = 2 * M_PI / nSensors; + double r = 20_mm; + std::vector> surfaces; + for (std::size_t i = 0; i < nSensors; i++) { + // Create a fan of sensors + + Transform3 trf = base * AngleAxis3{yrot, Vector3::UnitY()} * + AngleAxis3{deltaPhi * i, Vector3::UnitZ()} * + Translation3(Vector3::UnitX() * r); + + auto& element = detectorElements.emplace_back( + std::make_unique(trf, recBounds, thickness)); + + surfaces.push_back(element->surface().getSharedPtr()); + } + return surfaces; + }; + + std::vector> surfaces = makeFan(0_degree); + + ProtoLayer protoLayer(tgContext, surfaces); + + BOOST_CHECK_EQUAL(protoLayer.surfaces().size(), 8); + BOOST_CHECK_CLOSE(protoLayer.min(binX), -23_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.max(binX), 23_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.min(binY), -23_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.max(binY), 23_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.min(binZ), 0_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.max(binZ), 0_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.min(binR), 17_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.max(binR), 23.769728648_mm, 1e-8); + + surfaces = makeFan(45_degree); + + // Do NOT provide rotation matrix: sizing will be affected + protoLayer = {tgContext, surfaces}; + + BOOST_CHECK_EQUAL(protoLayer.surfaces().size(), 8); + BOOST_CHECK_CLOSE(protoLayer.min(binX), -16.26345596_mm, 1e-4); + BOOST_CHECK_CLOSE(protoLayer.max(binX), 16.26345596_mm, 1e-4); + BOOST_CHECK_CLOSE(protoLayer.min(binY), -23_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.max(binY), 23_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.min(binZ), -16.26345596_mm, 1e-4); + BOOST_CHECK_CLOSE(protoLayer.max(binZ), 16.26345596_mm, 1e-4); + + protoLayer = {tgContext, surfaces, + Transform3{AngleAxis3{45_degree, Vector3::UnitY()}}.inverse()}; + + BOOST_CHECK_EQUAL(protoLayer.surfaces().size(), 8); + BOOST_CHECK_CLOSE(protoLayer.range(binX), 46_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.min(binX), -23_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.max(binX), 23_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.range(binY), 46_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.min(binY), -23_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.max(binY), 23_mm, 1e-8); + CHECK_SMALL(protoLayer.range(binZ), 1e-14); + CHECK_SMALL(protoLayer.min(binZ), 1e-14); + CHECK_SMALL(protoLayer.max(binZ), 1e-14); + + surfaces = makeFan(0_degree, 10_mm); + + protoLayer = {tgContext, surfaces}; + + BOOST_CHECK_EQUAL(protoLayer.surfaces().size(), 8); + BOOST_CHECK_CLOSE(protoLayer.range(binX), 46_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.min(binX), -23_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.max(binX), 23_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.range(binY), 46_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.min(binY), -23_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.max(binY), 23_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.range(binZ), 10_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.min(binZ), -5_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.max(binZ), 5_mm, 1e-8); + + surfaces = makeFan(45_degree, 10_mm); + + protoLayer = {tgContext, surfaces, + Transform3{AngleAxis3{45_degree, Vector3::UnitY()}}.inverse()}; + + BOOST_CHECK_EQUAL(protoLayer.surfaces().size(), 8); + BOOST_CHECK_CLOSE(protoLayer.range(binX), 46_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.min(binX), -23_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.max(binX), 23_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.range(binY), 46_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.min(binY), -23_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.max(binY), 23_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.range(binZ), 10_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.min(binZ), -5_mm, 1e-8); + BOOST_CHECK_CLOSE(protoLayer.max(binZ), 5_mm, 1e-8); +} + BOOST_AUTO_TEST_SUITE_END() } // namespace Acts::Test::Layers diff --git a/Tests/UnitTests/Core/Seeding/SeedFinderTest.cpp b/Tests/UnitTests/Core/Seeding/SeedFinderTest.cpp index 4f263e693f7..9d89c1c96c6 100644 --- a/Tests/UnitTests/Core/Seeding/SeedFinderTest.cpp +++ b/Tests/UnitTests/Core/Seeding/SeedFinderTest.cpp @@ -10,7 +10,6 @@ #include "Acts/Definitions/Units.hpp" #include "Acts/EventData/Seed.hpp" #include "Acts/EventData/SpacePointContainer.hpp" -#include "Acts/Geometry/Extent.hpp" #include "Acts/Seeding/BinnedGroup.hpp" #include "Acts/Seeding/SeedFilter.hpp" #include "Acts/Seeding/SeedFilterConfig.hpp" @@ -146,6 +145,7 @@ int main(int argc, char** argv) { Acts::SeedFinderConfig config; // silicon detector max config.rMax = 160._mm; + config.rMin = 0._mm; config.deltaRMin = 5._mm; config.deltaRMax = 160._mm; config.deltaRMinTopSP = config.deltaRMin; @@ -173,19 +173,16 @@ int main(int argc, char** argv) { int numPhiNeighbors = 1; - // extent used to store r range for middle spacepoint - Acts::Extent rRangeSPExtent; - config.useVariableMiddleSPRange = false; const Acts::Range1D rMiddleSPRange; std::vector> zBinNeighborsTop; std::vector> zBinNeighborsBottom; - auto bottomBinFinder = std::make_unique>( - Acts::GridBinFinder<2ul>(numPhiNeighbors, zBinNeighborsBottom)); - auto topBinFinder = std::make_unique>( - Acts::GridBinFinder<2ul>(numPhiNeighbors, zBinNeighborsTop)); + auto bottomBinFinder = std::make_unique>( + numPhiNeighbors, zBinNeighborsBottom, 0); + auto topBinFinder = std::make_unique>( + numPhiNeighbors, zBinNeighborsTop, 0); Acts::SeedFilterConfig sfconf; Acts::ATLASCuts atlasCuts = Acts::ATLASCuts(); @@ -213,8 +210,7 @@ int main(int argc, char** argv) { Acts::CylindricalSpacePointGridCreator::createGrid(gridConf, gridOpts); Acts::CylindricalSpacePointGridCreator::fillGrid( - config, options, grid, spContainer.begin(), spContainer.end(), - rRangeSPExtent); + config, options, grid, spContainer.begin(), spContainer.end()); auto spGroup = Acts::CylindricalBinnedGroup( std::move(grid), *bottomBinFinder, *topBinFinder); diff --git a/Tests/UnitTests/Core/Surfaces/AnnulusBoundsTests.cpp b/Tests/UnitTests/Core/Surfaces/AnnulusBoundsTests.cpp index c284d6d4796..9f09fb2c213 100644 --- a/Tests/UnitTests/Core/Surfaces/AnnulusBoundsTests.cpp +++ b/Tests/UnitTests/Core/Surfaces/AnnulusBoundsTests.cpp @@ -23,10 +23,10 @@ namespace Acts::Test { BOOST_AUTO_TEST_SUITE(Surfaces) -double minRadius = 7.2; -double maxRadius = 12.0; -double minPhi = 0.74195; -double maxPhi = 1.33970; +ActsScalar minRadius = 7.2; +ActsScalar maxRadius = 12.0; +ActsScalar minPhi = 0.74195; +ActsScalar maxPhi = 1.33970; Vector2 offset(-2., 2.); @@ -123,6 +123,25 @@ BOOST_AUTO_TEST_CASE(AnnulusBoundsProperties) { BOOST_CHECK_EQUAL(aBounds.get(AnnulusBounds::eMaxPhiRel), maxPhi); } +/// Unit tests for AnnulusBounds vertices +BOOST_AUTO_TEST_CASE(AnnulusBoundsVertices) { + /// Test construction with radii and default sector + AnnulusBounds aBounds(minRadius, maxRadius, minPhi, maxPhi, offset); + + // Retrieve the corners + auto corners = aBounds.corners(); + BOOST_CHECK_EQUAL(corners.size(), 4); + + // Retrieve the vertices + auto vertices = aBounds.vertices(0u); + BOOST_CHECK_EQUAL(vertices.size(), 4); + + // Now generate with more segments + unsigned int nQuarterSegments = 12; + vertices = aBounds.vertices(nQuarterSegments); + BOOST_CHECK_EQUAL(vertices.size(), 14u); +} + BOOST_AUTO_TEST_SUITE_END() } // namespace Acts::Test diff --git a/Tests/UnitTests/Core/Surfaces/ConvexPolygonBoundsTests.cpp b/Tests/UnitTests/Core/Surfaces/ConvexPolygonBoundsTests.cpp index bdb4c2948be..6b6712c230b 100644 --- a/Tests/UnitTests/Core/Surfaces/ConvexPolygonBoundsTests.cpp +++ b/Tests/UnitTests/Core/Surfaces/ConvexPolygonBoundsTests.cpp @@ -101,6 +101,10 @@ BOOST_AUTO_TEST_CASE(ConvexPolygonBoundsRecreation) { std::copy_n(valvector.begin(), poly<4>::eSize, values.begin()); poly<4> recreated(values); BOOST_CHECK_EQUAL(original, recreated); + + // Get the vertices back + auto rvertices = original.vertices(); + BOOST_CHECK_EQUAL(rvertices.size(), 4u); } BOOST_AUTO_TEST_CASE(ConvexPolygonBoundsDynamicTest) { diff --git a/Tests/UnitTests/Core/Surfaces/PolyhedronSurfacesTests.cpp b/Tests/UnitTests/Core/Surfaces/PolyhedronSurfacesTests.cpp index c858f10f6db..184d69e341f 100644 --- a/Tests/UnitTests/Core/Surfaces/PolyhedronSurfacesTests.cpp +++ b/Tests/UnitTests/Core/Surfaces/PolyhedronSurfacesTests.cpp @@ -42,7 +42,7 @@ namespace Acts::Test { const GeometryContext tgContext = GeometryContext(); const std::vector> testModes = { - {"Triangulate", 72}, {"Extrema", 1}}; + {"Triangulate", 18}, {"Extrema", 1}}; const Transform3 transform = Transform3::Identity(); const double epsAbs = 1e-12; @@ -61,9 +61,8 @@ BOOST_AUTO_TEST_CASE(ConeSurfacePolyhedrons) { const double rMax = hzPos * std::tan(alpha); - for (const auto& mode : testModes) { - ACTS_INFO("\tMode: " << std::get(mode)); - const unsigned int segments = std::get(mode); + for (const auto& [mode, segments] : testModes) { + ACTS_INFO("\tMode: " << mode); /// The full cone on one side { @@ -81,9 +80,10 @@ BOOST_AUTO_TEST_CASE(ConeSurfacePolyhedrons) { CHECK_CLOSE_ABS(extent.range(BinningValue::binZ).min(), 0_mm, epsAbs); CHECK_CLOSE_ABS(extent.range(BinningValue::binZ).max(), hzPos, epsAbs); - const unsigned int expectedFaces = segments < 4 ? 4 : segments; + const unsigned int expectedFaces = 4 * segments; BOOST_CHECK_EQUAL(oneConePh.faces.size(), expectedFaces); - BOOST_CHECK_EQUAL(oneConePh.vertices.size(), expectedFaces + 1); + // full segments + overlap at (pi/pi) + tip + BOOST_CHECK_EQUAL(oneConePh.vertices.size(), expectedFaces + 2); } /// The full cone on one side @@ -106,6 +106,11 @@ BOOST_AUTO_TEST_CASE(ConeSurfacePolyhedrons) { CHECK_CLOSE_ABS(extent.range(BinningValue::binR).max(), rMax, epsAbs); CHECK_CLOSE_ABS(extent.range(BinningValue::binZ).min(), hzpMin, epsAbs); CHECK_CLOSE_ABS(extent.range(BinningValue::binZ).max(), hzPos, epsAbs); + + const unsigned int expectedFaces = 4 * segments; + BOOST_CHECK_EQUAL(oneConePiecePh.faces.size(), expectedFaces); + BOOST_CHECK_EQUAL(oneConePiecePh.vertices.size(), + (expectedFaces + 1) * 2); } /// The full cone on both sides @@ -124,9 +129,11 @@ BOOST_AUTO_TEST_CASE(ConeSurfacePolyhedrons) { CHECK_CLOSE_ABS(extent.range(BinningValue::binZ).min(), hzNeg, epsAbs); CHECK_CLOSE_ABS(extent.range(BinningValue::binZ).max(), hzPos, epsAbs); - const unsigned int expectedFaces = segments < 4 ? 8 : 2 * segments; + const unsigned int expectedFaces = 2 * segments * 4; + const unsigned int expectedVertices = 2 * (4 * segments + 1) + 1; + BOOST_CHECK_EQUAL(twoConesPh.faces.size(), expectedFaces); - BOOST_CHECK_EQUAL(twoConesPh.vertices.size(), expectedFaces + 1); + BOOST_CHECK_EQUAL(twoConesPh.vertices.size(), expectedVertices); } /// A centered sectoral cone on both sides @@ -143,13 +150,16 @@ BOOST_AUTO_TEST_CASE(ConeSurfacePolyhedrons) { const auto extent = sectoralConesPh.extent(); CHECK_CLOSE_ABS(extent.range(BinningValue::binX).min(), 0, epsAbs); CHECK_CLOSE_ABS(extent.range(BinningValue::binX).max(), rMax, epsAbs); - // CHECK_CLOSE_ABS(extent.range(BinningValue::binY).min(), ???, - // epsAbs); CHECK_CLOSE_ABS(extent.range(BinningValue::binY).max(), - // ???, epsAbs); + CHECK_CLOSE_ABS(extent.range(BinningValue::binY).min(), + -rMax * std::sin(phiSector), epsAbs); + CHECK_CLOSE_ABS(extent.range(BinningValue::binY).max(), + rMax * std::sin(phiSector), epsAbs); CHECK_CLOSE_ABS(extent.range(BinningValue::binR).min(), 0_mm, epsAbs); CHECK_CLOSE_ABS(extent.range(BinningValue::binR).max(), rMax, epsAbs); CHECK_CLOSE_ABS(extent.range(BinningValue::binZ).min(), hzNeg, epsAbs); CHECK_CLOSE_ABS(extent.range(BinningValue::binZ).max(), hzPos, epsAbs); + + // Segment numbers are further checked with the VertexHelper checks } } } @@ -185,8 +195,8 @@ BOOST_AUTO_TEST_CASE(CylinderSurfacePolyhedrons) { CHECK_CLOSE_ABS(extent.range(BinningValue::binZ).min(), -hZ, epsAbs); CHECK_CLOSE_ABS(extent.range(BinningValue::binZ).max(), hZ, epsAbs); - const unsigned int expectedFaces = segments < 4 ? 4 : segments; - const unsigned int expectedVertices = segments < 4 ? 8 : 2 * segments; + const unsigned int expectedFaces = 4 * segments; + const unsigned int expectedVertices = (4 * segments + 1) * 2; BOOST_CHECK_EQUAL(fullCylinderPh.faces.size(), expectedFaces); BOOST_CHECK_EQUAL(fullCylinderPh.vertices.size(), expectedVertices); } @@ -248,7 +258,8 @@ BOOST_AUTO_TEST_CASE(DiscSurfacePolyhedrons) { CHECK_CLOSE_ABS(extent.range(BinningValue::binZ).max(), 0., epsAbs); const unsigned int expectedFaces = 1; - const unsigned int expectedVertices = segments > 4 ? segments + 1 : 4 + 1; + // Segments + overlap + center + const unsigned int expectedVertices = 4 * segments + 1 + 1; BOOST_CHECK_EQUAL(fullDiscPh.faces.size(), expectedFaces); BOOST_CHECK_EQUAL(fullDiscPh.vertices.size(), expectedVertices); } @@ -353,14 +364,7 @@ BOOST_AUTO_TEST_CASE(DiscSurfacePolyhedrons) { auto annulusDisc = Surface::makeShared(transform, annulus); auto annulusDiscPh = annulusDisc->polyhedronRepresentation(tgContext, segments); - const auto extent = annulusDiscPh.extent(); - // CHECK_CLOSE_ABS(extent.range(BinningValue::binX).min(), ???, - // epsAbs); CHECK_CLOSE_ABS(extent.range(BinningValue::binX).max(), - // ???, epsAbs); - // CHECK_CLOSE_ABS(extent.range(BinningValue::binY).min(), ???, - // epsAbs); CHECK_CLOSE_ABS(extent.range(BinningValue::binY).max(), - // ???, epsAbs); CHECK_CLOSE_ABS(extent.range(BinningValue::binR).min(), minRadius, epsAbs); CHECK_CLOSE_ABS(extent.range(BinningValue::binR).max(), maxRadius, diff --git a/Tests/UnitTests/Core/Surfaces/SurfaceStub.hpp b/Tests/UnitTests/Core/Surfaces/SurfaceStub.hpp index 573c9f55ce9..ce745bec85c 100644 --- a/Tests/UnitTests/Core/Surfaces/SurfaceStub.hpp +++ b/Tests/UnitTests/Core/Surfaces/SurfaceStub.hpp @@ -102,7 +102,7 @@ class SurfaceStub : public RegularSurface { /// Return a Polyhedron for the surfaces Polyhedron polyhedronRepresentation(const GeometryContext& /*gctx*/, - std::size_t /*lseg */) const final { + unsigned int /* ignored */) const final { std::vector vertices; std::vector> faces; std::vector> triangularMesh; diff --git a/Tests/UnitTests/Core/Surfaces/VerticesHelperTests.cpp b/Tests/UnitTests/Core/Surfaces/VerticesHelperTests.cpp index d2838760081..2b52064cb8d 100644 --- a/Tests/UnitTests/Core/Surfaces/VerticesHelperTests.cpp +++ b/Tests/UnitTests/Core/Surfaces/VerticesHelperTests.cpp @@ -92,6 +92,127 @@ BOOST_AUTO_TEST_CASE(VerticesHelperOnHyperPlane) { } } +BOOST_AUTO_TEST_CASE(GeneratePhiSegments) { + // Case (1): a small segment is given, no cartesian maximum vertex + ActsScalar minPhi = 0.1; + ActsScalar maxPhi = 0.3; + + auto phis = VerticesHelper::phiSegments(minPhi, maxPhi); + BOOST_CHECK_EQUAL(phis.size(), 2u); + BOOST_CHECK(phis[0] == minPhi); + BOOST_CHECK(phis[1] == maxPhi); + + // Case (2) a small segment is given, with one maximum vertex at phi = 0 + minPhi = -0.1; + phis = VerticesHelper::phiSegments(minPhi, maxPhi); + BOOST_CHECK_EQUAL(phis.size(), 3u); + BOOST_CHECK(phis[0] == minPhi); + BOOST_CHECK(phis[1] == 0.); + BOOST_CHECK(phis[2] == maxPhi); + + // Case (3) a small segment is given, with one maximum vertex at phi = 2pi, + // and one extra value + phis = VerticesHelper::phiSegments(minPhi, maxPhi, {0.25}); + BOOST_CHECK_EQUAL(phis.size(), 4u); + BOOST_CHECK(phis[0] == minPhi); + BOOST_CHECK(phis[1] == 0.); + BOOST_CHECK(phis[2] == 0.25); + BOOST_CHECK(phis[3] == maxPhi); + + // Case (4) a small segment is given, with one maximum vertex at phi = 2pi, + // and two extra values, one outside & hence throw an exception + BOOST_CHECK_THROW(VerticesHelper::phiSegments(minPhi, maxPhi, {0.25, 0.5}), + std::invalid_argument); + + // Case (5) an invalid phi range is given + BOOST_CHECK_THROW(VerticesHelper::phiSegments(0.8, 0.2, {0.25, 0.5}), + std::invalid_argument); + + // Case (6) a wrong number of minimum segments is given + BOOST_CHECK_THROW(VerticesHelper::phiSegments(0.1, 0.3, {0.25, 0.5}, 3), + std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(GenerateSegmentVertices) { + // Case (1): a small segment is given, no cartesian maximum vertex & 1 step + // segment + ActsScalar rx = 10.; + ActsScalar ry = 10.; + ActsScalar minPhi = 0.1; + ActsScalar maxPhi = 0.3; + + auto vertices = VerticesHelper::segmentVertices( + {rx, ry}, minPhi, maxPhi, {}, 1); + std::size_t expectedVertices = 2u; + BOOST_CHECK_EQUAL(vertices.size(), expectedVertices); + + // Now with a reference phi value + vertices = VerticesHelper::segmentVertices( + {rx, ry}, minPhi, maxPhi, {0.2}, 1); + expectedVertices = 3u; // the reference is inserted + BOOST_CHECK_EQUAL(vertices.size(), expectedVertices); + + // Now with more vertices - the the two corners and the ones from the + // reference + unsigned int quarterVertices = 36; + vertices = VerticesHelper::segmentVertices( + {rx, ry}, minPhi, maxPhi, {}, quarterVertices); + expectedVertices = + static_cast((maxPhi - minPhi) / M_PI_2 * quarterVertices) + + 2u; + BOOST_CHECK_EQUAL(vertices.size(), expectedVertices); + + // Case (2) a small segment is given, with one maximum vertex at phi = 0 + minPhi = -0.1; + vertices = VerticesHelper::segmentVertices( + {rx, ry}, minPhi, maxPhi, {}, 1); + expectedVertices = 3u; + BOOST_CHECK_EQUAL(vertices.size(), expectedVertices); + + // Same with more segments + quarterVertices = 12; + vertices = VerticesHelper::segmentVertices( + {rx, ry}, minPhi, maxPhi, {}, quarterVertices); + // Extrema will be covered by the segments + expectedVertices = + static_cast((maxPhi - minPhi) / M_PI_2 * quarterVertices) + + 2u; + BOOST_CHECK_EQUAL(vertices.size(), expectedVertices); +} + +BOOST_AUTO_TEST_CASE(GenerateCircleEllipseVertices) { + // Case (1): A full disc + ActsScalar ri = 0.; + ActsScalar ro = 10.; + + // Extreme points in phi - only outer radius + auto vertices = VerticesHelper::circularVertices(ri, ro, 0., M_PI, 1u); + unsigned int expectedVertices = 5u; + BOOST_CHECK_EQUAL(vertices.size(), expectedVertices); + + // Case (2): A ring + ri = 3.; + + // Extreme points in phi - only outer radius + vertices = VerticesHelper::circularVertices(ri, ro, 0., M_PI, 1u); + expectedVertices = 10u; + BOOST_CHECK_EQUAL(vertices.size(), expectedVertices); + + // Now with 10 bins per sector + ri = 0.; + + vertices = VerticesHelper::circularVertices(ri, ro, 0., M_PI, 10u); + expectedVertices = 41u; // 4 sectors + 1 overlap at (-pi/pi) + BOOST_CHECK_EQUAL(vertices.size(), expectedVertices); + + // Now ellipsiod + ActsScalar riy = 4.; + ActsScalar roy = 14.; + vertices = VerticesHelper::ellipsoidVertices(ri, riy, ro, roy, 0., M_PI, 10u); + expectedVertices = 41u; // 4 sectors + 1 overlap at (-pi/pi) + BOOST_CHECK_EQUAL(vertices.size(), expectedVertices); +} + BOOST_AUTO_TEST_SUITE_END() } // namespace Acts::detail::Test diff --git a/Tests/UnitTests/Core/TrackFitting/Gx2fTests.cpp b/Tests/UnitTests/Core/TrackFitting/Gx2fTests.cpp index 7ef5373f41b..bce69cba0b2 100644 --- a/Tests/UnitTests/Core/TrackFitting/Gx2fTests.cpp +++ b/Tests/UnitTests/Core/TrackFitting/Gx2fTests.cpp @@ -1054,7 +1054,7 @@ BOOST_AUTO_TEST_CASE(Material) { ViewConfig viewContainer = {.color = {220, 220, 0}}; viewContainer.triangulate = triangulate; ViewConfig viewGrid = {.color = {220, 0, 0}}; - viewGrid.nSegments = 8; + viewGrid.quarterSegments = 8; viewGrid.offset = 3.; viewGrid.triangulate = triangulate; diff --git a/Tests/UnitTests/Core/Visualization/EventDataView3DTests.cpp b/Tests/UnitTests/Core/Visualization/EventDataView3DTests.cpp index 36f823a02b6..bac538e4b58 100644 --- a/Tests/UnitTests/Core/Visualization/EventDataView3DTests.cpp +++ b/Tests/UnitTests/Core/Visualization/EventDataView3DTests.cpp @@ -29,7 +29,7 @@ BOOST_AUTO_TEST_CASE(BoundTrackParametersVisualizationObj) { for (const auto& objerr : objErrors) { std::cout << objerr << std::endl; } - BOOST_CHECK_EQUAL(std::count(objTest.begin(), objTest.end(), '\n'), 1458); + BOOST_CHECK_EQUAL(std::count(objTest.begin(), objTest.end(), '\n'), 4924); } BOOST_AUTO_TEST_CASE(BoundTrackParametersVisualizationPly) { @@ -40,7 +40,7 @@ BOOST_AUTO_TEST_CASE(BoundTrackParametersVisualizationPly) { for (const auto& plyerr : plyErrors) { std::cout << plyerr << std::endl; } - BOOST_CHECK_EQUAL(std::count(plyTest.begin(), plyTest.end(), '\n'), 973); + BOOST_CHECK_EQUAL(std::count(plyTest.begin(), plyTest.end(), '\n'), 3143); } BOOST_AUTO_TEST_CASE(MeasurementVisualizationObj) { @@ -85,7 +85,7 @@ BOOST_AUTO_TEST_CASE(MultiTrajectoryVisualizationObj) { for (const auto& objerr : objErrors) { std::cout << objerr << std::endl; } - BOOST_CHECK_EQUAL(std::count(objTest.begin(), objTest.end(), '\n'), 31010); + BOOST_CHECK_EQUAL(std::count(objTest.begin(), objTest.end(), '\n'), 103796); } BOOST_AUTO_TEST_CASE(MultiTrajectoryVisualizationPly) { @@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(MultiTrajectoryVisualizationPly) { for (const auto& plyerr : plyErrors) { std::cout << plyerr << std::endl; } - BOOST_CHECK_EQUAL(std::count(plyTest.begin(), plyTest.end(), '\n'), 20521); + BOOST_CHECK_EQUAL(std::count(plyTest.begin(), plyTest.end(), '\n'), 66091); } BOOST_AUTO_TEST_SUITE_END() diff --git a/Tests/UnitTests/Core/Visualization/SurfaceView3DBase.hpp b/Tests/UnitTests/Core/Visualization/SurfaceView3DBase.hpp index be83a27cb7b..146935279f0 100644 --- a/Tests/UnitTests/Core/Visualization/SurfaceView3DBase.hpp +++ b/Tests/UnitTests/Core/Visualization/SurfaceView3DBase.hpp @@ -68,7 +68,7 @@ static inline std::string run(IVisualization3D& helper, bool triangulate, coneSurfaces.push_back(cone); GeometryView3D::drawSurface(helper, *cone, gctx, Transform3::Identity(), sConfig); - ; + helper.write(std::string("Surfaces_ConeSurface") + tag); helper.write(cStream); helper.clear(); @@ -80,7 +80,7 @@ static inline std::string run(IVisualization3D& helper, bool triangulate, coneSurfaces.push_back(cone); GeometryView3D::drawSurface(helper, *cone, gctx, Transform3::Identity(), sConfig); - ; + helper.write(std::string("Surfaces_ConeSurfaceSector") + tag); helper.write(cStream); helper.clear(); @@ -92,7 +92,7 @@ static inline std::string run(IVisualization3D& helper, bool triangulate, coneSurfaces.push_back(cone); GeometryView3D::drawSurface(helper, *cone, gctx, Transform3::Identity(), sConfig); - ; + helper.write(std::string("Surfaces_ConeSurfaceSectorShifted") + tag); helper.write(cStream); helper.clear(); @@ -126,7 +126,7 @@ static inline std::string run(IVisualization3D& helper, bool triangulate, cylinderSurfaces.push_back(cylinder); GeometryView3D::drawSurface(helper, *cylinder, gctx, Transform3::Identity(), sConfig); - ; + helper.write(std::string("Surfaces_CylinderSurface") + tag); helper.write(cStream); helper.clear(); @@ -138,7 +138,7 @@ static inline std::string run(IVisualization3D& helper, bool triangulate, cylinderSurfaces.push_back(cylinder); GeometryView3D::drawSurface(helper, *cylinder, gctx, Transform3::Identity(), sConfig); - ; + helper.write(std::string("Surfaces_CylinderSurfaceSector") + tag); helper.write(cStream); helper.clear(); @@ -150,7 +150,7 @@ static inline std::string run(IVisualization3D& helper, bool triangulate, cylinderSurfaces.push_back(cylinder); GeometryView3D::drawSurface(helper, *cylinder, gctx, Transform3::Identity(), sConfig); - ; + helper.write(std::string("Surfaces_CylinderSurfaceSectorShifted") + tag); helper.write(cStream); helper.clear(); @@ -179,7 +179,7 @@ static inline std::string run(IVisualization3D& helper, bool triangulate, auto bbSurface = Surface::makeShared(identity, bbBounds); GeometryView3D::drawSurface(helper, *bbSurface, gctx, Transform3::Identity(), sConfig); - ; + helper.write(bbPath); helper.write(cStream); helper.clear(); @@ -199,7 +199,7 @@ static inline std::string run(IVisualization3D& helper, bool triangulate, radialSurfaces.push_back(disc); GeometryView3D::drawSurface(helper, *disc, gctx, Transform3::Identity(), sConfig); - ; + helper.write(std::string("Surfaces_DiscSurfaceFull") + tag); helper.write(cStream); helper.clear(); @@ -335,7 +335,7 @@ static inline std::string run(IVisualization3D& helper, bool triangulate, planarSurfaces.push_back(plane); GeometryView3D::drawSurface(helper, *plane, gctx, Transform3::Identity(), sConfig); - ; + helper.write(name + tag); helper.write(cStream); helper.clear(); @@ -349,7 +349,7 @@ static inline std::string run(IVisualization3D& helper, bool triangulate, planarSurfaces.push_back(plane); GeometryView3D::drawSurface(helper, *plane, gctx, Transform3::Identity(), sConfig); - ; + helper.write(name + tag); helper.write(cStream); helper.clear(); @@ -363,7 +363,7 @@ static inline std::string run(IVisualization3D& helper, bool triangulate, planarSurfaces.push_back(plane); GeometryView3D::drawSurface(helper, *plane, gctx, Transform3::Identity(), sConfig); - ; + helper.write(name + tag); helper.write(cStream); helper.clear(); @@ -377,7 +377,7 @@ static inline std::string run(IVisualization3D& helper, bool triangulate, planarSurfaces.push_back(plane); GeometryView3D::drawSurface(helper, *plane, gctx, Transform3::Identity(), sConfig); - ; + helper.write(name + tag); helper.write(cStream); helper.clear(); diff --git a/Tests/UnitTests/Core/Visualization/TrackingGeometryView3DBase.hpp b/Tests/UnitTests/Core/Visualization/TrackingGeometryView3DBase.hpp index b2fb89c0ee8..ea2e409222d 100644 --- a/Tests/UnitTests/Core/Visualization/TrackingGeometryView3DBase.hpp +++ b/Tests/UnitTests/Core/Visualization/TrackingGeometryView3DBase.hpp @@ -37,18 +37,22 @@ static inline std::string run(IVisualization3D& helper, bool triangulate, const std::string& tag) { std::stringstream cStream; - ViewConfig viewSensitive = {.color = {0, 180, 240}}; - viewSensitive.triangulate = triangulate; - ViewConfig viewPassive = {.color = {240, 280, 0}}; - viewPassive.triangulate = triangulate; - ViewConfig viewVolume = {.color = {220, 220, 0}}; - viewVolume.triangulate = triangulate; - ViewConfig viewContainer = {.color = {220, 220, 0}}; - viewContainer.triangulate = triangulate; - ViewConfig viewGrid = {.color = {220, 0, 0}}; - viewGrid.nSegments = 8; - viewGrid.offset = 3.; - viewGrid.triangulate = triangulate; + ViewConfig viewSensitive = {.color = {0, 180, 240}, + .quarterSegments = 72, + .triangulate = triangulate}; + ViewConfig viewPassive = {.color = {240, 280, 0}, + .quarterSegments = 72, + .triangulate = triangulate}; + ViewConfig viewVolume = {.color = {220, 220, 0}, + .quarterSegments = 72, + .triangulate = triangulate}; + ViewConfig viewContainer = {.color = {220, 220, 0}, + .quarterSegments = 72, + .triangulate = triangulate}; + ViewConfig viewGrid = {.color = {220, 0, 0}, + .offset = 3., + .quarterSegments = 8, + .triangulate = triangulate}; const Acts::TrackingVolume& tgVolume = *(tGeometry->highestTrackingVolume()); diff --git a/Tests/UnitTests/Core/Visualization/Visualization3DTests.cpp b/Tests/UnitTests/Core/Visualization/Visualization3DTests.cpp index 58958bbbe6c..ea3e810d119 100644 --- a/Tests/UnitTests/Core/Visualization/Visualization3DTests.cpp +++ b/Tests/UnitTests/Core/Visualization/Visualization3DTests.cpp @@ -335,6 +335,8 @@ BOOST_AUTO_TEST_CASE(ColorTests) { BOOST_CHECK_EQUAL(grey, Color(std::array{128 / 255.0, 128 / 255.0, 128 / 255.0})); BOOST_CHECK_EQUAL(grey, Color(128 / 255.0, 128 / 255.0, 128 / 255.0)); + + static_assert(Color{"#0000ff"} == Color(0, 0, 255)); } BOOST_AUTO_TEST_SUITE_END() diff --git a/Tests/UnitTests/Examples/Io/Csv/MeasurementReaderWriterTests.cpp b/Tests/UnitTests/Examples/Io/Csv/MeasurementReaderWriterTests.cpp index 1a3d9662a2a..7786a5ec8a1 100644 --- a/Tests/UnitTests/Examples/Io/Csv/MeasurementReaderWriterTests.cpp +++ b/Tests/UnitTests/Examples/Io/Csv/MeasurementReaderWriterTests.cpp @@ -20,6 +20,7 @@ #include "ActsExamples/Io/Csv/CsvMeasurementReader.hpp" #include "ActsExamples/Io/Csv/CsvMeasurementWriter.hpp" +#include #include #include #include @@ -152,7 +153,7 @@ BOOST_AUTO_TEST_CASE(CsvMeasurementRoundTrip) { std::abs(ca.activation - cb.activation) < 1.e-4; }; - BOOST_CHECK(std::any_of(b.channels.begin(), b.channels.end(), match)); + BOOST_CHECK(std::ranges::any_of(b.channels, match)); } } diff --git a/Tests/UnitTests/Fatras/Digitization/SegmentizerTests.cpp b/Tests/UnitTests/Fatras/Digitization/SegmentizerTests.cpp index 844122027d2..ad74a9024d1 100644 --- a/Tests/UnitTests/Fatras/Digitization/SegmentizerTests.cpp +++ b/Tests/UnitTests/Fatras/Digitization/SegmentizerTests.cpp @@ -217,9 +217,9 @@ BOOST_DATA_TEST_CASE( ".csv"); /// Run the Segmentizer - auto cSegement = cl.segments(geoCtx, *surface, segmentation, {start, end}); + auto cSegments = cl.segments(geoCtx, *surface, segmentation, {start, end}); - for (const auto& cs : cSegement) { + for (const auto& cs : cSegments) { csvHelper.writeLine(segments, cs.path2D[0], cs.path2D[1]); } diff --git a/Tests/UnitTests/Fatras/Kernel/SimulationActorTests.cpp b/Tests/UnitTests/Fatras/Kernel/SimulationActorTests.cpp index de87bf883c1..e52d586c30b 100644 --- a/Tests/UnitTests/Fatras/Kernel/SimulationActorTests.cpp +++ b/Tests/UnitTests/Fatras/Kernel/SimulationActorTests.cpp @@ -12,6 +12,7 @@ #include "Acts/Definitions/PdgParticle.hpp" #include "Acts/Definitions/Units.hpp" #include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Geometry/TrackingVolume.hpp" #include "Acts/Material/HomogeneousSurfaceMaterial.hpp" #include "Acts/Material/MaterialSlab.hpp" #include "Acts/Propagator/ConstrainedStep.hpp" @@ -148,6 +149,11 @@ struct MockNavigator { return state.currentSurface; } + const Acts::TrackingVolume *currentVolume( + const MockNavigatorState & /*state*/) const { + return nullptr; + } + bool endOfWorldReached(const MockNavigatorState & /*state*/) const { return false; } @@ -158,6 +164,10 @@ struct MockPropagatorState { MockStepperState stepping; Acts::GeometryContext geoContext; Acts::PropagatorStage stage = Acts::PropagatorStage::invalid; + + struct { + std::vector constrainToVolumeIds; + } options; }; template diff --git a/Tests/UnitTests/Plugins/ActSVG/IndexedSurfacesSvgConverterTests.cpp b/Tests/UnitTests/Plugins/ActSVG/IndexedSurfacesSvgConverterTests.cpp index bc33298431a..6f2c78620e9 100644 --- a/Tests/UnitTests/Plugins/ActSVG/IndexedSurfacesSvgConverterTests.cpp +++ b/Tests/UnitTests/Plugins/ActSVG/IndexedSurfacesSvgConverterTests.cpp @@ -42,7 +42,7 @@ IndexedSurfacesConverter::Options generateDrawOptions() { sensitiveStyle.highlights = {"onmouseover", "onmouseout"}; sensitiveStyle.strokeWidth = 0.5; sensitiveStyle.strokeColor = {0, 0, 0}; - sensitiveStyle.nSegments = 72u; + sensitiveStyle.quarterSegments = 72u; std::pair allSensitives = {GeometryIdentifier(0u), sensitiveStyle}; diff --git a/Tests/UnitTests/Plugins/ActSVG/LayerSvgConverterTests.cpp b/Tests/UnitTests/Plugins/ActSVG/LayerSvgConverterTests.cpp index 7dd3a93fe95..ff4afc789b6 100644 --- a/Tests/UnitTests/Plugins/ActSVG/LayerSvgConverterTests.cpp +++ b/Tests/UnitTests/Plugins/ActSVG/LayerSvgConverterTests.cpp @@ -45,16 +45,17 @@ void setupTools() { std::shared_ptr generateDiscLayer(Acts::ActsScalar rInner, Acts::ActsScalar rOuter, - unsigned int nSegments, + unsigned int quarterSegments, unsigned int nRings, bool useTrapezoids = false) { // Some preparations setupTools(); + unsigned int fullSegments = 4 * quarterSegments; std::vector> moduleSurfaces; - Acts::ActsScalar phiStep = 2 * M_PI / nSegments; + Acts::ActsScalar phiStep = 2 * M_PI / fullSegments; Acts::ActsScalar rStep = (rOuter - rInner) / nRings; // Reserve & fill - moduleSurfaces.reserve(nSegments * nRings); + moduleSurfaces.reserve(fullSegments * nRings); // Radial disc if (!useTrapezoids) { for (unsigned int ir = 0; ir < nRings; ++ir) { @@ -62,7 +63,7 @@ std::shared_ptr generateDiscLayer(Acts::ActsScalar rInner, rBounds = std::make_shared( rInner + ir * rStep - 0.025 * rInner, rInner + (ir + 1u) * rStep + 0.025 * rInner, 0.55 * phiStep, 0.); - for (unsigned int is = 0; is < nSegments; ++is) { + for (unsigned int is = 0; is < fullSegments; ++is) { // Place the module auto placement = Acts::Transform3::Identity(); if ((is % 2) != 0u) { @@ -82,14 +83,14 @@ std::shared_ptr generateDiscLayer(Acts::ActsScalar rInner, Acts::ActsScalar yHalf = rStep * 0.5125; Acts::ActsScalar xHalfMin = - 1.15 * (rInner + ir * rStep) * M_PI / nSegments; + 1.15 * (rInner + ir * rStep) * M_PI / fullSegments; Acts::ActsScalar xHalfMax = - 1.15 * (rInner + (ir + 1) * rStep) * M_PI / nSegments; + 1.15 * (rInner + (ir + 1) * rStep) * M_PI / fullSegments; std::shared_ptr tBounds = std::make_shared(xHalfMin, xHalfMax, yHalf); - for (unsigned int is = 0; is < nSegments; ++is) { + for (unsigned int is = 0; is < fullSegments; ++is) { // Setting the phi Acts::ActsScalar cphi = -M_PI + is * phiStep; Acts::Vector3 center(radius * std::cos(cphi), radius * std::sin(cphi), @@ -111,7 +112,7 @@ std::shared_ptr generateDiscLayer(Acts::ActsScalar rInner, } } // Let's create the disc layer - return lCreator->discLayer(tgContext, moduleSurfaces, nRings, nSegments); + return lCreator->discLayer(tgContext, moduleSurfaces, nRings, fullSegments); } } // namespace @@ -125,7 +126,7 @@ BOOST_AUTO_TEST_CASE(DiscLayerRadialSvg) { discLayerStyle.highlights = {"mouseover", "mouseout"}; discLayerStyle.strokeColor = {25, 25, 25}; discLayerStyle.strokeWidth = 0.5; - discLayerStyle.nSegments = 72u; + discLayerStyle.quarterSegments = 72u; Acts::GeometryIdentifier geoID{0}; @@ -155,7 +156,7 @@ BOOST_AUTO_TEST_CASE(DiscLayerTrapezoidSvg) { discLayerStyle.highlights = {"mouseover", "mouseout"}; discLayerStyle.strokeColor = {25, 25, 25}; discLayerStyle.strokeWidth = 0.5; - discLayerStyle.nSegments = 72u; + discLayerStyle.quarterSegments = 72u; Acts::GeometryIdentifier geoID{0}; @@ -185,7 +186,7 @@ BOOST_AUTO_TEST_CASE(CylinderLayerSvg) { cylinderLayerStyle.highlights = {"mouseover", "mouseout"}; cylinderLayerStyle.strokeColor = {25, 25, 25}; cylinderLayerStyle.strokeWidth = 0.5; - cylinderLayerStyle.nSegments = 72u; + cylinderLayerStyle.quarterSegments = 72u; Acts::GeometryIdentifier geoID{0}; diff --git a/Tests/UnitTests/Plugins/ActSVG/PortalSvgConverterTests.cpp b/Tests/UnitTests/Plugins/ActSVG/PortalSvgConverterTests.cpp index 7f4cfa5d425..9fb1fdffa40 100644 --- a/Tests/UnitTests/Plugins/ActSVG/PortalSvgConverterTests.cpp +++ b/Tests/UnitTests/Plugins/ActSVG/PortalSvgConverterTests.cpp @@ -35,7 +35,7 @@ BOOST_AUTO_TEST_CASE(CylinderPortalsSvg) { portalStyle.highlights = {}; portalStyle.strokeColor = {25, 25, 25}; portalStyle.strokeWidth = 0.5; - portalStyle.nSegments = 72u; + portalStyle.quarterSegments = 72u; Acts::ActsScalar rInner = 10.; Acts::ActsScalar rOuter = 100.; @@ -94,7 +94,7 @@ BOOST_AUTO_TEST_CASE(CylinderContainerPortalsSvg) { portalStyle.highlights = {}; portalStyle.strokeColor = {25, 25, 25}; portalStyle.strokeWidth = 0.5; - portalStyle.nSegments = 72u; + portalStyle.quarterSegments = 72u; Acts::ActsScalar rInner = 10.; Acts::ActsScalar rMiddle = 100.; diff --git a/Tests/UnitTests/Plugins/ActSVG/SurfaceSvgConverterTests.cpp b/Tests/UnitTests/Plugins/ActSVG/SurfaceSvgConverterTests.cpp index 49c92f3aaf9..8450453720c 100644 --- a/Tests/UnitTests/Plugins/ActSVG/SurfaceSvgConverterTests.cpp +++ b/Tests/UnitTests/Plugins/ActSVG/SurfaceSvgConverterTests.cpp @@ -74,7 +74,7 @@ BOOST_AUTO_TEST_CASE(PlanarSurfaces) { planarStyle.highlightColor = {255, 153, 51}; planarStyle.highlights = {"mouseover", "mouseout"}; planarStyle.strokeWidth = 0.5; - planarStyle.nSegments = 0u; + planarStyle.quarterSegments = 0u; // Rectangle case auto rectangleBounds = std::make_shared(36., 64.); @@ -169,7 +169,7 @@ BOOST_AUTO_TEST_CASE(DiscSurfaces) { discStyle.highlightColor = {153, 204, 0}; discStyle.highlights = {"mouseover", "mouseout"}; discStyle.strokeWidth = 0.5; - discStyle.nSegments = 72u; + discStyle.quarterSegments = 72u; auto transform = Acts::Transform3::Identity(); transform.pretranslate(Acts::Vector3{20., 20., 100.}); diff --git a/Tests/UnitTests/Plugins/ActSVG/TrackingGeometrySvgConverterTests.cpp b/Tests/UnitTests/Plugins/ActSVG/TrackingGeometrySvgConverterTests.cpp index 7c869e90de7..3b7a8856875 100644 --- a/Tests/UnitTests/Plugins/ActSVG/TrackingGeometrySvgConverterTests.cpp +++ b/Tests/UnitTests/Plugins/ActSVG/TrackingGeometrySvgConverterTests.cpp @@ -32,7 +32,7 @@ BOOST_AUTO_TEST_CASE(CylindricalTrackingGeometrySvg) { cylinderLayerStyle.highlights = {"mouseover", "mouseout"}; cylinderLayerStyle.strokeColor = {25, 25, 25}; cylinderLayerStyle.strokeWidth = 0.5; - cylinderLayerStyle.nSegments = 72u; + cylinderLayerStyle.quarterSegments = 72u; Acts::GeometryIdentifier geoID{0}; diff --git a/Tests/UnitTests/Plugins/TGeo/TGeoTubeConversionTests.cpp b/Tests/UnitTests/Plugins/TGeo/TGeoTubeConversionTests.cpp index 3309895866b..2f18c391958 100644 --- a/Tests/UnitTests/Plugins/TGeo/TGeoTubeConversionTests.cpp +++ b/Tests/UnitTests/Plugins/TGeo/TGeoTubeConversionTests.cpp @@ -99,7 +99,6 @@ BOOST_AUTO_TEST_CASE(TGeoTube_to_CylinderSurface) { objVis, center, center + 1.2 * bR * rotation.col(1), 4., 2.5, green); GeometryView3D::drawArrowForward( objVis, center, center + 1.2 * bhZ * rotation.col(2), 4., 2.5, blue); - objVis.write("TGeoConversion_TGeoTube_CylinderSurface_" + std::to_string(icyl)); objVis.clear(); diff --git a/cmake/ActsConfig.cmake.in b/cmake/ActsConfig.cmake.in index b66c5ae3544..7ed4b3884a5 100644 --- a/cmake/ActsConfig.cmake.in +++ b/cmake/ActsConfig.cmake.in @@ -77,8 +77,8 @@ if(PluginPodio IN_LIST Acts_COMPONENTS) find_dependency(podio @podio_VERSION@ CONFIG EXACT) endif() if(PluginGeoModel IN_LIST Acts_COMPONENTS) - find_dependency(GeoModelCore @GeoModel_VERSION@ CONFIG EXACT) - find_dependency(GeoModelIO @GeoModel_VERSION@ CONFIG EXACT) + find_dependency(GeoModelCore @GeoModelCore_VERSION@ CONFIG EXACT) + find_dependency(GeoModelIO @GeoModelIO_VERSION@ CONFIG EXACT) endif() if (PluginHashing IN_LIST Acts_COMPONENTS) find_dependency(Annoy @ANNOY_VERSION@ CONFIG EXACT)