diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index c2ece0d20f2..7073e2a413a 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -5,3 +5,7 @@ DO NOT USE @-MENTIONS HERE! --- END COMMIT MESSAGE --- Any further description goes here, @-mentions are ok here! + +- Use a *conventional commits* prefix: [quick summary](https://www.conventionalcommits.org/en/v1.0.0/#summary) + - We mostly use `feat`, `fix`, `refactor`, `docs`, `chore` and `build` types. +- A milestone will be assigned by one of the maintainers diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 5686d842b66..edd31d051a4 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -116,6 +116,16 @@ jobs: - name: Check run: > CI/check_spelling + math_macros: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Check + run: > + CI/check_math_macros.py . --exclude "thirdparty/*" missing_includes: runs-on: ubuntu-latest steps: diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4c6a7b166fc..b0a213e607d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -37,8 +37,6 @@ clang_tidy: -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DPython_EXECUTABLE=$(which python3) - -DACTS_RUN_CLANG_TIDY=ON - -DACTS_BUILD_ODD=OFF # Main clang-tidy run during cmake compilation - CI/clang_tidy/run_clang_tidy.sh clang-tidy build @@ -168,7 +166,7 @@ build_exatrkx: # - git clone $CLONE_URL src # - cd src # - git checkout $HEAD_SHA -# - pip3 install -r Examples/Python/tests/requirements_ubuntu2004.txt +# - pip3 install -r Examples/Python/tests/requirements.txt # - nvidia-smi # - pytest -rFsv -k test_exatrkx diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 76af4847b7f..68c78341c5d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -93,3 +93,11 @@ repos: name: Leftover conflict markers language: system entry: git diff --staged --check + + - repo: local + hooks: + - id: math_macros + name: math_macros + language: system + entry: CI/check_math_macros.py + files: \.(cpp|hpp|ipp|cu|cuh)$ diff --git a/.zenodo.json b/.zenodo.json index a274d3c2cf1..d9786fc4cf6 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -112,11 +112,15 @@ "affiliation": "CERN / University of Amsterdam", "name": "Stephen Nicholas Swatman", "orcid": "0000-0002-3747-3229" - } + }, { "affiliation": "CERN / TU Wien", "name": "Felix Russo", "orcid": "0009-0005-8975-2245" + }, + { + "affiliation": "UC Berkeley", + "name": "Carlo Varni" } ], "access_right": "open", diff --git a/AUTHORS b/AUTHORS index 4dab2740fe3..3e2e965ff27 100644 --- a/AUTHORS +++ b/AUTHORS @@ -21,3 +21,4 @@ The following people have contributed to the project (in alphabetical order): - Andreas Stefl, CERN, TU Wien - Stephen Nicholas Swatman, CERN, University of Amsterdam - Roman Urmanov, Weizmann Institute of Science +- Carlo Varni, UC Berkeley diff --git a/CI/check_math_macros.py b/CI/check_math_macros.py new file mode 100755 index 00000000000..29da233372e --- /dev/null +++ b/CI/check_math_macros.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 + +from pathlib import Path +import os +import argparse +from fnmatch import fnmatch +import re +import sys + + +math_constants = [ + ("M_PI", "std::numbers::pi"), + ("M_PI_2", "std::numbers::pi / 2."), + ("M_PI_4", "std::numbers::pi / 4."), + ("M_1_PI", "std::numbers::inv_pi"), + ("M_2_PI", "2. * std::numbers::inv_pi"), + ("M_2_SQRTPI", "2. * std::numbers::inv_sqrtpi"), + ("M_E", "std::numbers::e"), + ("M_LOG2E", "std::numbers::log2e"), + ("M_LOG10E", "std::numbers::log10e"), + ("M_LN2", "std::numbers::ln2"), + ("M_LN10", "std::numbers::ln10"), + ("M_SQRT2", "std::numbers::sqrt2"), + ("M_SQRT1_2", "1. / std::numbers::sqrt2"), + ("M_SQRT3", "std::numbers::sqrt3"), + ("M_INV_SQRT3", "std::numbers::inv_sqrt3"), + ("M_EGAMMA", "std::numbers::egamma"), + ("M_PHI", "std::numbers::phi"), +] + + +github = "GITHUB_ACTIONS" in os.environ + + +def handle_file( + file: Path, fix: bool, math_const: tuple[str, str] +) -> list[tuple[int, str]]: + ex = re.compile(rf"(? 0: + changed_lines.append((i, oline)) + + if fix and len(changed_lines) > 0: + file.write_text("\n".join(lines) + "\n") + + return changed_lines + + +def main(): + p = argparse.ArgumentParser() + p.add_argument("input", nargs="+") + p.add_argument("--fix", action="store_true", help="Attempt to fix M_* macros.") + p.add_argument("--exclude", "-e", action="append", default=[]) + + args = p.parse_args() + + exit_code = 0 + + inputs = [] + + if len(args.input) == 1 and os.path.isdir(args.input[0]): + # walk over all files + for root, _, files in os.walk(args.input[0]): + root = Path(root) + for filename in files: + # get the full path of the file + filepath = root / filename + if filepath.suffix not in ( + ".hpp", + ".cpp", + ".ipp", + ".h", + ".C", + ".c", + ".cu", + ".cuh", + ): + continue + + if any([fnmatch(str(filepath), e) for e in args.exclude]): + continue + + inputs.append(filepath) + else: + for file in args.input: + inputs.append(Path(file)) + + for filepath in inputs: + for math_const in math_constants: + changed_lines = handle_file( + file=filepath, fix=args.fix, math_const=math_const + ) + if len(changed_lines) > 0: + exit_code = 1 + print() + print(filepath) + for i, oline in changed_lines: + print(f"{i}: {oline}") + + if github: + print( + f"::error file={filepath},line={i+1},title=Do not use macro {math_const[0]}::Replace {math_const[0]} with std::{math_const[1]}" + ) + + if exit_code == 1 and github: + print(f"::info You will need in each flagged file #include ") + + return exit_code + + +if "__main__" == __name__: + sys.exit(main()) diff --git a/CI/physmon/reference/trackfinding_1muon/seeded/performance_fitting_ckf.root b/CI/physmon/reference/trackfinding_1muon/seeded/performance_fitting_ckf.root index 5ba97ecd168..94fcbafbdbf 100644 Binary files a/CI/physmon/reference/trackfinding_1muon/seeded/performance_fitting_ckf.root and b/CI/physmon/reference/trackfinding_1muon/seeded/performance_fitting_ckf.root differ diff --git a/CI/physmon/reference/trackfinding_1muon/truth_estimated/performance_fitting_ckf.root b/CI/physmon/reference/trackfinding_1muon/truth_estimated/performance_fitting_ckf.root index 3fcdb6021d1..652e0d8fd57 100644 Binary files a/CI/physmon/reference/trackfinding_1muon/truth_estimated/performance_fitting_ckf.root and b/CI/physmon/reference/trackfinding_1muon/truth_estimated/performance_fitting_ckf.root differ diff --git a/CI/physmon/reference/trackfinding_4muon_50vertices/performance_fitting_ckf.root b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_fitting_ckf.root index b90f40313eb..37ad131de0e 100644 Binary files a/CI/physmon/reference/trackfinding_4muon_50vertices/performance_fitting_ckf.root and b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_fitting_ckf.root differ diff --git a/CI/physmon/reference/trackfinding_4muon_50vertices/performance_vertexing_amvf_grid_time_hist.root b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_vertexing_amvf_grid_time_hist.root index d99436fa0f5..3b33e1bae98 100644 Binary files a/CI/physmon/reference/trackfinding_4muon_50vertices/performance_vertexing_amvf_grid_time_hist.root and b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_vertexing_amvf_grid_time_hist.root differ diff --git a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_fitting_ckf.root b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_fitting_ckf.root index 09d2dc033af..754dd91bb0a 100644 Binary files a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_fitting_ckf.root and b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_fitting_ckf.root differ diff --git a/CI/physmon/reference/trackfitting_gx2f/performance_trackfitting.root b/CI/physmon/reference/trackfitting_gx2f/performance_trackfitting.root index 21533ce8076..b2e2b47c2f5 100644 Binary files a/CI/physmon/reference/trackfitting_gx2f/performance_trackfitting.root and b/CI/physmon/reference/trackfitting_gx2f/performance_trackfitting.root differ diff --git a/CITATION.cff b/CITATION.cff index 910eade5312..95865537ecf 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -89,6 +89,9 @@ authors: family-names: Russo affiliation: CERN / TU Wien orcid: https://orcid.org/0009-0005-8975-2245 +- given-names: Carlo + family-names: Varni + affiliation: UC Berkeley version: 10.0.0 date-released: 2021-07-28 repository-code: https://github.com/acts-project/acts diff --git a/CMakeLists.txt b/CMakeLists.txt index f5209e0d210..601264badc0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -290,8 +290,12 @@ if(ACTS_SETUP_BOOST) endif() if(Boost_VERSION VERSION_EQUAL "1.85.0") + set(_boost_version_severity WARNING) + if(ACTS_BUILD_EXAMPLES) + set(_boost_version_severity FATAL_ERROR) + endif() message( - WARNING + ${_boost_version_severity} "Boost 1.85.0 is known to be broken (https://github.com/boostorg/container/issues/273). Please use a different version." ) endif() diff --git a/Core/include/Acts/EventData/ProxyAccessor.hpp b/Core/include/Acts/EventData/ProxyAccessor.hpp index 429c0ef670b..d6a9a3497ce 100644 --- a/Core/include/Acts/EventData/ProxyAccessor.hpp +++ b/Core/include/Acts/EventData/ProxyAccessor.hpp @@ -75,7 +75,7 @@ struct ProxyAccessorBase { /// Create the accessor from a string key /// @param _key the key constexpr ProxyAccessorBase(const std::string& _key) - : key{hashString(_key)} {} + : key{hashStringDynamic(_key)} {} /// Access the stored key on the proxy given as an argument. Mutable version /// @tparam proxy_t the type of the proxy diff --git a/Core/include/Acts/EventData/TrackContainer.hpp b/Core/include/Acts/EventData/TrackContainer.hpp index f70c430f002..03f7f1f8bb1 100644 --- a/Core/include/Acts/EventData/TrackContainer.hpp +++ b/Core/include/Acts/EventData/TrackContainer.hpp @@ -252,7 +252,7 @@ class TrackContainer { /// Check if this track container has a specific dynamic column /// @param key the key to check for constexpr bool hasColumn(const std::string& key) const { - return m_container->hasColumn_impl(hashString(key)); + return m_container->hasColumn_impl(hashStringDynamic(key)); } /// Check if a this track container has a specific dynamic column diff --git a/Core/include/Acts/EventData/TrackProxy.hpp b/Core/include/Acts/EventData/TrackProxy.hpp index 5939022e2e8..6ccb0f402b2 100644 --- a/Core/include/Acts/EventData/TrackProxy.hpp +++ b/Core/include/Acts/EventData/TrackProxy.hpp @@ -710,7 +710,7 @@ class TrackProxy { constexpr T& component(std::string_view key) requires(!ReadOnly) { - return m_container->template component(hashString(key), m_index); + return m_container->template component(hashStringDynamic(key), m_index); } /// Retrieve a const reference to a component @@ -738,7 +738,7 @@ class TrackProxy { /// @return Const reference to the component given by @p key template constexpr const T& component(std::string_view key) const { - return m_container->template component(hashString(key), m_index); + return m_container->template component(hashStringDynamic(key), m_index); } /// @} diff --git a/Core/include/Acts/EventData/TrackStateProxy.hpp b/Core/include/Acts/EventData/TrackStateProxy.hpp index 34de86cd3d7..741bfa5b511 100644 --- a/Core/include/Acts/EventData/TrackStateProxy.hpp +++ b/Core/include/Acts/EventData/TrackStateProxy.hpp @@ -1101,7 +1101,7 @@ class TrackStateProxy { /// @note This might hash the @p key at runtime instead of compile-time /// @return true if the component exists, false if not constexpr bool has(std::string_view key) const { - return has(hashString(key)); + return has(hashStringDynamic(key)); } /// Retrieve a mutable reference to a component @@ -1135,7 +1135,7 @@ class TrackStateProxy { constexpr T& component(std::string_view key) requires(!ReadOnly) { - return m_traj->template component(hashString(key), m_istate); + return m_traj->template component(hashStringDynamic(key), m_istate); } /// Retrieve a const reference to a component @@ -1163,7 +1163,7 @@ class TrackStateProxy { /// @return Const reference to the component given by @p key template constexpr const T& component(std::string_view key) const { - return m_traj->template component(hashString(key), m_istate); + return m_traj->template component(hashStringDynamic(key), m_istate); } /// @} diff --git a/Core/include/Acts/EventData/VectorMultiTrajectory.hpp b/Core/include/Acts/EventData/VectorMultiTrajectory.hpp index 7d2d05cc9b9..3859239ae69 100644 --- a/Core/include/Acts/EventData/VectorMultiTrajectory.hpp +++ b/Core/include/Acts/EventData/VectorMultiTrajectory.hpp @@ -456,7 +456,7 @@ class VectorMultiTrajectory final template void addColumn_impl(std::string_view key) { - HashedString hashedKey = hashString(key); + HashedString hashedKey = hashStringDynamic(key); m_dynamic.insert({hashedKey, std::make_unique>()}); } diff --git a/Core/include/Acts/EventData/VectorTrackContainer.hpp b/Core/include/Acts/EventData/VectorTrackContainer.hpp index 09ecf7b5b2e..8734f69eb4c 100644 --- a/Core/include/Acts/EventData/VectorTrackContainer.hpp +++ b/Core/include/Acts/EventData/VectorTrackContainer.hpp @@ -225,7 +225,7 @@ class VectorTrackContainer final : public detail_vtc::VectorTrackContainerBase { template constexpr void addColumn_impl(const std::string_view& key) { - HashedString hashedKey = hashString(key); + HashedString hashedKey = hashStringDynamic(key); m_dynamic.insert({hashedKey, std::make_unique>()}); } diff --git a/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp b/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp index 93ef7a3eb7c..a2e374c0cc2 100644 --- a/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp +++ b/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp @@ -1103,8 +1103,8 @@ class MultiTrajectoryTestsCommon { auto test = [&](const std::string& col, auto value) { using T = decltype(value); std::string col2 = col + "_2"; - HashedString h{hashString(col)}; - HashedString h2{hashString(col2)}; + HashedString h{hashStringDynamic(col)}; + HashedString h2{hashStringDynamic(col2)}; trajectory_t traj = m_factory.create(); BOOST_CHECK(!traj.hasColumn(h)); @@ -1188,7 +1188,7 @@ class MultiTrajectoryTestsCommon { } }; - runTest([](const std::string& c) { return hashString(c.c_str()); }); + runTest([](const std::string& c) { return hashStringDynamic(c.c_str()); }); // runTest([](const std::string& c) { return c.c_str(); }); // runTest([](const std::string& c) { return c; }); // runTest([](std::string_view c) { return c; }); diff --git a/Core/include/Acts/EventData/detail/TestSourceLink.hpp b/Core/include/Acts/EventData/detail/TestSourceLink.hpp index 34a234bbf4d..affec84aafa 100644 --- a/Core/include/Acts/EventData/detail/TestSourceLink.hpp +++ b/Core/include/Acts/EventData/detail/TestSourceLink.hpp @@ -139,14 +139,13 @@ void testSourceLinkCalibratorReturn( trackState.allocateCalibrated(2); trackState.template calibrated<2>() = sl.parameters; trackState.template calibratedCovariance<2>() = sl.covariance; - trackState.template setSubspaceIndices( - std::array{sl.indices[0], sl.indices[1]}); + trackState.setSubspaceIndices(std::array{sl.indices[0], sl.indices[1]}); } else if (sl.indices[0] != Acts::eBoundSize) { trackState.allocateCalibrated(1); trackState.template calibrated<1>() = sl.parameters.head<1>(); trackState.template calibratedCovariance<1>() = sl.covariance.topLeftCorner<1, 1>(); - trackState.template setSubspaceIndices(std::array{sl.indices[0]}); + trackState.setSubspaceIndices(std::array{sl.indices[0]}); } else { throw std::runtime_error( "Tried to extract measurement from invalid TestSourceLink"); diff --git a/Core/include/Acts/Navigation/TryAllNavigationPolicy.hpp b/Core/include/Acts/Navigation/TryAllNavigationPolicy.hpp index e7dc4bb3ddc..677a1dbd6dc 100644 --- a/Core/include/Acts/Navigation/TryAllNavigationPolicy.hpp +++ b/Core/include/Acts/Navigation/TryAllNavigationPolicy.hpp @@ -27,12 +27,13 @@ class TryAllNavigationPolicy final : public INavigationPolicy { }; /// Constructor from a volume - /// @param config The configuration for the policy /// @param gctx is the geometry context /// @param volume is the volume to navigate /// @param logger is the logger - TryAllNavigationPolicy(const Config& config, const GeometryContext& gctx, - const TrackingVolume& volume, const Logger& logger); + /// @param config The configuration for the policy + TryAllNavigationPolicy(const GeometryContext& gctx, + const TrackingVolume& volume, const Logger& logger, + const Config& config); /// Constructor from a volume /// @param gctx is the geometry context diff --git a/Core/include/Acts/Seeding/EstimateTrackParamsFromSeed.hpp b/Core/include/Acts/Seeding/EstimateTrackParamsFromSeed.hpp index f3850e102ce..5d6b4dbb97c 100644 --- a/Core/include/Acts/Seeding/EstimateTrackParamsFromSeed.hpp +++ b/Core/include/Acts/Seeding/EstimateTrackParamsFromSeed.hpp @@ -14,111 +14,92 @@ #include "Acts/Surfaces/Surface.hpp" #include "Acts/Utilities/Logger.hpp" #include "Acts/Utilities/MathHelpers.hpp" +#include "Acts/Utilities/Zip.hpp" #include #include #include #include #include +#include namespace Acts { -/// @todo: -/// 1) Implement the simple Line and Circle fit based on Taubin Circle fit -/// 2) Implement the simple Line and Parabola fit (from HPS reconstruction by -/// Robert Johnson) -/// Estimate the track parameters on the xy plane from at least three space -/// points. It assumes the trajectory projection on the xy plane is a circle, -/// i.e. the magnetic field is along global z-axis. +/// Estimate the full track parameters from three space points /// -/// The method is based on V. Karimaki NIM A305 (1991) 187-191: -/// https://doi.org/10.1016/0168-9002(91)90533-V -/// - no weights are used in Karimaki's fit; d0 is the distance of the point of -/// closest approach to the origin, 1/R is the curvature, phi is the angle of -/// the direction propagation (counter clockwise as positive) at the point of -/// cloest approach. +/// This method is based on the conformal map transformation. It estimates the +/// full free track parameters, i.e. (x, y, z, t, dx, dy, dz, q/p) at the +/// bottom space point. The bottom space is assumed to be the first element +/// in the range defined by the iterators. The magnetic field (which might be +/// along any direction) is also necessary for the momentum estimation. /// -/// @tparam spacepoint_iterator_t The type of space point iterator +/// This is a purely spatial estimation, i.e. the time parameter will be set to +/// 0. /// -/// @param spBegin is the begin iterator for the space points -/// @param spEnd is the end iterator for the space points -/// @param logger A logger instance +/// It resembles the method used in ATLAS for the track parameters +/// estimated from seed, i.e. the function InDet::SiTrackMaker_xk::getAtaPlane +/// here: +/// https://acode-browser.usatlas.bnl.gov/lxr/source/athena/InnerDetector/InDetRecTools/SiTrackMakerTool_xk/src/SiTrackMaker_xk.cxx /// -/// @return optional bound track parameters with the estimated d0, phi and 1/R -/// stored with the indices, eBoundLoc0, eBoundPhi and eBoundQOverP, -/// respectively. The bound parameters with other indices are set to zero. -template -std::optional estimateTrackParamsFromSeed( - spacepoint_iterator_t spBegin, spacepoint_iterator_t spEnd, - const Logger& logger = getDummyLogger()) { +/// @tparam spacepoint_iterator_t The type of space point iterator +/// +/// @param sp0 is the bottom space point +/// @param sp1 is the middle space point +/// @param sp2 is the top space point +/// @param bField is the magnetic field vector +/// +/// @return the free parameters +FreeVector estimateTrackParamsFromSeed(const Vector3& sp0, const Vector3& sp1, + const Vector3& sp2, + const Vector3& bField); + +/// Estimate the full track parameters from three space points +/// +/// This method is based on the conformal map transformation. It estimates the +/// full free track parameters, i.e. (x, y, z, t, dx, dy, dz, q/p) at the +/// bottom space point. The bottom space is assumed to be the first element +/// in the range defined by the iterators. The magnetic field (which might be +/// along any direction) is also necessary for the momentum estimation. +/// +/// It resembles the method used in ATLAS for the track parameters +/// estimated from seed, i.e. the function InDet::SiTrackMaker_xk::getAtaPlane +/// here: +/// https://acode-browser.usatlas.bnl.gov/lxr/source/athena/InnerDetector/InDetRecTools/SiTrackMakerTool_xk/src/SiTrackMaker_xk.cxx +/// +/// @tparam spacepoint_iterator_t The type of space point iterator +/// +/// @param spRange is the range of space points +/// @param bField is the magnetic field vector +/// +/// @return the free parameters +template +FreeVector estimateTrackParamsFromSeed(spacepoint_range_t spRange, + const Vector3& bField) { // Check the number of provided space points - std::size_t numSP = std::distance(spBegin, spEnd); - if (numSP < 3) { - ACTS_ERROR("At least three space points are required."); - return std::nullopt; + if (spRange.size() != 3) { + throw std::invalid_argument( + "There should be exactly three space points provided."); } - ActsScalar x2m = 0., xm = 0.; - ActsScalar xym = 0.; - ActsScalar y2m = 0., ym = 0.; - ActsScalar r2m = 0., r4m = 0.; - ActsScalar xr2m = 0., yr2m = 0.; - - for (spacepoint_iterator_t it = spBegin; it != spEnd; it++) { - if (*it == nullptr) { - ACTS_ERROR("Empty space point found. This should not happen."); - return std::nullopt; + // The global positions of the bottom, middle and space points + std::array spPositions = {Vector3::Zero(), Vector3::Zero(), + Vector3::Zero()}; + std::array, 3> spTimes = {std::nullopt, std::nullopt, + std::nullopt}; + // The first, second and third space point are assumed to be bottom, middle + // and top space point, respectively + for (auto [sp, spPosition, spTime] : + Acts::zip(spRange, spPositions, spTimes)) { + if (sp == nullptr) { + throw std::invalid_argument("Empty space point found."); } - - const auto& sp = *it; - - ActsScalar x = sp->x(); - ActsScalar y = sp->y(); - ActsScalar r2 = x * x + y * y; - x2m += x * x; - xm += x; - xym += x * y; - y2m += y * y; - ym += y; - r2m += r2; - r4m += r2 * r2; - xr2m += x * r2; - yr2m += y * r2; - numSP++; + spPosition = Vector3(sp->x(), sp->y(), sp->z()); + spTime = sp->t(); } - x2m = x2m / numSP; - xm = xm / numSP; - xym = xym / numSP; - y2m = y2m / numSP; - ym = ym / numSP; - r2m = r2m / numSP; - r4m = r4m / numSP; - xr2m = xr2m / numSP; - yr2m = yr2m / numSP; - - ActsScalar Cxx = x2m - xm * xm; - ActsScalar Cxy = xym - xm * ym; - ActsScalar Cyy = y2m - ym * ym; - ActsScalar Cxr2 = xr2m - xm * r2m; - ActsScalar Cyr2 = yr2m - ym * r2m; - ActsScalar Cr2r2 = r4m - r2m * r2m; - - ActsScalar q1 = Cr2r2 * Cxy - Cxr2 * Cyr2; - ActsScalar q2 = Cr2r2 * (Cxx - Cyy) - Cxr2 * Cxr2 + Cyr2 * Cyr2; - - ActsScalar phi = 0.5 * std::atan(2 * q1 / q2); - ActsScalar k = (std::sin(phi) * Cxr2 - std::cos(phi) * Cyr2) * (1. / Cr2r2); - ActsScalar delta = -k * r2m + std::sin(phi) * xm - std::cos(phi) * ym; - - ActsScalar rho = (2 * k) / (std::sqrt(1 - 4 * delta * k)); - ActsScalar d0 = (2 * delta) / (1 + std::sqrt(1 - 4 * delta * k)); - - // Initialize the bound parameters vector - BoundVector params = BoundVector::Zero(); - params[eBoundLoc0] = d0; - params[eBoundPhi] = phi; - params[eBoundQOverP] = rho; + FreeVector params = estimateTrackParamsFromSeed( + spPositions[0], spPositions[1], spPositions[2], bField); + params[eFreeTime] = spTimes[0].value_or(0); return params; } @@ -163,15 +144,15 @@ std::optional estimateTrackParamsFromSeed( } // Convert bField to Tesla - ActsScalar bFieldInTesla = bField.norm() / UnitConstants::T; - ActsScalar bFieldMinInTesla = bFieldMin / UnitConstants::T; + ActsScalar bFieldStrength = bField.norm(); // Check if magnetic field is too small - if (bFieldInTesla < bFieldMinInTesla) { + if (bFieldStrength < bFieldMin) { // @todo shall we use straight-line estimation and use default q/pt in such // case? - ACTS_WARNING("The magnetic field at the bottom space point: B = " - << bFieldInTesla << " T is smaller than |B|_min = " - << bFieldMinInTesla << " T. Estimation is not performed."); + ACTS_WARNING( + "The magnetic field at the bottom space point: B = " + << bFieldStrength / UnitConstants::T << " T is smaller than |B|_min = " + << bFieldMin / UnitConstants::T << " T. Estimation is not performed."); return std::nullopt; } @@ -241,7 +222,7 @@ std::optional estimateTrackParamsFromSeed( int sign = ia > 0 ? -1 : 1; const ActsScalar R = circleCenter.norm(); ActsScalar invTanTheta = - local2.z() / (2.f * R * std::asin(local2.head<2>().norm() / (2.f * R))); + local2.z() / (2 * R * std::asin(local2.head<2>().norm() / (2 * R))); // The momentum direction in the new frame (the center of the circle has the // coordinate (-1.*A/(2*B), 1./(2*B))) ActsScalar A = -circleCenter(0) / circleCenter(1); @@ -273,7 +254,7 @@ std::optional estimateTrackParamsFromSeed( // The estimated q/pt in [GeV/c]^-1 (note that the pt is the projection of // momentum on the transverse plane of the new frame) - ActsScalar qOverPt = sign * (UnitConstants::m) / (0.3 * bFieldInTesla * R); + ActsScalar qOverPt = sign / (bFieldStrength * R); // The estimated q/p in [GeV/c]^-1 params[eBoundQOverP] = qOverPt / fastHypot(1., invTanTheta); diff --git a/Core/include/Acts/TrackFinding/TrackSelector.hpp b/Core/include/Acts/TrackFinding/TrackSelector.hpp index 459ab996857..5a2cf53df27 100644 --- a/Core/include/Acts/TrackFinding/TrackSelector.hpp +++ b/Core/include/Acts/TrackFinding/TrackSelector.hpp @@ -304,24 +304,32 @@ inline TrackSelector::Config& TrackSelector::Config::pt(double min, inline std::ostream& operator<<(std::ostream& os, const TrackSelector::Config& cuts) { - auto print = [&](const char* name, const auto& min, const auto& max) { + // for printing cuts set up with `within` + auto printMinMax = [&](const char* name, const auto& min, const auto& max) { os << " - " << min << " <= " << name << " < " << max << "\n"; }; + // for printing cuts set up with `checkMin` + auto printMin = [&](const char* name, const auto& min) { + os << " - " << min << " <= " << name << "\n"; + }; + // for printing cuts set up with `checkMax` + auto printMax = [&](const char* name, const auto& max) { + os << " - " << name << " <= " << max << "\n"; + }; - print("loc0", cuts.loc0Min, cuts.loc0Max); - print("loc1", cuts.loc1Min, cuts.loc1Max); - print("time", cuts.timeMin, cuts.timeMax); - print("phi", cuts.phiMin, cuts.phiMax); - print("eta", cuts.etaMin, cuts.etaMax); - print("absEta", cuts.absEtaMin, cuts.absEtaMax); - print("pt", cuts.ptMin, cuts.ptMax); - print("nHoles", 0, cuts.maxHoles); - print("nOutliers", 0, cuts.maxOutliers); - print("nHoles + nOutliers", 0, cuts.maxHolesAndOutliers); - print("nSharedHits", 0, cuts.maxSharedHits); - print("chi2", 0.0, cuts.maxChi2); - os << " - " << cuts.minMeasurements << " <= nMeasurements\n"; - + printMinMax("loc0", cuts.loc0Min, cuts.loc0Max); + printMinMax("loc1", cuts.loc1Min, cuts.loc1Max); + printMinMax("time", cuts.timeMin, cuts.timeMax); + printMinMax("phi", cuts.phiMin, cuts.phiMax); + printMinMax("eta", cuts.etaMin, cuts.etaMax); + printMinMax("absEta", cuts.absEtaMin, cuts.absEtaMax); + printMinMax("pt", cuts.ptMin, cuts.ptMax); + printMax("nHoles", cuts.maxHoles); + printMax("nOutliers", cuts.maxOutliers); + printMax("nHoles + nOutliers", cuts.maxHolesAndOutliers); + printMax("nSharedHits", cuts.maxSharedHits); + printMax("chi2", cuts.maxChi2); + printMin("nMeasurements", cuts.minMeasurements); return os; } diff --git a/Core/include/Acts/TrackFitting/GlobalChiSquareFitter.hpp b/Core/include/Acts/TrackFitting/GlobalChiSquareFitter.hpp index c5fb8483aa7..8442071a23f 100644 --- a/Core/include/Acts/TrackFitting/GlobalChiSquareFitter.hpp +++ b/Core/include/Acts/TrackFitting/GlobalChiSquareFitter.hpp @@ -392,10 +392,8 @@ void addMeasurementToGx2fSums(Gx2fSystem& extendedSystem, } // Create an extended Jacobian. This one contains only eBoundSize rows, - // because the rest is irrelevant. We fill it in the next steps + // because the rest is irrelevant. We fill it in the next steps. // TODO make dimsExtendedParams template with unrolling - - // We create an empty Jacobian and fill it in the next steps Eigen::MatrixXd extendedJacobian = Eigen::MatrixXd::Zero(eBoundSize, extendedSystem.nDims()); @@ -566,10 +564,11 @@ void addMaterialToGx2fSums( /// /// @tparam track_proxy_t The type of the track proxy /// -/// @param track A mutable track proxy to operate on +/// @param track A constant track proxy to inspect /// @param extendedSystem All parameters of the current equation system /// @param multipleScattering Flag to consider multiple scattering in the calculation -/// @param scatteringMap Map of geometry identifiers to scattering properties, containing all scattering angles and covariances +/// @param scatteringMap Map of geometry identifiers to scattering properties, +/// containing scattering angles and validation status /// @param geoIdVector A vector to store geometry identifiers for tracking processed elements /// @param logger A logger instance template @@ -650,6 +649,65 @@ void fillGx2fSystem( } } +/// @brief Count the valid material states in a track for scattering calculations. +/// +/// This function counts the valid material surfaces encountered in a track +/// by examining each track state. The count is based on the presence of +/// material flags and the availability of scattering information for each +/// surface. +/// +/// @tparam track_proxy_t The type of the track proxy +/// +/// @param track A constant track proxy to inspect +/// @param scatteringMap Map of geometry identifiers to scattering properties, +/// containing scattering angles and validation status +/// @param logger A logger instance +template +std::size_t countMaterialStates( + const track_proxy_t track, + const std::unordered_map& + scatteringMap, + const Logger& logger) { + std::size_t nMaterialSurfaces = 0; + ACTS_DEBUG("Count the valid material surfaces."); + for (const auto& trackState : track.trackStates()) { + const auto typeFlags = trackState.typeFlags(); + const bool stateHasMaterial = typeFlags.test(TrackStateFlag::MaterialFlag); + + if (!stateHasMaterial) { + continue; + } + + // Get and store geoId for the current material surface + const GeometryIdentifier geoId = trackState.referenceSurface().geometryId(); + + const auto scatteringMapId = scatteringMap.find(geoId); + assert(scatteringMapId != scatteringMap.end() && + "No scattering angles found for material surface."); + if (!scatteringMapId->second.materialIsValid()) { + continue; + } + + nMaterialSurfaces++; + } + + return nMaterialSurfaces; +} + +/// @brief Update parameters (and scattering angles if applicable) +/// +/// @param params Parameters to be updated +/// @param deltaParamsExtended Delta parameters for bound parameter and scattering angles +/// @param nMaterialSurfaces Number of material surfaces in the track +/// @param scatteringMap Map of geometry identifiers to scattering properties, +/// containing all scattering angles and covariances +/// @param geoIdVector Vector of geometry identifiers corresponding to material surfaces +void updateGx2fParams( + BoundTrackParameters& params, const Eigen::VectorXd& deltaParamsExtended, + const std::size_t nMaterialSurfaces, + std::unordered_map& scatteringMap, + const std::vector& geoIdVector); + /// @brief Calculate and update the covariance of the fitted parameters /// /// This function calculates the covariance of the fitted parameters using @@ -660,8 +718,6 @@ void fillGx2fSystem( /// /// @param fullCovariancePredicted The covariance matrix to update /// @param extendedSystem All parameters of the current equation system -/// -/// @return deltaParams The calculated delta parameters. void updateGx2fCovarianceParams(BoundMatrix& fullCovariancePredicted, Gx2fSystem& extendedSystem); @@ -1190,7 +1246,6 @@ class Gx2Fitter { using PropagatorOptions = typename propagator_t::template Options; start_parameters_t params = sParameters; - BoundVector deltaParams = BoundVector::Zero(); double chi2sum = 0; double oldChi2sum = std::numeric_limits::max(); @@ -1228,10 +1283,6 @@ class Gx2Fitter { for (nUpdate = 0; nUpdate < gx2fOptions.nUpdateMax; nUpdate++) { ACTS_DEBUG("nUpdate = " << nUpdate + 1 << "/" << gx2fOptions.nUpdateMax); - // update params - params.parameters() += deltaParams; - ACTS_VERBOSE("Updated parameters: " << params.parameters().transpose()); - // set up propagator and co Acts::GeometryContext geoCtx = gx2fOptions.geoContext; Acts::MagneticFieldContext magCtx = gx2fOptions.magFieldContext; @@ -1246,7 +1297,7 @@ class Gx2Fitter { auto& gx2fActor = propagatorOptions.actorList.template get(); gx2fActor.inputMeasurements = &inputMeasurements; - gx2fActor.multipleScattering = multipleScattering; + gx2fActor.multipleScattering = false; gx2fActor.extensions = gx2fOptions.extensions; gx2fActor.calibrationContext = &gx2fOptions.calibrationContext.get(); gx2fActor.actorLogger = m_actorLogger.get(); @@ -1262,12 +1313,12 @@ class Gx2Fitter { // existing states, but this needs some more thinking. trackContainerTemp.clear(); - auto propagationResult = m_propagator.template propagate(propagatorState); + auto propagationResult = m_propagator.propagate(propagatorState); // Run the fitter - auto result = m_propagator.template makeResult(std::move(propagatorState), - propagationResult, - propagatorOptions, false); + auto result = + m_propagator.makeResult(std::move(propagatorState), propagationResult, + propagatorOptions, false); if (!result.ok()) { ACTS_ERROR("Propagation failed: " << result.error()); @@ -1303,32 +1354,7 @@ class Gx2Fitter { // Count the material surfaces, to set up the system. In the multiple // scattering case, we need to extend our system. - std::size_t nMaterialSurfaces = 0; - if (multipleScattering) { - ACTS_DEBUG("Count the valid material surfaces."); - for (const auto& trackState : track.trackStates()) { - const auto typeFlags = trackState.typeFlags(); - const bool stateHasMaterial = - typeFlags.test(TrackStateFlag::MaterialFlag); - - if (!stateHasMaterial) { - continue; - } - - // Get and store geoId for the current material surface - const GeometryIdentifier geoId = - trackState.referenceSurface().geometryId(); - - const auto scatteringMapId = scatteringMap.find(geoId); - assert(scatteringMapId != scatteringMap.end() && - "No scattering angles found for material surface."); - if (!scatteringMapId->second.materialIsValid()) { - continue; - } - - nMaterialSurfaces++; - } - } + const std::size_t nMaterialSurfaces = 0u; // We need 6 dimensions for the bound parameters and 2 * nMaterialSurfaces // dimensions for the scattering angles. @@ -1344,8 +1370,8 @@ class Gx2Fitter { // all stored material in each propagation. std::vector geoIdVector; - fillGx2fSystem(track, extendedSystem, multipleScattering, scatteringMap, - geoIdVector, *m_addToSumLogger); + fillGx2fSystem(track, extendedSystem, false, scatteringMap, geoIdVector, + *m_addToSumLogger); chi2sum = extendedSystem.chi2(); @@ -1370,14 +1396,10 @@ class Gx2Fitter { extendedSystem.aMatrix().colPivHouseholderQr().solve( extendedSystem.bVector()); - deltaParams = deltaParamsExtended.topLeftCorner().eval(); - ACTS_VERBOSE("aMatrix:\n" << extendedSystem.aMatrix() << "\n" << "bVector:\n" << extendedSystem.bVector() << "\n" - << "deltaParams:\n" - << deltaParams << "\n" << "deltaParamsExtended:\n" << deltaParamsExtended << "\n" << "oldChi2sum = " << oldChi2sum << "\n" @@ -1394,10 +1416,7 @@ class Gx2Fitter { } if (extendedSystem.chi2() > oldChi2sum + 1e-5) { - ACTS_DEBUG("chi2 not converging monotonically"); - - updateGx2fCovarianceParams(fullCovariancePredicted, extendedSystem); - break; + ACTS_DEBUG("chi2 not converging monotonically in update " << nUpdate); } // If this is the final iteration, update the covariance and break. @@ -1418,19 +1437,9 @@ class Gx2Fitter { break; } - if (multipleScattering) { - // update the scattering angles - for (std::size_t matSurface = 0; matSurface < nMaterialSurfaces; - matSurface++) { - const std::size_t deltaPosition = eBoundSize + 2 * matSurface; - const GeometryIdentifier geoId = geoIdVector[matSurface]; - const auto scatteringMapId = scatteringMap.find(geoId); - assert(scatteringMapId != scatteringMap.end() && - "No scattering angles found for material surface."); - scatteringMapId->second.scatteringAngles().block<2, 1>(2, 0) += - deltaParamsExtended.block<2, 1>(deltaPosition, 0).eval(); - } - } + updateGx2fParams(params, deltaParamsExtended, nMaterialSurfaces, + scatteringMap, geoIdVector); + ACTS_VERBOSE("Updated parameters: " << params.parameters().transpose()); oldChi2sum = extendedSystem.chi2(); } @@ -1438,6 +1447,144 @@ class Gx2Fitter { ACTS_VERBOSE("Final parameters: " << params.parameters().transpose()); /// Finish Fitting ///////////////////////////////////////////////////////// + /// Actual MATERIAL Fitting //////////////////////////////////////////////// + ACTS_DEBUG("Start to evaluate material"); + if (multipleScattering) { + // set up propagator and co + Acts::GeometryContext geoCtx = gx2fOptions.geoContext; + Acts::MagneticFieldContext magCtx = gx2fOptions.magFieldContext; + // Set options for propagator + PropagatorOptions propagatorOptions(geoCtx, magCtx); + + // Add the measurement surface as external surface to the navigator. + // We will try to hit those surface by ignoring boundary checks. + for (const auto& [surfaceId, _] : inputMeasurements) { + propagatorOptions.navigation.insertExternalSurface(surfaceId); + } + + auto& gx2fActor = propagatorOptions.actorList.template get(); + gx2fActor.inputMeasurements = &inputMeasurements; + gx2fActor.multipleScattering = true; + gx2fActor.extensions = gx2fOptions.extensions; + gx2fActor.calibrationContext = &gx2fOptions.calibrationContext.get(); + gx2fActor.actorLogger = m_actorLogger.get(); + gx2fActor.scatteringMap = &scatteringMap; + gx2fActor.parametersWithHypothesis = ¶ms; + + auto propagatorState = m_propagator.makeState(params, propagatorOptions); + + auto& r = propagatorState.template get>(); + r.fittedStates = &trajectoryTempBackend; + + // Clear the track container. It could be more performant to update the + // existing states, but this needs some more thinking. + trackContainerTemp.clear(); + + auto propagationResult = m_propagator.propagate(propagatorState); + + // Run the fitter + auto result = + m_propagator.makeResult(std::move(propagatorState), propagationResult, + propagatorOptions, false); + + if (!result.ok()) { + ACTS_ERROR("Propagation failed: " << result.error()); + return result.error(); + } + + // TODO Improve Propagator + Actor [allocate before loop], rewrite + // makeMeasurements + auto& propRes = *result; + GX2FResult gx2fResult = std::move(propRes.template get()); + + if (!gx2fResult.result.ok()) { + ACTS_INFO("GlobalChiSquareFitter failed in actor: " + << gx2fResult.result.error() << ", " + << gx2fResult.result.error().message()); + return gx2fResult.result.error(); + } + + auto track = trackContainerTemp.makeTrack(); + tipIndex = gx2fResult.lastMeasurementIndex; + + // It could happen, that no measurements were found. Then the track would + // be empty and the following operations would be invalid. Usually, this + // only happens during the first iteration, due to bad initial parameters. + if (tipIndex == Acts::MultiTrajectoryTraits::kInvalid) { + ACTS_INFO("Did not find any measurements in material fit."); + return Experimental::GlobalChiSquareFitterError::NotEnoughMeasurements; + } + + track.tipIndex() = tipIndex; + track.linkForward(); + + // Count the material surfaces, to set up the system. In the multiple + // scattering case, we need to extend our system. + const std::size_t nMaterialSurfaces = + countMaterialStates(track, scatteringMap, *m_addToSumLogger); + + // We need 6 dimensions for the bound parameters and 2 * nMaterialSurfaces + // dimensions for the scattering angles. + const std::size_t dimsExtendedParams = eBoundSize + 2 * nMaterialSurfaces; + + // System that we fill with the information gathered by the actor and + // evaluate later + Gx2fSystem extendedSystem{dimsExtendedParams}; + + // This vector stores the IDs for each visited material in order. We use + // it later for updating the scattering angles. We cannot use + // scatteringMap directly, since we cannot guarantee, that we will visit + // all stored material in each propagation. + std::vector geoIdVector; + + fillGx2fSystem(track, extendedSystem, true, scatteringMap, geoIdVector, + *m_addToSumLogger); + + chi2sum = extendedSystem.chi2(); + + // This check takes into account the evaluated dimensions of the + // measurements. To fit, we need at least NDF+1 measurements. However, we + // count n-dimensional measurements for n measurements, reducing the + // effective number of needed measurements. We might encounter the case, + // where we cannot use some (parts of a) measurements, maybe if we do not + // support that kind of measurement. This is also taken into account here. + // We skip the check during the first iteration, since we cannot guarantee + // to hit all/enough measurement surfaces with the initial parameter + // guess. + if ((nUpdate > 0) && !extendedSystem.isWellDefined()) { + ACTS_INFO("Not enough measurements. Require " + << extendedSystem.findRequiredNdf() + 1 << ", but only " + << extendedSystem.ndf() << " could be used."); + return Experimental::GlobalChiSquareFitterError::NotEnoughMeasurements; + } + + // calculate delta params [a] * delta = b + Eigen::VectorXd deltaParamsExtended = + extendedSystem.aMatrix().colPivHouseholderQr().solve( + extendedSystem.bVector()); + + ACTS_VERBOSE("aMatrix:\n" + << extendedSystem.aMatrix() << "\n" + << "bVector:\n" + << extendedSystem.bVector() << "\n" + << "deltaParamsExtended:\n" + << deltaParamsExtended << "\n" + << "oldChi2sum = " << oldChi2sum << "\n" + << "chi2sum = " << extendedSystem.chi2()); + + chi2sum = extendedSystem.chi2(); + + updateGx2fParams(params, deltaParamsExtended, nMaterialSurfaces, + scatteringMap, geoIdVector); + ACTS_VERBOSE("Updated parameters: " << params.parameters().transpose()); + + updateGx2fCovarianceParams(fullCovariancePredicted, extendedSystem); + } + ACTS_DEBUG("Finished to evaluate material"); + ACTS_VERBOSE( + "Final parameters after material: " << params.parameters().transpose()); + /// Finish MATERIAL Fitting //////////////////////////////////////////////// + ACTS_VERBOSE("Final scattering angles:"); for (const auto& [key, value] : scatteringMap) { if (!value.materialIsValid()) { @@ -1456,7 +1603,6 @@ class Gx2Fitter { // step, we will not ignore the boundary checks for measurement surfaces. We // want to create trackstates only on surfaces, that we actually hit. if (gx2fOptions.nUpdateMax > 0) { - ACTS_VERBOSE("Final delta parameters: " << deltaParams.transpose()); ACTS_VERBOSE("Propagate with the final covariance."); // update covariance params.covariance() = fullCovariancePredicted; @@ -1480,12 +1626,12 @@ class Gx2Fitter { auto& r = propagatorState.template get>(); r.fittedStates = &trackContainer.trackStateContainer(); - auto propagationResult = m_propagator.template propagate(propagatorState); + auto propagationResult = m_propagator.propagate(propagatorState); // Run the fitter - auto result = m_propagator.template makeResult(std::move(propagatorState), - propagationResult, - propagatorOptions, false); + auto result = + m_propagator.makeResult(std::move(propagatorState), propagationResult, + propagatorOptions, false); if (!result.ok()) { ACTS_ERROR("Propagation failed: " << result.error()); diff --git a/Core/include/Acts/TrackFitting/KalmanFitter.hpp b/Core/include/Acts/TrackFitting/KalmanFitter.hpp index b0fe848c17b..12b70c8a562 100644 --- a/Core/include/Acts/TrackFitting/KalmanFitter.hpp +++ b/Core/include/Acts/TrackFitting/KalmanFitter.hpp @@ -1233,7 +1233,7 @@ class KalmanFitter { track_container_t& trackContainer) const -> Result { auto propagatorState = - m_propagator.template makeState(sParameters, propagatorOptions); + m_propagator.makeState(sParameters, propagatorOptions); auto& kalmanResult = propagatorState.template get>(); diff --git a/Core/include/Acts/Utilities/HashedString.hpp b/Core/include/Acts/Utilities/HashedString.hpp index 6cdbe9d21e6..88b50a34d05 100644 --- a/Core/include/Acts/Utilities/HashedString.hpp +++ b/Core/include/Acts/Utilities/HashedString.hpp @@ -8,9 +8,11 @@ #pragma once +#include #include #include #include +#include #include namespace Acts { @@ -35,7 +37,11 @@ constexpr int length(const char* str) { } } // namespace detail -constexpr HashedString hashString(std::string_view s) { +consteval HashedString hashString(std::string_view s) { + return detail::fnv1a_32(s); +} + +constexpr HashedString hashStringDynamic(std::string_view s) { return detail::fnv1a_32(s); } diff --git a/Core/include/Acts/Utilities/Logger.hpp b/Core/include/Acts/Utilities/Logger.hpp index 48cadb49ec4..83dc989ca85 100644 --- a/Core/include/Acts/Utilities/Logger.hpp +++ b/Core/include/Acts/Utilities/Logger.hpp @@ -482,7 +482,9 @@ class TimedOutputDecorator final : public OutputDecorator { char buffer[20]; time_t t{}; std::time(&t); - std::strftime(buffer, sizeof(buffer), m_format.c_str(), localtime(&t)); + struct tm tbuf {}; + std::strftime(buffer, sizeof(buffer), m_format.c_str(), + localtime_r(&t, &tbuf)); return buffer; } diff --git a/Core/include/Acts/Utilities/detail/ContextType.hpp b/Core/include/Acts/Utilities/detail/ContextType.hpp index 143e8b2d521..8ccadd77c4d 100644 --- a/Core/include/Acts/Utilities/detail/ContextType.hpp +++ b/Core/include/Acts/Utilities/detail/ContextType.hpp @@ -79,6 +79,28 @@ class ContextType { return std::any_cast&>(m_data); } + /// Retrieve a pointer to the contained type + /// + /// @note Returns `nullptr` if @p is not the contained type. + /// + /// @tparam T The type to attempt to retrieve the value as + /// @return Pointer to the contained value, may be null + template + std::decay_t* maybeGet() { + return std::any_cast>(&m_data); + } + + /// Retrieve a pointer to the contained type + /// + /// @note Returns `nullptr` if @p is not the contained type. + /// + /// @tparam T The type to attempt to retrieve the value as + /// @return Pointer to the contained value, may be null + template + const std::decay_t* maybeGet() const { + return std::any_cast>(&m_data); + } + /// Check if the contained type is initialized. /// @return Boolean indicating whether a type is present bool hasValue() const { return m_data.has_value(); } diff --git a/Core/src/Geometry/TrackingVolume.cpp b/Core/src/Geometry/TrackingVolume.cpp index bbe9b60fc98..6d3880bd4db 100644 --- a/Core/src/Geometry/TrackingVolume.cpp +++ b/Core/src/Geometry/TrackingVolume.cpp @@ -96,6 +96,13 @@ const TrackingVolume* TrackingVolume::lowestTrackingVolume( } } + // @TODO: Abstract this into an accelerateable structure + for (const auto& volume : volumes()) { + if (volume.inside(position, tol)) { + return volume.lowestTrackingVolume(gctx, position, tol); + } + } + // there is no lower sub structure return this; } diff --git a/Core/src/Navigation/TryAllNavigationPolicy.cpp b/Core/src/Navigation/TryAllNavigationPolicy.cpp index 40ca70c4079..4423c7d62a8 100644 --- a/Core/src/Navigation/TryAllNavigationPolicy.cpp +++ b/Core/src/Navigation/TryAllNavigationPolicy.cpp @@ -13,10 +13,10 @@ namespace Acts { -TryAllNavigationPolicy::TryAllNavigationPolicy(const Config& config, - const GeometryContext& /*gctx*/, +TryAllNavigationPolicy::TryAllNavigationPolicy(const GeometryContext& /*gctx*/, const TrackingVolume& volume, - const Logger& logger) + const Logger& logger, + const Config& config) : m_cfg{config}, m_volume(&volume) { assert(m_volume != nullptr); ACTS_VERBOSE("TryAllNavigationPolicy created for volume " @@ -26,7 +26,7 @@ TryAllNavigationPolicy::TryAllNavigationPolicy(const Config& config, TryAllNavigationPolicy::TryAllNavigationPolicy(const GeometryContext& gctx, const TrackingVolume& volume, const Logger& logger) - : TryAllNavigationPolicy({}, gctx, volume, logger) {} + : TryAllNavigationPolicy(gctx, volume, logger, {}) {} void TryAllNavigationPolicy::initializeCandidates( const NavigationArguments& args, AppendOnlyNavigationStream& stream, diff --git a/Core/src/Seeding/EstimateTrackParamsFromSeed.cpp b/Core/src/Seeding/EstimateTrackParamsFromSeed.cpp index eebcd1c5760..055691bbb2f 100644 --- a/Core/src/Seeding/EstimateTrackParamsFromSeed.cpp +++ b/Core/src/Seeding/EstimateTrackParamsFromSeed.cpp @@ -12,6 +12,84 @@ #include +Acts::FreeVector Acts::estimateTrackParamsFromSeed(const Vector3& sp0, + const Vector3& sp1, + const Vector3& sp2, + const Vector3& bField) { + // Define a new coordinate frame with its origin at the bottom space point, z + // axis long the magnetic field direction and y axis perpendicular to vector + // from the bottom to middle space point. Hence, the projection of the middle + // space point on the transverse plane will be located at the x axis of the + // new frame. + Vector3 relVec = sp1 - sp0; + Vector3 newZAxis = bField.normalized(); + Vector3 newYAxis = newZAxis.cross(relVec).normalized(); + Vector3 newXAxis = newYAxis.cross(newZAxis); + RotationMatrix3 rotation; + rotation.col(0) = newXAxis; + rotation.col(1) = newYAxis; + rotation.col(2) = newZAxis; + // The center of the new frame is at the bottom space point + Translation3 trans(sp0); + // The transform which constructs the new frame + Transform3 transform(trans * rotation); + + // The coordinate of the middle and top space point in the new frame + Vector3 local1 = transform.inverse() * sp1; + Vector3 local2 = transform.inverse() * sp2; + + // In the new frame the bottom sp is at the origin, while the middle + // sp in along the x axis. As such, the x-coordinate of the circle is + // at: x-middle / 2. + // The y coordinate can be found by using the straight line passing + // between the mid point between the middle and top sp and perpendicular to + // the line connecting them + Vector2 circleCenter; + circleCenter(0) = 0.5 * local1(0); + + ActsScalar deltaX21 = local2(0) - local1(0); + ActsScalar sumX21 = local2(0) + local1(0); + // straight line connecting the two points + // y = a * x + c (we don't care about c right now) + // we simply need the slope + // we compute 1./a since this is what we need for the following computation + ActsScalar ia = deltaX21 / local2(1); + // Perpendicular line is then y = -1/a *x + b + // we can evaluate b given we know a already by imposing + // the line passes through P = (0.5 * (x2 + x1), 0.5 * y2) + ActsScalar b = 0.5 * (local2(1) + ia * sumX21); + circleCenter(1) = -ia * circleCenter(0) + b; + // Radius is a signed distance between circleCenter and first sp, which is at + // (0, 0) in the new frame. Sign depends on the slope a (positive vs negative) + int sign = ia > 0 ? -1 : 1; + const ActsScalar R = circleCenter.norm(); + ActsScalar invTanTheta = + local2.z() / (2 * R * std::asin(local2.head<2>().norm() / (2 * R))); + // The momentum direction in the new frame (the center of the circle has the + // coordinate (-1.*A/(2*B), 1./(2*B))) + ActsScalar A = -circleCenter(0) / circleCenter(1); + Vector3 transDirection(1., A, fastHypot(1, A) * invTanTheta); + // Transform it back to the original frame + Vector3 direction = rotation * transDirection.normalized(); + + // Initialize the free parameters vector + FreeVector params = FreeVector::Zero(); + + // The bottom space point position + params.segment<3>(eFreePos0) = sp0; + + // The estimated direction + params.segment<3>(eFreeDir0) = direction; + + // The estimated q/pt in [GeV/c]^-1 (note that the pt is the projection of + // momentum on the transverse plane of the new frame) + ActsScalar qOverPt = sign / (bField.norm() * R); + // The estimated q/p in [GeV/c]^-1 + params[eFreeQOverP] = qOverPt / fastHypot(1., invTanTheta); + + return params; +} + Acts::BoundMatrix Acts::estimateTrackParamCovariance( const EstimateTrackParamCovarianceConfig& config, const BoundVector& params, bool hasTime) { diff --git a/Core/src/TrackFitting/GlobalChiSquareFitter.cpp b/Core/src/TrackFitting/GlobalChiSquareFitter.cpp index de61ee090d4..50b8b4cab8c 100644 --- a/Core/src/TrackFitting/GlobalChiSquareFitter.cpp +++ b/Core/src/TrackFitting/GlobalChiSquareFitter.cpp @@ -10,6 +10,30 @@ #include "Acts/Definitions/TrackParametrization.hpp" +void Acts::Experimental::updateGx2fParams( + BoundTrackParameters& params, const Eigen::VectorXd& deltaParamsExtended, + const std::size_t nMaterialSurfaces, + std::unordered_map& scatteringMap, + const std::vector& geoIdVector) { + // update params + params.parameters() += + deltaParamsExtended.topLeftCorner().eval(); + + // update the scattering angles. + for (std::size_t matSurface = 0; matSurface < nMaterialSurfaces; + matSurface++) { + const std::size_t deltaPosition = eBoundSize + 2 * matSurface; + const GeometryIdentifier geoId = geoIdVector[matSurface]; + const auto scatteringMapId = scatteringMap.find(geoId); + assert(scatteringMapId != scatteringMap.end() && + "No scattering angles found for material surface."); + scatteringMapId->second.scatteringAngles().block<2, 1>(2, 0) += + deltaParamsExtended.block<2, 1>(deltaPosition, 0).eval(); + } + + return; +} + void Acts::Experimental::updateGx2fCovarianceParams( BoundMatrix& fullCovariancePredicted, Gx2fSystem& extendedSystem) { // make invertible diff --git a/Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/TrackFindingAlgorithm.hpp b/Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/TrackFindingAlgorithm.hpp index c56e9508c9b..0f532be2d28 100644 --- a/Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/TrackFindingAlgorithm.hpp +++ b/Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/TrackFindingAlgorithm.hpp @@ -37,7 +37,10 @@ #include #include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wold-style-cast" #include +#pragma GCC diagnostic pop namespace Acts { class MagneticFieldProvider; diff --git a/Examples/Framework/include/ActsExamples/Framework/RandomNumbers.hpp b/Examples/Framework/include/ActsExamples/Framework/RandomNumbers.hpp index 6f9f9abbcd6..a94bac778f6 100644 --- a/Examples/Framework/include/ActsExamples/Framework/RandomNumbers.hpp +++ b/Examples/Framework/include/ActsExamples/Framework/RandomNumbers.hpp @@ -6,18 +6,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -// -// RandomNumbers.hpp -// ActsExamples -// -// Created by Andreas Salzburger on 17/05/16. -// -// - #pragma once -#include "ActsExamples/Framework/AlgorithmContext.hpp" - #include #include @@ -27,6 +17,9 @@ struct AlgorithmContext; /// The random number generator used in the framework. using RandomEngine = std::mt19937; ///< Mersenne Twister +/// The seed type used in the framework. +using RandomSeed = std::uint32_t; + /// Provide event and algorithm specific random number generator.s /// /// This provides local random number generators, allowing for @@ -41,7 +34,7 @@ using RandomEngine = std::mt19937; ///< Mersenne Twister class RandomNumbers { public: struct Config { - std::uint64_t seed = 1234567890u; ///< random seed + RandomSeed seed = 1234567890u; ///< random seed }; explicit RandomNumbers(const Config& cfg); @@ -59,7 +52,7 @@ class RandomNumbers { /// /// This should only be used in special cases e.g. where a custom /// random engine is used and `spawnGenerator` can not be used. - std::uint64_t generateSeed(const AlgorithmContext& context) const; + RandomSeed generateSeed(const AlgorithmContext& context) const; private: Config m_cfg; diff --git a/Examples/Framework/src/Framework/RandomNumbers.cpp b/Examples/Framework/src/Framework/RandomNumbers.cpp index 5fd0cdcf7d7..4313a5cce77 100644 --- a/Examples/Framework/src/Framework/RandomNumbers.cpp +++ b/Examples/Framework/src/Framework/RandomNumbers.cpp @@ -6,26 +6,21 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -// -// RandomNumbers.cpp -// ActsExamples -// -// Created by Andreas Salzburger on 17/05/16. -// -// - #include "ActsExamples/Framework/RandomNumbers.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" -ActsExamples::RandomNumbers::RandomNumbers(const Config& cfg) : m_cfg(cfg) {} +namespace ActsExamples { + +RandomNumbers::RandomNumbers(const Config& cfg) : m_cfg(cfg) {} -ActsExamples::RandomEngine ActsExamples::RandomNumbers::spawnGenerator( +RandomEngine RandomNumbers::spawnGenerator( const AlgorithmContext& context) const { return RandomEngine(generateSeed(context)); } -std::uint64_t ActsExamples::RandomNumbers::generateSeed( - const AlgorithmContext& context) const { +RandomSeed RandomNumbers::generateSeed(const AlgorithmContext& context) const { return m_cfg.seed + context.eventNumber; } + +} // namespace ActsExamples diff --git a/Examples/Io/Root/src/RootMaterialTrackReader.cpp b/Examples/Io/Root/src/RootMaterialTrackReader.cpp index 8781b134559..70b2ab8d997 100644 --- a/Examples/Io/Root/src/RootMaterialTrackReader.cpp +++ b/Examples/Io/Root/src/RootMaterialTrackReader.cpp @@ -89,6 +89,10 @@ RootMaterialTrackReader::RootMaterialTrackReader(const Config& config, // Sort the entry numbers of the events { + // necessary to guarantee that m_inputChain->GetV1() is valid for the + // entire range + m_inputChain->SetEstimate(nentries + 1); + m_entryNumbers.resize(nentries); m_inputChain->Draw("event_id", "", "goff"); RootUtility::stableSort(m_inputChain->GetEntries(), m_inputChain->GetV1(), diff --git a/Examples/Io/Root/src/RootParticleReader.cpp b/Examples/Io/Root/src/RootParticleReader.cpp index a76255dbb4a..631fc25ef3e 100644 --- a/Examples/Io/Root/src/RootParticleReader.cpp +++ b/Examples/Io/Root/src/RootParticleReader.cpp @@ -80,6 +80,10 @@ RootParticleReader::RootParticleReader(const RootParticleReader::Config& config, // Sort the entry numbers of the events { + // necessary to guarantee that m_inputChain->GetV1() is valid for the + // entire range + m_inputChain->SetEstimate(m_events + 1); + m_entryNumbers.resize(m_events); m_inputChain->Draw("event_id", "", "goff"); RootUtility::stableSort(m_inputChain->GetEntries(), m_inputChain->GetV1(), diff --git a/Examples/Io/Root/src/RootTrackSummaryReader.cpp b/Examples/Io/Root/src/RootTrackSummaryReader.cpp index 1827c26ad30..9ff3590271a 100644 --- a/Examples/Io/Root/src/RootTrackSummaryReader.cpp +++ b/Examples/Io/Root/src/RootTrackSummaryReader.cpp @@ -99,6 +99,10 @@ RootTrackSummaryReader::RootTrackSummaryReader( // Sort the entry numbers of the events { + // necessary to guarantee that m_inputChain->GetV1() is valid for the + // entire range + m_inputChain->SetEstimate(m_events + 1); + m_entryNumbers.resize(m_events); m_inputChain->Draw("event_nr", "", "goff"); RootUtility::stableSort(m_inputChain->GetEntries(), m_inputChain->GetV1(), diff --git a/Examples/Io/Root/src/RootVertexReader.cpp b/Examples/Io/Root/src/RootVertexReader.cpp index 336e0364f9b..31a8e6d5bec 100644 --- a/Examples/Io/Root/src/RootVertexReader.cpp +++ b/Examples/Io/Root/src/RootVertexReader.cpp @@ -8,13 +8,12 @@ #include "ActsExamples/Io/Root/RootVertexReader.hpp" -#include "Acts/Definitions/PdgParticle.hpp" #include "Acts/Utilities/Logger.hpp" #include "ActsExamples/EventData/SimParticle.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" +#include "ActsExamples/Io/Root/RootUtility.hpp" #include "ActsFatras/EventData/ProcessType.hpp" -#include #include #include #include @@ -64,11 +63,14 @@ RootVertexReader::RootVertexReader(const RootVertexReader::Config& config, // Sort the entry numbers of the events { + // necessary to guarantee that m_inputChain->GetV1() is valid for the + // entire range + m_inputChain->SetEstimate(m_events + 1); + m_entryNumbers.resize(m_events); m_inputChain->Draw("event_id", "", "goff"); - // Sort to get the entry numbers of the ordered events - TMath::Sort(m_inputChain->GetEntries(), m_inputChain->GetV1(), - m_entryNumbers.data(), false); + RootUtility::stableSort(m_inputChain->GetEntries(), m_inputChain->GetV1(), + m_entryNumbers.data(), false); } } diff --git a/Examples/Io/Root/src/SeedingPerformanceWriter.cpp b/Examples/Io/Root/src/SeedingPerformanceWriter.cpp index d11de8bc018..e37f115093d 100644 --- a/Examples/Io/Root/src/SeedingPerformanceWriter.cpp +++ b/Examples/Io/Root/src/SeedingPerformanceWriter.cpp @@ -13,7 +13,6 @@ #include "ActsExamples/Utilities/EventDataTransforms.hpp" #include "ActsExamples/Validation/TrackClassification.hpp" #include "ActsFatras/EventData/Barcode.hpp" -#include "ActsFatras/EventData/Particle.hpp" #include #include @@ -28,10 +27,6 @@ using Acts::VectorHelpers::eta; using Acts::VectorHelpers::phi; -namespace ActsExamples { -struct AlgorithmContext; -} // namespace ActsExamples - ActsExamples::SeedingPerformanceWriter::SeedingPerformanceWriter( ActsExamples::SeedingPerformanceWriter::Config config, Acts::Logging::Level level) @@ -127,6 +122,9 @@ ActsExamples::ProcessCode ActsExamples::SeedingPerformanceWriter::writeT( const auto& particles = m_inputParticles(ctx); const auto& hitParticlesMap = m_inputMeasurementParticlesMap(ctx); + // Exclusive access to the tree while writing + std::lock_guard lock(m_writeMutex); + std::size_t nSeeds = seeds.size(); std::size_t nMatchedSeeds = 0; // Map from particles to how many times they were successfully found by a seed diff --git a/Examples/Python/src/Material.cpp b/Examples/Python/src/Material.cpp index 5bc5aa6a1f3..6855fdc1737 100644 --- a/Examples/Python/src/Material.cpp +++ b/Examples/Python/src/Material.cpp @@ -81,7 +81,9 @@ void addMaterial(Context& ctx) { { py::class_>(m, - "IMaterialDecorator"); + "IMaterialDecorator") + .def("decorate", py::overload_cast( + &Acts::IMaterialDecorator::decorate, py::const_)); } { diff --git a/Examples/Python/src/Navigation.cpp b/Examples/Python/src/Navigation.cpp index 733bbe1a151..a4f55a532ac 100644 --- a/Examples/Python/src/Navigation.cpp +++ b/Examples/Python/src/Navigation.cpp @@ -37,6 +37,10 @@ struct AnyNavigationPolicyFactory : public Acts::NavigationPolicyFactory { virtual std::unique_ptr add( TypeTag /*type*/, SurfaceArrayNavigationPolicy::Config config) = 0; + + virtual std::unique_ptr add( + TypeTag /*type*/, + TryAllNavigationPolicy::Config config) = 0; }; template , @@ -61,6 +65,12 @@ struct NavigationPolicyFactoryT : public AnyNavigationPolicyFactory { return add(std::move(config)); } + std::unique_ptr add( + TypeTag /*type*/, + TryAllNavigationPolicy::Config config) override { + return add(config); + } + std::unique_ptr build( const GeometryContext& gctx, const TrackingVolume& volume, const Logger& logger) const override { @@ -108,6 +118,12 @@ class NavigationPolicyFactory : public Acts::NavigationPolicyFactory { return *this; } + NavigationPolicyFactory& addTryAll( + const py::object& /*cls*/, const TryAllNavigationPolicy::Config& config) { + m_impl = m_impl->add(Type, config); + return *this; + } + std::unique_ptr build( const GeometryContext& gctx, const TrackingVolume& volume, const Logger& logger) const override { @@ -153,7 +169,16 @@ void addNavigation(Context& ctx) { std::shared_ptr>( m, "_NavigationPolicyFactory"); - py::class_(m, "TryAllNavigationPolicy"); + { + auto tryAll = + py::class_(m, "TryAllNavigationPolicy"); + using Config = TryAllNavigationPolicy::Config; + auto c = py::class_(tryAll, "Config").def(py::init<>()); + ACTS_PYTHON_STRUCT_BEGIN(c, Config); + ACTS_PYTHON_MEMBER(portals); + ACTS_PYTHON_MEMBER(sensitives); + ACTS_PYTHON_STRUCT_END(); + } py::class_>( @@ -162,6 +187,7 @@ void addNavigation(Context& ctx) { .def_static("make", []() { return NavigationPolicyFactory{}; }) .def("add", &NavigationPolicyFactory::addNoArguments) .def("add", &NavigationPolicyFactory::addSurfaceArray) + .def("add", &NavigationPolicyFactory::addTryAll) .def("_buildTest", [](NavigationPolicyFactory& self) { auto vol1 = std::make_shared( Transform3::Identity(), diff --git a/Examples/Python/tests/requirements_ubuntu2004.in b/Examples/Python/tests/requirements_ubuntu2004.in deleted file mode 100644 index 86f307d37e4..00000000000 --- a/Examples/Python/tests/requirements_ubuntu2004.in +++ /dev/null @@ -1,9 +0,0 @@ -# to support python 3.8 in CI: test_exatrkx_python (ubuntu2004) -# higher versions of numpy don't support python 3.8 -numpy==1.24.4 - -pytest -pytest-check -uproot -awkward -pyyaml diff --git a/Examples/Python/tests/requirements_ubuntu2004.txt b/Examples/Python/tests/requirements_ubuntu2004.txt deleted file mode 100644 index 04521b16770..00000000000 --- a/Examples/Python/tests/requirements_ubuntu2004.txt +++ /dev/null @@ -1,53 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.10 -# by the following command: -# -# pip-compile Examples/Python/tests/requirements_ubuntu2004.in -# -awkward==2.6.1 - # via - # -r Examples/Python/tests/requirements_ubuntu2004.in - # uproot -awkward-cpp==29 - # via awkward -exceptiongroup==1.2.0 - # via pytest -fsspec==2024.2.0 - # via - # awkward - # uproot -importlib-metadata==7.0.1 - # via awkward -iniconfig==2.0.0 - # via pytest -numpy==1.24.4 - # via - # -r Examples/Python/tests/requirements_ubuntu2004.in - # awkward - # awkward-cpp - # uproot -packaging==23.2 - # via - # awkward - # pytest - # uproot -pluggy==1.4.0 - # via pytest -pytest==8.0.0 - # via - # -r Examples/Python/tests/requirements_ubuntu2004.in - # pytest-check -pytest-check==2.3.1 - # via -r Examples/Python/tests/requirements_ubuntu2004.in -pyyaml==6.0.1 - # via -r Examples/Python/tests/requirements_ubuntu2004.in -tomli==2.0.1 - # via pytest -typing-extensions==4.9.0 - # via - # awkward - # uproot -uproot==5.2.2 - # via -r Examples/Python/tests/requirements_ubuntu2004.in -zipp==3.17.0 - # via importlib-metadata diff --git a/Examples/Python/tests/root_file_hashes.txt b/Examples/Python/tests/root_file_hashes.txt index c6ed65f4564..45337b2f762 100644 --- a/Examples/Python/tests/root_file_hashes.txt +++ b/Examples/Python/tests/root_file_hashes.txt @@ -3,16 +3,16 @@ test_fatras__particles_simulation.root: bc970873fef0c2efd86ed5413623802353d2cd04 test_fatras__hits.root: 6e4beb045fa1712c4d14c280ba33c3fa13e4aff9de88d55c3e32f62ad226f724 test_geant4__particles_simulation.root: 49926c71a9b54e13aa1cc7596d3302baf3c87d8e2c1d0267cb4523f6abdc0ac2 test_geant4__hits.root: 4c9e704a75f47ed2e61652679a1d6f18fa4d9cf53faa8f8f5bbf7995634207aa -test_seeding__estimatedparams.root: 69c0e268f9025a0991a212ea2a7f26f53112fecf614b475605bd1cb08415ba56 +test_seeding__estimatedparams.root: 6759004f945cabe03098c94b3eea7e3323acd9f37edfa71641797007336643c8 test_seeding__performance_seeding.root: 992f9c611d30dde0d3f3ab676bab19ada61ab6a4442828e27b65ec5e5b7a2880 test_seeding__particles.root: c423bc666df3674f1a1140dec68ea13f44173232b8057e8a02572aee4f3e7d5b test_seeding__particles_simulation.root: f937a4cc474e80cfbb6eac4384e42e9c5c7ac981fcd6870d624cc898d1a0c006 -test_hashing_seeding__estimatedparams.root: 8daa3f04342c265f32f1608ccc921ab0041686a6280b956f811638ad4328330e -test_seeding_orthogonal__estimatedparams.root: ca5896ec325daf5c8012291bc454269c61c32fe3d7e33bd1fa3b812826930299 +test_hashing_seeding__estimatedparams.root: 6b52f27b2feac2fa46a8ed52abacfe6dc8e6319f86e031cdc2f9ba28a0393cb2 +test_seeding_orthogonal__estimatedparams.root: 6cb69ee239e11ff112dd50c2bcfe945a6f7b00e43e13b2cba4e08f1bfcf6a583 test_seeding_orthogonal__performance_seeding.root: 60fbedcf5cb2b37cd8e526251940564432890d3a159d231ed819e915a904682c test_seeding_orthogonal__particles.root: c423bc666df3674f1a1140dec68ea13f44173232b8057e8a02572aee4f3e7d5b test_seeding_orthogonal__particles_simulation.root: f937a4cc474e80cfbb6eac4384e42e9c5c7ac981fcd6870d624cc898d1a0c006 -test_itk_seeding__estimatedparams.root: 1cc05f9f2aefb5f71a85b31e97bc4e5845fedfcef6c53199495a6340c6b6210b +test_itk_seeding__estimatedparams.root: fc042037f12a434f2236df7d225b8ca24209b6910f04a4496ae3a06516a6ff8c test_itk_seeding__performance_seeding.root: 78ebda54cd0f026ba4b7f316724ffd946de56a932735914baf1b7bba9505c29d test_itk_seeding__particles.root: 907ff693262c0db14b12c74b16586cb20d79caf5f03f93b178943e41ed35a1b6 test_itk_seeding__particles_simulation.root: ef0246069aa697019f28a8b270a68de95312cae5f2f2c74848566c3ce4f70363 @@ -33,19 +33,19 @@ test_digitization_example_input[smeared]__particles.root: 669d0304eb8bcf244aa627 test_digitization_example_input[smeared]__measurements.root: 243c2f69b7b0db9dbeaa7494d4ea0f3dd1691dc90f16e10df6c0491ff4dc7d62 test_digitization_example_input[geometric]__particles.root: 669d0304eb8bcf244aa627809a117944e5e3b994fdfcfb8710f2b9a8f9a62d3b test_digitization_example_input[geometric]__measurements.root: 63ec81635979058fb8976f94455bf490cf92b7b142c4a05cc39de6225f5de2fb -test_ckf_tracks_example[generic-full_seeding]__trackstates_ckf.root: 7c48ec32a2cb1723416a9791a8067ef09825fcf71a6cf561c1f6d2ab9dc1c1ad -test_ckf_tracks_example[generic-full_seeding]__tracksummary_ckf.root: e6b9e539998ba007e9b7d2c8d9d022c47726a39e8ab9b1724c52b1d78234be03 +test_ckf_tracks_example[generic-full_seeding]__trackstates_ckf.root: ec6487dfca5f944cfacfef903eb4b9a97f8f6a668d07f77d0c3ec45c68054824 +test_ckf_tracks_example[generic-full_seeding]__tracksummary_ckf.root: 84085bcc63562cfb1b4c70d2665bf06938ac559bb40c2b01c076e1d8b5c7b43b test_ckf_tracks_example[generic-full_seeding]__performance_seeding_trees.root: 0e0676ffafdb27112fbda50d1cf627859fa745760f98073261dcf6db3f2f991e -test_ckf_tracks_example[generic-truth_estimated]__trackstates_ckf.root: df730fd00a7e6a0941f5f94c07ea9cffdb763853272d284d25bec0eb2072bb2e -test_ckf_tracks_example[generic-truth_estimated]__tracksummary_ckf.root: 417f7326e1e1bb4519f1378145ac733bdda6653eb9871fd69e455e0269d996a6 +test_ckf_tracks_example[generic-truth_estimated]__trackstates_ckf.root: 8e15cceeef4b115708596702988925b7506d39e0531dc5534636ec411a9b4ca2 +test_ckf_tracks_example[generic-truth_estimated]__tracksummary_ckf.root: 8e0116c656e1cc67446d54a5205c4a3e2f4c1fc90fa551bb608c881877dfa0ab test_ckf_tracks_example[generic-truth_estimated]__performance_seeding.root: 1facb05c066221f6361b61f015cdf0918e94d9f3fce2269ec7b6a4dffeb2bc7e test_ckf_tracks_example[generic-truth_smeared]__trackstates_ckf.root: 82a6744980553e6274df78eea15f0dec22676b1c04e14afc3828bff9bbf5e1b1 test_ckf_tracks_example[generic-truth_smeared]__tracksummary_ckf.root: 06d6ae1d05cb611b19df3c59531997c9b0108f5ef6027d76c4827bd2d9edb921 -test_ckf_tracks_example[odd-full_seeding]__trackstates_ckf.root: 0fb43661cc3a7973c28940a283dc168ceb13bc60badf1f520096edaa5982a039 -test_ckf_tracks_example[odd-full_seeding]__tracksummary_ckf.root: c2e029e462d4ca77df2c7f8963093da43be66c8279ca2cc9aee8c0bc35259eec +test_ckf_tracks_example[odd-full_seeding]__trackstates_ckf.root: 17c48c5a61b1a5495d91336cdf06f9c24e50d81349c1f31d7c70ffff5810a376 +test_ckf_tracks_example[odd-full_seeding]__tracksummary_ckf.root: b5805e54030ab8ac80a8c0a764700c65433dc659783fc8ff3b2c96e512a1d045 test_ckf_tracks_example[odd-full_seeding]__performance_seeding_trees.root: 43c58577aafe07645e5660c4f43904efadf91d8cda45c5c04c248bbe0f59814f -test_ckf_tracks_example[odd-truth_estimated]__trackstates_ckf.root: 39ac67c47f371c576d7094bca987a04e0315bd286dc79503a63a5f568b58ac97 -test_ckf_tracks_example[odd-truth_estimated]__tracksummary_ckf.root: 59e2c75e9524653a80a9fd62fe99e958f73f80aa09240dcbb4ea469372e4811d +test_ckf_tracks_example[odd-truth_estimated]__trackstates_ckf.root: 86be5a086d2a87dfde9320bb880bd0788d733ea9727cb5ee6dc0282ec4be39f4 +test_ckf_tracks_example[odd-truth_estimated]__tracksummary_ckf.root: ffce6a73f16986cb3f0386d4a8c1e0ff6f0b4130b9bb12d1af0eb905d000e3e9 test_ckf_tracks_example[odd-truth_estimated]__performance_seeding.root: 1a36b7017e59f1c08602ef3c2cb0483c51df248f112e3780c66594110719c575 test_ckf_tracks_example[odd-truth_smeared]__trackstates_ckf.root: 35a65e15a6f479f628a96f56ee78e1ac371d71a686ee0c974944d681499fe6bd test_ckf_tracks_example[odd-truth_smeared]__tracksummary_ckf.root: 3e257de624674fa9a19dcc72598c78c29a52633821acaa56dc2aa39a1395f1b5 diff --git a/Examples/Python/tests/test_navigation.py b/Examples/Python/tests/test_navigation.py index 55ec8ac9540..56c908f7911 100644 --- a/Examples/Python/tests/test_navigation.py +++ b/Examples/Python/tests/test_navigation.py @@ -40,3 +40,9 @@ def test_navigation_policy_factory_add_multiple(): .add(acts.TryAllNavigationPolicy) .add(acts.TryAllNavigationPolicy) ) + + +def test_try_all_arguments(): + acts.NavigationPolicyFactory.make().add( + acts.TryAllNavigationPolicy, acts.TryAllNavigationPolicy.Config(sensitives=True) + ) diff --git a/Examples/Scripts/TrackingPerformance/TreeReader.h b/Examples/Scripts/TrackingPerformance/TreeReader.h index 4ab47746dc0..b12ce19d373 100644 --- a/Examples/Scripts/TrackingPerformance/TreeReader.h +++ b/Examples/Scripts/TrackingPerformance/TreeReader.h @@ -145,6 +145,7 @@ struct TrackStatesReader : public TreeReader { // It's not necessary if you just need to read one file, but please do it to // synchronize events if multiple root files are read if (sortEvents) { + tree->SetEstimate(tree->GetEntries() + 1); entryNumbers.resize(tree->GetEntries()); tree->Draw("event_nr", "", "goff"); // Sort to get the entry numbers of the ordered events @@ -338,6 +339,7 @@ struct TrackSummaryReader : public TreeReader { // It's not necessary if you just need to read one file, but please do it to // synchronize events if multiple root files are read if (sortEvents) { + tree->SetEstimate(tree->GetEntries() + 1); entryNumbers.resize(tree->GetEntries()); tree->Draw("event_nr", "", "goff"); // Sort to get the entry numbers of the ordered events @@ -368,7 +370,8 @@ struct TrackSummaryReader : public TreeReader { std::vector>* outlierLayer = new std::vector>; std::vector* nMajorityHits = new std::vector; - std::vector* majorityParticleId = new std::vector; + std::vector* majorityParticleId = + new std::vector; std::vector* hasFittedParams = new std::vector; @@ -427,6 +430,7 @@ struct ParticleReader : public TreeReader { // It's not necessary if you just need to read one file, but please do it to // synchronize events if multiple root files are read if (sortEvents) { + tree->SetEstimate(tree->GetEntries() + 1); entryNumbers.resize(tree->GetEntries()); tree->Draw("event_id", "", "goff"); // Sort to get the entry numbers of the ordered events @@ -436,7 +440,8 @@ struct ParticleReader : public TreeReader { } // Get all the particles with requested event id - std::vector getParticles(const std::uint32_t& eventNumber) const { + std::vector getParticles( + const std::uint32_t& eventNumber) const { // Find the start entry and the batch size for this event std::string eventNumberStr = std::to_string(eventNumber); std::string findStartEntry = "event_id<" + eventNumberStr; diff --git a/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackContainer.hpp b/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackContainer.hpp index b6cba524a8e..79ccf2249a1 100644 --- a/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackContainer.hpp +++ b/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackContainer.hpp @@ -238,7 +238,7 @@ class MutablePodioTrackContainer : public PodioTrackContainerBase { template constexpr void addColumn_impl(std::string_view key) { - Acts::HashedString hashedKey = hashString(key); + Acts::HashedString hashedKey = hashStringDynamic(key); m_dynamic.insert( {hashedKey, std::make_unique>(key)}); } diff --git a/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackStateContainer.hpp b/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackStateContainer.hpp index 8322249a654..e503f3ca2f3 100644 --- a/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackStateContainer.hpp +++ b/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackStateContainer.hpp @@ -610,7 +610,7 @@ class MutablePodioTrackStateContainer final template constexpr void addColumn_impl(std::string_view key) { - HashedString hashedKey = hashString(key); + HashedString hashedKey = hashStringDynamic(key); m_dynamic.insert( {hashedKey, std::make_unique>(key)}); } diff --git a/Plugins/Podio/src/PodioUtil.cpp b/Plugins/Podio/src/PodioUtil.cpp index 6518fcdff07..7b2fc0668a3 100644 --- a/Plugins/Podio/src/PodioUtil.cpp +++ b/Plugins/Podio/src/PodioUtil.cpp @@ -261,7 +261,7 @@ void recoverDynamicColumns( "' is not of allowed type"}; } - HashedString hashedKey = hashString(dynName); + HashedString hashedKey = hashStringDynamic(dynName); dynamic.insert({hashedKey, std::move(up)}); } } diff --git a/Tests/Benchmarks/CMakeLists.txt b/Tests/Benchmarks/CMakeLists.txt index b19e67fed59..0edff123e9d 100644 --- a/Tests/Benchmarks/CMakeLists.txt +++ b/Tests/Benchmarks/CMakeLists.txt @@ -32,3 +32,4 @@ add_benchmark(StraightLineStepper StraightLineStepperBenchmark.cpp) add_benchmark(SympyStepper SympyStepperBenchmark.cpp) add_benchmark(Stepper StepperBenchmark.cpp) add_benchmark(SourceLink SourceLinkBenchmark.cpp) +add_benchmark(TrackEdm TrackEdmBenchmark.cpp) diff --git a/Tests/Benchmarks/TrackEdmBenchmark.cpp b/Tests/Benchmarks/TrackEdmBenchmark.cpp new file mode 100644 index 00000000000..b063254e154 --- /dev/null +++ b/Tests/Benchmarks/TrackEdmBenchmark.cpp @@ -0,0 +1,184 @@ +// 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/EventData/SubspaceHelpers.hpp" +#include "Acts/EventData/TrackContainer.hpp" +#include "Acts/EventData/TrackStatePropMask.hpp" +#include "Acts/EventData/TrackStateType.hpp" +#include "Acts/EventData/VectorMultiTrajectory.hpp" +#include "Acts/EventData/VectorTrackContainer.hpp" +#include "Acts/EventData/detail/GenerateParameters.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Surfaces/PerigeeSurface.hpp" +#include "Acts/Surfaces/PlaneSurface.hpp" +#include "Acts/Surfaces/RectangleBounds.hpp" +#include "Acts/Utilities/TrackHelpers.hpp" + +#include +#include +#include +#include + +using namespace Acts; + +class BenchmarkSourceLink final { + public: + using Index = std::uint32_t; + + /// Construct from geometry identifier and index. + constexpr BenchmarkSourceLink(Acts::GeometryIdentifier gid, Index idx) + : m_geometryId(gid), m_index(idx) {} + + BenchmarkSourceLink() = default; + BenchmarkSourceLink(const BenchmarkSourceLink&) = default; + BenchmarkSourceLink(BenchmarkSourceLink&&) = default; + BenchmarkSourceLink& operator=(const BenchmarkSourceLink&) = default; + BenchmarkSourceLink& operator=(BenchmarkSourceLink&&) = default; + + /// Access the index. + constexpr Index index() const { return m_index; } + + Acts::GeometryIdentifier geometryId() const { return m_geometryId; } + + private: + Acts::GeometryIdentifier m_geometryId; + Index m_index = 0; + + friend bool operator==(const BenchmarkSourceLink& lhs, + const BenchmarkSourceLink& rhs) { + return (lhs.geometryId() == rhs.geometryId()) && + (lhs.m_index == rhs.m_index); + } +}; + +int main(int /*argc*/, char** /*argv[]*/) { + std::size_t runs = 1000000; + std::size_t nTracks = 10000; + + VectorMultiTrajectory mtj; + VectorTrackContainer vtc; + TrackContainer tc{vtc, mtj}; + + VectorMultiTrajectory mtjOut; + VectorTrackContainer vtcOut; + TrackContainer output{vtcOut, mtjOut}; + + GeometryIdentifier gid; + gid.setVolume(5); + gid.setLayer(3); + gid.setSensitive(1); + + static_assert(sizeof(BenchmarkSourceLink) <= ACTS_SOURCELINK_SBO_SIZE); + + static_assert(std::is_trivially_move_constructible_v); + + std::uniform_int_distribution<> nStatesDist(1, 20); + std::uniform_int_distribution<> measDimDist(1, 3); + std::uniform_real_distribution<> typeDist(0, 1); + std::uniform_real_distribution<> copyDist(0, 1); + std::mt19937 rng{42}; + + std::vector> surfaces; + std::vector> parametersVector; + for (std::size_t s = 0; s < 50; ++s) { + surfaces.push_back(Surface::makeShared( + Transform3::Identity(), std::make_shared(50, 50))); + + parametersVector.push_back( + detail::Test::generateBoundParametersCovariance(rng, {})); + } + + std::size_t nSurface = 0; + auto surface = [&]() { + nSurface++; + return surfaces.at(nSurface % surfaces.size()); + }; + + std::size_t nParams = 0; + auto parameters = [&]() -> const std::pair& { + nParams++; + return parametersVector.at(nParams % parametersVector.size()); + }; + + auto perigee = Surface::makeShared(Vector3::Zero()); + + std::cout << "Creating " << nTracks << " tracks x " << runs << " runs" + << std::endl; + for (std::size_t r = 0; r < runs; ++r) { + tc.clear(); + for (std::size_t i = 0; i < nTracks; ++i) { + auto track = tc.makeTrack(); + + std::size_t nStates = nStatesDist(rng); + + for (std::size_t j = 0; j < nStates; ++j) { + auto trackState = track.appendTrackState(TrackStatePropMask::All); + trackState.setReferenceSurface(surface()); + + trackState.jacobian().setZero(); + trackState.jacobian().row(j % eBoundSize).setOnes(); + + double crit = typeDist(rng); + + if (crit < 0.1) { + // hole + trackState.typeFlags().set(TrackStateFlag::HoleFlag); + } else if (crit < 0.2) { + // material + trackState.typeFlags().set(TrackStateFlag::MaterialFlag); + } else { + BenchmarkSourceLink bsl{gid, 123}; + trackState.allocateCalibrated(measDimDist(rng)); + + const auto& [predicted, covariance] = parameters(); + trackState.predicted() = predicted; + trackState.predictedCovariance() = covariance; + + visit_measurement( + trackState.calibratedSize(), + [&](std::integral_constant /*d*/) { + trackState.calibrated().setOnes(); + trackState.calibratedCovariance().setIdentity(); + + std::array indices{0}; + std::iota(indices.begin(), indices.end(), 0); + trackState.setBoundSubspaceIndices(indices); + }); + + trackState.typeFlags().set(TrackStateFlag::MeasurementFlag); + if (crit < 0.4) { + // outlier + trackState.typeFlags().set(TrackStateFlag::OutlierFlag); + } + } + } + + track.setReferenceSurface(perigee); + + const auto& [ref, cov] = parameters(); + track.parameters() = ref; + track.covariance() = cov; + + track.linkForward(); + + calculateTrackQuantities(track); + } + + for (const auto& track : tc) { + if (copyDist(rng) > 0.1) { + // copy only 10% of tracks + continue; + } + + auto target = output.makeTrack(); + target.copyFrom(track); + } + } + + return 0; +} diff --git a/Tests/UnitTests/Core/Seeding/EstimateTrackParamsFromSeedTest.cpp b/Tests/UnitTests/Core/Seeding/EstimateTrackParamsFromSeedTest.cpp index de15f7e09c2..e39a6a1a900 100644 --- a/Tests/UnitTests/Core/Seeding/EstimateTrackParamsFromSeedTest.cpp +++ b/Tests/UnitTests/Core/Seeding/EstimateTrackParamsFromSeedTest.cpp @@ -9,10 +9,8 @@ #include #include "Acts/Definitions/Algebra.hpp" -#include "Acts/Definitions/Direction.hpp" #include "Acts/Definitions/TrackParametrization.hpp" #include "Acts/Definitions/Units.hpp" -#include "Acts/EventData/GenericCurvilinearTrackParameters.hpp" #include "Acts/EventData/TrackParameters.hpp" #include "Acts/EventData/detail/TestSourceLink.hpp" #include "Acts/Geometry/GeometryContext.hpp" @@ -29,7 +27,6 @@ #include "Acts/Tests/CommonHelpers/CylindricalTrackingGeometry.hpp" #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp" #include "Acts/Tests/CommonHelpers/MeasurementsCreator.hpp" -#include "Acts/Utilities/CalibrationContext.hpp" #include "Acts/Utilities/Logger.hpp" #include @@ -39,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -99,8 +95,8 @@ BOOST_AUTO_TEST_CASE(trackparameters_estimation_test) { true, // material false // passive }); - auto field = - std::make_shared(Acts::Vector3(0.0, 0.0, 2._T)); + const Vector3 bField(0, 0, 2._T); + auto field = std::make_shared(bField); ConstantFieldStepper stepper(std::move(field)); ConstantFieldPropagator propagator(std::move(stepper), std::move(navigator)); @@ -165,9 +161,6 @@ BOOST_AUTO_TEST_CASE(trackparameters_estimation_test) { BOOST_TEST_INFO( "The truth track parameters at the bottom space point: \n" << expParams.transpose()); - // The curvature of track projection on the transverse plane in unit - // of 1/mm - double rho = expParams[eBoundQOverP] * 0.3 * 2. / UnitConstants::m; // The space point pointers std::array spacePointPtrs{}; @@ -175,30 +168,15 @@ BOOST_AUTO_TEST_CASE(trackparameters_estimation_test) { spacePointPtrs.begin(), [](const auto& sp) { return &sp.second; }); - // Test the partial track parameters estimator - auto partialParamsOpt = estimateTrackParamsFromSeed( - spacePointPtrs.begin(), spacePointPtrs.end(), *logger); - BOOST_REQUIRE(partialParamsOpt.has_value()); - const auto& estPartialParams = partialParamsOpt.value(); - BOOST_TEST_INFO( - "The estimated track parameters at the transverse plane: \n" - << estPartialParams.transpose()); - - // The particle starting position is (0, 0, 0). Hence, d0 is zero; the - // phi at the point of cloest approach is exactly the phi of the truth - // particle - CHECK_CLOSE_ABS(estPartialParams[eBoundLoc0], 0., 1e-5); - CHECK_CLOSE_ABS(estPartialParams[eBoundPhi], phi, 1e-5); - CHECK_CLOSE_ABS(estPartialParams[eBoundQOverP], rho, 1e-4); - // The loc1, theta and time are set to zero in the estimator - CHECK_CLOSE_ABS(estPartialParams[eBoundLoc1], 0., 1e-10); - CHECK_CLOSE_ABS(estPartialParams[eBoundTheta], 0., 1e-10); - CHECK_CLOSE_ABS(estPartialParams[eBoundTime], 0., 1e-10); - - // Test the full track parameters estimator + // Test the free track parameters estimator + FreeVector estFreeParams = + estimateTrackParamsFromSeed(spacePointPtrs, bField); + BOOST_CHECK(!estFreeParams.hasNaN()); + + // Test the bound track parameters estimator auto fullParamsOpt = estimateTrackParamsFromSeed( geoCtx, spacePointPtrs.begin(), spacePointPtrs.end(), - *bottomSurface, Vector3(0, 0, 2._T), 0.1_T, *logger); + *bottomSurface, bField, 0.1_T, *logger); BOOST_REQUIRE(fullParamsOpt.has_value()); const auto& estFullParams = fullParamsOpt.value(); BOOST_TEST_INFO( diff --git a/Tests/UnitTests/Core/Surfaces/SurfaceBoundsTests.cpp b/Tests/UnitTests/Core/Surfaces/SurfaceBoundsTests.cpp index e150e9a64c9..470512383a0 100644 --- a/Tests/UnitTests/Core/Surfaces/SurfaceBoundsTests.cpp +++ b/Tests/UnitTests/Core/Surfaces/SurfaceBoundsTests.cpp @@ -27,13 +27,15 @@ class SurfaceBoundsStub : public SurfaceBounds { std::iota(m_values.begin(), m_values.end(), 0); } -#if defined(__GNUC__) && __GNUC__ == 13 && !defined(__clang__) +#if defined(__GNUC__) && (__GNUC__ == 13 || __GNUC__ == 14) && \ + !defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Warray-bounds" #pragma GCC diagnostic ignored "-Wstringop-overflow" #endif SurfaceBoundsStub(const SurfaceBoundsStub& other) = default; -#if defined(__GNUC__) && __GNUC__ == 13 && !defined(__clang__) +#if defined(__GNUC__) && (__GNUC__ == 13 || __GNUC__ == 14) && \ + !defined(__clang__) #pragma GCC diagnostic pop #endif diff --git a/Tests/UnitTests/Core/TrackFitting/Gx2fTests.cpp b/Tests/UnitTests/Core/TrackFitting/Gx2fTests.cpp index e3dbe1d4cde..71b2bf2b1f8 100644 --- a/Tests/UnitTests/Core/TrackFitting/Gx2fTests.cpp +++ b/Tests/UnitTests/Core/TrackFitting/Gx2fTests.cpp @@ -1108,15 +1108,15 @@ BOOST_AUTO_TEST_CASE(Material) { // Parameters // We need quite coarse checks here, since on different builds // the created measurements differ in the randomness - BOOST_CHECK_CLOSE(track.parameters()[eBoundLoc0], -11., 7e0); - BOOST_CHECK_CLOSE(track.parameters()[eBoundLoc1], -15., 6e0); - BOOST_CHECK_CLOSE(track.parameters()[eBoundPhi], 1e-5, 1e3); + BOOST_CHECK_CLOSE(track.parameters()[eBoundLoc0], -11., 26e0); + BOOST_CHECK_CLOSE(track.parameters()[eBoundLoc1], -15., 15e0); + BOOST_CHECK_CLOSE(track.parameters()[eBoundPhi], 1e-5, 1.1e3); BOOST_CHECK_CLOSE(track.parameters()[eBoundTheta], std::numbers::pi / 2, - 1e-3); + 2e-2); BOOST_CHECK_EQUAL(track.parameters()[eBoundQOverP], 1); BOOST_CHECK_CLOSE(track.parameters()[eBoundTime], startParametersFit.parameters()[eBoundTime], 1e-6); - // BOOST_CHECK_CLOSE(track.covariance().determinant(), 1e-27, 4e0); + BOOST_CHECK_CLOSE(track.covariance().determinant(), 3.5e-27, 1e1); // Convergence BOOST_CHECK_EQUAL( diff --git a/Tests/UnitTests/Core/Utilities/BoundingBoxTest.cpp b/Tests/UnitTests/Core/Utilities/BoundingBoxTest.cpp index f3aa6b2de14..675d7d49320 100644 --- a/Tests/UnitTests/Core/Utilities/BoundingBoxTest.cpp +++ b/Tests/UnitTests/Core/Utilities/BoundingBoxTest.cpp @@ -46,10 +46,10 @@ using Vector3F = Eigen::Matrix; using AngleAxis3F = Eigen::AngleAxis; std::filesystem::path tmp_path = []() { - auto p = std::filesystem::temp_directory_path() / "acts_unit_tests"; - std::filesystem::create_directory(p); - std::cout << "Writing test output to: " << p << std::endl; - return p; + auto tmpPath = std::filesystem::temp_directory_path() / "acts_unit_tests"; + std::filesystem::create_directory(tmpPath); + std::cout << "Writing test output to: " << tmpPath << std::endl; + return tmpPath; }(); std::ofstream tmp(const std::string& path) { @@ -140,7 +140,6 @@ BOOST_AUTO_TEST_CASE(intersect_points) { } BOOST_AUTO_TEST_CASE(intersect_rays) { - /* temporarily removed, fails with double precision BOOST_TEST_CONTEXT("2D") { using Box = AxisAlignedBoundingBox; @@ -158,9 +157,9 @@ BOOST_AUTO_TEST_CASE(intersect_rays) { ray = {{-2, -2}, {1, 0}}; BOOST_CHECK(!bb.intersect(ray)); - // upper bound is exclusive - ray = {{-2, 1}, {1, 0}}; - BOOST_CHECK(!bb.intersect(ray)); + // upper bound is exclusive - temporarily removed, fails macOS ci + // ray = {{-2, 1}, {1, 0}}; + // BOOST_CHECK(!bb.intersect(ray)); // lower bound is inclusive ray = {{-2, -1}, {1, 0}}; @@ -181,9 +180,9 @@ BOOST_AUTO_TEST_CASE(intersect_rays) { ray = {{2, -2}, {-1, 0}}; BOOST_CHECK(!bb.intersect(ray)); - // upper bound is exclusive - ray = {{2, 1}, {-1, 0}}; - BOOST_CHECK(!bb.intersect(ray)); + // upper bound is exclusive - temporarily removed, fails macOS ci + // ray = {{2, 1}, {-1, 0}}; + // BOOST_CHECK(!bb.intersect(ray)); // lower bound is inclusive ray = {{2, -1}, {-1, 0}}; @@ -204,8 +203,7 @@ BOOST_AUTO_TEST_CASE(intersect_rays) { ray = {{1, -2}, {0, 1}}; BOOST_CHECK(!bb.intersect(ray)); - // lower bound is not inclusive, - // due to Eigen's NaN handling. + // lower bound is not inclusive, due to Eigen's NaN handling. ray = {{-1, -2}, {0, 1}}; BOOST_CHECK(!bb.intersect(ray)); @@ -228,8 +226,7 @@ BOOST_AUTO_TEST_CASE(intersect_rays) { ray = {{1, 2}, {0, -1}}; BOOST_CHECK(!bb.intersect(ray)); - // lower bound is not inclusive, - // due to Eigen's NaN handling. + // lower bound is not inclusive, due to Eigen's NaN handling. ray = {{-1, 2}, {0, -1}}; BOOST_CHECK(!bb.intersect(ray)); @@ -261,31 +258,15 @@ BOOST_AUTO_TEST_CASE(intersect_rays) { BOOST_CHECK(!bb.intersect(ray)); // starting point inside - ray = {{ - 0, - 0, - }, - {-1, 0}}; + ray = {{0, 0}, {-1, 0}}; BOOST_CHECK(bb.intersect(ray)); - ray = {{ - 0, - 0, - }, - {1, 0}}; + ray = {{0, 0}, {1, 0}}; BOOST_CHECK(bb.intersect(ray)); - ray = {{ - 0, - 0, - }, - {0, -1}}; + ray = {{0, 0}, {0, -1}}; BOOST_CHECK(bb.intersect(ray)); - ray = {{ - 0, - 0, - }, - {0, 1}}; + ray = {{0, 0}, {0, 1}}; BOOST_CHECK(bb.intersect(ray)); - } */ + } BOOST_TEST_CONTEXT("3D visualize") { Object o; @@ -322,21 +303,21 @@ BOOST_AUTO_TEST_CASE(intersect_rays) { ray3 = {{0, -2, -2}, {0, 0, 1}}; BOOST_CHECK(!bb3.intersect(ray3)); - // right on slab - temporarily removed, fails with double precision + // right on slab - temporarily removed, fails macOS ci // ray3 = {{0, 1, -2}, {0, 0, 1}}; // BOOST_CHECK(!bb3.intersect(ray3)); - // right on slab - temporarily removed, fails with double precision - // ray3 = {{0, -1, -2}, {0, 0, 1}}; - // BOOST_CHECK(bb3.intersect(ray3)); + // right on slab + ray3 = {{0, -1, -2}, {0, 0, 1}}; + BOOST_CHECK(bb3.intersect(ray3)); // right on slab ray3 = {{-1, 0, -2}, {0, 0, 1}}; BOOST_CHECK(!bb3.intersect(ray3)); - // right on slab - temporarily removed, fails with double precision - // ray3 = {{1, 0, -2}, {0, 0, 1}}; - // BOOST_CHECK(!bb3.intersect(ray3)); + // right on slab + ray3 = {{1, 0, -2}, {0, 0, 1}}; + BOOST_CHECK(!bb3.intersect(ray3)); ray3 = {{-0.95, 0, -2}, {0, 0, 1}}; BOOST_CHECK(bb3.intersect(ray3)); @@ -461,10 +442,11 @@ BOOST_AUTO_TEST_CASE(ray_obb_intersect) { BOOST_AUTO_TEST_CASE(frustum_intersect) { BOOST_TEST_CONTEXT("2D") { - auto make_svg = [](const std::string& fname, std::size_t w, std::size_t h) { + auto make_svg = [](const std::string& fname, std::size_t width, + std::size_t height) { auto os = tmp(fname); os << "\n"; - os << "\n"; return os; }; @@ -473,30 +455,31 @@ BOOST_AUTO_TEST_CASE(frustum_intersect) { std::ofstream os; - const std::size_t w = 1000; - const std::size_t n = 10; - - // BEGIN VISUAL PARAMETER TEST - - // BoundingBoxScalar min = -20, max = 20; - // os = make_svg("frust2d.svg", w, w); - - // BoundingBoxScalar step = (max - min) / - // static_cast(n); for (std::size_t i = 0; i <= n; i++) { - // for (std::size_t j = 0; j <= n; j++) { - // ActsVector dir = {1, 0}; - // ActsVector origin = {min + step * i, min + step * - // j}; origin.x() *= 1.10; // visual Eigen::Rotation2D - // rot(2 * std::numbers::pi / static_cast(n) * i); - // BoundingBoxScalar angle = std::numbers::pi / 2. / n * j; Frustum2 - // fr(origin, rot * dir, angle); fr.svg(os, w, w, 2); - //} - //} - - // os << ""; - // os.close(); + const std::size_t svgWidth = 1000; + const std::size_t svgHeight = svgWidth; + const std::size_t nSteps = 10; + + // Visualise the parameters + const BoundingBoxScalar min = -20; + const BoundingBoxScalar max = 20; + os = make_svg("frust2d_parameters.svg", svgWidth, svgHeight); + + const BoundingBoxScalar step = (max - min) / nSteps; + for (std::size_t i = 0; i <= nSteps; i++) { + for (std::size_t j = 0; j <= nSteps; j++) { + Vector2F dir(1, 0); + Vector2F origin(min + step * i, min + step * j); + origin.x() *= 1.10; + Eigen::Rotation2D rot(2 * std::numbers::pi / nSteps * + i); + BoundingBoxScalar angle = std::numbers::pi / 2. / nSteps * j; + Frustum2 fr(origin, rot * dir, angle); + fr.svg(os, svgWidth, svgHeight, 2); + } + } - // END VISUAL PARAMETER TEST + os << ""; + os.close(); const BoundingBoxScalar unit = 20; @@ -504,18 +487,18 @@ BOOST_AUTO_TEST_CASE(frustum_intersect) { Object o; Box::Size size(Eigen::Matrix(2, 2)); - BoundingBoxScalar minx = -20; - BoundingBoxScalar miny = -20; - BoundingBoxScalar maxx = 20; - BoundingBoxScalar maxy = 20; - BoundingBoxScalar stepx = (maxx - minx) / static_cast(n); - BoundingBoxScalar stepy = (maxy - miny) / static_cast(n); + const BoundingBoxScalar minX = -20; + const BoundingBoxScalar minY = -20; + const BoundingBoxScalar maxX = 20; + const BoundingBoxScalar maxY = 20; + const BoundingBoxScalar stepX = (maxX - minX) / nSteps; + const BoundingBoxScalar stepY = (maxY - minY) / nSteps; - std::set act_idxs; + std::set idxsAct; // clang-format off - std::vector>> fr_exp; - fr_exp = { + std::vector>> frExp; + frExp = { {Frustum2({0, 0}, {1, 0}, std::numbers::pi / 2.), {60, 70, 71, 72, 80, 81, 82, 83, 84, 90, 91, 92, 93, 94, 95, 96, 100, 101, 102, 103, 104, 105, 106, 107, @@ -583,22 +566,22 @@ BOOST_AUTO_TEST_CASE(frustum_intersect) { }; // clang-format on - for (std::size_t l = 0; l < fr_exp.size(); l++) { - const Frustum2& fr = fr_exp.at(l).first; - const std::set& exp_idxs = fr_exp.at(l).second; + for (std::size_t l = 0; l < frExp.size(); l++) { + const Frustum2& fr = frExp.at(l).first; + const std::set& idxsExp = frExp.at(l).second; std::stringstream ss; ss << "frust2d_test_" << l << ".svg"; - os = make_svg(ss.str(), w, w); + os = make_svg(ss.str(), svgWidth, svgHeight); - act_idxs.clear(); + idxsAct.clear(); std::vector boxes; - boxes.reserve((n + 1) * (n + 1)); - for (std::size_t i = 0; i <= n; i++) { - for (std::size_t j = 0; j <= n; j++) { + boxes.reserve((nSteps + 1) * (nSteps + 1)); + for (std::size_t i = 0; i <= nSteps; i++) { + for (std::size_t j = 0; j <= nSteps; j++) { boxes.emplace_back(&o, Eigen::Matrix{ - minx + i * stepx, miny + j * stepy}, + minX + i * stepX, minY + j * stepY}, size); std::stringstream st; st << boxes.size() - 1; @@ -606,16 +589,16 @@ BOOST_AUTO_TEST_CASE(frustum_intersect) { std::string color = "red"; if (boxes.back().intersect(fr)) { color = "green"; - act_idxs.insert(boxes.size() - 1); + idxsAct.insert(boxes.size() - 1); } - boxes.back().svg(os, w, w, unit, st.str(), color); + boxes.back().svg(os, svgWidth, svgHeight, unit, st.str(), color); } } - BOOST_CHECK(act_idxs == exp_idxs); + BOOST_CHECK(idxsAct == idxsExp); - fr.svg(os, w, w, maxx, unit); + fr.svg(os, svgWidth, svgHeight, maxX, unit); os << ""; os.close(); @@ -627,73 +610,64 @@ BOOST_AUTO_TEST_CASE(frustum_intersect) { using Frustum3 = Frustum; std::ofstream os; std::size_t n = 10; - std::size_t s = 5; - double min = -10, max = 10; - double step = (max - min) / s; + const std::size_t nSteps = 5; + double min = -10; + double max = 10; + double step = (max - min) / nSteps; + + // Visualise the parameters + auto make = [&](double angle, const Vector3F& origin, + std::ofstream& osTmp) { + helper.clear(); + BoundingBoxScalar far = 1; + Frustum3 fr(origin, {0, 0, 1}, angle); + fr.draw(helper, far); + fr = Frustum3(origin, {0, 0, -1}, angle); + fr.draw(helper, far); + fr = Frustum3(origin, {1, 0, 0}, angle); + fr.draw(helper, far); + fr = Frustum3(origin, {-1, 0, 0}, angle); + fr.draw(helper, far); + + fr = Frustum3(origin, {0, 1, 0}, angle); + fr.draw(helper, far); + fr = Frustum3(origin, {0, -1, 0}, angle); + fr.draw(helper, far); + + osTmp << helper << std::flush; + + helper.clear(); + }; + + os = std::ofstream("frust3d_dir.ply"); + for (std::size_t i = 0; i <= nSteps; i++) { + for (std::size_t j = 0; j <= nSteps; j++) { + for (std::size_t k = 0; k <= nSteps; k++) { + Vector3F origin(min + i * step, min + j * step, min + k * step); + make(std::numbers::pi / 4., origin, os); + } + } + } + os.close(); + + os = tmp("frust3D_angle.ply"); + helper.clear(); + for (std::size_t i = 0; i <= n; i++) { + Vector3F origin(i * 4, 0, 0); + AngleAxis3F rot(std::numbers::pi / n * i, Vector3F::UnitY()); + BoundingBoxScalar angle = (std::numbers::pi / 2.) / n * (1 + i); + Vector3F dir(1, 0, 0); + Frustum3 fr(origin, rot * dir, angle); + fr.draw(helper, 2); + } + + os << helper << std::flush; + os.close(); - // BEGIN VISUAL PARAMETER TEST - - // std::size_t n_vtx = 1; - // auto make = [&](double angle, ActsVector origin, - // std::ofstream& os) - // { - // helper.clear(); - // BoundingBoxScalar far = 1; - // Frustum3 fr(origin, {0, 0, 1}, angle); - // fr.draw(helper, far); - // fr = Frustum3(origin, {0, 0, -1}, angle); - // fr.draw(helper, far); - // fr = Frustum3(origin, {1, 0, 0}, angle); - // fr.draw(helper, far); - // fr = Frustum3(origin, {-1, 0, 0}, angle); - // fr.draw(helper, far); - - // fr = Frustum3(origin, {0, 1, 0}, angle); - // fr.draw(helper, far); - // fr = Frustum3(origin, {0, -1, 0}, angle); - // fr.draw(helper, far); - - // os << helper << std::flush; - - // helper.clear(); - //}; - - // os = std::ofstreams("frust3d_dir.ply"); - // for (std::size_t i = 0; i <= s; i++) { - // for (std::size_t j = 0; j <= s; j++) { - // for (std::size_t k = 0; k <= s; k++) { - // ActsVector origin( - // min + i * step, min + j * step, min + k * step); - //// std::cout << origin.transpose() << std::endl; - // make(std::numbers::pi / 4., origin, os); - //} - //} - //} - // os.close(); - - // os = tmp("frust3D_angle.ply"); - // helper.clear(); - // n_vtx = 1; - // Eigen::Affine3f rot; - // for (std::size_t i = 0; i <= n; i++) { - // ActsVector origin(i * 4, 0, 0); - // rot = Eigen::AngleAxisf(std::numbers::pi / - // static_cast(n) * i, - // ActsVector::UnitY()); BoundingBoxScalar angle = - // (std::numbers::pi / 2.) / static_cast(n) * (1 + i); - // ActsVector dir(1, 0, 0); Frustum3 fr(origin, rot * - // dir, angle); fr.draw(helper, 2); - //} - - // os << helper << std::flush; - // os.close(); - - //// END VISUAL PARAMETER TEST - - std::set act_idxs; - - std::vector>> fr_exp; - fr_exp = { + std::set idxsAct; + + std::vector>> frExp; + frExp = { {Frustum3({0, 0, 0}, {1, 0, 0}, std::numbers::pi / 2.), { 665, 763, 774, 775, 785, 786, 787, 788, 796, 797, 807, @@ -856,9 +830,9 @@ BOOST_AUTO_TEST_CASE(frustum_intersect) { 1088, 1143, 1154, 1165, 1175, 1176, 1186, 1187, 1197, 1198, 1207, 1208, 1209, 1308, 1319, 1330}}}; - for (std::size_t l = 0; l < fr_exp.size(); l++) { - const Frustum3& fr = fr_exp.at(l).first; - const std::set& exp_idxs = fr_exp.at(l).second; + for (std::size_t l = 0; l < frExp.size(); l++) { + const Frustum3& fr = frExp.at(l).first; + const std::set& idxsExp = frExp.at(l).second; std::stringstream ss; ss << "frust3d-3s_test_" << l << ".ply"; @@ -866,14 +840,14 @@ BOOST_AUTO_TEST_CASE(frustum_intersect) { helper.clear(); - act_idxs.clear(); + idxsAct.clear(); fr.draw(helper, 50); n = 10; min = -33; max = 33; - step = (max - min) / static_cast(n); + step = (max - min) / n; Object o; using Box = AxisAlignedBoundingBox; @@ -892,7 +866,7 @@ BOOST_AUTO_TEST_CASE(frustum_intersect) { if (bb.intersect(fr)) { color = {0, 255, 0}; - act_idxs.insert(idx); + idxsAct.insert(idx); } bb.draw(helper, color); @@ -904,76 +878,64 @@ BOOST_AUTO_TEST_CASE(frustum_intersect) { os << helper << std::flush; os.close(); - BOOST_CHECK(act_idxs == exp_idxs); + BOOST_CHECK(idxsAct == idxsExp); } } BOOST_TEST_CONTEXT("3D - 4 Sides") { using Frustum34 = Frustum; - std::size_t n = 10; - double min = -10, max = 10; - std::size_t s = 5; + const std::size_t n = 10; + double min = -10; + double max = 10; + const std::size_t s = 5; double step = (max - min) / s; std::ofstream os; - // BEGIN VISUAL PARAMETER TEST - - // std::size_t n_vtx = 1; - - // helper.clear(); - // os = tmp("frust3d-4s_dir.ply"); - - // double angle = std::numbers::pi / 4.; - // for (std::size_t i = 0; i <= s; i++) { - // for (std::size_t j = 0; j <= s; j++) { - // for (std::size_t k = 0; k <= s; k++) { - // ActsVector origin( - // min + i * step, min + j * step, min + k * step); - // ActsVector dir(1, 0, 0); - - // Eigen::Affine3f rot; - // rot = Eigen::AngleAxisf(std::numbers::pi / - // static_cast(s) * i, - // ActsVector::UnitX()) - //* Eigen::AngleAxisf(std::numbers::pi / static_cast(s) * - // j, - // ActsVector::UnitY()) - //* Eigen::AngleAxisf(std::numbers::pi / static_cast(s) * - // k, - // ActsVector::UnitZ()); - - // Frustum34 fr(origin, rot * dir, angle); - // fr.draw(helper, 1); - //} - //} - //} - - // os << helper << std::flush; - // os.close(); - // os = tmp("frust3d-4s_angle.ply"); - // helper.clear(); - - // n_vtx = 1; - // for (std::size_t i = 0; i <= n; i++) { - // ActsVector origin(i * 4, 0, 0); - // Eigen::Affine3f rot; - // rot = Eigen::AngleAxisf(std::numbers::pi / - // static_cast(n) * i, - // ActsVector::UnitY()); - // angle = (std::numbers::pi / 2.) / static_cast(n) * (1 - // + i); ActsVector dir(1, 0, 0); Frustum34 fr(origin, - // rot * dir, angle); fr.draw(helper, 2); - //} - - // os << helper << std::flush; - // os.close(); - - // END VISUAL PARAMETER TEST - - std::set act_idxs; - - std::vector>> fr_exp; - fr_exp = { + // Visualise the parameters + helper.clear(); + os = tmp("frust3d-4s_dir.ply"); + + const double constAngle = std::numbers::pi / 4.; + for (std::size_t i = 0; i <= s; i++) { + for (std::size_t j = 0; j <= s; j++) { + for (std::size_t k = 0; k <= s; k++) { + Vector3F origin(min + i * step, min + j * step, min + k * step); + Vector3F dir(1, 0, 0); + + BoundingBoxScalar piOverS = std::numbers::pi_v / s; + AngleAxis3F rot; + rot = AngleAxis3F(piOverS * i, Vector3F::UnitX()) * + AngleAxis3F(piOverS * j, Vector3F::UnitY()) * + AngleAxis3F(piOverS * k, Vector3F::UnitZ()); + + Frustum34 fr(origin, rot * dir, constAngle); + fr.draw(helper, 1); + } + } + } + + os << helper << std::flush; + os.close(); + + os = tmp("frust3d-4s_angle.ply"); + helper.clear(); + + for (std::size_t i = 0; i <= n; i++) { + Vector3F origin(i * 4, 0, 0); + AngleAxis3F rot(std::numbers::pi / n * i, Vector3F::UnitY()); + const double angle = (std::numbers::pi / 2.) / n * (1 + i); + Vector3F dir(1, 0, 0); + Frustum34 fr(origin, rot * dir, angle); + fr.draw(helper, 2); + } + + os << helper << std::flush; + os.close(); + + std::set idxsAct; + + std::vector>> frExp; + frExp = { {Frustum34({0, 0, 0}, {1, 0, 0}, std::numbers::pi / 2.), {665, 774, 775, 776, 785, 786, 787, 796, 797, 798, 883, 884, 885, 886, 887, 894, 895, 896, 897, 898, 905, 906, @@ -1123,9 +1085,13 @@ BOOST_AUTO_TEST_CASE(frustum_intersect) { 1088, 1143, 1154, 1165, 1175, 1176, 1186, 1187, 1197, 1198, 1209, 1308, 1319, 1330}}}; - for (std::size_t l = 0; l < fr_exp.size(); l++) { - const Frustum34& fr = fr_exp.at(l).first; - const std::set& exp_idxs = fr_exp.at(l).second; + min = -33; + max = 33; + step = (max - min) / n; + + for (std::size_t l = 0; l < frExp.size(); l++) { + const Frustum34& fr = frExp.at(l).first; + const std::set& idxsExp = frExp.at(l).second; std::stringstream ss; ss << "frust3d-4s_test_" << l << ".ply"; @@ -1133,15 +1099,10 @@ BOOST_AUTO_TEST_CASE(frustum_intersect) { helper.clear(); - act_idxs.clear(); + idxsAct.clear(); fr.draw(helper, 50); - n = 10; - min = -33; - max = 33; - step = (max - min) / static_cast(n); - Object o; using Box = AxisAlignedBoundingBox; Box::Size size(Eigen::Matrix(2, 2, 2)); @@ -1158,7 +1119,7 @@ BOOST_AUTO_TEST_CASE(frustum_intersect) { if (bb.intersect(fr)) { color = {0, 255, 0}; - act_idxs.insert(idx); + idxsAct.insert(idx); } bb.draw(helper, color); @@ -1170,7 +1131,7 @@ BOOST_AUTO_TEST_CASE(frustum_intersect) { os << helper << std::flush; os.close(); - BOOST_CHECK(act_idxs == exp_idxs); + BOOST_CHECK(idxsAct == idxsExp); } } @@ -1206,7 +1167,6 @@ BOOST_AUTO_TEST_CASE(frustum_intersect) { PlyVisualization3D ply; - // Frustum fr({0, 0, 0}, {0, 0, 1}, std::numbers::pi/8.); vec3 pos = {-12.4205, 29.3578, 44.6207}; vec3 dir = {-0.656862, 0.48138, 0.58035}; Frustum fr(pos, dir, 0.972419); diff --git a/Tests/UnitTests/Core/Utilities/CMakeLists.txt b/Tests/UnitTests/Core/Utilities/CMakeLists.txt index cb5249b6be9..955b58b31c9 100644 --- a/Tests/UnitTests/Core/Utilities/CMakeLists.txt +++ b/Tests/UnitTests/Core/Utilities/CMakeLists.txt @@ -61,3 +61,4 @@ add_unittest(VectorHelpers VectorHelpersTests.cpp) add_unittest(TrackHelpers TrackHelpersTests.cpp) add_unittest(GraphViz GraphVizTests.cpp) +add_unittest(ContextType ContextTypeTests.cpp) diff --git a/Tests/UnitTests/Core/Utilities/ContextTypeTests.cpp b/Tests/UnitTests/Core/Utilities/ContextTypeTests.cpp new file mode 100644 index 00000000000..2bd67ee1e5f --- /dev/null +++ b/Tests/UnitTests/Core/Utilities/ContextTypeTests.cpp @@ -0,0 +1,38 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include +#include + +#include "Acts/Utilities/detail/ContextType.hpp" + +using namespace Acts; + +BOOST_AUTO_TEST_SUITE(ContextTypeTests) + +BOOST_AUTO_TEST_CASE(PackUnpack) { + ContextType ctx; + + int v = 42; + ctx = v; + + BOOST_CHECK_EQUAL(ctx.get(), 42); + BOOST_CHECK_THROW(ctx.get(), std::bad_any_cast); +} + +BOOST_AUTO_TEST_CASE(MaybeUnpack) { + ContextType ctx; + + int v = 42; + ctx = v; + + BOOST_CHECK_EQUAL(*ctx.maybeGet(), 42); + BOOST_CHECK_EQUAL(ctx.maybeGet(), nullptr); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/Tests/UnitTests/Core/Utilities/HashedStringTests.cpp b/Tests/UnitTests/Core/Utilities/HashedStringTests.cpp index f38a71cbe89..0045ec4a6dc 100644 --- a/Tests/UnitTests/Core/Utilities/HashedStringTests.cpp +++ b/Tests/UnitTests/Core/Utilities/HashedStringTests.cpp @@ -28,7 +28,7 @@ BOOST_AUTO_TEST_CASE(string_hashes) { BOOST_CHECK_EQUAL("abc"_hash, 440920331); std::string s = "abc"; - BOOST_CHECK_EQUAL(hashString(s), 440920331); + BOOST_CHECK_EQUAL(hashStringDynamic(s), 440920331); constexpr std::string_view sv{"abc"}; BOOST_CHECK_EQUAL(hashString(sv), 440920331); static_assert(hashString(sv) == 440920331, "Invalid"); diff --git a/cmake/setup_withdeps.sh.in b/cmake/setup_withdeps.sh.in index b4a17641134..ce1dc3506e7 100644 --- a/cmake/setup_withdeps.sh.in +++ b/cmake/setup_withdeps.sh.in @@ -51,6 +51,9 @@ if [[ -d "@Geant4_DIR@" ]]; then fi if [[ -d "@DD4hep_DIR@" ]]; then . @DD4hep_INCLUDE_DIRS@/../bin/thisdd4hep.sh + # Without this, DD4hep's Xerces-C XML parsing fails with: + # > Could not load a transcoding service + export LC_ALL=C fi if [[ -d "@podio_DIR@" ]]; then export LD_LIBRARY_PATH="@podio_LIBRARY_DIR@:${LD_LIBRARY_PATH}" diff --git a/docs/codeguide.md b/docs/codeguide.md index 402ba00be6f..0030cef319d 100644 --- a/docs/codeguide.md +++ b/docs/codeguide.md @@ -30,7 +30,7 @@ pos4[eTime] = 12.3; BoundVector pars; pars[eBoundLoc0] = 1.2; ... -pars[eBoundPhi] = M_PI; +pars[eBoundPhi] = std::numbers::pi; ... ``` diff --git a/docs/conf.py b/docs/conf.py index 7788dad8dce..0f333f385a5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -121,7 +121,6 @@ nitpick_ignore = [ ("cpp:identifier", "Acts"), ("cpp:identifier", "detail"), - ("cpp:identifier", "M_PI"), ("cpp:identifier", "eSize"), ("cpp:identifier", "eBoundSize"), ("cpp:identifier", "eFreeSize"),