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 edd31d051a4..e84044776a8 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -145,7 +145,7 @@ jobs: python-version: '3.12' - name: Install dependencies run: > - pip install -r CI/requirements_fpe_masks.txt + pip install -r CI/fpe_masks/requirements.txt - name: Check run: > CI/check_fpe_masks.py --token ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/milestone.yml b/.github/workflows/milestone.yml new file mode 100644 index 00000000000..de5ee80356c --- /dev/null +++ b/.github/workflows/milestone.yml @@ -0,0 +1,58 @@ +name: Check PR milestone + +on: + pull_request_target: + types: [milestoned, demilestoned, opened, reopened] + branches: + - main + +jobs: + check_milestone: + if: ${{ github.event.issue.pull_request || github.event.pull_request }} + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: "Check for milestone on PR" + uses: actions/github-script@v7 + with: + script: | + let milestone = context.payload.pull_request.milestone; + + if(context.payload.action === 'opened' || context.payload.action === 'reopened') { + if(milestone !== null) { + core.notice(`Milestone is ${milestone.title}`); + } else { + const milestones = await github.rest.issues.listMilestones({ + owner: context.repo.owner, + repo: context.repo.repo, + state: "open" + }); + for (const default_milestone of milestones.data) { + if (default_milestone.title === "next") { + core.notice(`No milestone set, setting default milestone: ${default_milestone.title}`); + + await github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + milestone: default_milestone.number + }); + return; + } + } + + core.warning("Could not find default milestone named 'next'"); + + } + + } + else { + if(milestone !== null) { + core.notice(`Milestone is ${milestone.title}`); + } else { + core.setFailed("No milestone: Please add a version milestone"); + } + } diff --git a/.github/workflows/update-pip-requirements.yml b/.github/workflows/update-pip-requirements.yml new file mode 100755 index 00000000000..444ade7b287 --- /dev/null +++ b/.github/workflows/update-pip-requirements.yml @@ -0,0 +1,76 @@ +name: Update Pip Requirements + +on: + workflow_dispatch: # Allow running on-demand + schedule: + # Runs every Sunday at 1:23 UTC + - cron: '23 1 * * 0' + +jobs: + update-pip-requirements: + # This action checks all monitored (specified in `folder_list` below) requirements.in + # files and generates a new requirements.txt file with pip-compile. If any + # requirements changed, a PR is created with the changes. + runs-on: ubuntu-latest + env: + # This branch will receive updates each time the workflow runs + # It doesn't matter if it's deleted when merged, it'll be re-created + BRANCH_NAME: auto-dependency-upgrades + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: 3.12 + + - name: Install pip-tools + run: pip install pip-tools + + - name: Compile all requirements.txt + run: | + # Update this list after adding/removing requirements-files + folder_list=( + CI/clang_tidy + CI/fpe_masks + docs + Examples/Python/tests/ + Examples/Scripts + ) + for folder in "${folder_list[@]}"; do + pip-compile "${folder}/requirements.in" > "${folder}/requirements.txt" + done + + - name: Detect changes + id: changes + run: + # This output boolean tells us if the dependencies have actually changed + echo "count=$(git status --porcelain=v1 2>/dev/null | wc -l)" >> $GITHUB_OUTPUT + + - name: Commit & push changes + # Only push if changes exist + if: steps.changes.outputs.count > 0 + run: | + git config user.name github-actions + git config user.email github-actions@github.com + git add . + git commit -m "Weekly Update: Regenerate requirements.txt" + git push -f origin ${{ github.ref_name }}:$BRANCH_NAME + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Open pull request if needed + if: steps.changes.outputs.count > 0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Only open a PR if the branch is not attached to an existing one + run: | + PR=$(gh pr list --head $BRANCH_NAME --json number -q '.[0].number') + if [ -z $PR ]; then + gh pr create \ + --head $BRANCH_NAME \ + --title "chore: automated python requirements upgrades" \ + --body "Full log: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + else + echo "Pull request already exists, won't create a new one." + fi diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 14e59882291..b0a213e607d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -166,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/.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/clang_tidy/requirements.txt b/CI/clang_tidy/requirements.txt index 6bd13b68d95..d0d78f5904e 100644 --- a/CI/clang_tidy/requirements.txt +++ b/CI/clang_tidy/requirements.txt @@ -4,41 +4,41 @@ # # pip-compile CI/clang_tidy/requirements.in # -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic appdirs==1.4.4 # via fs -codereport==0.3.2 +codereport==0.4.0 # via -r CI/clang_tidy/requirements.in fs==2.4.16 # via codereport -jinja2==3.1.2 +jinja2==3.1.4 # via codereport markdown-it-py==3.0.0 # via rich -markupsafe==2.1.3 +markupsafe==3.0.2 # via jinja2 mdurl==0.1.2 # via markdown-it-py -pydantic==2.5.2 +pydantic==2.9.2 # via -r CI/clang_tidy/requirements.in -pydantic-core==2.14.5 +pydantic-core==2.23.4 # via pydantic -pygments==2.17.2 +pygments==2.18.0 # via # codereport # rich python-slugify==6.1.2 # via codereport -pyyaml==6.0.1 +pyyaml==6.0.2 # via -r CI/clang_tidy/requirements.in -rich==13.7.0 +rich==13.9.4 # via -r CI/clang_tidy/requirements.in six==1.16.0 # via fs text-unidecode==1.3 # via python-slugify -typing-extensions==4.8.0 +typing-extensions==4.12.2 # via # pydantic # pydantic-core diff --git a/CI/requirements_fpe_masks.in b/CI/fpe_masks/requirements.in similarity index 100% rename from CI/requirements_fpe_masks.in rename to CI/fpe_masks/requirements.in diff --git a/CI/fpe_masks/requirements.txt b/CI/fpe_masks/requirements.txt new file mode 100644 index 00000000000..01f945e3d74 --- /dev/null +++ b/CI/fpe_masks/requirements.txt @@ -0,0 +1,62 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile CI/fpe_masks/requirements.in +# +aiohappyeyeballs==2.4.3 + # via aiohttp +aiohttp==3.11.6 + # via -r CI/fpe_masks/requirements.in +aiosignal==1.3.1 + # via aiohttp +attrs==24.2.0 + # via aiohttp +cffi==1.17.1 + # via cryptography +click==8.1.7 + # via typer +cryptography==43.0.3 + # via pyjwt +frozenlist==1.5.0 + # via + # aiohttp + # aiosignal +gidgethub==5.3.0 + # via -r CI/fpe_masks/requirements.in +idna==3.10 + # via yarl +markdown-it-py==3.0.0 + # via rich +mdurl==0.1.2 + # via markdown-it-py +multidict==6.1.0 + # via + # aiohttp + # yarl +propcache==0.2.0 + # via + # aiohttp + # yarl +pycparser==2.22 + # via cffi +pygments==2.18.0 + # via rich +pyjwt[crypto]==2.10.0 + # via + # gidgethub + # pyjwt +rich==13.9.4 + # via + # -r CI/fpe_masks/requirements.in + # typer +shellingham==1.5.4 + # via typer +typer==0.13.1 + # via -r CI/fpe_masks/requirements.in +typing-extensions==4.12.2 + # via typer +uritemplate==4.1.1 + # via gidgethub +yarl==1.17.2 + # via aiohttp 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/CI/requirements_fpe_masks.txt b/CI/requirements_fpe_masks.txt deleted file mode 100644 index 07e86bd58d5..00000000000 --- a/CI/requirements_fpe_masks.txt +++ /dev/null @@ -1,50 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.12 -# by the following command: -# -# pip-compile CI/requirements_fpe_masks.in -# -aiohttp==3.9.1 - # via -r CI/requirements_fpe_masks.in -aiosignal==1.3.1 - # via aiohttp -attrs==23.1.0 - # via aiohttp -cffi==1.15.1 - # via cryptography -click==8.1.4 - # via typer -cryptography==41.0.1 - # via pyjwt -frozenlist==1.4.0 - # via - # aiohttp - # aiosignal -gidgethub==5.3.0 - # via -r CI/requirements_fpe_masks.in -idna==3.4 - # via yarl -markdown-it-py==3.0.0 - # via rich -mdurl==0.1.2 - # via markdown-it-py -multidict==6.0.4 - # via - # aiohttp - # yarl -pycparser==2.21 - # via cffi -pygments==2.15.1 - # via rich -pyjwt[crypto]==2.7.0 - # via gidgethub -rich==13.4.2 - # via -r CI/requirements_fpe_masks.in -typer==0.9.0 - # via -r CI/requirements_fpe_masks.in -typing-extensions==4.7.1 - # via typer -uritemplate==4.1.1 - # via gidgethub -yarl==1.9.2 - # via aiohttp 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/AmbiguityResolution/ScoreBasedAmbiguityResolution.hpp b/Core/include/Acts/AmbiguityResolution/ScoreBasedAmbiguityResolution.hpp index fbccb611d1a..6ed24a71be8 100644 --- a/Core/include/Acts/AmbiguityResolution/ScoreBasedAmbiguityResolution.hpp +++ b/Core/include/Acts/AmbiguityResolution/ScoreBasedAmbiguityResolution.hpp @@ -12,6 +12,7 @@ #include "Acts/EventData/TrackContainer.hpp" #include "Acts/EventData/TrackContainerFrontendConcept.hpp" #include "Acts/EventData/TrackProxyConcept.hpp" +#include "Acts/EventData/TrackStateProxy.hpp" #include "Acts/Utilities/Delegate.hpp" #include "Acts/Utilities/Logger.hpp" @@ -81,11 +82,17 @@ class ScoreBasedAmbiguityResolution { std::size_t nSharedHits = 0; }; - /// @brief MeasurementInfo : contains the measurement ID and the detector ID - struct MeasurementInfo { - std::size_t iMeasurement = 0; - std::size_t detectorId = 0; - bool isOutlier = false; + enum class TrackStateTypes : std::uint8_t { + // A measurement not yet used in any other track + UnsharedHit, + // A measurement shared with another track + SharedHit, + // A hit that needs to be removed from the track + RejectedHit, + // An outlier, to be copied in case + Outlier, + // Other trackstate types to be copied in case + OtherTrackStateType }; /// @brief Configuration struct : contains the configuration for the ambiguity resolution. @@ -125,11 +132,17 @@ class ScoreBasedAmbiguityResolution { using OptionalScoreModifier = std::function; + + using OptionalHitSelection = std::function; + std::vector cuts = {}; std::vector weights = {}; /// applied only if useAmbiguityFunction is true std::vector scores = {}; + std::vector hitSelections = {}; }; ScoreBasedAmbiguityResolution( @@ -141,16 +154,10 @@ class ScoreBasedAmbiguityResolution { /// Compute the initial state of the tracks. /// /// @param tracks is the input track container - /// @param sourceLinkHash is the source links - /// @param sourceLinkEquality is the equality function for the source links - /// @param trackFeaturesVectors is the trackFeatures map from detector ID to trackFeatures - /// @return a vector of the initial state of the tracks - template - std::vector> computeInitialState( - const track_container_t& tracks, source_link_hash_t sourceLinkHash, - source_link_equality_t sourceLinkEquality, - std::vector>& trackFeaturesVectors) const; + /// @return trackFeaturesVectors is the trackFeatures map from detector ID to trackFeatures + template + std::vector> computeInitialState( + const track_container_t& tracks) const; /// Compute the score of each track. /// @@ -182,29 +189,35 @@ class ScoreBasedAmbiguityResolution { /// that have a score below a certain threshold or not enough hits. /// /// @brief Remove tracks that are not good enough based on cuts + /// @param track is the input track /// @param trackScore is the score of each track - /// @param trackFeaturesVectors is the trackFeatures map for each track /// @param measurementsPerTrack is the list of measurements for each track + /// @param nTracksPerMeasurement is the number of tracks per measurement + /// @param optionalHitSelections is the optional hit selections to be applied /// @return a vector of IDs of the tracks we want to keep - std::vector getCleanedOutTracks( - const std::vector& trackScore, - const std::vector>& trackFeaturesVectors, - const std::vector>& measurementsPerTrack) - const; + template + bool getCleanedOutTracks( + const track_proxy_t& track, const double& trackScore, + const std::vector& measurementsPerTrack, + const std::map& nTracksPerMeasurement, + const std::vector>& optionalHitSelections = {}) const; /// Remove tracks that are bad based on cuts and weighted scores. /// /// @brief Remove tracks that are not good enough /// @param tracks is the input track container - /// @param measurementsPerTrack is the list of measurements for each track - /// @param trackFeaturesVectors is the map of detector id to trackFeatures for each track + /// @param sourceLinkHash is the source links + /// @param sourceLinkEquality is the equality function for the source links /// @param optionalCuts is the optional cuts to be applied /// @return a vector of IDs of the tracks we want to keep - template + template std::vector solveAmbiguity( - const track_container_t& tracks, - const std::vector>& measurementsPerTrack, - const std::vector>& trackFeaturesVectors, + const track_container_t& tracks, source_link_hash_t sourceLinkHash, + source_link_equality_t sourceLinkEquality, const OptionalCuts& optionalCuts = {}) const; diff --git a/Core/include/Acts/AmbiguityResolution/ScoreBasedAmbiguityResolution.ipp b/Core/include/Acts/AmbiguityResolution/ScoreBasedAmbiguityResolution.ipp index 58742d7d11a..247b767dd3d 100644 --- a/Core/include/Acts/AmbiguityResolution/ScoreBasedAmbiguityResolution.ipp +++ b/Core/include/Acts/AmbiguityResolution/ScoreBasedAmbiguityResolution.ipp @@ -21,27 +21,17 @@ inline const Logger& ScoreBasedAmbiguityResolution::logger() const { return *m_logger; } -template -std::vector> +template +std::vector> ScoreBasedAmbiguityResolution::computeInitialState( - const track_container_t& tracks, source_link_hash_t sourceLinkHash, - source_link_equality_t sourceLinkEquality, - std::vector>& trackFeaturesVectors) const { - auto MeasurementIndexMap = - std::unordered_map(0, sourceLinkHash, - sourceLinkEquality); - - std::vector> measurementsPerTrack; - measurementsPerTrack.reserve(tracks.size()); + const track_container_t& tracks) const { ACTS_VERBOSE("Starting to compute initial state"); + std::vector> trackFeaturesVectors; + trackFeaturesVectors.reserve(tracks.size()); for (const auto& track : tracks) { int numberOfDetectors = m_cfg.detectorConfigs.size(); - int numberOfTrackStates = track.nTrackStates(); - std::vector measurements; - measurements.reserve(numberOfTrackStates); + std::vector trackFeaturesVector(numberOfDetectors); for (const auto& ts : track.trackStatesReversed()) { @@ -58,43 +48,25 @@ ScoreBasedAmbiguityResolution::computeInitialState( auto detectorId = volume_it->second; if (ts.typeFlags().test(Acts::TrackStateFlag::HoleFlag)) { - ACTS_DEBUG("Track state type is HoleFlag"); + ACTS_VERBOSE("Track state type is HoleFlag"); trackFeaturesVector[detectorId].nHoles++; } else if (ts.typeFlags().test(Acts::TrackStateFlag::OutlierFlag)) { - Acts::SourceLink sourceLink = ts.getUncalibratedSourceLink(); - ACTS_DEBUG("Track state type is OutlierFlag"); + ACTS_VERBOSE("Track state type is OutlierFlag"); trackFeaturesVector[detectorId].nOutliers++; - // assign a new measurement index if the source link was not seen yet - auto emplace = MeasurementIndexMap.try_emplace( - sourceLink, MeasurementIndexMap.size()); - - bool isOutliner = true; - - measurements.push_back({emplace.first->second, detectorId, isOutliner}); } else if (ts.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) { - Acts::SourceLink sourceLink = ts.getUncalibratedSourceLink(); - ACTS_DEBUG("Track state type is MeasurementFlag"); + ACTS_VERBOSE("Track state type is MeasurementFlag"); if (ts.typeFlags().test(Acts::TrackStateFlag::SharedHitFlag)) { trackFeaturesVector[detectorId].nSharedHits++; } trackFeaturesVector[detectorId].nHits++; - - // assign a new measurement index if the source link was not seen yet - auto emplace = MeasurementIndexMap.try_emplace( - sourceLink, MeasurementIndexMap.size()); - - bool isoutliner = false; - - measurements.push_back({emplace.first->second, detectorId, isoutliner}); } } - measurementsPerTrack.push_back(std::move(measurements)); trackFeaturesVectors.push_back(std::move(trackFeaturesVector)); } - return measurementsPerTrack; + return trackFeaturesVectors; } template @@ -363,12 +335,6 @@ std::vector Acts::ScoreBasedAmbiguityResolution::ambiguityScore( // choosing a scaling factor based on the number of hits in a track per // detector. std::size_t nHits = trackFeatures.nHits; - if (detector.factorHits.size() < nHits) { - ACTS_WARNING("Detector " << detectorId - << " has not enough factorhits in the " - "detector.factorHits vector"); - continue; - } if (nHits > detector.maxHits) { score = score * (detector.maxHits - nHits + 1); // hits are good ! nHits = detector.maxHits; @@ -381,12 +347,6 @@ std::vector Acts::ScoreBasedAmbiguityResolution::ambiguityScore( // choosing a scaling factor based on the number of holes in a track per // detector. std::size_t iHoles = trackFeatures.nHoles; - if (detector.factorHoles.size() < iHoles) { - ACTS_WARNING("Detector " << detectorId - << " has not enough factorholes in the " - "detector.factorHoles vector"); - continue; - } if (iHoles > detector.maxHoles) { score /= (iHoles - detector.maxHoles + 1); // holes are bad ! iHoles = detector.maxHoles; @@ -421,17 +381,20 @@ std::vector Acts::ScoreBasedAmbiguityResolution::ambiguityScore( return trackScore; } -template +template std::vector Acts::ScoreBasedAmbiguityResolution::solveAmbiguity( - const track_container_t& tracks, - const std::vector>& measurementsPerTrack, - const std::vector>& trackFeaturesVectors, + const track_container_t& tracks, source_link_hash_t sourceLinkHash, + source_link_equality_t sourceLinkEquality, const OptionalCuts& optionalCuts) const { ACTS_INFO("Number of tracks before Ambiguty Resolution: " << tracks.size()); // vector of trackFeaturesVectors. where each trackFeaturesVector contains the // number of hits/hole/outliers for each detector in a track. + const std::vector> trackFeaturesVectors = + computeInitialState(tracks); + std::vector trackScore; trackScore.reserve(tracks.size()); if (m_cfg.useAmbiguityFunction) { @@ -440,14 +403,72 @@ std::vector Acts::ScoreBasedAmbiguityResolution::solveAmbiguity( trackScore = simpleScore(tracks, trackFeaturesVectors, optionalCuts); } - std::vector cleanTracks = getCleanedOutTracks( - trackScore, trackFeaturesVectors, measurementsPerTrack); + auto MeasurementIndexMap = + std::unordered_map(0, sourceLinkHash, + sourceLinkEquality); + + std::vector> measurementsPerTrackVector; + std::map nTracksPerMeasurement; + + // Stores tracks measurement into a vector or vectors + // (measurementsPerTrackVector) and counts the number of tracks per + // measurement.(nTracksPerMeasurement) + + for (const auto& track : tracks) { + std::vector measurementsPerTrack; + for (const auto& ts : track.trackStatesReversed()) { + if (!ts.typeFlags().test(Acts::TrackStateFlag::OutlierFlag) && + !ts.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) { + continue; + } + Acts::SourceLink sourceLink = ts.getUncalibratedSourceLink(); + // assign a new measurement index if the source link was not seen yet + auto emplace = MeasurementIndexMap.try_emplace( + sourceLink, MeasurementIndexMap.size()); + std::size_t iMeasurement = emplace.first->second; + measurementsPerTrack.push_back(iMeasurement); + if (nTracksPerMeasurement.find(iMeasurement) == + nTracksPerMeasurement.end()) { + nTracksPerMeasurement[iMeasurement] = 0; + } + nTracksPerMeasurement[iMeasurement]++; + } + measurementsPerTrackVector.push_back(std::move(measurementsPerTrack)); + } std::vector goodTracks; int cleanTrackIndex = 0; - std::size_t iTrack = 0; - for (const auto& track : tracks) { - if (cleanTracks[iTrack]) { + + auto optionalHitSelections = optionalCuts.hitSelections; + + // Loop over all the tracks in the container + // For each track, check if the track has too many shared hits to be accepted. + // If the track is accepted, remove bad hits and check if the track has a + // score higher than the minimum score for shared tracks. + // If the track is good, add it to the goodTracks vector. + for (std::size_t iTrack = 0; const auto& track : tracks) { + // Check if the track has too many shared hits to be accepted. + auto trackFeaturesVector = trackFeaturesVectors.at(iTrack); + bool trkCouldBeAccepted = true; + for (std::size_t detectorId = 0; detectorId < m_cfg.detectorConfigs.size(); + detectorId++) { + auto detector = m_cfg.detectorConfigs.at(detectorId); + if (trackFeaturesVector[detectorId].nSharedHits > + detector.maxSharedHits) { + trkCouldBeAccepted = false; + break; + } + } + if (!trkCouldBeAccepted) { + iTrack++; + continue; + } + + trkCouldBeAccepted = getCleanedOutTracks( + track, trackScore[iTrack], measurementsPerTrackVector[iTrack], + nTracksPerMeasurement, optionalHitSelections); + if (trkCouldBeAccepted) { cleanTrackIndex++; if (trackScore[iTrack] >= m_cfg.minScore) { goodTracks.push_back(track.index()); @@ -455,10 +476,120 @@ std::vector Acts::ScoreBasedAmbiguityResolution::solveAmbiguity( } iTrack++; } - ACTS_VERBOSE("Number of clean tracks: " << cleanTrackIndex); + ACTS_INFO("Number of clean tracks: " << cleanTrackIndex); ACTS_VERBOSE("Min score: " << m_cfg.minScore); ACTS_INFO("Number of Good tracks: " << goodTracks.size()); return goodTracks; } +template +bool Acts::ScoreBasedAmbiguityResolution::getCleanedOutTracks( + const track_proxy_t& track, const double& trackScore, + const std::vector& measurementsPerTrack, + const std::map& nTracksPerMeasurement, + const std::vector< + std::function>& optionalHitSelections) const { + // For tracks with shared hits, we need to check and remove bad hits + + std::vector trackStateTypes; + // Loop over all measurements of the track and for each hit a + // trackStateTypes is assigned. + for (std::size_t index = 0; const auto& ts : track.trackStatesReversed()) { + if (ts.typeFlags().test(Acts::TrackStateFlag::OutlierFlag) || + ts.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) { + std::size_t iMeasurement = measurementsPerTrack[index]; + auto it = nTracksPerMeasurement.find(iMeasurement); + if (it == nTracksPerMeasurement.end()) { + trackStateTypes.push_back(TrackStateTypes::OtherTrackStateType); + index++; + continue; + } + + std::size_t nTracksShared = it->second; + auto isoutliner = ts.typeFlags().test(Acts::TrackStateFlag::OutlierFlag); + + if (isoutliner) { + ACTS_VERBOSE("Measurement is outlier on a fitter track, copy it over"); + trackStateTypes.push_back(TrackStateTypes::Outlier); + continue; + } + if (nTracksShared == 1) { + ACTS_VERBOSE("Measurement is not shared, copy it over"); + + trackStateTypes.push_back(TrackStateTypes::UnsharedHit); + continue; + } else if (nTracksShared > 1) { + ACTS_VERBOSE("Measurement is shared, copy it over"); + trackStateTypes.push_back(TrackStateTypes::SharedHit); + continue; + } + } + } + std::vector newMeasurementsPerTrack; + std::size_t measurement = 0; + std::size_t nshared = 0; + + // Loop over all measurements of the track and process them according to the + // trackStateTypes and other conditions. + // Good measurements are copied to the newMeasurementsPerTrack vector. + for (std::size_t index = 0; auto ts : track.trackStatesReversed()) { + if (ts.typeFlags().test(Acts::TrackStateFlag::OutlierFlag) || + ts.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) { + if (!ts.hasReferenceSurface()) { + ACTS_DEBUG("Track state has no reference surface"); + continue; + } + measurement = measurementsPerTrack[index]; + + auto it = nTracksPerMeasurement.find(measurement); + if (it == nTracksPerMeasurement.end()) { + index++; + continue; + } + auto nTracksShared = it->second; + + // Loop over all optionalHitSelections and apply them to trackStateType of + // the TrackState. + + for (const auto& hitSelection : optionalHitSelections) { + hitSelection(track, ts, trackStateTypes[index]); + } + + if (trackStateTypes[index] == TrackStateTypes::RejectedHit) { + ACTS_DEBUG("Dropping rejected hit"); + } else if (trackStateTypes[index] != TrackStateTypes::SharedHit) { + ACTS_DEBUG("Good TSOS, copy hit"); + newMeasurementsPerTrack.push_back(measurement); + + // a counter called nshared is used to keep track of the number of + // shared hits accepted. + } else if (nshared >= m_cfg.maxShared) { + ACTS_DEBUG("Too many shared hit, drop it"); + } + // If the track is shared, the hit is only accepted if the track has + // score higher than the minimum score for shared tracks. + else { + ACTS_DEBUG("Try to recover shared hit "); + if (nTracksShared <= m_cfg.maxSharedTracksPerMeasurement && + trackScore > m_cfg.minScoreSharedTracks) { + ACTS_DEBUG("Accepted hit shared with " << nTracksShared << " tracks"); + newMeasurementsPerTrack.push_back(measurement); + nshared++; + } else { + ACTS_DEBUG("Rejected hit shared with " << nTracksShared << " tracks"); + } + } + index++; + } + } + // Check if the track has enough hits to be accepted. + if (newMeasurementsPerTrack.size() < 3) { + return false; + } else { + return true; + } +} + } // namespace Acts diff --git a/Core/include/Acts/EventData/ProxyAccessor.hpp b/Core/include/Acts/EventData/ProxyAccessor.hpp index 429c0ef670b..d6a9a3497ce 100644 --- a/Core/include/Acts/EventData/ProxyAccessor.hpp +++ b/Core/include/Acts/EventData/ProxyAccessor.hpp @@ -75,7 +75,7 @@ struct ProxyAccessorBase { /// Create the accessor from a string key /// @param _key the key constexpr ProxyAccessorBase(const std::string& _key) - : key{hashString(_key)} {} + : key{hashStringDynamic(_key)} {} /// Access the stored key on the proxy given as an argument. Mutable version /// @tparam proxy_t the type of the proxy diff --git a/Core/include/Acts/EventData/TrackContainer.hpp b/Core/include/Acts/EventData/TrackContainer.hpp index f70c430f002..03f7f1f8bb1 100644 --- a/Core/include/Acts/EventData/TrackContainer.hpp +++ b/Core/include/Acts/EventData/TrackContainer.hpp @@ -252,7 +252,7 @@ class TrackContainer { /// Check if this track container has a specific dynamic column /// @param key the key to check for constexpr bool hasColumn(const std::string& key) const { - return m_container->hasColumn_impl(hashString(key)); + return m_container->hasColumn_impl(hashStringDynamic(key)); } /// Check if a this track container has a specific dynamic column diff --git a/Core/include/Acts/EventData/TrackProxy.hpp b/Core/include/Acts/EventData/TrackProxy.hpp index 5939022e2e8..6ccb0f402b2 100644 --- a/Core/include/Acts/EventData/TrackProxy.hpp +++ b/Core/include/Acts/EventData/TrackProxy.hpp @@ -710,7 +710,7 @@ class TrackProxy { constexpr T& component(std::string_view key) requires(!ReadOnly) { - return m_container->template component(hashString(key), m_index); + return m_container->template component(hashStringDynamic(key), m_index); } /// Retrieve a const reference to a component @@ -738,7 +738,7 @@ class TrackProxy { /// @return Const reference to the component given by @p key template constexpr const T& component(std::string_view key) const { - return m_container->template component(hashString(key), m_index); + return m_container->template component(hashStringDynamic(key), m_index); } /// @} diff --git a/Core/include/Acts/EventData/TrackStateProxy.hpp b/Core/include/Acts/EventData/TrackStateProxy.hpp index 34de86cd3d7..741bfa5b511 100644 --- a/Core/include/Acts/EventData/TrackStateProxy.hpp +++ b/Core/include/Acts/EventData/TrackStateProxy.hpp @@ -1101,7 +1101,7 @@ class TrackStateProxy { /// @note This might hash the @p key at runtime instead of compile-time /// @return true if the component exists, false if not constexpr bool has(std::string_view key) const { - return has(hashString(key)); + return has(hashStringDynamic(key)); } /// Retrieve a mutable reference to a component @@ -1135,7 +1135,7 @@ class TrackStateProxy { constexpr T& component(std::string_view key) requires(!ReadOnly) { - return m_traj->template component(hashString(key), m_istate); + return m_traj->template component(hashStringDynamic(key), m_istate); } /// Retrieve a const reference to a component @@ -1163,7 +1163,7 @@ class TrackStateProxy { /// @return Const reference to the component given by @p key template constexpr const T& component(std::string_view key) const { - return m_traj->template component(hashString(key), m_istate); + return m_traj->template component(hashStringDynamic(key), m_istate); } /// @} diff --git a/Core/include/Acts/EventData/VectorMultiTrajectory.hpp b/Core/include/Acts/EventData/VectorMultiTrajectory.hpp index 7d2d05cc9b9..3859239ae69 100644 --- a/Core/include/Acts/EventData/VectorMultiTrajectory.hpp +++ b/Core/include/Acts/EventData/VectorMultiTrajectory.hpp @@ -456,7 +456,7 @@ class VectorMultiTrajectory final template void addColumn_impl(std::string_view key) { - HashedString hashedKey = hashString(key); + HashedString hashedKey = hashStringDynamic(key); m_dynamic.insert({hashedKey, std::make_unique>()}); } diff --git a/Core/include/Acts/EventData/VectorTrackContainer.hpp b/Core/include/Acts/EventData/VectorTrackContainer.hpp index 09ecf7b5b2e..8734f69eb4c 100644 --- a/Core/include/Acts/EventData/VectorTrackContainer.hpp +++ b/Core/include/Acts/EventData/VectorTrackContainer.hpp @@ -225,7 +225,7 @@ class VectorTrackContainer final : public detail_vtc::VectorTrackContainerBase { template constexpr void addColumn_impl(const std::string_view& key) { - HashedString hashedKey = hashString(key); + HashedString hashedKey = hashStringDynamic(key); m_dynamic.insert({hashedKey, std::make_unique>()}); } diff --git a/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp b/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp index 93ef7a3eb7c..a2e374c0cc2 100644 --- a/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp +++ b/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp @@ -1103,8 +1103,8 @@ class MultiTrajectoryTestsCommon { auto test = [&](const std::string& col, auto value) { using T = decltype(value); std::string col2 = col + "_2"; - HashedString h{hashString(col)}; - HashedString h2{hashString(col2)}; + HashedString h{hashStringDynamic(col)}; + HashedString h2{hashStringDynamic(col2)}; trajectory_t traj = m_factory.create(); BOOST_CHECK(!traj.hasColumn(h)); @@ -1188,7 +1188,7 @@ class MultiTrajectoryTestsCommon { } }; - runTest([](const std::string& c) { return hashString(c.c_str()); }); + runTest([](const std::string& c) { return hashStringDynamic(c.c_str()); }); // runTest([](const std::string& c) { return c.c_str(); }); // runTest([](const std::string& c) { return c; }); // runTest([](std::string_view c) { return c; }); diff --git a/Core/include/Acts/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..c59a55ad533 100644 --- a/Core/include/Acts/Seeding/EstimateTrackParamsFromSeed.hpp +++ b/Core/include/Acts/Seeding/EstimateTrackParamsFromSeed.hpp @@ -14,111 +14,91 @@ #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; } @@ -145,8 +125,6 @@ std::optional estimateTrackParamsFromSeed( /// @param surface is the surface of the bottom space point. The estimated bound /// track parameters will be represented also at this surface /// @param bField is the magnetic field vector -/// @param bFieldMin is the minimum magnetic field required to trigger the -/// estimation of q/pt /// @param logger A logger instance /// /// @return optional bound parameters @@ -154,7 +132,7 @@ template std::optional estimateTrackParamsFromSeed( const GeometryContext& gctx, spacepoint_iterator_t spBegin, spacepoint_iterator_t spEnd, const Surface& surface, const Vector3& bField, - ActsScalar bFieldMin, const Acts::Logger& logger = getDummyLogger()) { + const Acts::Logger& logger = getDummyLogger()) { // Check the number of provided space points std::size_t numSP = std::distance(spBegin, spEnd); if (numSP != 3) { @@ -162,19 +140,6 @@ std::optional estimateTrackParamsFromSeed( return std::nullopt; } - // Convert bField to Tesla - ActsScalar bFieldInTesla = bField.norm() / UnitConstants::T; - ActsScalar bFieldMinInTesla = bFieldMin / UnitConstants::T; - // Check if magnetic field is too small - if (bFieldInTesla < bFieldMinInTesla) { - // @todo shall we use straight-line estimation and use default q/pt in such - // case? - ACTS_WARNING("The magnetic field at the bottom space point: B = " - << bFieldInTesla << " T is smaller than |B|_min = " - << bFieldMinInTesla << " T. Estimation is not performed."); - return std::nullopt; - } - // The global positions of the bottom, middle and space points std::array spGlobalPositions = {Vector3::Zero(), Vector3::Zero(), Vector3::Zero()}; @@ -241,7 +206,7 @@ std::optional estimateTrackParamsFromSeed( int sign = ia > 0 ? -1 : 1; const ActsScalar R = circleCenter.norm(); ActsScalar invTanTheta = - local2.z() / (2.f * R * std::asin(local2.head<2>().norm() / (2.f * R))); + local2.z() / (2 * R * std::asin(local2.head<2>().norm() / (2 * R))); // The momentum direction in the new frame (the center of the circle has the // coordinate (-1.*A/(2*B), 1./(2*B))) ActsScalar A = -circleCenter(0) / circleCenter(1); @@ -271,9 +236,10 @@ std::optional estimateTrackParamsFromSeed( params[eBoundLoc1] = bottomLocalPos.y(); params[eBoundTime] = spGlobalTimes[0].value_or(0.); + ActsScalar bFieldStrength = bField.norm(); // The estimated q/pt in [GeV/c]^-1 (note that the pt is the projection of // momentum on the transverse plane of the new frame) - ActsScalar qOverPt = sign * (UnitConstants::m) / (0.3 * bFieldInTesla * R); + ActsScalar qOverPt = sign / (bFieldStrength * R); // The estimated q/p in [GeV/c]^-1 params[eBoundQOverP] = qOverPt / fastHypot(1., invTanTheta); diff --git a/Core/include/Acts/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 867b161201c..8442071a23f 100644 --- a/Core/include/Acts/TrackFitting/GlobalChiSquareFitter.hpp +++ b/Core/include/Acts/TrackFitting/GlobalChiSquareFitter.hpp @@ -694,6 +694,20 @@ std::size_t countMaterialStates( return nMaterialSurfaces; } +/// @brief Update parameters (and scattering angles if applicable) +/// +/// @param params Parameters to be updated +/// @param deltaParamsExtended Delta parameters for bound parameter and scattering angles +/// @param nMaterialSurfaces Number of material surfaces in the track +/// @param scatteringMap Map of geometry identifiers to scattering properties, +/// containing all scattering angles and covariances +/// @param geoIdVector Vector of geometry identifiers corresponding to material surfaces +void updateGx2fParams( + BoundTrackParameters& params, const Eigen::VectorXd& deltaParamsExtended, + const std::size_t nMaterialSurfaces, + std::unordered_map& scatteringMap, + const std::vector& geoIdVector); + /// @brief Calculate and update the covariance of the fitted parameters /// /// This function calculates the covariance of the fitted parameters using @@ -704,8 +718,6 @@ std::size_t countMaterialStates( /// /// @param fullCovariancePredicted The covariance matrix to update /// @param extendedSystem All parameters of the current equation system -/// -/// @return deltaParams The calculated delta parameters. void updateGx2fCovarianceParams(BoundMatrix& fullCovariancePredicted, Gx2fSystem& extendedSystem); @@ -1234,7 +1246,6 @@ class Gx2Fitter { using PropagatorOptions = typename propagator_t::template Options; start_parameters_t params = sParameters; - BoundVector deltaParams = BoundVector::Zero(); double chi2sum = 0; double oldChi2sum = std::numeric_limits::max(); @@ -1272,10 +1283,6 @@ class Gx2Fitter { for (nUpdate = 0; nUpdate < gx2fOptions.nUpdateMax; nUpdate++) { ACTS_DEBUG("nUpdate = " << nUpdate + 1 << "/" << gx2fOptions.nUpdateMax); - // update params - params.parameters() += deltaParams; - ACTS_VERBOSE("Updated parameters: " << params.parameters().transpose()); - // set up propagator and co Acts::GeometryContext geoCtx = gx2fOptions.geoContext; Acts::MagneticFieldContext magCtx = gx2fOptions.magFieldContext; @@ -1290,7 +1297,7 @@ class Gx2Fitter { auto& gx2fActor = propagatorOptions.actorList.template get(); gx2fActor.inputMeasurements = &inputMeasurements; - gx2fActor.multipleScattering = multipleScattering; + gx2fActor.multipleScattering = false; gx2fActor.extensions = gx2fOptions.extensions; gx2fActor.calibrationContext = &gx2fOptions.calibrationContext.get(); gx2fActor.actorLogger = m_actorLogger.get(); @@ -1306,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()); @@ -1347,10 +1354,7 @@ class Gx2Fitter { // Count the material surfaces, to set up the system. In the multiple // scattering case, we need to extend our system. - const std::size_t nMaterialSurfaces = - multipleScattering - ? countMaterialStates(track, scatteringMap, *m_addToSumLogger) - : 0u; + const std::size_t nMaterialSurfaces = 0u; // We need 6 dimensions for the bound parameters and 2 * nMaterialSurfaces // dimensions for the scattering angles. @@ -1366,8 +1370,8 @@ class Gx2Fitter { // all stored material in each propagation. std::vector geoIdVector; - fillGx2fSystem(track, extendedSystem, multipleScattering, scatteringMap, - geoIdVector, *m_addToSumLogger); + fillGx2fSystem(track, extendedSystem, false, scatteringMap, geoIdVector, + *m_addToSumLogger); chi2sum = extendedSystem.chi2(); @@ -1392,14 +1396,10 @@ class Gx2Fitter { extendedSystem.aMatrix().colPivHouseholderQr().solve( extendedSystem.bVector()); - deltaParams = deltaParamsExtended.topLeftCorner().eval(); - ACTS_VERBOSE("aMatrix:\n" << extendedSystem.aMatrix() << "\n" << "bVector:\n" << extendedSystem.bVector() << "\n" - << "deltaParams:\n" - << deltaParams << "\n" << "deltaParamsExtended:\n" << deltaParamsExtended << "\n" << "oldChi2sum = " << oldChi2sum << "\n" @@ -1416,10 +1416,7 @@ class Gx2Fitter { } if (extendedSystem.chi2() > oldChi2sum + 1e-5) { - ACTS_DEBUG("chi2 not converging monotonically"); - - updateGx2fCovarianceParams(fullCovariancePredicted, extendedSystem); - break; + ACTS_DEBUG("chi2 not converging monotonically in update " << nUpdate); } // If this is the final iteration, update the covariance and break. @@ -1440,19 +1437,9 @@ class Gx2Fitter { break; } - if (multipleScattering) { - // update the scattering angles - for (std::size_t matSurface = 0; matSurface < nMaterialSurfaces; - matSurface++) { - const std::size_t deltaPosition = eBoundSize + 2 * matSurface; - const GeometryIdentifier geoId = geoIdVector[matSurface]; - const auto scatteringMapId = scatteringMap.find(geoId); - assert(scatteringMapId != scatteringMap.end() && - "No scattering angles found for material surface."); - scatteringMapId->second.scatteringAngles().block<2, 1>(2, 0) += - deltaParamsExtended.block<2, 1>(deltaPosition, 0).eval(); - } - } + updateGx2fParams(params, deltaParamsExtended, nMaterialSurfaces, + scatteringMap, geoIdVector); + ACTS_VERBOSE("Updated parameters: " << params.parameters().transpose()); oldChi2sum = extendedSystem.chi2(); } @@ -1460,6 +1447,144 @@ class Gx2Fitter { ACTS_VERBOSE("Final parameters: " << params.parameters().transpose()); /// Finish Fitting ///////////////////////////////////////////////////////// + /// Actual MATERIAL Fitting //////////////////////////////////////////////// + ACTS_DEBUG("Start to evaluate material"); + if (multipleScattering) { + // set up propagator and co + Acts::GeometryContext geoCtx = gx2fOptions.geoContext; + Acts::MagneticFieldContext magCtx = gx2fOptions.magFieldContext; + // Set options for propagator + PropagatorOptions propagatorOptions(geoCtx, magCtx); + + // Add the measurement surface as external surface to the navigator. + // We will try to hit those surface by ignoring boundary checks. + for (const auto& [surfaceId, _] : inputMeasurements) { + propagatorOptions.navigation.insertExternalSurface(surfaceId); + } + + auto& gx2fActor = propagatorOptions.actorList.template get(); + gx2fActor.inputMeasurements = &inputMeasurements; + gx2fActor.multipleScattering = true; + gx2fActor.extensions = gx2fOptions.extensions; + gx2fActor.calibrationContext = &gx2fOptions.calibrationContext.get(); + gx2fActor.actorLogger = m_actorLogger.get(); + gx2fActor.scatteringMap = &scatteringMap; + gx2fActor.parametersWithHypothesis = ¶ms; + + auto propagatorState = m_propagator.makeState(params, propagatorOptions); + + auto& r = propagatorState.template get>(); + r.fittedStates = &trajectoryTempBackend; + + // Clear the track container. It could be more performant to update the + // existing states, but this needs some more thinking. + trackContainerTemp.clear(); + + auto propagationResult = m_propagator.propagate(propagatorState); + + // Run the fitter + auto result = + m_propagator.makeResult(std::move(propagatorState), propagationResult, + propagatorOptions, false); + + if (!result.ok()) { + ACTS_ERROR("Propagation failed: " << result.error()); + return result.error(); + } + + // TODO Improve Propagator + Actor [allocate before loop], rewrite + // makeMeasurements + auto& propRes = *result; + GX2FResult gx2fResult = std::move(propRes.template get()); + + if (!gx2fResult.result.ok()) { + ACTS_INFO("GlobalChiSquareFitter failed in actor: " + << gx2fResult.result.error() << ", " + << gx2fResult.result.error().message()); + return gx2fResult.result.error(); + } + + auto track = trackContainerTemp.makeTrack(); + tipIndex = gx2fResult.lastMeasurementIndex; + + // It could happen, that no measurements were found. Then the track would + // be empty and the following operations would be invalid. Usually, this + // only happens during the first iteration, due to bad initial parameters. + if (tipIndex == Acts::MultiTrajectoryTraits::kInvalid) { + ACTS_INFO("Did not find any measurements in material fit."); + return Experimental::GlobalChiSquareFitterError::NotEnoughMeasurements; + } + + track.tipIndex() = tipIndex; + track.linkForward(); + + // Count the material surfaces, to set up the system. In the multiple + // scattering case, we need to extend our system. + const std::size_t nMaterialSurfaces = + countMaterialStates(track, scatteringMap, *m_addToSumLogger); + + // We need 6 dimensions for the bound parameters and 2 * nMaterialSurfaces + // dimensions for the scattering angles. + const std::size_t dimsExtendedParams = eBoundSize + 2 * nMaterialSurfaces; + + // System that we fill with the information gathered by the actor and + // evaluate later + Gx2fSystem extendedSystem{dimsExtendedParams}; + + // This vector stores the IDs for each visited material in order. We use + // it later for updating the scattering angles. We cannot use + // scatteringMap directly, since we cannot guarantee, that we will visit + // all stored material in each propagation. + std::vector geoIdVector; + + fillGx2fSystem(track, extendedSystem, true, scatteringMap, geoIdVector, + *m_addToSumLogger); + + chi2sum = extendedSystem.chi2(); + + // This check takes into account the evaluated dimensions of the + // measurements. To fit, we need at least NDF+1 measurements. However, we + // count n-dimensional measurements for n measurements, reducing the + // effective number of needed measurements. We might encounter the case, + // where we cannot use some (parts of a) measurements, maybe if we do not + // support that kind of measurement. This is also taken into account here. + // We skip the check during the first iteration, since we cannot guarantee + // to hit all/enough measurement surfaces with the initial parameter + // guess. + if ((nUpdate > 0) && !extendedSystem.isWellDefined()) { + ACTS_INFO("Not enough measurements. Require " + << extendedSystem.findRequiredNdf() + 1 << ", but only " + << extendedSystem.ndf() << " could be used."); + return Experimental::GlobalChiSquareFitterError::NotEnoughMeasurements; + } + + // calculate delta params [a] * delta = b + Eigen::VectorXd deltaParamsExtended = + extendedSystem.aMatrix().colPivHouseholderQr().solve( + extendedSystem.bVector()); + + ACTS_VERBOSE("aMatrix:\n" + << extendedSystem.aMatrix() << "\n" + << "bVector:\n" + << extendedSystem.bVector() << "\n" + << "deltaParamsExtended:\n" + << deltaParamsExtended << "\n" + << "oldChi2sum = " << oldChi2sum << "\n" + << "chi2sum = " << extendedSystem.chi2()); + + chi2sum = extendedSystem.chi2(); + + updateGx2fParams(params, deltaParamsExtended, nMaterialSurfaces, + scatteringMap, geoIdVector); + ACTS_VERBOSE("Updated parameters: " << params.parameters().transpose()); + + updateGx2fCovarianceParams(fullCovariancePredicted, extendedSystem); + } + ACTS_DEBUG("Finished to evaluate material"); + ACTS_VERBOSE( + "Final parameters after material: " << params.parameters().transpose()); + /// Finish MATERIAL Fitting //////////////////////////////////////////////// + ACTS_VERBOSE("Final scattering angles:"); for (const auto& [key, value] : scatteringMap) { if (!value.materialIsValid()) { @@ -1478,7 +1603,6 @@ class Gx2Fitter { // step, we will not ignore the boundary checks for measurement surfaces. We // want to create trackstates only on surfaces, that we actually hit. if (gx2fOptions.nUpdateMax > 0) { - ACTS_VERBOSE("Final delta parameters: " << deltaParams.transpose()); ACTS_VERBOSE("Propagate with the final covariance."); // update covariance params.covariance() = fullCovariancePredicted; @@ -1502,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/AmbiguityResolution/ScoreBasedAmbiguityResolution.cpp b/Core/src/AmbiguityResolution/ScoreBasedAmbiguityResolution.cpp index 4dcbb5071d4..c7e47f41046 100644 --- a/Core/src/AmbiguityResolution/ScoreBasedAmbiguityResolution.cpp +++ b/Core/src/AmbiguityResolution/ScoreBasedAmbiguityResolution.cpp @@ -7,186 +7,3 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. #include "Acts/AmbiguityResolution/ScoreBasedAmbiguityResolution.hpp" - -#include "Acts/EventData/SourceLink.hpp" - -#include - -std::vector Acts::ScoreBasedAmbiguityResolution::getCleanedOutTracks( - const std::vector& trackScore, - const std::vector>& trackFeaturesVectors, - const std::vector>& measurementsPerTrack) - const { - std::vector cleanTracks(measurementsPerTrack.size(), false); - - ACTS_VERBOSE("Cleaning tracks"); - - if (trackScore.size() != measurementsPerTrack.size()) { - throw std::invalid_argument( - "Track score and measurementsPerTrack size mismatch"); - } - - std::size_t numberOfTracks = measurementsPerTrack.size(); - ACTS_DEBUG("Number of tracks: " << numberOfTracks); - - boost::container::flat_map> - tracksPerMeasurement; - - // Removes bad tracks and counts computes the vector of tracks per - // measurement. - for (std::size_t iTrack = 0; iTrack < numberOfTracks; ++iTrack) { - if (trackScore[iTrack] <= 0) { - continue; - } - for (auto measurementObjects : measurementsPerTrack[iTrack]) { - auto iMeasurement = measurementObjects.iMeasurement; - tracksPerMeasurement[iMeasurement].insert(iTrack); - } - } - - enum TrackStateTypes { - // A measurement not yet used in any other track - UnsharedHit = 1, - // A measurement shared with another track - SharedHit = 2, - // A hit that needs to be removed from the track - RejectedHit = 3, - // an outlier, to be copied in case - Outlier = 4, - // other trackstate types to be copied in case - OtherTrackStateType = 5 - }; - - std::vector> newMeasurements; - // Loop over all tracks in the track container - for (std::size_t iTrack = 0; iTrack < numberOfTracks; ++iTrack) { - double track_score = trackScore[iTrack]; - ACTS_DEBUG("Track score: " << track_score); - - if (track_score <= 0) { - ACTS_DEBUG("Track " << iTrack << " could not be accepted - low score"); - continue; - } - - const auto& trackFeaturesVector = trackFeaturesVectors.at(iTrack); - - bool trkCouldBeAccepted = true; - - // For tracks with shared hits, we need to check and remove bad hits - - std::vector trackStateTypes(measurementsPerTrack[iTrack].size(), - OtherTrackStateType); - int index = 0; - - // Loop over all measurements of the track and for each hit a - // trackStateTypes is assigned. - for (const auto& measurementObjects : measurementsPerTrack[iTrack]) { - auto iMeasurement = measurementObjects.iMeasurement; - auto isoutliner = measurementObjects.isOutlier; - auto detectorId = measurementObjects.detectorId; - - auto detector = m_cfg.detectorConfigs.at(detectorId); - if (isoutliner) { - ACTS_VERBOSE("Measurement is outlier on a fitter track, copy it over"); - trackStateTypes[index] = Outlier; - index++; - continue; - } - if (tracksPerMeasurement[iMeasurement].size() == 1) { - ACTS_VERBOSE("Measurement is not shared, copy it over"); - - trackStateTypes[index] = UnsharedHit; - - index++; - continue; - } - if (tracksPerMeasurement[iMeasurement].size() > 1) { - ACTS_VERBOSE("Measurement is shared, copy it over"); - - if (detector.sharedHitsFlag == true) { - ACTS_VERBOSE("Measurement is shared, Reject it"); - trackStateTypes[index] = RejectedHit; - index++; - continue; - } - - trackStateTypes[index] = SharedHit; - - index++; - continue; - } - } - - std::vector newMeasurementsPerTrack; - std::size_t measurement = 0; - std::size_t nshared = 0; - - // Loop over all measurements of the track and process them according to the - // trackStateTypes and other conditions. - // Good measurements are copied to the newMeasurementsPerTrack vector. - for (std::size_t i = 0; i < trackStateTypes.size(); i++) { - auto& measurementObjects = measurementsPerTrack[iTrack][i]; - measurement = measurementObjects.iMeasurement; - - if (trackStateTypes[i] == RejectedHit) { - ACTS_DEBUG("Dropping rejected hit"); - } else if (trackStateTypes[i] != SharedHit) { - ACTS_DEBUG("Good TSOS, copy hit"); - newMeasurementsPerTrack.push_back(measurement); - - // a counter called nshared is used to keep track of the number of - // shared hits accepted. - } else if (nshared >= m_cfg.maxShared) { - ACTS_DEBUG("Too many shared hit, drop it"); - } - // If the track is shared, the hit is only accepted if the track has score - // higher than the minimum score for shared tracks. - else { - ACTS_DEBUG("Try to recover shared hit "); - if (tracksPerMeasurement[measurement].size() < - m_cfg.maxSharedTracksPerMeasurement && - track_score > m_cfg.minScoreSharedTracks) { - ACTS_DEBUG("Accepted hit shared with " - << tracksPerMeasurement[measurement].size() << " tracks"); - newMeasurementsPerTrack.push_back(measurement); - nshared++; - } else { - ACTS_DEBUG("Rejected hit shared with " - << tracksPerMeasurement[measurement].size() << " tracks"); - } - } - } - - // Check if the track has enough hits to be accepted. - if (newMeasurementsPerTrack.size() < 3) { - trkCouldBeAccepted = false; - ACTS_DEBUG(std::endl - << "Track " << iTrack - << " could not be accepted - not enough hits"); - ACTS_DEBUG("Number of hits: " << measurementsPerTrack[iTrack].size()); - ACTS_DEBUG("Number of good hits: " << newMeasurementsPerTrack.size()); - continue; - } - - // Check if the track has too many shared hits to be accepted. - for (std::size_t detectorId = 0; detectorId < m_cfg.detectorConfigs.size(); - detectorId++) { - auto detector = m_cfg.detectorConfigs.at(detectorId); - if (trackFeaturesVector[detectorId].nSharedHits > - detector.maxSharedHits) { - trkCouldBeAccepted = false; - break; - } - } - - if (trkCouldBeAccepted) { - cleanTracks[iTrack] = true; - newMeasurements.push_back(newMeasurementsPerTrack); - ACTS_VERBOSE("Track " << iTrack << " is accepted"); - continue; - } - } - - return cleanTracks; -} diff --git a/Core/src/Geometry/TrackingVolume.cpp b/Core/src/Geometry/TrackingVolume.cpp index bbe9b60fc98..6d3880bd4db 100644 --- a/Core/src/Geometry/TrackingVolume.cpp +++ b/Core/src/Geometry/TrackingVolume.cpp @@ -96,6 +96,13 @@ const TrackingVolume* TrackingVolume::lowestTrackingVolume( } } + // @TODO: Abstract this into an accelerateable structure + for (const auto& volume : volumes()) { + if (volume.inside(position, tol)) { + return volume.lowestTrackingVolume(gctx, position, tol); + } + } + // there is no lower sub structure return this; } diff --git a/Core/src/Navigation/TryAllNavigationPolicy.cpp b/Core/src/Navigation/TryAllNavigationPolicy.cpp index 40ca70c4079..4423c7d62a8 100644 --- a/Core/src/Navigation/TryAllNavigationPolicy.cpp +++ b/Core/src/Navigation/TryAllNavigationPolicy.cpp @@ -13,10 +13,10 @@ namespace Acts { -TryAllNavigationPolicy::TryAllNavigationPolicy(const Config& config, - const GeometryContext& /*gctx*/, +TryAllNavigationPolicy::TryAllNavigationPolicy(const GeometryContext& /*gctx*/, const TrackingVolume& volume, - const Logger& logger) + const Logger& logger, + const Config& config) : m_cfg{config}, m_volume(&volume) { assert(m_volume != nullptr); ACTS_VERBOSE("TryAllNavigationPolicy created for volume " @@ -26,7 +26,7 @@ TryAllNavigationPolicy::TryAllNavigationPolicy(const Config& config, TryAllNavigationPolicy::TryAllNavigationPolicy(const GeometryContext& gctx, const TrackingVolume& volume, const Logger& logger) - : TryAllNavigationPolicy({}, gctx, volume, logger) {} + : TryAllNavigationPolicy(gctx, volume, logger, {}) {} void TryAllNavigationPolicy::initializeCandidates( const NavigationArguments& args, AppendOnlyNavigationStream& stream, diff --git a/Core/src/Seeding/EstimateTrackParamsFromSeed.cpp b/Core/src/Seeding/EstimateTrackParamsFromSeed.cpp index eebcd1c5760..055691bbb2f 100644 --- a/Core/src/Seeding/EstimateTrackParamsFromSeed.cpp +++ b/Core/src/Seeding/EstimateTrackParamsFromSeed.cpp @@ -12,6 +12,84 @@ #include +Acts::FreeVector Acts::estimateTrackParamsFromSeed(const Vector3& sp0, + const Vector3& sp1, + const Vector3& sp2, + const Vector3& bField) { + // Define a new coordinate frame with its origin at the bottom space point, z + // axis long the magnetic field direction and y axis perpendicular to vector + // from the bottom to middle space point. Hence, the projection of the middle + // space point on the transverse plane will be located at the x axis of the + // new frame. + Vector3 relVec = sp1 - sp0; + Vector3 newZAxis = bField.normalized(); + Vector3 newYAxis = newZAxis.cross(relVec).normalized(); + Vector3 newXAxis = newYAxis.cross(newZAxis); + RotationMatrix3 rotation; + rotation.col(0) = newXAxis; + rotation.col(1) = newYAxis; + rotation.col(2) = newZAxis; + // The center of the new frame is at the bottom space point + Translation3 trans(sp0); + // The transform which constructs the new frame + Transform3 transform(trans * rotation); + + // The coordinate of the middle and top space point in the new frame + Vector3 local1 = transform.inverse() * sp1; + Vector3 local2 = transform.inverse() * sp2; + + // In the new frame the bottom sp is at the origin, while the middle + // sp in along the x axis. As such, the x-coordinate of the circle is + // at: x-middle / 2. + // The y coordinate can be found by using the straight line passing + // between the mid point between the middle and top sp and perpendicular to + // the line connecting them + Vector2 circleCenter; + circleCenter(0) = 0.5 * local1(0); + + ActsScalar deltaX21 = local2(0) - local1(0); + ActsScalar sumX21 = local2(0) + local1(0); + // straight line connecting the two points + // y = a * x + c (we don't care about c right now) + // we simply need the slope + // we compute 1./a since this is what we need for the following computation + ActsScalar ia = deltaX21 / local2(1); + // Perpendicular line is then y = -1/a *x + b + // we can evaluate b given we know a already by imposing + // the line passes through P = (0.5 * (x2 + x1), 0.5 * y2) + ActsScalar b = 0.5 * (local2(1) + ia * sumX21); + circleCenter(1) = -ia * circleCenter(0) + b; + // Radius is a signed distance between circleCenter and first sp, which is at + // (0, 0) in the new frame. Sign depends on the slope a (positive vs negative) + int sign = ia > 0 ? -1 : 1; + const ActsScalar R = circleCenter.norm(); + ActsScalar invTanTheta = + local2.z() / (2 * R * std::asin(local2.head<2>().norm() / (2 * R))); + // The momentum direction in the new frame (the center of the circle has the + // coordinate (-1.*A/(2*B), 1./(2*B))) + ActsScalar A = -circleCenter(0) / circleCenter(1); + Vector3 transDirection(1., A, fastHypot(1, A) * invTanTheta); + // Transform it back to the original frame + Vector3 direction = rotation * transDirection.normalized(); + + // Initialize the free parameters vector + FreeVector params = FreeVector::Zero(); + + // The bottom space point position + params.segment<3>(eFreePos0) = sp0; + + // The estimated direction + params.segment<3>(eFreeDir0) = direction; + + // The estimated q/pt in [GeV/c]^-1 (note that the pt is the projection of + // momentum on the transverse plane of the new frame) + ActsScalar qOverPt = sign / (bField.norm() * R); + // The estimated q/p in [GeV/c]^-1 + params[eFreeQOverP] = qOverPt / fastHypot(1., invTanTheta); + + return params; +} + Acts::BoundMatrix Acts::estimateTrackParamCovariance( const EstimateTrackParamCovarianceConfig& config, const BoundVector& params, bool hasTime) { diff --git a/Core/src/TrackFitting/GlobalChiSquareFitter.cpp b/Core/src/TrackFitting/GlobalChiSquareFitter.cpp index de61ee090d4..50b8b4cab8c 100644 --- a/Core/src/TrackFitting/GlobalChiSquareFitter.cpp +++ b/Core/src/TrackFitting/GlobalChiSquareFitter.cpp @@ -10,6 +10,30 @@ #include "Acts/Definitions/TrackParametrization.hpp" +void Acts::Experimental::updateGx2fParams( + BoundTrackParameters& params, const Eigen::VectorXd& deltaParamsExtended, + const std::size_t nMaterialSurfaces, + std::unordered_map& scatteringMap, + const std::vector& geoIdVector) { + // update params + params.parameters() += + deltaParamsExtended.topLeftCorner().eval(); + + // update the scattering angles. + for (std::size_t matSurface = 0; matSurface < nMaterialSurfaces; + matSurface++) { + const std::size_t deltaPosition = eBoundSize + 2 * matSurface; + const GeometryIdentifier geoId = geoIdVector[matSurface]; + const auto scatteringMapId = scatteringMap.find(geoId); + assert(scatteringMapId != scatteringMap.end() && + "No scattering angles found for material surface."); + scatteringMapId->second.scatteringAngles().block<2, 1>(2, 0) += + deltaParamsExtended.block<2, 1>(deltaPosition, 0).eval(); + } + + return; +} + void Acts::Experimental::updateGx2fCovarianceParams( BoundMatrix& fullCovariancePredicted, Gx2fSystem& extendedSystem) { // make invertible diff --git a/Examples/Algorithms/AmbiguityResolution/src/ScoreBasedAmbiguityResolutionAlgorithm.cpp b/Examples/Algorithms/AmbiguityResolution/src/ScoreBasedAmbiguityResolutionAlgorithm.cpp index bd3584fa4b2..b1a6e251dba 100644 --- a/Examples/Algorithms/AmbiguityResolution/src/ScoreBasedAmbiguityResolutionAlgorithm.cpp +++ b/Examples/Algorithms/AmbiguityResolution/src/ScoreBasedAmbiguityResolutionAlgorithm.cpp @@ -116,19 +116,11 @@ ActsExamples::ScoreBasedAmbiguityResolutionAlgorithm::execute( const auto& tracks = m_inputTracks(ctx); // Read input data ACTS_VERBOSE("Number of input tracks: " << tracks.size()); - std::vector> - measurementsPerTracks; - - std::vector> - trackFeaturesVectors; - measurementsPerTracks = m_ambi.computeInitialState( - tracks, &sourceLinkHash, &sourceLinkEquality, trackFeaturesVectors); - Acts::ScoreBasedAmbiguityResolution::OptionalCuts optionalCuts; optionalCuts.cuts.push_back(doubleHolesFilter); std::vector goodTracks = m_ambi.solveAmbiguity( - tracks, measurementsPerTracks, trackFeaturesVectors, optionalCuts); + tracks, &sourceLinkHash, &sourceLinkEquality, optionalCuts); // Prepare the output track collection from the IDs TrackContainer solvedTracks{std::make_shared(), std::make_shared()}; diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationAlgorithm.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationAlgorithm.hpp index fd8937bd300..331408faa9a 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationAlgorithm.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationAlgorithm.hpp @@ -8,18 +8,14 @@ #pragma once -#include "Acts/Definitions/Algebra.hpp" -#include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/Geometry/GeometryContext.hpp" #include "Acts/Geometry/GeometryHierarchyMap.hpp" #include "Acts/Utilities/Logger.hpp" #include "ActsExamples/Digitization/DigitizationConfig.hpp" #include "ActsExamples/Digitization/MeasurementCreation.hpp" -#include "ActsExamples/Digitization/SmearingConfig.hpp" #include "ActsExamples/EventData/Cluster.hpp" -#include "ActsExamples/EventData/Index.hpp" #include "ActsExamples/EventData/Measurement.hpp" #include "ActsExamples/EventData/SimHit.hpp" +#include "ActsExamples/EventData/SimParticle.hpp" #include "ActsExamples/Framework/DataHandle.hpp" #include "ActsExamples/Framework/IAlgorithm.hpp" #include "ActsExamples/Framework/ProcessCode.hpp" @@ -29,28 +25,62 @@ #include "ActsFatras/Digitization/UncorrelatedHitSmearer.hpp" #include -#include #include -#include -#include #include #include -namespace ActsFatras { -class Barcode; -} // namespace ActsFatras - namespace ActsExamples { -struct AlgorithmContext; /// Algorithm that turns simulated hits into measurements by truth smearing. class DigitizationAlgorithm final : public IAlgorithm { public: + class Config { + public: + /// Input collection of simulated hits. + std::string inputSimHits = "simhits"; + /// Output measurements collection. + std::string outputMeasurements = "measurements"; + /// Output cells map (geoID -> collection of cells). + std::string outputCells = "cells"; + /// Output cluster collection. + std::string outputClusters = "clusters"; + /// Output collection to map measured hits to contributing particles. + std::string outputMeasurementParticlesMap = "measurement_particles_map"; + /// Output collection to map measured hits to simulated hits. + std::string outputMeasurementSimHitsMap = "measurement_simhits_map"; + + /// Map of surface by identifier to allow local - to global + std::unordered_map + surfaceByIdentifier; + /// Random numbers tool. + std::shared_ptr randomNumbers = nullptr; + /// Flag to determine whether cell data should be written to the + /// `outputCells` collection; if true, writes (rather voluminous) cell data. + bool doOutputCells = false; + /// Flag to determine whether or not to run the clusterization; if true, + /// clusters, measurements, and sim-hit-maps are output. + bool doClusterization = true; + /// Do we merge hits or not + bool doMerge = false; + /// How close do parameters have to be to consider merged + double mergeNsigma = 1.0; + /// Consider clusters that share a corner as merged (8-cell connectivity) + bool mergeCommonCorner = false; + /// Energy deposit threshold for accepting a hit + /// For a generic readout frontend we assume 1000 e/h pairs, in Si each + /// e/h-pair requiers on average an energy of 3.65 eV (PDG review 2023, + /// Table 35.10) + /// @NOTE The default is set to 0 because this works only well with Geant4 + double minEnergyDeposit = 0.0; // 1000 * 3.65 * Acts::UnitConstants::eV; + /// The digitizers per GeometryIdentifiers + Acts::GeometryHierarchyMap digitizationConfigs; + }; + /// Construct the smearing algorithm. /// /// @param config is the algorithm configuration /// @param level is the logging level - DigitizationAlgorithm(DigitizationConfig config, Acts::Logging::Level level); + DigitizationAlgorithm(Config config, Acts::Logging::Level level); /// Build measurement from simulation hits at input. /// @@ -59,7 +89,7 @@ class DigitizationAlgorithm final : public IAlgorithm { ProcessCode execute(const AlgorithmContext& ctx) const override; /// Get const access to the config - const DigitizationConfig& config() const { return m_cfg; } + const Config& config() const { return m_cfg; } private: /// Helper method for creating digitized parameters from clusters @@ -89,7 +119,7 @@ class DigitizationAlgorithm final : public IAlgorithm { CombinedDigitizer<4>>; /// Configuration of the Algorithm - DigitizationConfig m_cfg; + Config m_cfg; /// Digitizers within geometry hierarchy Acts::GeometryHierarchyMap m_digitizers; /// Geometric digtizer @@ -98,17 +128,17 @@ class DigitizationAlgorithm final : public IAlgorithm { using CellsMap = std::map>; - ReadDataHandle m_simContainerReadHandle{this, - "SimHitContainer"}; - - WriteDataHandle m_measurementWriteHandle{ - this, "Measurements"}; - WriteDataHandle m_cellsWriteHandle{this, "Cells"}; - WriteDataHandle m_clusterWriteHandle{this, "Clusters"}; - WriteDataHandle> - m_measurementParticlesMapWriteHandle{this, "MeasurementParticlesMap"}; - WriteDataHandle> m_measurementSimHitsMapWriteHandle{ - this, "MeasurementSimHitsMap"}; + ReadDataHandle m_inputHits{this, "InputHits"}; + + WriteDataHandle m_outputMeasurements{ + this, "OutputMeasurements"}; + WriteDataHandle m_outputCells{this, "OutputCells"}; + WriteDataHandle m_outputClusters{this, "OutputClusters"}; + + WriteDataHandle> m_outputMeasurementParticlesMap{ + this, "OutputMeasurementParticlesMap"}; + WriteDataHandle> m_outputMeasurementSimHitsMap{ + this, "OutputMeasurementSimHitsMap"}; /// Construct a fixed-size smearer from a configuration. /// diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfig.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfig.hpp index 6a933f50075..213abe4d322 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfig.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfig.hpp @@ -8,107 +8,12 @@ #pragma once -#include "Acts/Definitions/Algebra.hpp" -#include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/Definitions/Units.hpp" #include "Acts/Geometry/GeometryHierarchyMap.hpp" -#include "Acts/Utilities/BinUtility.hpp" -#include "Acts/Utilities/BinningType.hpp" -#include "Acts/Utilities/Logger.hpp" -#include "Acts/Utilities/Result.hpp" -#include "ActsExamples/Digitization/DigitizationConfig.hpp" -#include "ActsExamples/Digitization/Smearers.hpp" +#include "ActsExamples/Digitization/GeometricConfig.hpp" #include "ActsExamples/Digitization/SmearingConfig.hpp" -#include "ActsExamples/Framework/RandomNumbers.hpp" -#include "ActsFatras/Digitization/UncorrelatedHitSmearer.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Acts { -class GeometryIdentifier; -} // namespace Acts namespace ActsExamples { -/// Configuration struct for geometric digitization -/// -/// If this is defined, then the geometric digitization -/// will create clusters with cells. -/// The BinUtility defines the segmentation and which parameters -/// are defined by this. -/// -struct GeometricConfig { - // The dimensions of the measurement - std::vector indices = {}; - - // The (multidimensional) binning definition for the segmentation of the - // sensor - Acts::BinUtility segmentation; - - // The thickness of the sensor - double thickness = 0.; - - /// The charge smearer - ActsFatras::SingleParameterSmearFunction - chargeSmearer = Digitization::Exact(0); - - // The threshold below a cell activation is ignored - double threshold = 0.; - - // Whether to assume digital readout (activation is either 0 or 1) - bool digital = false; - - // Flag as strip - bool strip = false; - - /// The variances for this digitization - std::map> varianceMap = {}; - - /// Charge generation (configurable via the chargeSmearer) - Acts::ActsScalar charge(Acts::ActsScalar path, RandomEngine &rng) const { - if (!chargeSmearer) { - return path; - } - auto res = chargeSmearer(path, rng); - if (res.ok()) { - return std::max(0.0, res->first); - } else { - throw std::runtime_error(res.error().message()); - } - } - - /// This generates the variances for a given cluster - /// - /// @note either the variances are directly taken from a pre-read - /// variance map, or they are generated from the pitch size - /// - /// @param csizes is the cluster size in the different dimensions - /// @param cmins is the cluster minimum in the different dimensions - /// - /// @return a vector of variances for the cluster - std::vector variances( - const std::array &csizes, - const std::array &cmins) const; - - /// Drift generation (currently not implemented) - /// Takes as an argument the position, and a random engine - /// @return drift direction in local 3D coordinates - Acts::Vector3 drift(const Acts::Vector3 & /*position*/, - RandomEngine & /*rng*/) const { - return Acts::Vector3(0., 0., 0.); - }; -}; - /// Configuration struct for the Digitization algorithm /// /// It contains: @@ -116,63 +21,9 @@ struct GeometricConfig { /// - optional SmearingConfig struct DigiComponentsConfig { GeometricConfig geometricDigiConfig; - SmearingConfig smearingDigiConfig = {}; + SmearingConfig smearingDigiConfig; }; -class DigitizationConfig { - public: - DigitizationConfig(bool merge, double sigma, bool commonCorner) - : DigitizationConfig(merge, sigma, commonCorner, - Acts::GeometryHierarchyMap()) { - } - - DigitizationConfig( - bool doMerge, double mergeNsigma, bool mergeCommonCorner, - Acts::GeometryHierarchyMap &&digiCfgs); - - explicit DigitizationConfig( - Acts::GeometryHierarchyMap &&digiCfgs); +using DigiConfigContainer = Acts::GeometryHierarchyMap; - /// Input collection of simulated hits. - std::string inputSimHits = "simhits"; - /// Output measurements collection. - std::string outputMeasurements = "measurements"; - /// Output cells map (geoID -> collection of cells). - std::string outputCells = "cells"; - /// Output cluster collection. - std::string outputClusters = "clusters"; - /// Output collection to map measured hits to contributing particles. - std::string outputMeasurementParticlesMap = "measurement_particles_map"; - /// Output collection to map measured hits to simulated hits. - std::string outputMeasurementSimHitsMap = "measurement_simhits_map"; - /// Map of surface by identifier to allow local - to global - std::unordered_map - surfaceByIdentifier; - /// Random numbers tool. - std::shared_ptr randomNumbers = nullptr; - /// Flag to determine whether cell data should be written to the - /// `outputCells` collection; if true, writes (rather voluminous) cell data. - bool doOutputCells = false; - /// Flag to determine whether or not to run the clusterization; if true, - /// clusters, measurements, and sim-hit-maps are output. - bool doClusterization = true; - /// Do we merge hits or not - bool doMerge; - /// How close do parameters have to be to consider merged - const double mergeNsigma; - /// Consider clusters that share a corner as merged (8-cell connectivity) - const bool mergeCommonCorner; - /// Energy deposit threshold for accepting a hit - /// For a generic readout frontend we assume 1000 e/h pairs, in Si each - /// e/h-pair requiers on average an energy of 3.65 eV (PDG review 2023, - /// Table 35.10) - /// @NOTE The default is set to 0 because this works only well with Geant4 - double minEnergyDeposit = 0.0; // 1000 * 3.65 * Acts::UnitConstants::eV; - /// The digitizers per GeometryIdentifiers - Acts::GeometryHierarchyMap digitizationConfigs; - - std::vector< - std::pair>> - getBoundIndices() const; -}; } // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfigurator.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfigurator.hpp index 55754eb79f7..3e6d01dea0f 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfigurator.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfigurator.hpp @@ -11,21 +11,9 @@ #include "Acts/Geometry/GeometryHierarchyMap.hpp" #include "Acts/Geometry/GeometryIdentifier.hpp" #include "Acts/Geometry/TrackingGeometry.hpp" -#include "Acts/Surfaces/AnnulusBounds.hpp" -#include "Acts/Surfaces/DiscTrapezoidBounds.hpp" -#include "Acts/Surfaces/RadialBounds.hpp" -#include "Acts/Surfaces/RectangleBounds.hpp" -#include "Acts/Surfaces/SurfaceBounds.hpp" -#include "Acts/Surfaces/TrapezoidBounds.hpp" -#include "Acts/Utilities/BinUtility.hpp" -#include "Acts/Utilities/BinningData.hpp" -#include "ActsExamples/Digitization/DigitizationAlgorithm.hpp" #include "ActsExamples/Digitization/DigitizationConfig.hpp" #include -#include -#include -#include namespace Acts { class Surface; @@ -66,4 +54,5 @@ struct DigitizationConfigurator { /// it adds an appropriate entry into the digitisation configuration void operator()(const Acts::Surface* surface); }; + } // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationCoordinatesConverter.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationCoordinatesConverter.hpp index 21c4f619b8a..382e113844f 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationCoordinatesConverter.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationCoordinatesConverter.hpp @@ -8,6 +8,7 @@ #pragma once +#include "ActsExamples/Digitization/DigitizationAlgorithm.hpp" #include "ActsExamples/Digitization/DigitizationConfig.hpp" namespace ActsExamples { @@ -18,10 +19,11 @@ class DigitizationCoordinatesConverter final { /// Construct the converter /// /// @param config is the configuration - explicit DigitizationCoordinatesConverter(DigitizationConfig config); + explicit DigitizationCoordinatesConverter( + DigitizationAlgorithm::Config config); /// Get const access to the config - const DigitizationConfig& config() const { return m_cfg; } + const DigitizationAlgorithm::Config& config() const { return m_cfg; } /// Convert the hit coordinates to the local frame. std::tuple globalToLocal(std::uint64_t moduleId, double x, @@ -33,7 +35,7 @@ class DigitizationCoordinatesConverter final { private: /// Configuration - DigitizationConfig m_cfg; + DigitizationAlgorithm::Config m_cfg; }; } // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/GeometricConfig.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/GeometricConfig.hpp new file mode 100644 index 00000000000..6b4348e20f6 --- /dev/null +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/GeometricConfig.hpp @@ -0,0 +1,98 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Definitions/TrackParametrization.hpp" +#include "Acts/Utilities/BinUtility.hpp" +#include "Acts/Utilities/Result.hpp" +#include "ActsExamples/Digitization/Smearers.hpp" +#include "ActsExamples/Framework/RandomNumbers.hpp" +#include "ActsFatras/Digitization/UncorrelatedHitSmearer.hpp" + +#include +#include +#include +#include +#include +#include +#include + +namespace ActsExamples { + +/// Configuration struct for geometric digitization +/// +/// If this is defined, then the geometric digitization +/// will create clusters with cells. +/// The BinUtility defines the segmentation and which parameters +/// are defined by this. +/// +struct GeometricConfig { + // The dimensions of the measurement + std::vector indices = {}; + + // The (multidimensional) binning definition for the segmentation of the + // sensor + Acts::BinUtility segmentation; + + // The thickness of the sensor + double thickness = 0.; + + /// The charge smearer + ActsFatras::SingleParameterSmearFunction + chargeSmearer = Digitization::Exact(0); + + // The threshold below a cell activation is ignored + double threshold = 0.; + + // Whether to assume digital readout (activation is either 0 or 1) + bool digital = false; + + // Flag as strip + bool strip = false; + + /// The variances for this digitization + std::map> varianceMap = {}; + + /// Charge generation (configurable via the chargeSmearer) + Acts::ActsScalar charge(Acts::ActsScalar path, RandomEngine &rng) const { + if (!chargeSmearer) { + return path; + } + auto res = chargeSmearer(path, rng); + if (res.ok()) { + return std::max(0.0, res->first); + } else { + throw std::runtime_error(res.error().message()); + } + } + + /// This generates the variances for a given cluster + /// + /// @note either the variances are directly taken from a pre-read + /// variance map, or they are generated from the pitch size + /// + /// @param csizes is the cluster size in the different dimensions + /// @param cmins is the cluster minimum in the different dimensions + /// + /// @return a vector of variances for the cluster + std::vector variances( + const std::array &csizes, + const std::array &cmins) const; + + /// Drift generation (currently not implemented) + /// Takes as an argument the position, and a random engine + /// @return drift direction in local 3D coordinates + Acts::Vector3 drift(const Acts::Vector3 & /*position*/, + RandomEngine & /*rng*/) const { + return Acts::Vector3(0., 0., 0.); + }; +}; + +} // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/ModuleClusters.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/ModuleClusters.hpp index 675f86af07d..452111db2eb 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/ModuleClusters.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/ModuleClusters.hpp @@ -16,10 +16,8 @@ #include "ActsExamples/EventData/Cluster.hpp" #include "ActsExamples/EventData/SimHit.hpp" -#include #include #include -#include #include #include #include @@ -69,4 +67,5 @@ class ModuleClusters { std::vector> mergeParameters( std::vector values); }; + } // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/Smearers.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/Smearers.hpp index c51b8e26b64..8d0130831ae 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/Smearers.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/Smearers.hpp @@ -12,13 +12,10 @@ #include "Acts/Utilities/Result.hpp" #include "ActsExamples/Framework/RandomNumbers.hpp" #include "ActsFatras/Digitization/DigitizationError.hpp" -#include "ActsFatras/Digitization/UncorrelatedHitSmearer.hpp" #include #include #include -#include -#include #include namespace ActsExamples::Digitization { diff --git a/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp b/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp index 72f3905ab57..07019be74ca 100644 --- a/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp +++ b/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp @@ -11,35 +11,24 @@ #include "Acts/Definitions/Algebra.hpp" #include "Acts/Definitions/TrackParametrization.hpp" #include "Acts/Geometry/GeometryIdentifier.hpp" -#include "Acts/Geometry/TrackingGeometry.hpp" -#include "Acts/Surfaces/Surface.hpp" #include "Acts/Utilities/BinUtility.hpp" -#include "Acts/Utilities/Result.hpp" #include "ActsExamples/Digitization/ModuleClusters.hpp" -#include "ActsExamples/EventData/GeometryContainers.hpp" -#include "ActsExamples/EventData/Index.hpp" -#include "ActsExamples/EventData/SimHit.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" -#include "ActsExamples/Utilities/GroupBy.hpp" -#include "ActsExamples/Utilities/Range.hpp" #include "ActsFatras/EventData/Barcode.hpp" -#include "ActsFatras/EventData/Hit.hpp" #include #include -#include -#include #include #include -#include #include #include #include -ActsExamples::DigitizationAlgorithm::DigitizationAlgorithm( - DigitizationConfig config, Acts::Logging::Level level) - : ActsExamples::IAlgorithm("DigitizationAlgorithm", level), - m_cfg(std::move(config)) { +namespace ActsExamples { + +DigitizationAlgorithm::DigitizationAlgorithm(Config config, + Acts::Logging::Level level) + : IAlgorithm("DigitizationAlgorithm", level), m_cfg(std::move(config)) { if (m_cfg.inputSimHits.empty()) { throw std::invalid_argument("Missing simulated hits input collection"); } @@ -69,12 +58,11 @@ ActsExamples::DigitizationAlgorithm::DigitizationAlgorithm( "Missing hit-to-simulated-hits map output collection"); } - m_measurementWriteHandle.initialize(m_cfg.outputMeasurements); - m_clusterWriteHandle.initialize(m_cfg.outputClusters); - m_measurementParticlesMapWriteHandle.initialize( + m_outputMeasurements.initialize(m_cfg.outputMeasurements); + m_outputClusters.initialize(m_cfg.outputClusters); + m_outputMeasurementParticlesMap.initialize( m_cfg.outputMeasurementParticlesMap); - m_measurementSimHitsMapWriteHandle.initialize( - m_cfg.outputMeasurementSimHitsMap); + m_outputMeasurementSimHitsMap.initialize(m_cfg.outputMeasurementSimHitsMap); } if (m_cfg.doOutputCells) { @@ -82,10 +70,10 @@ ActsExamples::DigitizationAlgorithm::DigitizationAlgorithm( throw std::invalid_argument("Missing cell output collection"); } - m_cellsWriteHandle.initialize(m_cfg.outputCells); + m_outputCells.initialize(m_cfg.outputCells); } - m_simContainerReadHandle.initialize(m_cfg.inputSimHits); + m_inputHits.initialize(m_cfg.inputSimHits); // Create the digitizers from the configuration std::vector> digitizerInput; @@ -139,16 +127,16 @@ ActsExamples::DigitizationAlgorithm::DigitizationAlgorithm( m_digitizers = Acts::GeometryHierarchyMap(digitizerInput); } -ActsExamples::ProcessCode ActsExamples::DigitizationAlgorithm::execute( - const AlgorithmContext& ctx) const { +ProcessCode DigitizationAlgorithm::execute(const AlgorithmContext& ctx) const { // Retrieve input - const auto& simHits = m_simContainerReadHandle(ctx); + const auto& simHits = m_inputHits(ctx); ACTS_DEBUG("Loaded " << simHits.size() << " sim hits"); // Prepare output containers // need list here for stable addresses MeasurementContainer measurements; ClusterContainer clusters; + IndexMultimap measurementParticlesMap; IndexMultimap measurementSimHitsMap; measurements.reserve(simHits.size()); @@ -271,7 +259,7 @@ ActsExamples::ProcessCode ActsExamples::DigitizationAlgorithm::execute( // Store the cell data into a map. if (m_cfg.doOutputCells) { std::vector cells; - for (const auto& [dParameters, simhits] : + for (const auto& [dParameters, simHitsIdxs] : digitizeParametersResult) { for (const auto& cell : dParameters.cluster.channels) { cells.push_back(cell); @@ -281,21 +269,18 @@ ActsExamples::ProcessCode ActsExamples::DigitizationAlgorithm::execute( } if (m_cfg.doClusterization) { - for (auto& [dParameters, simhits] : digitizeParametersResult) { - // The measurement container is unordered and the index under - // which the measurement will be stored is known before adding it. - Index measurementIdx = measurements.size(); - - createMeasurement(measurements, moduleGeoId, dParameters); + for (auto& [dParameters, simHitsIdxs] : digitizeParametersResult) { + auto measurement = + createMeasurement(measurements, moduleGeoId, dParameters); clusters.emplace_back(std::move(dParameters.cluster)); - // this digitization does hit merging so there can be more than - // one mapping entry for each digitized hit. - for (auto simHitIdx : simhits) { + + for (auto [i, simHitIdx] : Acts::enumerate(simHitsIdxs)) { measurementParticlesMap.emplace_hint( - measurementParticlesMap.end(), measurementIdx, + measurementParticlesMap.end(), measurement.index(), simHits.nth(simHitIdx)->particleId()); measurementSimHitsMap.emplace_hint(measurementSimHitsMap.end(), - measurementIdx, simHitIdx); + measurement.index(), + simHitIdx); } } } @@ -309,23 +294,22 @@ ActsExamples::ProcessCode ActsExamples::DigitizationAlgorithm::execute( << " skipped in Digitization. Enable DEBUG mode to see more details."); } - if (m_cfg.doOutputCells) { - m_cellsWriteHandle(ctx, std::move(cellsMap)); + if (m_cfg.doClusterization) { + m_outputMeasurements(ctx, std::move(measurements)); + m_outputClusters(ctx, std::move(clusters)); + + m_outputMeasurementParticlesMap(ctx, std::move(measurementParticlesMap)); + m_outputMeasurementSimHitsMap(ctx, std::move(measurementSimHitsMap)); } - if (m_cfg.doClusterization) { - m_measurementWriteHandle(ctx, std::move(measurements)); - m_clusterWriteHandle(ctx, std::move(clusters)); - m_measurementParticlesMapWriteHandle(ctx, - std::move(measurementParticlesMap)); - m_measurementSimHitsMapWriteHandle(ctx, std::move(measurementSimHitsMap)); + if (m_cfg.doOutputCells) { + m_outputCells(ctx, std::move(cellsMap)); } return ProcessCode::SUCCESS; } -ActsExamples::DigitizedParameters -ActsExamples::DigitizationAlgorithm::localParameters( +DigitizedParameters DigitizationAlgorithm::localParameters( const GeometricConfig& geoCfg, const std::vector& channels, RandomEngine& rng) const { @@ -377,3 +361,5 @@ ActsExamples::DigitizationAlgorithm::localParameters( return dParameters; } + +} // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/src/DigitizationConfig.cpp b/Examples/Algorithms/Digitization/src/DigitizationConfig.cpp index e19452d1e7a..8c23ba729d1 100644 --- a/Examples/Algorithms/Digitization/src/DigitizationConfig.cpp +++ b/Examples/Algorithms/Digitization/src/DigitizationConfig.cpp @@ -8,59 +8,9 @@ #include "ActsExamples/Digitization/DigitizationConfig.hpp" -#include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/Geometry/GeometryIdentifier.hpp" -#include "ActsExamples/Digitization/SmearingConfig.hpp" +namespace ActsExamples { -namespace { - -enum SmearingTypes : int { - eGauss = 0, - eGaussTruncated = 1, - eGaussClipped = 2, - eUniform = 3, - eDigital = 4, -}; - -} // namespace - -ActsExamples::DigitizationConfig::DigitizationConfig( - bool merge, double sigma, bool commonCorner, - Acts::GeometryHierarchyMap&& digiCfgs) - : doMerge(merge), mergeNsigma(sigma), mergeCommonCorner(commonCorner) { - digitizationConfigs = std::move(digiCfgs); -} - -ActsExamples::DigitizationConfig::DigitizationConfig( - Acts::GeometryHierarchyMap&& digiCfgs) - : doMerge(false), mergeNsigma(1.0), mergeCommonCorner(false) { - digitizationConfigs = std::move(digiCfgs); -} - -std::vector< - std::pair>> -ActsExamples::DigitizationConfig::getBoundIndices() const { - std::vector< - std::pair>> - bIndexInput; - - for (std::size_t ibi = 0; ibi < digitizationConfigs.size(); ++ibi) { - Acts::GeometryIdentifier geoID = digitizationConfigs.idAt(ibi); - const auto dCfg = digitizationConfigs.valueAt(ibi); - std::vector boundIndices; - boundIndices.insert(boundIndices.end(), - dCfg.geometricDigiConfig.indices.begin(), - dCfg.geometricDigiConfig.indices.end()); - // we assume nobody will add multiple smearers to a single bound index - for (const auto& c : dCfg.smearingDigiConfig) { - boundIndices.push_back(c.index); - } - bIndexInput.push_back({geoID, boundIndices}); - } - return bIndexInput; -} - -std::vector ActsExamples::GeometricConfig::variances( +std::vector GeometricConfig::variances( const std::array& csizes, const std::array& cmins) const { std::vector rVariances; @@ -80,3 +30,5 @@ std::vector ActsExamples::GeometricConfig::variances( } return rVariances; } + +} // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/src/DigitizationConfigurator.cpp b/Examples/Algorithms/Digitization/src/DigitizationConfigurator.cpp index e7bd2ddfa09..bbf6ec7583b 100644 --- a/Examples/Algorithms/Digitization/src/DigitizationConfigurator.cpp +++ b/Examples/Algorithms/Digitization/src/DigitizationConfigurator.cpp @@ -9,7 +9,6 @@ #include "ActsExamples/Digitization/DigitizationConfigurator.hpp" #include "Acts/Definitions/Algebra.hpp" -#include "Acts/Definitions/TrackParametrization.hpp" #include "Acts/Surfaces/AnnulusBounds.hpp" #include "Acts/Surfaces/DiscTrapezoidBounds.hpp" #include "Acts/Surfaces/RadialBounds.hpp" @@ -25,9 +24,9 @@ #include #include -#include namespace { + /// @note This does not really compare if the configs are equal, therefore /// it is no operator==. The contained std::function types cannot really /// be checked for equality. @@ -47,6 +46,7 @@ bool digiConfigMaybeEqual(ActsExamples::DigiComponentsConfig &a, ag.thickness == bg.thickness && ag.threshold == bg.threshold && ag.digital == bg.digital); } + } // namespace void ActsExamples::DigitizationConfigurator::operator()( diff --git a/Examples/Algorithms/Digitization/src/DigitizationCoordinatesConverter.cpp b/Examples/Algorithms/Digitization/src/DigitizationCoordinatesConverter.cpp index e83e7be995b..b996306fb13 100644 --- a/Examples/Algorithms/Digitization/src/DigitizationCoordinatesConverter.cpp +++ b/Examples/Algorithms/Digitization/src/DigitizationCoordinatesConverter.cpp @@ -10,21 +10,22 @@ #include "Acts/Definitions/Algebra.hpp" #include "Acts/Geometry/GeometryContext.hpp" +#include "ActsExamples/Digitization/DigitizationAlgorithm.hpp" -#include #include #include -ActsExamples::DigitizationCoordinatesConverter:: - DigitizationCoordinatesConverter(DigitizationConfig config) +namespace ActsExamples { + +DigitizationCoordinatesConverter::DigitizationCoordinatesConverter( + DigitizationAlgorithm::Config config) : m_cfg(std::move(config)) { if (m_cfg.surfaceByIdentifier.empty()) { throw std::invalid_argument("Missing Surface-GeometryID association map"); } } -std::tuple -ActsExamples::DigitizationCoordinatesConverter::globalToLocal( +std::tuple DigitizationCoordinatesConverter::globalToLocal( std::uint64_t moduleId, double x, double y, double z) const { const Acts::GeometryIdentifier moduleGeoId = moduleId; auto surfaceItr = m_cfg.surfaceByIdentifier.find(moduleGeoId); @@ -44,8 +45,8 @@ ActsExamples::DigitizationCoordinatesConverter::globalToLocal( } std::tuple -ActsExamples::DigitizationCoordinatesConverter::localToGlobal( - std::uint64_t moduleId, double x, double y) const { +DigitizationCoordinatesConverter::localToGlobal(std::uint64_t moduleId, + double x, double y) const { const Acts::GeometryIdentifier moduleGeoId = moduleId; auto surfaceItr = m_cfg.surfaceByIdentifier.find(moduleGeoId); if (surfaceItr == m_cfg.surfaceByIdentifier.end()) { @@ -61,3 +62,5 @@ ActsExamples::DigitizationCoordinatesConverter::localToGlobal( return {pos2Global.x(), pos2Global.y(), pos2Global.z()}; } + +} // namespace ActsExamples diff --git a/Examples/Algorithms/TrackFinding/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/Algorithms/TrackFinding/src/TrackParamsEstimationAlgorithm.cpp b/Examples/Algorithms/TrackFinding/src/TrackParamsEstimationAlgorithm.cpp index c8a30c7147d..dfb0269a56d 100644 --- a/Examples/Algorithms/TrackFinding/src/TrackParamsEstimationAlgorithm.cpp +++ b/Examples/Algorithms/TrackFinding/src/TrackParamsEstimationAlgorithm.cpp @@ -112,10 +112,16 @@ ProcessCode TrackParamsEstimationAlgorithm::execute( } Acts::Vector3 field = *fieldRes; + if (field.norm() < m_cfg.bFieldMin) { + ACTS_WARNING("Magnetic field at seed " << iseed << " is too small " + << field.norm()); + continue; + } + // Estimate the track parameters from seed auto optParams = Acts::estimateTrackParamsFromSeed( ctx.geoContext, seed.sp().begin(), seed.sp().end(), *surface, field, - m_cfg.bFieldMin, logger()); + logger()); if (!optParams.has_value()) { ACTS_WARNING("Estimation of track parameters for seed " << iseed << " failed."); diff --git a/Examples/Algorithms/TrackFindingExaTrkX/src/PrototracksToParameters.cpp b/Examples/Algorithms/TrackFindingExaTrkX/src/PrototracksToParameters.cpp index c8d34f71bd2..9ffe49ae460 100644 --- a/Examples/Algorithms/TrackFindingExaTrkX/src/PrototracksToParameters.cpp +++ b/Examples/Algorithms/TrackFindingExaTrkX/src/PrototracksToParameters.cpp @@ -154,16 +154,21 @@ ProcessCode PrototracksToParameters::execute( .geometryId(); const auto &surface = *m_cfg.geometry->findSurface(geoId); - auto field = m_cfg.magneticField->getField( + auto fieldRes = m_cfg.magneticField->getField( {bottomSP->x(), bottomSP->y(), bottomSP->z()}, bCache); - if (!field.ok()) { - ACTS_ERROR("Field lookup error: " << field.error()); + if (!fieldRes.ok()) { + ACTS_ERROR("Field lookup error: " << fieldRes.error()); return ProcessCode::ABORT; } + Acts::Vector3 field = *fieldRes; + + if (field.norm() < m_cfg.bFieldMin) { + ACTS_WARNING("Magnetic field at seed is too small " << field.norm()); + continue; + } auto pars = Acts::estimateTrackParamsFromSeed( - ctx.geoContext, seed.sp().begin(), seed.sp().end(), surface, *field, - m_cfg.bFieldMin); + ctx.geoContext, seed.sp().begin(), seed.sp().end(), surface, field); if (not pars) { ACTS_WARNING("Skip track because of bad params"); diff --git a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp index cfc62ab9da9..4c09134ef20 100644 --- a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp +++ b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp @@ -10,21 +10,15 @@ #include "Acts/Definitions/Algebra.hpp" #include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/EventData/ParticleHypothesis.hpp" #include "Acts/Seeding/EstimateTrackParamsFromSeed.hpp" #include "Acts/Surfaces/PerigeeSurface.hpp" #include "Acts/Surfaces/Surface.hpp" -#include "Acts/Utilities/Helpers.hpp" #include "Acts/Utilities/detail/periodic.hpp" #include "ActsExamples/EventData/SimParticle.hpp" #include "ActsExamples/EventData/Track.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" #include "ActsExamples/Framework/RandomNumbers.hpp" -#include "ActsExamples/Utilities/GroupBy.hpp" -#include "ActsExamples/Utilities/Range.hpp" -#include "ActsFatras/EventData/Particle.hpp" -#include #include #include #include diff --git a/Examples/Framework/include/ActsExamples/EventData/Cluster.hpp b/Examples/Framework/include/ActsExamples/EventData/Cluster.hpp index 3eb850b1214..bfd81c9f130 100644 --- a/Examples/Framework/include/ActsExamples/EventData/Cluster.hpp +++ b/Examples/Framework/include/ActsExamples/EventData/Cluster.hpp @@ -8,10 +8,10 @@ #pragma once +#include "Acts/Definitions/Algebra.hpp" #include "ActsFatras/Digitization/Segmentizer.hpp" #include -#include #include namespace ActsExamples { diff --git a/Examples/Framework/include/ActsExamples/Framework/RandomNumbers.hpp b/Examples/Framework/include/ActsExamples/Framework/RandomNumbers.hpp index 6f9f9abbcd6..a94bac778f6 100644 --- a/Examples/Framework/include/ActsExamples/Framework/RandomNumbers.hpp +++ b/Examples/Framework/include/ActsExamples/Framework/RandomNumbers.hpp @@ -6,18 +6,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -// -// RandomNumbers.hpp -// ActsExamples -// -// Created by Andreas Salzburger on 17/05/16. -// -// - #pragma once -#include "ActsExamples/Framework/AlgorithmContext.hpp" - #include #include @@ -27,6 +17,9 @@ struct AlgorithmContext; /// The random number generator used in the framework. using RandomEngine = std::mt19937; ///< Mersenne Twister +/// The seed type used in the framework. +using RandomSeed = std::uint32_t; + /// Provide event and algorithm specific random number generator.s /// /// This provides local random number generators, allowing for @@ -41,7 +34,7 @@ using RandomEngine = std::mt19937; ///< Mersenne Twister class RandomNumbers { public: struct Config { - std::uint64_t seed = 1234567890u; ///< random seed + RandomSeed seed = 1234567890u; ///< random seed }; explicit RandomNumbers(const Config& cfg); @@ -59,7 +52,7 @@ class RandomNumbers { /// /// This should only be used in special cases e.g. where a custom /// random engine is used and `spawnGenerator` can not be used. - std::uint64_t generateSeed(const AlgorithmContext& context) const; + RandomSeed generateSeed(const AlgorithmContext& context) const; private: Config m_cfg; diff --git a/Examples/Framework/src/Framework/RandomNumbers.cpp b/Examples/Framework/src/Framework/RandomNumbers.cpp index 5fd0cdcf7d7..4313a5cce77 100644 --- a/Examples/Framework/src/Framework/RandomNumbers.cpp +++ b/Examples/Framework/src/Framework/RandomNumbers.cpp @@ -6,26 +6,21 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -// -// RandomNumbers.cpp -// ActsExamples -// -// Created by Andreas Salzburger on 17/05/16. -// -// - #include "ActsExamples/Framework/RandomNumbers.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" -ActsExamples::RandomNumbers::RandomNumbers(const Config& cfg) : m_cfg(cfg) {} +namespace ActsExamples { + +RandomNumbers::RandomNumbers(const Config& cfg) : m_cfg(cfg) {} -ActsExamples::RandomEngine ActsExamples::RandomNumbers::spawnGenerator( +RandomEngine RandomNumbers::spawnGenerator( const AlgorithmContext& context) const { return RandomEngine(generateSeed(context)); } -std::uint64_t ActsExamples::RandomNumbers::generateSeed( - const AlgorithmContext& context) const { +RandomSeed RandomNumbers::generateSeed(const AlgorithmContext& context) const { return m_cfg.seed + context.eventNumber; } + +} // namespace ActsExamples diff --git a/Examples/Io/Json/include/ActsExamples/Io/Json/JsonDigitizationConfig.hpp b/Examples/Io/Json/include/ActsExamples/Io/Json/JsonDigitizationConfig.hpp index 11e063acaa8..a67756b1dbc 100644 --- a/Examples/Io/Json/include/ActsExamples/Io/Json/JsonDigitizationConfig.hpp +++ b/Examples/Io/Json/include/ActsExamples/Io/Json/JsonDigitizationConfig.hpp @@ -9,12 +9,10 @@ #pragma once #include "Acts/Geometry/GeometryHierarchyMap.hpp" -#include "Acts/Plugins/Json/ActsJson.hpp" #include "Acts/Plugins/Json/GeometryHierarchyMapJsonConverter.hpp" #include "ActsExamples/Digitization/DigitizationConfig.hpp" #include "ActsExamples/Digitization/SmearingConfig.hpp" -#include #include #include @@ -44,7 +42,6 @@ void writeDigiConfigToJson( const Acts::GeometryHierarchyMap& cfg, const std::string& path); -using DigiConfigContainer = Acts::GeometryHierarchyMap; using DigiConfigConverter = Acts::GeometryHierarchyMapJsonConverter; diff --git a/Examples/Io/Root/include/ActsExamples/Io/Root/RootMeasurementWriter.hpp b/Examples/Io/Root/include/ActsExamples/Io/Root/RootMeasurementWriter.hpp index 3958e845fb2..a578295e530 100644 --- a/Examples/Io/Root/include/ActsExamples/Io/Root/RootMeasurementWriter.hpp +++ b/Examples/Io/Root/include/ActsExamples/Io/Root/RootMeasurementWriter.hpp @@ -8,9 +8,6 @@ #pragma once -#include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/Geometry/GeometryContext.hpp" -#include "Acts/Geometry/GeometryHierarchyMap.hpp" #include "Acts/Geometry/GeometryIdentifier.hpp" #include "Acts/Utilities/Logger.hpp" #include "ActsExamples/EventData/Cluster.hpp" @@ -24,7 +21,6 @@ #include #include #include -#include class TFile; class TTree; @@ -34,7 +30,6 @@ class TrackingGeometry; } // namespace Acts namespace ActsExamples { -struct AlgorithmContext; /// @class RootMeasurementWriter /// @@ -64,8 +59,6 @@ class RootMeasurementWriter final : public WriterT { /// file access mode std::string fileMode = "RECREATE"; - /// The indices for this digitization configurations - Acts::GeometryHierarchyMap> boundIndices; /// Map of the geometry identifier to the surface std::unordered_map surfaceByIdentifier; diff --git a/Examples/Io/Root/src/RootMaterialTrackReader.cpp b/Examples/Io/Root/src/RootMaterialTrackReader.cpp index 8781b134559..70b2ab8d997 100644 --- a/Examples/Io/Root/src/RootMaterialTrackReader.cpp +++ b/Examples/Io/Root/src/RootMaterialTrackReader.cpp @@ -89,6 +89,10 @@ RootMaterialTrackReader::RootMaterialTrackReader(const Config& config, // Sort the entry numbers of the events { + // necessary to guarantee that m_inputChain->GetV1() is valid for the + // entire range + m_inputChain->SetEstimate(nentries + 1); + m_entryNumbers.resize(nentries); m_inputChain->Draw("event_id", "", "goff"); RootUtility::stableSort(m_inputChain->GetEntries(), m_inputChain->GetV1(), diff --git a/Examples/Io/Root/src/RootMeasurementWriter.cpp b/Examples/Io/Root/src/RootMeasurementWriter.cpp index b7ab332fdea..df095557664 100644 --- a/Examples/Io/Root/src/RootMeasurementWriter.cpp +++ b/Examples/Io/Root/src/RootMeasurementWriter.cpp @@ -9,20 +9,17 @@ #include "ActsExamples/Io/Root/RootMeasurementWriter.hpp" #include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/Utilities/Enumerate.hpp" #include "ActsExamples/EventData/AverageSimHits.hpp" #include "ActsExamples/EventData/Index.hpp" #include "ActsExamples/EventData/Measurement.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" #include "ActsExamples/Utilities/Range.hpp" -#include #include #include #include #include #include -#include #include #include diff --git a/Examples/Io/Root/src/RootParticleReader.cpp b/Examples/Io/Root/src/RootParticleReader.cpp index a76255dbb4a..631fc25ef3e 100644 --- a/Examples/Io/Root/src/RootParticleReader.cpp +++ b/Examples/Io/Root/src/RootParticleReader.cpp @@ -80,6 +80,10 @@ RootParticleReader::RootParticleReader(const RootParticleReader::Config& config, // Sort the entry numbers of the events { + // necessary to guarantee that m_inputChain->GetV1() is valid for the + // entire range + m_inputChain->SetEstimate(m_events + 1); + m_entryNumbers.resize(m_events); m_inputChain->Draw("event_id", "", "goff"); RootUtility::stableSort(m_inputChain->GetEntries(), m_inputChain->GetV1(), diff --git a/Examples/Io/Root/src/RootTrackSummaryReader.cpp b/Examples/Io/Root/src/RootTrackSummaryReader.cpp index 1827c26ad30..9ff3590271a 100644 --- a/Examples/Io/Root/src/RootTrackSummaryReader.cpp +++ b/Examples/Io/Root/src/RootTrackSummaryReader.cpp @@ -99,6 +99,10 @@ RootTrackSummaryReader::RootTrackSummaryReader( // Sort the entry numbers of the events { + // necessary to guarantee that m_inputChain->GetV1() is valid for the + // entire range + m_inputChain->SetEstimate(m_events + 1); + m_entryNumbers.resize(m_events); m_inputChain->Draw("event_nr", "", "goff"); RootUtility::stableSort(m_inputChain->GetEntries(), m_inputChain->GetV1(), diff --git a/Examples/Io/Root/src/RootVertexReader.cpp b/Examples/Io/Root/src/RootVertexReader.cpp index 336e0364f9b..31a8e6d5bec 100644 --- a/Examples/Io/Root/src/RootVertexReader.cpp +++ b/Examples/Io/Root/src/RootVertexReader.cpp @@ -8,13 +8,12 @@ #include "ActsExamples/Io/Root/RootVertexReader.hpp" -#include "Acts/Definitions/PdgParticle.hpp" #include "Acts/Utilities/Logger.hpp" #include "ActsExamples/EventData/SimParticle.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" +#include "ActsExamples/Io/Root/RootUtility.hpp" #include "ActsFatras/EventData/ProcessType.hpp" -#include #include #include #include @@ -64,11 +63,14 @@ RootVertexReader::RootVertexReader(const RootVertexReader::Config& config, // Sort the entry numbers of the events { + // necessary to guarantee that m_inputChain->GetV1() is valid for the + // entire range + m_inputChain->SetEstimate(m_events + 1); + m_entryNumbers.resize(m_events); m_inputChain->Draw("event_id", "", "goff"); - // Sort to get the entry numbers of the ordered events - TMath::Sort(m_inputChain->GetEntries(), m_inputChain->GetV1(), - m_entryNumbers.data(), false); + RootUtility::stableSort(m_inputChain->GetEntries(), m_inputChain->GetV1(), + m_entryNumbers.data(), false); } } diff --git a/Examples/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/python/acts/examples/simulation.py b/Examples/Python/python/acts/examples/simulation.py index 21c4149661f..65b6820d8b8 100644 --- a/Examples/Python/python/acts/examples/simulation.py +++ b/Examples/Python/python/acts/examples/simulation.py @@ -778,8 +778,8 @@ def addDigitization( rnd = rnd or acts.examples.RandomNumbers() # Digitization - digiCfg = acts.examples.DigitizationConfig( - acts.examples.readDigiConfigFromJson( + digiCfg = acts.examples.DigitizationAlgorithm.Config( + digitizationConfigs=acts.examples.readDigiConfigFromJson( str(digiConfigFile), ), surfaceByIdentifier=trackingGeometry.geoIdSurfaceMap(), @@ -788,7 +788,9 @@ def addDigitization( outputMeasurements="measurements", outputMeasurementParticlesMap="measurement_particles_map", outputMeasurementSimHitsMap="measurement_simhits_map", - doMerge=doMerge, + **acts.examples.defaultKWArgs( + doMerge=doMerge, + ), ) # Not sure how to do this in our style @@ -811,7 +813,6 @@ def addDigitization( filePath=str(outputDirRoot / f"{digiAlg.config.outputMeasurements}.root"), surfaceByIdentifier=trackingGeometry.geoIdSurfaceMap(), ) - rmwConfig.addBoundIndicesFromDigiConfig(digiAlg.config) s.addWriter(acts.examples.RootMeasurementWriter(rmwConfig, customLogLevel())) if outputDirCsv is not None: diff --git a/Examples/Python/src/Digitization.cpp b/Examples/Python/src/Digitization.cpp index 948bcc9593b..5bcce4b74ca 100644 --- a/Examples/Python/src/Digitization.cpp +++ b/Examples/Python/src/Digitization.cpp @@ -6,33 +6,22 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -#include "Acts/Definitions/Algebra.hpp" -#include "Acts/Geometry/GeometryHierarchyMap.hpp" #include "Acts/Plugins/Python/Utilities.hpp" #include "Acts/Utilities/Logger.hpp" #include "ActsExamples/Digitization/DigitizationAlgorithm.hpp" #include "ActsExamples/Digitization/DigitizationConfig.hpp" #include "ActsExamples/Digitization/DigitizationConfigurator.hpp" #include "ActsExamples/Digitization/DigitizationCoordinatesConverter.hpp" -#include "ActsExamples/Framework/AlgorithmContext.hpp" #include "ActsExamples/Io/Json/JsonDigitizationConfig.hpp" #include #include #include #include -#include #include #include -namespace Acts { -class GeometryIdentifier; -} // namespace Acts -namespace ActsExamples { -class IAlgorithm; -} // namespace ActsExamples - namespace py = pybind11; using namespace ActsExamples; @@ -47,19 +36,18 @@ void addDigitization(Context& ctx) { mex.def("writeDigiConfigToJson", ActsExamples::writeDigiConfigToJson); { - using Config = ActsExamples::DigitizationConfig; + using Config = ActsExamples::DigitizationAlgorithm::Config; - py::class_>( - mex, "DigitizationAlgorithm") - .def(py::init(), py::arg("config"), - py::arg("level")) - .def_property_readonly("config", - &ActsExamples::DigitizationAlgorithm::config); + auto a = py::class_>( + mex, "DigitizationAlgorithm") + .def(py::init(), + py::arg("config"), py::arg("level")) + .def_property_readonly( + "config", &ActsExamples::DigitizationAlgorithm::config); - auto c = py::class_(mex, "DigitizationConfig") - .def(py::init>()); + auto c = py::class_(a, "Config").def(py::init<>()); ACTS_PYTHON_STRUCT_BEGIN(c, Config); ACTS_PYTHON_MEMBER(inputSimHits); @@ -81,10 +69,15 @@ void addDigitization(Context& ctx) { patchKwargsConstructor(c); - py::class_(mex, "DigiComponentsConfig"); + auto cc = py::class_(mex, "DigiComponentsConfig") + .def(py::init<>()); + + ACTS_PYTHON_STRUCT_BEGIN(cc, DigiComponentsConfig); + ACTS_PYTHON_MEMBER(geometricDigiConfig); + ACTS_PYTHON_MEMBER(smearingDigiConfig); + ACTS_PYTHON_STRUCT_END(); - py::class_>( - mex, "GeometryHierarchyMap_DigiComponentsConfig") + py::class_(mex, "DigiConfigContainer") .def(py::init>>()); } @@ -107,7 +100,8 @@ void addDigitization(Context& ctx) { py::class_>( mex, "DigitizationCoordinatesConverter") - .def(py::init(), py::arg("config")) + .def(py::init(), + py::arg("config")) .def_property_readonly( "config", &ActsExamples::DigitizationCoordinatesConverter::config) .def("globalToLocal", diff --git a/Examples/Python/src/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/src/Output.cpp b/Examples/Python/src/Output.cpp index 8b742e74b9c..4281f2db26e 100644 --- a/Examples/Python/src/Output.cpp +++ b/Examples/Python/src/Output.cpp @@ -12,8 +12,7 @@ #include "Acts/Utilities/Logger.hpp" #include "Acts/Visualization/IVisualization3D.hpp" #include "Acts/Visualization/ViewConfig.hpp" -#include "ActsExamples/Digitization/DigitizationConfig.hpp" -#include "ActsExamples/Framework/ProcessCode.hpp" +#include "ActsExamples/Digitization/DigitizationAlgorithm.hpp" #include "ActsExamples/Io/Csv/CsvBFieldWriter.hpp" #include "ActsExamples/Io/Csv/CsvExaTrkXGraphWriter.hpp" #include "ActsExamples/Io/Csv/CsvMeasurementWriter.hpp" @@ -52,10 +51,8 @@ #include "ActsExamples/TrackFinding/ITrackParamsLookupReader.hpp" #include "ActsExamples/TrackFinding/ITrackParamsLookupWriter.hpp" -#include #include #include -#include #include #include @@ -270,13 +267,6 @@ void addOutput(Context& ctx) { auto c = py::class_(w, "Config").def(py::init<>()); - c.def("addBoundIndicesFromDigiConfig", - [](Writer::Config& self, const DigitizationConfig& digiCfg) { - self.boundIndices = - Acts::GeometryHierarchyMap>( - digiCfg.getBoundIndices()); - }); - ACTS_PYTHON_STRUCT_BEGIN(c, Writer::Config); ACTS_PYTHON_MEMBER(inputMeasurements); ACTS_PYTHON_MEMBER(inputClusters); @@ -284,7 +274,6 @@ void addOutput(Context& ctx) { ACTS_PYTHON_MEMBER(inputMeasurementSimHitsMap); ACTS_PYTHON_MEMBER(filePath); ACTS_PYTHON_MEMBER(fileMode); - ACTS_PYTHON_MEMBER(boundIndices); ACTS_PYTHON_MEMBER(surfaceByIdentifier); ACTS_PYTHON_STRUCT_END(); } diff --git a/Examples/Python/tests/conftest.py b/Examples/Python/tests/conftest.py index b2015c3f6a0..71c0899fe3f 100644 --- a/Examples/Python/tests/conftest.py +++ b/Examples/Python/tests/conftest.py @@ -357,8 +357,8 @@ def _factory(s): s.addAlgorithm(simAlg) # Digitization - digiCfg = acts.examples.DigitizationConfig( - acts.examples.readDigiConfigFromJson( + digiCfg = acts.examples.DigitizationAlgorithm.Config( + digitizationConfigs=acts.examples.readDigiConfigFromJson( str( Path(__file__).parent.parent.parent.parent / "Examples/Algorithms/Digitization/share/default-smearing-config-generic.json" diff --git a/Examples/Python/tests/requirements.txt b/Examples/Python/tests/requirements.txt index c4067c4adf6..535d3458274 100644 --- a/Examples/Python/tests/requirements.txt +++ b/Examples/Python/tests/requirements.txt @@ -4,42 +4,46 @@ # # pip-compile Examples/Python/tests/requirements.in # -awkward==2.6.1 +awkward==2.7.0 # via # -r Examples/Python/tests/requirements.in # uproot -awkward-cpp==29 +awkward-cpp==41 # via awkward -execnet==2.0.2 +cramjam==2.9.0 + # via uproot +execnet==2.1.1 # via pytest-xdist -fsspec==2024.2.0 +fsspec==2024.10.0 # via # awkward # uproot iniconfig==2.0.0 # via pytest -numpy==1.26.4 +numpy==2.1.3 # via # awkward # awkward-cpp # uproot -packaging==23.2 +packaging==24.2 # via # awkward # pytest # uproot -pluggy==1.4.0 +pluggy==1.5.0 # via pytest -pytest==8.0.0 +pytest==8.3.3 # via # -r Examples/Python/tests/requirements.in # pytest-check # pytest-xdist -pytest-check==2.3.1 +pytest-check==2.4.1 # via -r Examples/Python/tests/requirements.in -pytest-xdist==3.5.0 +pytest-xdist==3.6.1 # via -r Examples/Python/tests/requirements.in -pyyaml==6.0.1 +pyyaml==6.0.2 # via -r Examples/Python/tests/requirements.in -uproot==5.2.2 +uproot==5.5.0 # via -r Examples/Python/tests/requirements.in +xxhash==3.5.0 + # via uproot 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_detectors.py b/Examples/Python/tests/test_detectors.py index c4d2c6ea9ed..3de27524db9 100644 --- a/Examples/Python/tests/test_detectors.py +++ b/Examples/Python/tests/test_detectors.py @@ -161,8 +161,8 @@ def eq(self, other): def test_coordinate_converter(trk_geo): - digiCfg = acts.examples.DigitizationConfig( - acts.examples.readDigiConfigFromJson( + digiCfg = acts.examples.DigitizationAlgorithm.Config( + digitizationConfigs=acts.examples.readDigiConfigFromJson( str( Path(__file__).parent.parent.parent.parent / "Examples/Algorithms/Digitization/share/default-smearing-config-generic.json" diff --git a/Examples/Python/tests/test_navigation.py b/Examples/Python/tests/test_navigation.py index 55ec8ac9540..56c908f7911 100644 --- a/Examples/Python/tests/test_navigation.py +++ b/Examples/Python/tests/test_navigation.py @@ -40,3 +40,9 @@ def test_navigation_policy_factory_add_multiple(): .add(acts.TryAllNavigationPolicy) .add(acts.TryAllNavigationPolicy) ) + + +def test_try_all_arguments(): + acts.NavigationPolicyFactory.make().add( + acts.TryAllNavigationPolicy, acts.TryAllNavigationPolicy.Config(sensitives=True) + ) diff --git a/Examples/Python/tests/test_writer.py b/Examples/Python/tests/test_writer.py index 95cd67decd1..4c9e220f899 100644 --- a/Examples/Python/tests/test_writer.py +++ b/Examples/Python/tests/test_writer.py @@ -165,7 +165,6 @@ def test_root_meas_writer(tmp_path, fatras, trk_geo, assert_root_hash): filePath=str(out), surfaceByIdentifier=trk_geo.geoIdSurfaceMap(), ) - config.addBoundIndicesFromDigiConfig(digiAlg.config) s.addWriter(RootMeasurementWriter(level=acts.logging.INFO, config=config)) s.run() diff --git a/Examples/Scripts/Python/digitization_config.py b/Examples/Scripts/Python/digitization_config.py index dfad1913fd6..1b6de07f477 100755 --- a/Examples/Scripts/Python/digitization_config.py +++ b/Examples/Scripts/Python/digitization_config.py @@ -7,7 +7,7 @@ DigitizationConfigurator, writeDigiConfigToJson, GenericDetector, - GeometryHierarchyMap_DigiComponentsConfig, + DigiConfigContainer, ) @@ -27,9 +27,7 @@ def runDigitizationConfig( trackingGeometry.visitSurfaces(digiConfigurator) - outputConfig = GeometryHierarchyMap_DigiComponentsConfig( - digiConfigurator.outputDigiComponents - ) + outputConfig = DigiConfigContainer(digiConfigurator.outputDigiComponents) writeDigiConfigToJson(outputConfig, str(output)) diff --git a/Examples/Scripts/Python/full_chain_test.py b/Examples/Scripts/Python/full_chain_test.py new file mode 100755 index 00000000000..f0010bd498e --- /dev/null +++ b/Examples/Scripts/Python/full_chain_test.py @@ -0,0 +1,805 @@ +#!/usr/bin/env python3 + +import sys, os, argparse, pathlib + + +def parse_args(): + from acts.examples.reconstruction import SeedingAlgorithm + + parser = argparse.ArgumentParser( + description=""" +Script to test the full chain ACTS simulation and reconstruction. + +This script is provided for interactive developer testing only. +It is not intended (and not supported) for end user use, automated testing, +and certainly should never be called in production. The Python API is the +proper way to access the ActsExamples from scripts. The other Examples/Scripts +are much better examples of how to do that. physmon in the CI is the proper +way to do automated integration tests. This script is only for the case of +interactive testing with one-off configuration specified by command-line options. +""" + ) + parser.add_argument( + "-G", + "--generic-detector", + action="store_true", + help="Use generic detector geometry and config", + ) + parser.add_argument( + "--odd", + default=True, + action=argparse.BooleanOptionalAction, + help="Use Open Data Detector geometry and config (default unless overridden by -G or -A). Requires ACTS_BUILD_ODD.", + ) + parser.add_argument( + "-A", + "--itk", + action="store_true", + help="Use ATLAS ITk geometry and config. Requires acts-itk/ in current directory.", + ) + parser.add_argument( + "-g", + "--geant4", + action="store_true", + help="Use Geant4 instead of Fatras for detector simulation", + ) + parser.add_argument( + "--edm4hep", + type=pathlib.Path, + help="Use edm4hep inputs", + ) + parser.add_argument( + "-b", + "--bf-constant", + action="store_true", + help="Use constant 2T B-field also for ITk; and don't include material map", + ) + parser.add_argument( + "-j", + "--threads", + type=int, + default=-1, + help="Number of parallel threads, negative for automatic (default).", + ) + parser.add_argument( + "-o", + "--output-dir", + "--output", + default=None, + type=pathlib.Path, + help="Directory to write outputs to", + ) + parser.add_argument( + "-O", + "--output-detail", + action="count", + default=0, + help="fewer output files. Use -OO for more output files. Use -OOO to disable all output.", + ) + parser.add_argument( + "-c", + "--output-csv", + action="count", + default=0, + help="Use CSV output instead of ROOT. Specify -cc to output both.", + ) + parser.add_argument( + "-n", + "--events", + type=int, + default=100, + help="The number of events to process (default=%(default)d).", + ) + parser.add_argument( + "-s", + "--skip", + type=int, + default=0, + help="Number of events to skip (default=%(default)d)", + ) + # Many of the following option names were inherited from the old examples binaries and full_chain_odd.py. + # To maintain compatibility, both option names are supported. + parser.add_argument( + "-N", + "--gen-nparticles", + "--gun-particles", + type=int, + default=4, + help="Number of generated particles per vertex from the particle gun (default=%(default)d).", + ) + parser.add_argument( + "-M", + "--gen-nvertices", + "--gun-multiplicity", + "--ttbar-pu", + type=int, + default=200, + help="Number of vertices per event (multiplicity) from the particle gun; or number of pileup events (default=%(default)d)", + ) + parser.add_argument( + "-t", + "--ttbar-pu200", + "--ttbar", + action="store_true", + help="Generate ttbar + mu=200 pile-up using Pythia8", + ) + parser.add_argument( + "-p", + "--gen-pt-range", + "--gun-pt-range", + default="1:10", + help="transverse momentum (pT) range (min:max) of the particle gun in GeV (default=%(default)s)", + ) + parser.add_argument( + "--gen-eta-range", + "--gun-eta-range", + help="Eta range (min:max) of the particle gun (default -2:2 (Generic), -3:3 (ODD), -4:4 (ITk))", + ) + parser.add_argument( + "--gen-cos-theta", + action="store_true", + help="Sample eta as cos(theta) and not uniform", + ) + parser.add_argument( + "-r", + "--random-seed", + type=int, + default=42, + help="Random number seed (default=%(default)d)", + ) + parser.add_argument( + "-F", + "--disable-fpemon", + action="store_true", + help="sets ACTS_SEQUENCER_DISABLE_FPEMON=1", + ) + parser.add_argument( + "-l", + "--loglevel", + type=int, + default=2, + help="The output log level. Please set the wished number (0 = VERBOSE, 1 = DEBUG, 2 = INFO (default), 3 = WARNING, 4 = ERROR, 5 = FATAL).", + ) + parser.add_argument( + "-d", + "--dump-args-calls", + action="store_true", + help="Show pybind function call details", + ) + parser.add_argument( + "--digi-config", + type=pathlib.Path, + help="Digitization configuration file", + ) + parser.add_argument( + "--material-config", + type=pathlib.Path, + help="Material map configuration file", + ) + parser.add_argument( + "-S", + "--seeding-algorithm", + action=EnumAction, + enum=SeedingAlgorithm, + default=SeedingAlgorithm.Default, + help="Select the seeding algorithm to use", + ) + parser.add_argument( + "--ckf", + default=True, + action=argparse.BooleanOptionalAction, + help="Switch CKF on/off", + ) + parser.add_argument( + "--reco", + default=True, + action=argparse.BooleanOptionalAction, + help="Switch reco on/off", + ) + parser.add_argument( + "--vertexing", + default=True, + action=argparse.BooleanOptionalAction, + help="Switch vertexing on/off", + ) + parser.add_argument( + "--MLSeedFilter", + action="store_true", + help="Use the ML seed filter to select seed after the seeding step", + ) + parser.add_argument( + "--ambi-solver", + type=str, + choices=["greedy", "scoring", "ML", "none"], + default="greedy", + help="Set which ambiguity solver to use (default=%(default)s)", + ) + parser.add_argument( + "--ambi-config", + type=pathlib.Path, + default=pathlib.Path.cwd() / "ambi_config.json", + help="Set the configuration file for the Score Based ambiguity resolution (default=%(default)s)", + ) + return parser.parse_args() + + +def full_chain(args): + import acts + + # keep these in memory after we return the sequence + global detector, trackingGeometry, decorators, field, rnd + global logger + + if args.disable_fpemon: + os.environ["ACTS_SEQUENCER_DISABLE_FPEMON"] = "1" + + if args.dump_args_calls: + acts.examples.dump_args_calls(locals()) + + logger = acts.logging.getLogger("full_chain_test") + + nDetArgs = [args.generic_detector, args.odd, args.itk].count(True) + if nDetArgs == 0: + args.generic_detector = True + elif nDetArgs == 2: + args.odd = False + nDetArgs = [args.generic_detector, args.odd, args.itk].count(True) + if nDetArgs != 1: + logger.fatal("require exactly one of: --generic-detector --odd --itk") + sys.exit(2) + if args.generic_detector: + detname = "gen" + elif args.itk: + detname = "itk" + elif args.odd: + detname = "odd" + + u = acts.UnitConstants + + if args.output_detail == 3: + outputDirLess = None + elif args.output_dir is None: + outputDirLess = pathlib.Path.cwd() / f"{detname}_output" + else: + outputDirLess = args.output_dir + + outputDir = None if args.output_detail == 1 else outputDirLess + outputDirMore = None if args.output_detail in (0, 1) else outputDirLess + + outputDirRoot = outputDir if args.output_csv != 1 else None + outputDirLessRoot = outputDirLess if args.output_csv != 1 else None + outputDirMoreRoot = outputDirMore if args.output_csv != 1 else None + outputDirCsv = outputDir if args.output_csv != 0 else None + outputDirLessCsv = outputDirLess if args.output_csv != 0 else None + outputDirMoreCsv = outputDirMore if args.output_csv != 0 else None + + # fmt: off + if args.generic_detector: + etaRange = (-2.0, 2.0) + ptMin = 0.5 * u.GeV + rhoMax = 24.0 * u.mm + geo_dir = pathlib.Path(acts.__file__).resolve().parent.parent.parent.parent.parent + if args.loglevel <= 2: + logger.info(f"Load Generic Detector from {geo_dir}") + if args.digi_config is None: + args.digi_config = geo_dir / "Examples/Algorithms/Digitization/share/default-smearing-config-generic.json" + seedingConfigFile = geo_dir / "Examples/Algorithms/TrackFinding/share/geoSelection-genericDetector.json" + args.bf_constant = True + detector, trackingGeometry, decorators = acts.examples.GenericDetector.create() + elif args.odd: + import acts.examples.odd + etaRange = (-3.0, 3.0) + ptMin = 1.0 * u.GeV + rhoMax = 24.0 * u.mm + beamTime = 1.0 * u.ns + geo_dir = acts.examples.odd.getOpenDataDetectorDirectory() + if args.loglevel <= 2: + logger.info(f"Load Open Data Detector from {geo_dir.resolve()}") + if args.digi_config is None: + args.digi_config = geo_dir / "config/odd-digi-smearing-config.json" + seedingConfigFile = geo_dir / "config/odd-seeding-config.json" + if args.material_config is None: + args.material_config = geo_dir / "data/odd-material-maps.root" + args.bf_constant = True + detector, trackingGeometry, decorators = acts.examples.odd.getOpenDataDetector( + odd_dir=geo_dir, + mdecorator=acts.IMaterialDecorator.fromFile(args.material_config), + ) + elif args.itk: + import acts.examples.itk as itk + etaRange = (-4.0, 4.0) + ptMin = 1.0 * u.GeV + rhoMax = 28.0 * u.mm + beamTime = 5.0 * u.ns + geo_dir = pathlib.Path("acts-itk") + if args.loglevel <= 2: + logger.info(f"Load ATLAS ITk from {geo_dir.resolve()}") + if args.digi_config is None: + args.digi_config = geo_dir / "itk-hgtd/itk-smearing-config.json" + seedingConfigFile = geo_dir / "itk-hgtd/geoSelection-ITk.json" + # args.material_config defaulted in itk.buildITkGeometry: geo_dir / "itk-hgtd/material-maps-ITk-HGTD.json" + bFieldFile = geo_dir / "bfield/ATLAS-BField-xyz.root" + detector, trackingGeometry, decorators = itk.buildITkGeometry( + geo_dir, + customMaterialFile=args.material_config, + material=not args.bf_constant, + logLevel=acts.logging.Level(args.loglevel), + ) + # fmt: on + + if args.bf_constant: + field = acts.ConstantBField(acts.Vector3(0.0, 0.0, 2.0 * u.T)) + else: + logger.info("Create magnetic field map from %s" % str(bFieldFile)) + field = acts.examples.MagneticFieldMapXyz(str(bFieldFile)) + rnd = acts.examples.RandomNumbers(seed=42) + + from acts.examples.simulation import ( + MomentumConfig, + EtaConfig, + PhiConfig, + ParticleConfig, + ParticleSelectorConfig, + addDigitization, + addParticleSelection, + ) + + s = acts.examples.Sequencer( + events=args.events, + skip=args.skip, + numThreads=args.threads if not (args.geant4 and args.threads == -1) else 1, + logLevel=acts.logging.Level(args.loglevel), + outputDir="" if outputDirLess is None else str(outputDirLess), + ) + + # is this needed? + for d in decorators: + s.addContextDecorator(d) + + preSelectParticles = ( + ParticleSelectorConfig( + rho=(0.0 * u.mm, rhoMax), + absZ=(0.0 * u.mm, 1.0 * u.m), + eta=etaRange, + pt=(150 * u.MeV, None), + ) + if args.edm4hep or args.geant4 or args.ttbar_pu200 + else ParticleSelectorConfig() + ) + + postSelectParticles = ParticleSelectorConfig( + pt=(ptMin, None), + eta=etaRange if not args.generic_detector else (None, None), + measurements=(9, None), + removeNeutral=True, + ) + + if args.edm4hep: + import acts.examples.edm4hep + + edm4hepReader = acts.examples.edm4hep.EDM4hepReader( + inputPath=str(args.edm4hep), + inputSimHits=[ + "PixelBarrelReadout", + "PixelEndcapReadout", + "ShortStripBarrelReadout", + "ShortStripEndcapReadout", + "LongStripBarrelReadout", + "LongStripEndcapReadout", + ], + outputParticlesGenerator="particles_input", + outputParticlesInitial="particles_initial", + outputParticlesFinal="particles_final", + outputSimHits="simhits", + graphvizOutput="graphviz", + dd4hepDetector=detector, + trackingGeometry=trackingGeometry, + sortSimHitsInTime=True, + level=acts.logging.INFO, + ) + s.addReader(edm4hepReader) + s.addWhiteboardAlias("particles", edm4hepReader.config.outputParticlesGenerator) + + addParticleSelection( + s, + config=preSelectParticles, + inputParticles="particles", + outputParticles="particles_selected", + ) + + else: + + if not args.ttbar_pu200: + from acts.examples.simulation import addParticleGun + + addParticleGun( + s, + MomentumConfig( + *strToRange(args.gen_pt_range, "--gen-pt-range", u.GeV), + transverse=True, + ), + EtaConfig( + *( + strToRange(args.gen_eta_range, "--gen-eta-range") + if args.gen_eta_range + else etaRange + ), + uniform=( + not args.gen_cos_theta + if args.gen_cos_theta or not args.odd + else None + ), + ), + PhiConfig(0.0, 360.0 * u.degree) if not args.itk else PhiConfig(), + ParticleConfig( + args.gen_nparticles, acts.PdgParticle.eMuon, randomizeCharge=True + ), + vtxGen=( + acts.examples.GaussianVertexGenerator( + mean=acts.Vector4(0, 0, 0, 0), + stddev=acts.Vector4( + 0.0125 * u.mm, 0.0125 * u.mm, 55.5 * u.mm, 1.0 * u.ns + ), + ) + if args.odd + else None + ), + multiplicity=args.gen_nvertices, + rnd=rnd, + outputDirRoot=outputDirMoreRoot, + outputDirCsv=outputDirMoreCsv, + ) + else: + from acts.examples.simulation import addPythia8 + + addPythia8( + s, + hardProcess=["Top:qqbar2ttbar=on"], + npileup=args.gen_nvertices, + vtxGen=acts.examples.GaussianVertexGenerator( + stddev=acts.Vector4( + 0.0125 * u.mm, 0.0125 * u.mm, 55.5 * u.mm, 5.0 * u.ns + ), + mean=acts.Vector4(0, 0, 0, 0), + ), + rnd=rnd, + outputDirRoot=outputDirRoot, + outputDirCsv=outputDirCsv, + ) + + if not args.geant4: + from acts.examples.simulation import addFatras + + addFatras( + s, + trackingGeometry, + field, + rnd=rnd, + preSelectParticles=preSelectParticles, + postSelectParticles=postSelectParticles, + outputDirRoot=outputDirRoot, + outputDirCsv=outputDirCsv, + ) + else: + if s.config.numThreads != 1: + logger.fatal( + f"Geant 4 simulation does not support multi-threading (threads={s.config.numThreads})" + ) + sys.exit(2) + + from acts.examples.simulation import addGeant4 + + # Pythia can sometime simulate particles outside the world volume, a cut on the Z of the track help mitigate this effect + # Older version of G4 might not work, this as has been tested on version `geant4-11-00-patch-03` + # For more detail see issue #1578 + addGeant4( + s, + detector, + trackingGeometry, + field, + rnd=rnd, + preSelectParticles=preSelectParticles, + postSelectParticles=postSelectParticles, + killVolume=trackingGeometry.highestTrackingVolume, + killAfterTime=25 * u.ns, + outputDirRoot=outputDirRoot, + outputDirCsv=outputDirCsv, + ) + + addDigitization( + s, + trackingGeometry, + field, + digiConfigFile=args.digi_config, + rnd=rnd, + outputDirRoot=outputDirRoot, + outputDirCsv=outputDirCsv, + ) + + if not args.reco: + return s + + from acts.examples.reconstruction import ( + addSeeding, + ParticleSmearingSigmas, + addCKFTracks, + CkfConfig, + SeedingAlgorithm, + TrackSelectorConfig, + addAmbiguityResolution, + AmbiguityResolutionConfig, + addVertexFitting, + VertexFinder, + ) + + if args.itk and args.seeding_algorithm == SeedingAlgorithm.Default: + seedingAlgConfig = itk.itkSeedingAlgConfig( + itk.InputSpacePointsType.PixelSpacePoints + ) + else: + seedingAlgConfig = [] + + addSeeding( + s, + trackingGeometry, + field, + *seedingAlgConfig, + seedingAlgorithm=args.seeding_algorithm, + **( + dict( + particleSmearingSigmas=ParticleSmearingSigmas(ptRel=0.01), + rnd=rnd, + ) + if args.seeding_algorithm == SeedingAlgorithm.TruthSmeared + else {} + ), + initialSigmas=[ + 1 * u.mm, + 1 * u.mm, + 1 * u.degree, + 1 * u.degree, + 0.1 * u.e / u.GeV, + 1 * u.ns, + ], + initialSigmaPtRel=0.1, + initialVarInflation=[1.0] * 6, + geoSelectionConfigFile=seedingConfigFile, + outputDirRoot=outputDirLessRoot, + outputDirCsv=outputDirLessCsv, + ) + + if args.MLSeedFilter: + from acts.examples.reconstruction import ( + addSeedFilterML, + SeedFilterMLDBScanConfig, + ) + + addSeedFilterML( + s, + SeedFilterMLDBScanConfig( + epsilonDBScan=0.03, minPointsDBScan=2, minSeedScore=0.1 + ), + onnxModelFile=str( + geo_dir + / "Examples/Scripts/Python/MLAmbiguityResolution/seedDuplicateClassifier.onnx" + ), + outputDirRoot=outputDirLessRoot, + outputDirCsv=outputDirLessCsv, + ) + + if not args.ckf: + return s + + if args.seeding_algorithm != SeedingAlgorithm.TruthSmeared: + ckfConfig = CkfConfig( + seedDeduplication=True, + stayOnSeed=True, + ) + else: + ckfConfig = CkfConfig() + + if not args.itk: + trackSelectorConfig = TrackSelectorConfig( + pt=(ptMin if args.ttbar_pu200 else 0.0, None), + absEta=(None, 3.0), + loc0=(-4.0 * u.mm, 4.0 * u.mm), + nMeasurementsMin=7, + maxHoles=2, + maxOutliers=2, + ) + ckfConfig = ckfConfig._replace( + chi2CutOffMeasurement=15.0, + chi2CutOffOutlier=25.0, + numMeasurementsCutOff=10, + ) + else: + # fmt: off + trackSelectorConfig = ( + TrackSelectorConfig(absEta=(None, 2.0), pt=(0.9 * u.GeV, None), nMeasurementsMin=9, maxHoles=2, maxOutliers=2, maxSharedHits=2), + TrackSelectorConfig(absEta=(None, 2.6), pt=(0.4 * u.GeV, None), nMeasurementsMin=8, maxHoles=2, maxOutliers=2, maxSharedHits=2), + TrackSelectorConfig(absEta=(None, 4.0), pt=(0.4 * u.GeV, None), nMeasurementsMin=7, maxHoles=2, maxOutliers=2, maxSharedHits=2), + ) + # fmt: on + + if args.odd: + ckfConfig = ckfConfig._replace( + pixelVolumes=[16, 17, 18], + stripVolumes=[23, 24, 25], + maxPixelHoles=1, + maxStripHoles=2, + constrainToVolumes=[ + 2, # beam pipe + 32, + 4, # beam pip gap + 16, + 17, + 18, # pixel + 20, # PST + 23, + 24, + 25, # short strip + 26, + 8, # long strip gap + 28, + 29, + 30, # long strip + ], + ) + elif args.itk: + ckfConfig = ckfConfig._replace( + # ITk volumes from Noemi's plot + pixelVolumes=[8, 9, 10, 13, 14, 15, 16, 18, 19, 20], + stripVolumes=[22, 23, 24], + maxPixelHoles=1, + maxStripHoles=2, + ) + + if args.output_detail == 1: + writeDetail = dict(writeTrackSummary=False) + elif args.output_detail == 2: + writeDetail = dict(writeTrackStates=True) + else: + writeDetail = {} + + if args.odd and args.output_detail != 1: + writeCovMat = dict(writeCovMat=True) + else: + writeCovMat = {} + + addCKFTracks( + s, + trackingGeometry, + field, + trackSelectorConfig=trackSelectorConfig, + ckfConfig=ckfConfig, + **writeDetail, + **writeCovMat, + outputDirRoot=outputDirLessRoot, + outputDirCsv=outputDirLessCsv, + ) + + if args.ambi_solver == "ML": + + from acts.examples.reconstruction import ( + addAmbiguityResolutionML, + AmbiguityResolutionMLConfig, + ) + + addAmbiguityResolutionML( + s, + AmbiguityResolutionMLConfig( + maximumSharedHits=3, maximumIterations=1000000, nMeasurementsMin=7 + ), + onnxModelFile=str( + geo_dir + / "Examples/Scripts/Python/MLAmbiguityResolution/duplicateClassifier.onnx" + ), + outputDirRoot=outputDirLessRoot, + outputDirCsv=outputDirLessCsv, + ) + + elif args.ambi_solver == "scoring": + + from acts.examples.reconstruction import ( + addScoreBasedAmbiguityResolution, + ScoreBasedAmbiguityResolutionConfig, + ) + import math + + addScoreBasedAmbiguityResolution( + s, + ScoreBasedAmbiguityResolutionConfig( + minScore=0, + minScoreSharedTracks=1, + maxShared=2, + maxSharedTracksPerMeasurement=2, + pTMax=1400, + pTMin=0.5, + phiMax=math.pi, + phiMin=-math.pi, + etaMax=4, + etaMin=-4, + useAmbiguityFunction=False, + ), + ambiVolumeFile=args.ambi_config, + **writeCovMat, + outputDirRoot=outputDirLessRoot, + outputDirCsv=outputDirLessCsv, + ) + + elif args.ambi_solver == "greedy": + + addAmbiguityResolution( + s, + AmbiguityResolutionConfig( + maximumSharedHits=3, + maximumIterations=10000 if args.itk else 1000000, + nMeasurementsMin=6 if args.itk else 7, + ), + **writeDetail, + **writeCovMat, + outputDirRoot=outputDirLessRoot, + outputDirCsv=outputDirLessCsv, + ) + + if args.vertexing: + addVertexFitting( + s, + field, + vertexFinder=VertexFinder.AMVF, + outputDirRoot=outputDirLessRoot, + ) + + return s + + +def strToRange(s: str, optName: str, unit: float = 1.0): + global logger + try: + range = [float(e) * unit if e != "" else None for e in s.split(":")] + except ValueError: + range = [] + if len(range) == 1: + range.append(range[0]) # 100 -> 100:100 + if len(range) != 2: + logger.fatal(f"bad option value: {optName} {s}") + sys.exit(2) + return range + + +# Graciously taken from https://stackoverflow.com/a/60750535/4280680 (via seeding.py) +class EnumAction(argparse.Action): + """ + Argparse action for handling Enums + """ + + def __init__(self, **kwargs): + import enum + + # Pop off the type value + enum_type = kwargs.pop("enum", None) + + # Ensure an Enum subclass is provided + if enum_type is None: + raise ValueError("type must be assigned an Enum when using EnumAction") + if not issubclass(enum_type, enum.Enum): + raise TypeError("type must be an Enum when using EnumAction") + + # Generate choices from the Enum + kwargs.setdefault("choices", tuple(e.name for e in enum_type)) + + super(EnumAction, self).__init__(**kwargs) + + self._enum = enum_type + + def __call__(self, parser, namespace, values, option_string=None): + for e in self._enum: + if e.name == values: + setattr(namespace, self.dest, e) + break + else: + raise ValueError("%s is not a validly enumerated algorithm." % values) + + +# main program: parse arguments, setup sequence, and run the full chain +full_chain(parse_args()).run() 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/Examples/Scripts/requirements.txt b/Examples/Scripts/requirements.txt index 371122cba63..05f1e49374f 100644 --- a/Examples/Scripts/requirements.txt +++ b/Examples/Scripts/requirements.txt @@ -4,45 +4,51 @@ # # pip-compile Examples/Scripts/requirements.in # -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -awkward==2.5.0 +awkward==2.7.0 # via # -r Examples/Scripts/requirements.in # uproot -awkward-cpp==26 +awkward-cpp==41 # via awkward -boost-histogram==1.4.0 +boost-histogram==1.5.0 # via hist click==8.1.7 # via # histoprint # typer -contourpy==1.2.0 +contourpy==1.3.1 # via matplotlib +cramjam==2.9.0 + # via uproot cycler==0.12.1 # via matplotlib -fonttools==4.46.0 +fonttools==4.55.0 # via matplotlib -hist==2.7.2 +fsspec==2024.10.0 + # via + # awkward + # uproot +hist==2.8.0 # via -r Examples/Scripts/requirements.in -histoprint==2.4.0 +histoprint==2.5.0 # via hist -kiwisolver==1.4.5 +kiwisolver==1.4.7 # via matplotlib markdown-it-py==3.0.0 # via rich -matplotlib==3.8.2 +matplotlib==3.9.2 # via # -r Examples/Scripts/requirements.in # mplhep mdurl==0.1.2 # via markdown-it-py -mplhep==0.3.31 +mplhep==0.3.55 # via -r Examples/Scripts/requirements.in -mplhep-data==0.0.3 +mplhep-data==0.0.4 # via mplhep -numpy==1.26.2 +numpy==2.1.3 # via # awkward # awkward-cpp @@ -56,50 +62,56 @@ numpy==1.26.2 # scipy # uhi # uproot -packaging==23.2 +packaging==24.2 # via # awkward # matplotlib # mplhep # uproot -pandas==2.1.3 +pandas==2.2.3 # via -r Examples/Scripts/requirements.in -pillow==10.1.0 +pillow==11.0.0 # via matplotlib -pydantic==2.5.2 +pydantic==2.9.2 # via -r Examples/Scripts/requirements.in -pydantic-core==2.14.5 +pydantic-core==2.23.4 # via pydantic -pygments==2.17.2 +pygments==2.18.0 # via rich -pyparsing==3.1.1 +pyparsing==3.2.0 # via matplotlib -python-dateutil==2.8.2 +python-dateutil==2.9.0.post0 # via # matplotlib # pandas -pytz==2023.3.post1 +pytz==2024.2 # via pandas -pyyaml==6.0.1 - # via -r Examples/Scripts/requirements.in -rich==13.7.0 +pyyaml==6.0.2 # via -r Examples/Scripts/requirements.in -scipy==1.11.4 +rich==13.9.4 + # via + # -r Examples/Scripts/requirements.in + # typer +scipy==1.14.1 # via -r Examples/Scripts/requirements.in +shellingham==1.5.4 + # via typer six==1.16.0 # via python-dateutil -typer==0.9.0 +typer==0.13.1 # via -r Examples/Scripts/requirements.in -typing-extensions==4.8.0 +typing-extensions==4.12.2 # via # pydantic # pydantic-core # typer -tzdata==2023.3 +tzdata==2024.2 # via pandas -uhi==0.4.0 +uhi==0.5.0 # via # histoprint # mplhep -uproot==5.1.2 +uproot==5.5.0 # via -r Examples/Scripts/requirements.in +xxhash==3.5.0 + # via uproot 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/AmbiguityResolution/ScoreBasedAmbiguityResolutionTest.cpp b/Tests/UnitTests/Core/AmbiguityResolution/ScoreBasedAmbiguityResolutionTest.cpp index 568e817031a..55beab4ca2f 100644 --- a/Tests/UnitTests/Core/AmbiguityResolution/ScoreBasedAmbiguityResolutionTest.cpp +++ b/Tests/UnitTests/Core/AmbiguityResolution/ScoreBasedAmbiguityResolutionTest.cpp @@ -18,10 +18,7 @@ #include "Acts/EventData/VectorTrackContainer.hpp" #include "Acts/EventData/detail/TestSourceLink.hpp" #include "Acts/EventData/detail/TestTrackState.hpp" -#include "Acts/Geometry/GeometryContext.hpp" -#include "Acts/Surfaces/PerigeeSurface.hpp" -#include "Acts/TrackFinding/TrackSelector.hpp" -#include "Acts/Utilities/CalibrationContext.hpp" +#include "Acts/Utilities/TrackHelpers.hpp" #include @@ -30,7 +27,6 @@ using Acts::MultiTrajectoryTraits::IndexType; namespace Acts::Test { BOOST_AUTO_TEST_SUITE(ScoreBasedAmbiguityResolutionTest) -using MeasurementInfo = ScoreBasedAmbiguityResolution::MeasurementInfo; // Test fixture for ScoreBasedAmbiguityResolution struct Fixture { @@ -65,64 +61,137 @@ struct Fixture { ~Fixture() = default; }; -// Helper function to create a sample input for getCleanedOutTracks -std::vector> createSampleInput() { - Fixture fixture; - std::vector>> trackVolumes = { - {0, {19, 18, 18, 18, 10, 10, 10, 10, 10, 10, 10, 10, 10}}, - {1, {19, 18, 18, 18, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}}, - {2, {13, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}}, - {3, {13, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}}, - {4, {19, 18, 18, 18, 10, 10, 10, 10, 10, 10, 10, 10, 10}}}; - - std::vector> measurementsPerTrack; - // Add sample measurements for each track - - for (const auto& trackVolume : trackVolumes) { - std::vector measurements; - for (std::size_t i = 0; i < trackVolume.second.size(); ++i) { - std::size_t detectorID = fixture.config.volumeMap[trackVolume.second[i]]; - measurements.push_back({i + 2, detectorID, false}); +template +auto createTestTrack(TrackContainer& tc, const FlagsPerState& flagsPerState) { + auto t = tc.makeTrack(); + for (const auto& flags : flagsPerState) { + auto ts = t.appendTrackState(); + for (auto f : flags) { + ts.typeFlags().set(f); } - measurementsPerTrack.push_back(measurements); } - return measurementsPerTrack; + calculateTrackQuantities(t); + + return t; } -BOOST_FIXTURE_TEST_CASE(GetCleanedOutTracksTest, Fixture) { +BOOST_FIXTURE_TEST_CASE(ComputeInitialStateTest, Fixture) { Fixture fixture; // Create an instance of ScoreBasedAmbiguityResolution ScoreBasedAmbiguityResolution tester(fixture.config); - // Create sample input - std::vector> measurementsPerTrack = - createSampleInput(); + VectorTrackContainer mutVtc; + VectorMultiTrajectory mutMtj; - std::vector TrackSore; - for (std::size_t i = 0; i < measurementsPerTrack.size(); i++) { - TrackSore.push_back(60 + 40 * i); - } - std::vector> trackFeaturesVectors = { - {{0, 14, 0, 0}, {0, 2, 0, 0}}, - {{0, 15, 0, 0}, {0, 2, 0, 0}}, - {{0, 17, 0, 0}, {0, 2, 0, 0}}, - {{0, 18, 0, 0}, {0, 2, 0, 0}}, - {{0, 14, 0, 0}, {0, 3, 0, 0}}}; + TrackContainer mutTc{mutVtc, mutMtj}; + static_assert(!mutTc.ReadOnly, "Unexpectedly read only"); + + auto t = createTestTrack(mutTc, std::vector>{ + {MeasurementFlag}, + {OutlierFlag}, + {MeasurementFlag, SharedHitFlag}, + {HoleFlag}, + {OutlierFlag}, + {HoleFlag}, + {MeasurementFlag, SharedHitFlag}, + {OutlierFlag}, + }); + + BOOST_CHECK_EQUAL(t.nHoles(), 2); + BOOST_CHECK_EQUAL(t.nMeasurements(), 3); + BOOST_CHECK_EQUAL(t.nOutliers(), 3); + BOOST_CHECK_EQUAL(t.nSharedHits(), 2); + + ConstVectorTrackContainer vtc{std::move(mutVtc)}; + ConstVectorMultiTrajectory mtj{std::move(mutMtj)}; + + TrackContainer ctc{vtc, mtj}; + + std::vector> trackFeaturesVectors; + trackFeaturesVectors = tester.computeInitialState(ctc); + + BOOST_CHECK_EQUAL(trackFeaturesVectors.size(), ctc.size()); + + std::vector trackScores; + trackScores = tester.simpleScore(ctc, trackFeaturesVectors); - // Call the function under testBOOST_FIXTURE_TEST_CASE - std::vector cleanTracks = tester.getCleanedOutTracks( - TrackSore, trackFeaturesVectors, measurementsPerTrack); + BOOST_CHECK_EQUAL(trackScores.size(), ctc.size()); + + trackScores = tester.ambiguityScore(ctc, trackFeaturesVectors); + + BOOST_CHECK_EQUAL(trackScores.size(), ctc.size()); // Assert the expected results - BOOST_CHECK_EQUAL(measurementsPerTrack.size(), 5); +} - for (std::size_t i = 0; i < cleanTracks.size(); i++) { - auto score = TrackSore[i]; - if (cleanTracks[i]) { - BOOST_CHECK_GT(score, fixture.config.minScoreSharedTracks); +BOOST_FIXTURE_TEST_CASE(GetCleanedOutTracksTest, Fixture) { + Fixture fixture; + // Create an instance of ScoreBasedAmbiguityResolution + ScoreBasedAmbiguityResolution tester(fixture.config); + + VectorTrackContainer mutVtc; + VectorMultiTrajectory mutMtj; + + TrackContainer mutTc{mutVtc, mutMtj}; + static_assert(!mutTc.ReadOnly, "Unexpectedly read only"); + + auto t = createTestTrack(mutTc, std::vector>{ + {MeasurementFlag}, + {OutlierFlag}, + {MeasurementFlag, SharedHitFlag}, + {HoleFlag}, + {OutlierFlag}, + {HoleFlag}, + {MeasurementFlag, SharedHitFlag}, + {OutlierFlag}, + }); + + BOOST_CHECK_EQUAL(t.nHoles(), 2); + BOOST_CHECK_EQUAL(t.nMeasurements(), 3); + BOOST_CHECK_EQUAL(t.nOutliers(), 3); + BOOST_CHECK_EQUAL(t.nSharedHits(), 2); + + ConstVectorTrackContainer vtc{std::move(mutVtc)}; + ConstVectorMultiTrajectory mtj{std::move(mutMtj)}; + + TrackContainer ctc{vtc, mtj}; + + std::vector> trackFeaturesVectors; + std::vector> measurementsPerTrackVector; + std::map nTracksPerMeasurement; + + trackFeaturesVectors = tester.computeInitialState(ctc); + + BOOST_CHECK_EQUAL(trackFeaturesVectors.size(), ctc.size()); + + for (std::size_t iMeasurement = 1; const auto& track : ctc) { + std::vector measurementsPerTrack; + for (auto ts : track.trackStatesReversed()) { + if (ts.typeFlags().test(Acts::TrackStateFlag::OutlierFlag) || + ts.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) { + measurementsPerTrack.push_back(iMeasurement); + if (nTracksPerMeasurement.find(iMeasurement) == + nTracksPerMeasurement.end()) { + nTracksPerMeasurement[iMeasurement] = 0; + } + nTracksPerMeasurement[iMeasurement]++; + } + + iMeasurement++; } + measurementsPerTrackVector.push_back(std::move(measurementsPerTrack)); } + + auto trackScore = tester.ambiguityScore(ctc, trackFeaturesVectors); + + const auto& track = ctc.getTrack(0); + std::size_t iTrack = track.index(); + bool accepted = tester.getCleanedOutTracks(track, trackScore[iTrack], + measurementsPerTrackVector[iTrack], + nTracksPerMeasurement); + + BOOST_CHECK_EQUAL(accepted, false); } BOOST_AUTO_TEST_SUITE_END() diff --git a/Tests/UnitTests/Core/Seeding/EstimateTrackParamsFromSeedTest.cpp b/Tests/UnitTests/Core/Seeding/EstimateTrackParamsFromSeedTest.cpp index de15f7e09c2..9aab6c1c70b 100644 --- a/Tests/UnitTests/Core/Seeding/EstimateTrackParamsFromSeedTest.cpp +++ b/Tests/UnitTests/Core/Seeding/EstimateTrackParamsFromSeedTest.cpp @@ -9,10 +9,8 @@ #include #include "Acts/Definitions/Algebra.hpp" -#include "Acts/Definitions/Direction.hpp" #include "Acts/Definitions/TrackParametrization.hpp" #include "Acts/Definitions/Units.hpp" -#include "Acts/EventData/GenericCurvilinearTrackParameters.hpp" #include "Acts/EventData/TrackParameters.hpp" #include "Acts/EventData/detail/TestSourceLink.hpp" #include "Acts/Geometry/GeometryContext.hpp" @@ -29,7 +27,6 @@ #include "Acts/Tests/CommonHelpers/CylindricalTrackingGeometry.hpp" #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp" #include "Acts/Tests/CommonHelpers/MeasurementsCreator.hpp" -#include "Acts/Utilities/CalibrationContext.hpp" #include "Acts/Utilities/Logger.hpp" #include @@ -39,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -99,8 +95,8 @@ BOOST_AUTO_TEST_CASE(trackparameters_estimation_test) { true, // material false // passive }); - auto field = - std::make_shared(Acts::Vector3(0.0, 0.0, 2._T)); + const Vector3 bField(0, 0, 2._T); + auto field = std::make_shared(bField); ConstantFieldStepper stepper(std::move(field)); ConstantFieldPropagator propagator(std::move(stepper), std::move(navigator)); @@ -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, *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/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/requirements.in b/docs/requirements.in index cd5b9dff585..1633d176167 100644 --- a/docs/requirements.in +++ b/docs/requirements.in @@ -1,6 +1,6 @@ breathe myst-parser -sphinx +sphinx==7.3.7 sphinx_rtd_theme docutils rich diff --git a/docs/requirements.txt b/docs/requirements.txt index dd60e5e5724..0ac5d41d6b6 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -4,52 +4,54 @@ # # pip-compile docs/requirements.in # -aiohttp==3.9.1 +aiohappyeyeballs==2.4.3 + # via aiohttp +aiohttp==3.11.5 # via -r docs/requirements.in aiosignal==1.3.1 # via aiohttp -alabaster==0.7.13 +alabaster==0.7.16 # via sphinx -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -attrs==23.1.0 +attrs==24.2.0 # via aiohttp -babel==2.13.1 +babel==2.16.0 # via sphinx breathe==4.35.0 # via -r docs/requirements.in -certifi==2023.11.17 +certifi==2024.8.30 # via requests -cffi==1.16.0 +cffi==1.17.1 # via cryptography -charset-normalizer==3.3.2 +charset-normalizer==3.4.0 # via requests click==8.1.7 # via typer -cryptography==41.0.7 +cryptography==43.0.3 # via pyjwt -docutils==0.20.1 +docutils==0.21.2 # via # -r docs/requirements.in # breathe # myst-parser # sphinx # sphinx-rtd-theme -frozenlist==1.4.0 +frozenlist==1.5.0 # via # aiohttp # aiosignal -fsspec==2023.12.0 +fsspec==2024.10.0 # via -r docs/requirements.in gidgethub==5.3.0 # via -r docs/requirements.in -idna==3.6 +idna==3.10 # via # requests # yarl imagesize==1.4.1 # via sphinx -jinja2==3.1.2 +jinja2==3.1.4 # via # -r docs/requirements.in # myst-parser @@ -59,85 +61,85 @@ markdown-it-py==3.0.0 # mdit-py-plugins # myst-parser # rich -markupsafe==2.1.3 +markupsafe==3.0.2 # via jinja2 -mdit-py-plugins==0.4.0 +mdit-py-plugins==0.4.2 # via myst-parser mdurl==0.1.2 # via markdown-it-py -multidict==6.0.4 +multidict==6.1.0 # via # aiohttp # yarl -myst-parser==2.0.0 +myst-parser==4.0.0 # via -r docs/requirements.in -packaging==23.2 +packaging==24.2 # via sphinx -pycparser==2.21 +propcache==0.2.0 + # via + # aiohttp + # yarl +pycparser==2.22 # via cffi -pydantic==2.5.2 +pydantic==2.9.2 # via -r docs/requirements.in -pydantic-core==2.14.5 +pydantic-core==2.23.4 # via pydantic -pygments==2.17.2 +pygments==2.18.0 # via # rich # sphinx -pyjwt[crypto]==2.8.0 +pyjwt[crypto]==2.10.0 # via gidgethub -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via -r docs/requirements.in -pyyaml==6.0.1 +pyyaml==6.0.2 # via myst-parser -requests==2.31.0 +requests==2.32.3 # via sphinx -rich==13.7.0 - # via -r docs/requirements.in +rich==13.9.4 + # via + # -r docs/requirements.in + # typer +shellingham==1.5.4 + # via typer snowballstemmer==2.2.0 # via sphinx -sphinx==7.2.6 +sphinx==7.3.7 # via # -r docs/requirements.in # breathe # myst-parser # sphinx-rtd-theme - # sphinxcontrib-applehelp - # sphinxcontrib-devhelp - # sphinxcontrib-htmlhelp # sphinxcontrib-jquery - # sphinxcontrib-qthelp - # sphinxcontrib-serializinghtml -sphinx-rtd-theme==2.0.0 +sphinx-rtd-theme==3.0.2 # via -r docs/requirements.in -sphinxcontrib-applehelp==1.0.7 +sphinxcontrib-applehelp==2.0.0 # via sphinx -sphinxcontrib-devhelp==1.0.5 +sphinxcontrib-devhelp==2.0.0 # via sphinx -sphinxcontrib-htmlhelp==2.0.4 +sphinxcontrib-htmlhelp==2.1.0 # via sphinx sphinxcontrib-jquery==4.1 # via sphinx-rtd-theme sphinxcontrib-jsmath==1.0.1 # via sphinx -sphinxcontrib-qthelp==1.0.6 +sphinxcontrib-qthelp==2.0.0 # via sphinx -sphinxcontrib-serializinghtml==1.1.9 +sphinxcontrib-serializinghtml==2.0.0 # via sphinx toml==0.10.2 # via -r docs/requirements.in -typer==0.9.0 +typer==0.13.1 # via -r docs/requirements.in -typing-extensions==4.8.0 +typing-extensions==4.12.2 # via # pydantic # pydantic-core # typer uritemplate==4.1.1 # via gidgethub -urllib3==2.1.0 +urllib3==2.2.3 # via requests -yarl==1.9.3 +yarl==1.17.2 # via aiohttp - -# The following packages are considered to be unsafe in a requirements file: -# setuptools