From 5a81237e090fb594c4c567d5a33e0b5df5f827a2 Mon Sep 17 00:00:00 2001 From: Frederik Date: Fri, 12 Jul 2024 14:47:47 +0200 Subject: [PATCH] Traccc core (rebased) --- .../Acts/Geometry/GeometryHierarchyMap.hpp | 10 + Examples/Algorithms/CMakeLists.txt | 1 + .../Digitization/DigitizationAlgorithm.hpp | 6 +- .../Digitization/DigitizationConfig.hpp | 4 +- .../src/DigitizationAlgorithm.cpp | 20 +- Examples/Algorithms/Traccc/CMakeLists.txt | 2 + .../Algorithms/Traccc/Common/CMakeLists.txt | 26 ++ .../Common/Conversion/CellMapConversion.hpp | 34 +++ .../Conversion/DigitizationConversion.hpp | 29 ++ .../Conversion/MeasurementConversion.hpp | 175 ++++++++++++ .../ActsExamples/Traccc/Common/Converter.hpp | 220 +++++++++++++++ .../Traccc/Common/Measurement/Debug.hpp | 38 +++ .../Common/Measurement/MeasurementMatch.hpp | 97 +++++++ .../Common/TracccChainAlgorithmBase.hpp | 107 +++++++ .../Traccc/Common/TracccChainConfig.hpp | 44 +++ .../Traccc/Common/Util/IndexMap.hpp | 127 +++++++++ .../src/Conversion/CellMapConversion.cpp | 83 ++++++ .../src/Conversion/DigitizationConversion.cpp | 48 ++++ .../src/Conversion/MeasurementConversion.cpp | 44 +++ .../Traccc/Common/src/Debug/Debug.cpp | 117 ++++++++ .../Common/src/TracccChainAlgorithmBase.cpp | 76 +++++ .../Algorithms/Traccc/Host/CMakeLists.txt | 20 ++ .../Traccc/Host/TracccChainAlgorithm.hpp | 50 ++++ .../ActsExamples/Traccc/Host/Types.hpp | 51 ++++ .../Traccc/Host/src/TracccChainAlgorithm.cpp | 98 +++++++ .../python/acts/examples/reconstruction.py | 67 +++++ .../Python/python/acts/examples/simulation.py | 2 + Examples/Python/src/Digitization.cpp | 2 +- Examples/Python/src/ModuleEntry.cpp | 5 + Examples/Python/src/TracccChainConfig.cpp | 184 ++++++++++++ Examples/Python/src/TracccChainConfigStub.cpp | 22 ++ Examples/Python/src/TracccChainHost.cpp | 32 +++ Examples/Python/src/TracccChainHostStub.cpp | 16 ++ .../Scripts/Python/full_chain_odd_traccc.py | 267 ++++++++++++++++++ 34 files changed, 2119 insertions(+), 5 deletions(-) create mode 100644 Examples/Algorithms/Traccc/CMakeLists.txt create mode 100644 Examples/Algorithms/Traccc/Common/CMakeLists.txt create mode 100644 Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Conversion/CellMapConversion.hpp create mode 100644 Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Conversion/DigitizationConversion.hpp create mode 100644 Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Conversion/MeasurementConversion.hpp create mode 100644 Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Converter.hpp create mode 100644 Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Measurement/Debug.hpp create mode 100644 Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Measurement/MeasurementMatch.hpp create mode 100644 Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/TracccChainAlgorithmBase.hpp create mode 100644 Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/TracccChainConfig.hpp create mode 100644 Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Util/IndexMap.hpp create mode 100644 Examples/Algorithms/Traccc/Common/src/Conversion/CellMapConversion.cpp create mode 100644 Examples/Algorithms/Traccc/Common/src/Conversion/DigitizationConversion.cpp create mode 100644 Examples/Algorithms/Traccc/Common/src/Conversion/MeasurementConversion.cpp create mode 100644 Examples/Algorithms/Traccc/Common/src/Debug/Debug.cpp create mode 100644 Examples/Algorithms/Traccc/Common/src/TracccChainAlgorithmBase.cpp create mode 100644 Examples/Algorithms/Traccc/Host/CMakeLists.txt create mode 100644 Examples/Algorithms/Traccc/Host/include/ActsExamples/Traccc/Host/TracccChainAlgorithm.hpp create mode 100644 Examples/Algorithms/Traccc/Host/include/ActsExamples/Traccc/Host/Types.hpp create mode 100644 Examples/Algorithms/Traccc/Host/src/TracccChainAlgorithm.cpp create mode 100644 Examples/Python/src/TracccChainConfig.cpp create mode 100644 Examples/Python/src/TracccChainConfigStub.cpp create mode 100644 Examples/Python/src/TracccChainHost.cpp create mode 100644 Examples/Python/src/TracccChainHostStub.cpp create mode 100755 Examples/Scripts/Python/full_chain_odd_traccc.py diff --git a/Core/include/Acts/Geometry/GeometryHierarchyMap.hpp b/Core/include/Acts/Geometry/GeometryHierarchyMap.hpp index 1106761d372..63735ac0082 100644 --- a/Core/include/Acts/Geometry/GeometryHierarchyMap.hpp +++ b/Core/include/Acts/Geometry/GeometryHierarchyMap.hpp @@ -93,6 +93,16 @@ class GeometryHierarchyMap { /// Return the number of stored elements. Size size() const { return m_values.size(); } + // Return the geometry identifier - value pairs (i.e., it reconstructs the + // input). + const std::vector getElements() const { + std::vector res; + for (std::size_t i = 0; i < size(); i++) { + res.push_back({m_ids[i], m_values[i]}); + } + return res; + } + /// Access the geometry identifier for the i-th element with bounds check. /// /// @throws std::out_of_range for invalid indices diff --git a/Examples/Algorithms/CMakeLists.txt b/Examples/Algorithms/CMakeLists.txt index bdfc0195b7a..1fce8f85245 100644 --- a/Examples/Algorithms/CMakeLists.txt +++ b/Examples/Algorithms/CMakeLists.txt @@ -18,3 +18,4 @@ add_subdirectory(Vertexing) add_subdirectory_if(Alignment ACTS_BUILD_ALIGNMENT) add_subdirectory(Utilities) add_subdirectory(AmbiguityResolution) +add_subdirectory_if(Traccc ACTS_BUILD_PLUGIN_TRACCC) \ No newline at end of file diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationAlgorithm.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationAlgorithm.hpp index 9fafaf0af21..d702caeda16 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationAlgorithm.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationAlgorithm.hpp @@ -88,7 +88,7 @@ class DigitizationAlgorithm final : public IAlgorithm { using Digitizer = std::variant, CombinedDigitizer<1>, CombinedDigitizer<2>, CombinedDigitizer<3>, CombinedDigitizer<4>>; - + /// Configuration of the Algorithm DigitizationConfig m_cfg; /// Digitizers within geometry hierarchy @@ -96,6 +96,9 @@ class DigitizationAlgorithm final : public IAlgorithm { /// Geometric digtizer ActsFatras::Channelizer m_channelizer; + using CellsMap = + std::map>; + ReadDataHandle m_simContainerReadHandle{this, "SimHitContainer"}; @@ -103,6 +106,7 @@ class DigitizationAlgorithm final : public IAlgorithm { this, "SourceLinks"}; WriteDataHandle m_measurementWriteHandle{ this, "Measurements"}; + WriteDataHandle m_cellsWriteHandle{this, "Cells"}; WriteDataHandle m_clusterWriteHandle{this, "Clusters"}; WriteDataHandle> m_measurementParticlesMapWriteHandle{this, "MeasurementParticlesMap"}; diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfig.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfig.hpp index bea13649440..1a360c9dd1a 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfig.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfig.hpp @@ -139,6 +139,8 @@ class DigitizationConfig { std::string outputSourceLinks = "sourcelinks"; /// 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. @@ -155,7 +157,7 @@ class DigitizationConfig { /// 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; + 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, diff --git a/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp b/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp index f3b04ac0aff..ddf3a16bc79 100644 --- a/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp +++ b/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp @@ -72,6 +72,7 @@ ActsExamples::DigitizationAlgorithm::DigitizationAlgorithm( m_simContainerReadHandle.initialize(m_cfg.inputSimHits); m_sourceLinkWriteHandle.initialize(m_cfg.outputSourceLinks); m_measurementWriteHandle.initialize(m_cfg.outputMeasurements); + m_cellsWriteHandle.initialize(m_cfg.outputCells); m_clusterWriteHandle.initialize(m_cfg.outputClusters); m_measurementParticlesMapWriteHandle.initialize( m_cfg.outputMeasurementParticlesMap); @@ -154,6 +155,10 @@ ActsExamples::ProcessCode ActsExamples::DigitizationAlgorithm::execute( // Some statistics std::size_t skippedHits = 0; + // Some algorithms do the clusterization themselves such as the traccc chain. + // Thus we need to store the cell data from the simulation. + CellsMap cellsMap; + ACTS_DEBUG("Starting loop over modules ..."); for (const auto& simHitsGroup : groupByModule(simHits)) { // Manual pair unpacking instead of using @@ -255,8 +260,18 @@ ActsExamples::ProcessCode ActsExamples::DigitizationAlgorithm::execute( moduleClusters.add(std::move(dParameters), simHitIdx); } - for (auto& [dParameters, simhits] : - moduleClusters.digitizedParameters()) { + auto digitizeParametersResult = moduleClusters.digitizedParameters(); + + // Store the data of the cells from the simulation. + std::vector cells; + for (auto& [dParameters, simhits] : digitizeParametersResult) { + for (auto cell : dParameters.cluster.channels) { + cells.push_back(std::move(cell)); + } + } + cellsMap.insert({moduleGeoId, cells}); + + 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(); @@ -293,6 +308,7 @@ ActsExamples::ProcessCode ActsExamples::DigitizationAlgorithm::execute( m_sourceLinkWriteHandle(ctx, std::move(sourceLinks)); m_measurementWriteHandle(ctx, std::move(measurements)); + m_cellsWriteHandle(ctx, std::move(cellsMap)); m_clusterWriteHandle(ctx, std::move(clusters)); m_measurementParticlesMapWriteHandle(ctx, std::move(measurementParticlesMap)); m_measurementSimHitsMapWriteHandle(ctx, std::move(measurementSimHitsMap)); diff --git a/Examples/Algorithms/Traccc/CMakeLists.txt b/Examples/Algorithms/Traccc/CMakeLists.txt new file mode 100644 index 00000000000..4f969248ae2 --- /dev/null +++ b/Examples/Algorithms/Traccc/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(Common) +add_subdirectory(Host) \ No newline at end of file diff --git a/Examples/Algorithms/Traccc/Common/CMakeLists.txt b/Examples/Algorithms/Traccc/Common/CMakeLists.txt new file mode 100644 index 00000000000..826632ec5f4 --- /dev/null +++ b/Examples/Algorithms/Traccc/Common/CMakeLists.txt @@ -0,0 +1,26 @@ +add_library( + ActsExamplesTracccCommon SHARED + src/TracccChainAlgorithmBase.cpp + src/Conversion/CellMapConversion.cpp + src/Conversion/DigitizationConversion.cpp + src/Conversion/MeasurementConversion.cpp + src/Debug/Debug.cpp +) + +target_include_directories( + ActsExamplesTracccCommon + PUBLIC $ +) + +target_link_libraries( + ActsExamplesTracccCommon + PUBLIC + ActsPluginTraccc + ActsExamplesFramework + ActsExamplesDigitization +) + +install( + TARGETS ActsExamplesTracccCommon + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} +) diff --git a/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Conversion/CellMapConversion.hpp b/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Conversion/CellMapConversion.hpp new file mode 100644 index 00000000000..61ec39fe5cc --- /dev/null +++ b/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Conversion/CellMapConversion.hpp @@ -0,0 +1,34 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2023 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 http://mozilla.org/MPL/2.0/. + +#pragma once + +// Acts include(s) +#include "Acts/Geometry/GeometryIdentifier.hpp" + +// Acts Examples include(s) +#include "ActsExamples/EventData/Cluster.hpp" + +// Traccc include(s) +#include "traccc/edm/cell.hpp" + +// System include(s). +#include +#include +#include +#include + +namespace ActsExamples::Traccc::Common::Conversion { + +/// @brief Converts a "geometry ID -> generic cell collection type" map to a "geometry ID -> traccc cell collection" map. +/// @note The function sets the module link of the cells in the output to 0. +/// @return Map from geometry ID to its cell data (as a vector of traccc cell data) +std::map> tracccCellsMap( + const std::map>& map); + +} // namespace ActsExamples::Traccc::Common::Conversion diff --git a/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Conversion/DigitizationConversion.hpp b/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Conversion/DigitizationConversion.hpp new file mode 100644 index 00000000000..715962a5f52 --- /dev/null +++ b/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Conversion/DigitizationConversion.hpp @@ -0,0 +1,29 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2023 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 http://mozilla.org/MPL/2.0/. + +#pragma once + +// Acts include(s) +#include "Acts/Geometry/GeometryHierarchyMap.hpp" + +// Acts Examples include(s) +#include "ActsExamples/Digitization/DigitizationConfig.hpp" + +// Traccc include(s) +#include "traccc/io/digitization_config.hpp" + +namespace ActsExamples::Traccc::Common::Conversion { + +/// @brief Creates a traccc digitalization config from an Acts geometry hierarchy map +/// that contains the digitization configuration. +/// @param config the Acts geometry hierarchy map that contains the digitization configuration. +/// @return a traccc digitization config. +traccc::digitization_config tracccConfig( + const Acts::GeometryHierarchyMap& config); + +} // namespace ActsExamples::Traccc::Common::Conversion diff --git a/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Conversion/MeasurementConversion.hpp b/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Conversion/MeasurementConversion.hpp new file mode 100644 index 00000000000..1cd806b4dc8 --- /dev/null +++ b/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Conversion/MeasurementConversion.hpp @@ -0,0 +1,175 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2023 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 http://mozilla.org/MPL/2.0/. + +#pragma once + +// Plugin include(s) +#include "Acts/Plugins/Traccc/Detail/AlgebraConversion.hpp" + +// Acts include(s) +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Definitions/TrackParametrization.hpp" +#include "Acts/EventData/Measurement.hpp" +#include "Acts/EventData/SourceLink.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" + +// Acts Examples include(s) +#include "ActsExamples/EventData/IndexSourceLink.hpp" + +// Detray include(s) +#include "detray/core/detector.hpp" +#include "detray/tracks/bound_track_parameters.hpp" + +// Traccc include(s) +#include "traccc/definitions/qualifiers.hpp" +#include "traccc/definitions/track_parametrization.hpp" +#include "traccc/edm/measurement.hpp" +#include "traccc/edm/track_state.hpp" + +// System include(s) +#include +#include +#include +#include +#include + +namespace ActsExamples::Traccc::Common::Conversion { + +/// @brief Converts a traccc bound index to an Acts bound index. +/// @param tracccBoundIndex the traccc bound index. +/// @returns an Acts bound index. +Acts::BoundIndices boundIndex(const traccc::bound_indices tracccBoundIndex); + +/// @brief Creates an Acts measurement from a traccc measurement. +/// @tparam the dimension of the Acts measurement (subspace size). +/// @param m the traccc measurement. +/// @param sl the Acts source link to use for the Acts measurement. +/// @returns an Acts measurement with data copied from the traccc measurement +/// and with its source link set to the one provided to the function. +template +inline Acts::Measurement measurement( + const traccc::measurement& m, const Acts::SourceLink sl) { + auto params = Acts::TracccPlugin::detail::toActsVector(m.local); + std::array indices; + for (unsigned int i = 0; i < dim; i++) { + indices[i] = boundIndex(traccc::bound_indices(m.subs.get_indices()[i])); + } + auto cov = Eigen::DiagonalMatrix(dim)>( + Acts::TracccPlugin::detail::toActsVector(m.variance)) + .toDenseMatrix(); + return Acts::Measurement(std::move(sl), indices, + params, cov); +} + +/// @brief Creates an Acts bound variant measurement from a traccc measurement. +/// Using recursion, the functions determines the dimension of the traccc +/// measurement which is used for the Acts measurement that the bound variant +/// measurement holds. The dimension must lie between [0; max_dim]. +/// @tparam max_dim the largest possible dimension of any measurement type in the variant (default = 4). +/// @param m the traccc measurement. +/// @param sl the Acts source link to use for the Acts measurement. +/// @returns an Acts bound variant measurement with data copied from the traccc measurement +/// and with its source link set to the one provided to the function. +template +inline Acts::BoundVariantMeasurement boundVariantMeasurement( + const traccc::measurement& m, const Acts::SourceLink sl) { + if constexpr (max_dim == 0UL) { + std::string errorMsg = "Invalid/mismatching measurement dimension: " + + std::to_string(m.meas_dim); + throw std::runtime_error(errorMsg.c_str()); + } else { + if (m.meas_dim == max_dim) { + return measurement(m, sl); + } + return boundVariantMeasurement(m, sl); + } +} + +/// @brief Gets the the local position of the measurement. +/// @param measurement the Acts measurement. +/// @returns A two-dimensional vector containing the local position. +/// The first item in the vector is local position on axis 0 and +/// I.e., [local position (axis 0), local position (axis 1)]. +/// @note if the dimension is less than 2 then the remaining values are set to 0. +template +inline Acts::ActsVector<2> getLocal( + const Acts::Measurement& measurement) { + traccc::scalar loc0 = 0; + traccc::scalar loc1 = 0; + if constexpr (dim > Acts::BoundIndices::eBoundLoc0) { + loc0 = measurement.parameters()(Acts::BoundIndices::eBoundLoc0); + } + if constexpr (dim > Acts::BoundIndices::eBoundLoc1) { + loc1 = measurement.parameters()(Acts::BoundIndices::eBoundLoc1); + } + return Acts::ActsVector<2>(loc0, loc1); +} + +/// @brief Get the the local position of the measurement. +/// @param measurement the Acts bound variant measurement. +/// @return A two-dimensional vector containing the local position. +/// I.e., [local position (axis 0), local position (axis 1)]. +/// @note if the dimension is less than 2 then the remaining values are set to 0. +inline Acts::ActsVector<2> getLocal( + const Acts::BoundVariantMeasurement& measurement) { + return std::visit([](auto& m) { return getLocal(m); }, measurement); +} + +/// @brief Get the the variance of the measurement. +/// @param measurement the Acts measurement. +/// @return A two-dimensional vector containing the variance. +/// I.e., [variance (axis 0), variance (axis 1)]. +/// @note if the dimension is less than 2 then the remaining values are set to 0. +template +inline Acts::ActsVector<2> getVariance( + const Acts::Measurement& measurement) { + traccc::scalar var0 = 0; + traccc::scalar var1 = 0; + if constexpr (dim >= Acts::BoundIndices::eBoundLoc0) { + var0 = measurement.covariance()(Acts::BoundIndices::eBoundLoc0, + Acts::BoundIndices::eBoundLoc0); + } + if constexpr (dim > Acts::BoundIndices::eBoundLoc1) { + var1 = measurement.covariance()(Acts::BoundIndices::eBoundLoc1, + Acts::BoundIndices::eBoundLoc1); + } + return Acts::ActsVector<2>(var0, var1); +} + +/// @brief Get the the variance of the measurement. +/// @param measurement the Acts bound variant measurement. +/// @return A two-dimensional vector containing the variance. +/// I.e., [variance (axis 0), variance (axis 1)]. +/// @note if the dimension is less than 2 then the remaining values are set to 0. +inline Acts::ActsVector<2> getVariance( + const Acts::BoundVariantMeasurement& measurement) { + return std::visit([](auto& m) { return getVariance(m); }, measurement); +} + +/// @brief Converts traccc measurements to acts measurements. +/// @param detector The detray detector, +/// @param measurements The traccc measurements, +/// @return A vector of Acts bound variant measurements. +/// @note The type IndexSourceLink is used for the measurements' source links. +template +inline auto createActsMeasurements( + const detector_t& detector, + const std::vector& measurements) { + std::vector measurementContainer; + for (const traccc::measurement& m : measurements) { + Acts::GeometryIdentifier moduleGeoId( + detector.surface(m.surface_link).source); + Index measurementIdx = measurementContainer.size(); + IndexSourceLink idxSourceLink{moduleGeoId, measurementIdx}; + measurementContainer.push_back( + boundVariantMeasurement(m, Acts::SourceLink{idxSourceLink})); + } + return measurementContainer; +} + +} // namespace ActsExamples::Traccc::Common::Conversion diff --git a/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Converter.hpp b/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Converter.hpp new file mode 100644 index 00000000000..dea5c6eae12 --- /dev/null +++ b/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Converter.hpp @@ -0,0 +1,220 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2020 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 http://mozilla.org/MPL/2.0/. + +#pragma once + +// Traccc Plugin include(s) +#include "Acts/Plugins/Traccc/CellConversion.hpp" +#include "Acts/Plugins/Traccc/TrackConversion.hpp" + +// Acts Examples include(s) +#include "ActsExamples/EventData/Track.hpp" +#include "ActsExamples/Traccc/Common/Conversion/CellMapConversion.hpp" +#include "ActsExamples/Traccc/Common/Conversion/DigitizationConversion.hpp" +#include "ActsExamples/Traccc/Common/Conversion/MeasurementConversion.hpp" +#include "ActsExamples/Traccc/Common/Measurement/Debug.hpp" +#include "ActsExamples/Traccc/Common/Measurement/MeasurementMatch.hpp" +#include "ActsExamples/Traccc/Common/Util/IndexMap.hpp" + +// Acts include(s) +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/EventData//TrackContainer.hpp" +#include "Acts/EventData/VectorMultiTrajectory.hpp" +#include "Acts/EventData/VectorTrackContainer.hpp" +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/Utilities/Logger.hpp" +#include "ActsExamples/EventData/Measurement.hpp" + +// Detray include(s). +#include "detray/core/detector.hpp" + +// Traccc include(s). +#include "traccc/geometry/geometry.hpp" + +// VecMem include(s). +#include + +// System include(s) +#include +#include +#include + +namespace ActsExamples::Traccc::Common { + +/// @brief Class for converting Acts data to traccc data. +class Converter { + private: + using detector_t = + detray::detector; + + const Acts::TrackingGeometry& trackingGeometry; + const detector_t& detector; + + // Cache the converted digitalization configuration, the surface transforms, + // and the barcode map. + const traccc::digitization_config digitizationConfig; + const traccc::geometry surfaceTransforms; + const std::map barcodeMap; + + const Acts::Logger& actsLogger; + + /// @brief Writes the number of traccc measurements and Acts measurements to the logger. + /// If the number of measurements do not matching a warning is shown. + /// @param tracccMeasurements the traccc measurements. + /// @param measurements the Acts measurements. + template + void logMeasurementCountComparison( + const std::vector& tracccMeasurements, + const std::vector& measurements) const { + if (tracccMeasurements.size() != measurements.size()) { + std::stringstream ss; + ss << "Number of measurements do not match (traccc: " + << tracccMeasurements.size() << ", acts: " << measurements.size() + << ")\n" + << "Perhaps mergeCommonCorner or doMerge is false in the digitization " + "algorithm config?"; + ACTS_WARNING(ss.str()); + } else { + std::stringstream ss; + ss << "Number of Acts and Traccc measurements match (count: " + << measurements.size() << ")"; + ACTS_INFO(ss.str()); + } + } + + /// @brief Creates a map from traccc measurements to acts measurements. + /// The traccc elements will map to an acts measurement that it is equivalent + /// to. The resulting map is assumed to be bijective, thus if any element is + /// unable to find a match an error is thrown. + /// @param tracccMeasurements the traccc measurements. + /// @param measurements the acts measurements. + /// @return A map from traccc measurement to acts bound variant measurement. + template + std::map + measurementConversionMap( + const std::vector& tracccMeasurements, + const std::vector& measurements) const { + logMeasurementCountComparison(tracccMeasurements, measurements); + + auto convertedMeasurements = + Conversion::createActsMeasurements(detector, tracccMeasurements); + auto indexMap = Measurement::matchMap(convertedMeasurements, measurements); + + ACTS_DEBUG(std::string("Traccc (1) and Acts (2) measurement index pairing " + "information:\n") + + Measurement::pairingStatistics(convertedMeasurements, + measurements, indexMap)); + + return Util::referenceMap(tracccMeasurements, measurements, indexMap); + } + + template class holder_t> + void mapMeasurements( + Acts::TrackContainer& + trackContainer, + const std::map map) + const { + for (auto track : trackContainer) { + for (auto trackState : track.trackStates()) { + const auto tracccMeasurement = trackState.getUncalibratedSourceLink() + .template get(); + const Acts::BoundVariantMeasurement& measurement = + map.at(tracccMeasurement); + std::visit( + [&trackState](auto& m) { + trackState.setUncalibratedSourceLink(m.sourceLink()); + trackState.setCalibrated(m); + }, + measurement); + } + } + } + + protected: + const Acts::Logger& logger() const { return actsLogger; } + + public: + Converter(const Acts::TrackingGeometry& tg, const detector_t& det, + const traccc::digitization_config& dc, const traccc::geometry& sf, + const std::map& bm, + const Acts::Logger& l) + : trackingGeometry(tg), + detector(det), + digitizationConfig(dc), + surfaceTransforms(sf), + barcodeMap(bm), + actsLogger(l) {} + + /// @brief Converts a map of cells to traccc cells and modules. + /// @param map The geometry id -> cell collection map which corresponds to each geometry's cells. + /// @param mr The memory resource to use. + /// @returns a tuple containing traccc input data, i.e. (cells, modules). + auto convertCells( + const std::map>& map, + vecmem::memory_resource* mr) const { + auto tcm = Conversion::tracccCellsMap(map); + auto res = Acts::TracccPlugin::createCellsAndModules( + mr, tcm, &surfaceTransforms, &digitizationConfig, &barcodeMap); + + std::stringstream ss; + ss << "Successfully converted Acts cells (obtained " + << std::get<0>(res).size() << " traccc cells and " + << std::get<1>(res).size() << " traccc modules)"; + ACTS_INFO(ss.str()) + + return res; + } + + /// @brief Converts a container of traccc tracks to a container of Acts tracks. + /// The given traccc measurements are compared with the given acts + /// measurements to determine the mapping between measurements and ensure that + /// the two collections of measurements are equivalent. The newly created Acts + /// tracks will use measurements from the acts measurement container. The Acts + /// measurements provided will be used for setting both the calibrated and + /// uncalibrated measurements/sourcelinks. + /// @param tracccTrackContainer The traccc tracks. + /// @param tracccMeasurements the traccc measurements. + /// @param measurements the Acts measurements. + /// @return An Acts const track container. + template + auto convertTracks( + traccc_track_container_t& tracccTrackContainer, + const std::vector& tracccMeasurements, + const std::vector& measurements) const { + auto trackContainer = std::make_shared(); + auto trackStateContainer = std::make_shared(); + TrackContainer tracks(trackContainer, trackStateContainer); + + Acts::TracccPlugin::makeTracks(tracccTrackContainer, tracks, detector, + trackingGeometry); + + std::stringstream ss; + ss << "Converted " << tracccTrackContainer.size() << " traccc tracks"; + ACTS_INFO(ss.str()) + + auto mcm = measurementConversionMap(tracccMeasurements, measurements); + + ACTS_INFO( + "Found a 1:1 mapping of indexes between traccc and Acts measurements"); + + mapMeasurements(tracks, mcm); + + ACTS_INFO("Updated track state measurements"); + + ConstTrackContainer constTracks{ + std::make_shared( + std::move(*trackContainer)), + std::make_shared( + std::move(*trackStateContainer))}; + + return constTracks; + } +}; + +} // namespace ActsExamples::Traccc::Common \ No newline at end of file diff --git a/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Measurement/Debug.hpp b/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Measurement/Debug.hpp new file mode 100644 index 00000000000..fa503630263 --- /dev/null +++ b/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Measurement/Debug.hpp @@ -0,0 +1,38 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2023 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 http://mozilla.org/MPL/2.0/. + +#pragma once + +// Acts include(s) +#include "ActsExamples/EventData/Measurement.hpp" + +// System include(s). +#include +#include +#include +#include +#include + +// This file is for debugging and for getting the matching between two +// collections of measurements as a string. + +namespace ActsExamples::Traccc::Common::Measurement { + +/// @brief Creates a string with the data of the measurements and their relation according to the index map. +/// @param measurements1 the measurements (1). +/// @param measurements2 the measurements (2). +/// @param indexMap the index map: measurements1 indices -> measurement2 indices. +/// The index map describes which elements are related in the two measurement +/// collections. +/// @return a string formatted as a table. +std::string pairingStatistics( + const std::vector& measurements1, + const std::vector& measurements2, + const std::map& indexMap); + +} // namespace ActsExamples::Traccc::Common::Measurement diff --git a/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Measurement/MeasurementMatch.hpp b/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Measurement/MeasurementMatch.hpp new file mode 100644 index 00000000000..1027a75ab2d --- /dev/null +++ b/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Measurement/MeasurementMatch.hpp @@ -0,0 +1,97 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2023 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 http://mozilla.org/MPL/2.0/. + +#pragma once + +// Acts include(s) +#include "Acts/Geometry/GeometryIdentifier.hpp" + +// Acts examples include(s) +#include "ActsExamples/EventData/IndexSourceLink.hpp" +#include "ActsExamples/EventData/Measurement.hpp" +#include "ActsExamples/Traccc/Common/Util/IndexMap.hpp" + +// System include(s). +#include +#include +#include +#include +#include + +// This file is for matching similar measurements in two collections of +// measurements. + +namespace ActsExamples::Traccc::Common::Measurement { + +/// @brief Get the geometry ID from the measurement through its source link. +/// @note Sourcelink is assumed to be of type IndexSourceLink. +inline Acts::GeometryIdentifier getGeometryID( + const Acts::BoundVariantMeasurement& measurement) { + return std::visit( + [](auto& m) { + return m.sourceLink() + .template get() + .geometryId(); + }, + measurement); +} + +/// @brief Checks if two measurements are equal based on their geometry ID and position alone. +/// @param measurement1 the first measurement. +/// @param measurement2 the second measurement. +/// @param maxDistance the tolerance of the difference in local position. +/// The maximum distance between the local positions of the measurements must be +/// less or equal to this value to be considered equal. +/// @returns true or false depending on whether they are considered equal. +inline bool measurementEqual(const Acts::BoundVariantMeasurement& measurement1, + const Acts::BoundVariantMeasurement& measurement2, + const double maxDistance = .001) { + auto gidEq = getGeometryID(measurement1) == getGeometryID(measurement2); + + auto sqNorm = + (Conversion::getLocal(measurement1) - Conversion::getLocal(measurement2)) + .squaredNorm(); + auto locEq = sqNorm <= maxDistance * maxDistance; + + return gidEq && locEq; +} + +/// @brief Generates a hash for the measurement. +/// This hash is used for the locality sensitive hashing to calculate the match +/// map. Thus, this hash is not sensitive to small variations in position that +/// could could from numerical errors. +inline std::size_t measurementHash( + const Acts::BoundVariantMeasurement& measurement) { + // The hash function can be optimized to reduce collisions. + return static_cast(getGeometryID(measurement).value()); +} + +namespace { +const auto wrappedHash = + std::function( + measurementHash); +const auto wrappedEq = + std::function( + [](const Acts::BoundVariantMeasurement& m1, + const Acts::BoundVariantMeasurement& m2) { + return measurementEqual(m1, m2); + }); +} // namespace + +/// @brief Creates a match map by matching the elements in two collection based on their geometry id and approximate position. +/// The two collections of measurements are assumed to contain the same +/// measurements. However, equivalent measurements may be at different indices +/// in the collections. This function determines which indexes correspond to +/// matching measurements. +inline auto matchMap(const std::vector& from, + const std::vector& to) { + return Util::matchMap(from, to, wrappedHash, wrappedEq); +} + +} // namespace ActsExamples::Traccc::Common::Measurement diff --git a/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/TracccChainAlgorithmBase.hpp b/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/TracccChainAlgorithmBase.hpp new file mode 100644 index 00000000000..ea8e16e2d3f --- /dev/null +++ b/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/TracccChainAlgorithmBase.hpp @@ -0,0 +1,107 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2020 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 http://mozilla.org/MPL/2.0/. + +#pragma once + +// Acts include(s) +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/MagneticField/ConstantBField.hpp" +#include "Acts/MagneticField/MagneticFieldProvider.hpp" +#include "Acts/Utilities/Logger.hpp" +#include "ActsExamples/Digitization/DigitizationConfig.hpp" +#include "ActsExamples/EventData/Cluster.hpp" +#include "ActsExamples/EventData/IndexSourceLink.hpp" +#include "ActsExamples/EventData/Measurement.hpp" +#include "ActsExamples/Framework/DataHandle.hpp" +#include "ActsExamples/Framework/IAlgorithm.hpp" +#include "ActsExamples/Framework/ProcessCode.hpp" + +// Acts Examples include(s) +#include "ActsExamples/Traccc/Common/Converter.hpp" +#include "ActsExamples/Traccc/Common/TracccChainConfig.hpp" + +// Covfie Plugin include(s) +#include "Acts/Plugins/Covfie/FieldConversion.hpp" + +// Detray include(s). +#include "detray/core/detector.hpp" + +// VecMem include(s). +#include + +// System include(s) +#include +#include + +namespace ActsExamples::Traccc::Common { + +class TracccChainAlgorithmBase : public IAlgorithm { + public: + using DetectorHostType = + detray::detector; + using FieldType = Acts::CovfiePlugin::ConstantField; + using CellsMapType = + std::map>; + + struct Config { + std::string inputCells; + std::string inputMeasurements; + std::string outputTracks; + std::shared_ptr trackingGeometry = nullptr; + std::shared_ptr field; + Acts::GeometryHierarchyMap digitizationConfigs; + std::shared_ptr chainConfig; + }; + + /// Construct the traccc algorithm. + /// + /// @param cfg is the algorithm configuration + /// @param lvl is the logging level + TracccChainAlgorithmBase(Config cfg, Acts::Logging::Level lvl); + + /// Const access to the config + const Config& config() const { return m_cfg; } + + protected: + Config m_cfg; + + ReadDataHandle m_inputCells{this, "InputCells"}; + ReadDataHandle m_inputMeasurements{this, + "InputMeasurements"}; + WriteDataHandle m_outputTracks{this, "OutputTracks"}; + + // Memory resource, detector, and converter should be declared in that order + // to ensure order of destructor call. + vecmem::host_memory_resource hostMemoryResource; + const DetectorHostType detector; + const FieldType field; + const Converter converter; + + private: + /// @brief Test if the configuration is valid. + void TestValidConfig() { + if (m_cfg.inputCells.empty()) { + throw std::invalid_argument("Missing input cells"); + } + + if (m_cfg.field == nullptr) { + throw std::invalid_argument("Missing field"); + } + + if (m_cfg.trackingGeometry == nullptr) { + throw std::invalid_argument("Missing track geometry"); + } + + if (m_cfg.digitizationConfigs.empty()) { + throw std::invalid_argument("Missing digitization configuration"); + } + } +}; + +} // namespace ActsExamples::Traccc::Common \ No newline at end of file diff --git a/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/TracccChainConfig.hpp b/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/TracccChainConfig.hpp new file mode 100644 index 00000000000..10b1584ac0c --- /dev/null +++ b/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/TracccChainConfig.hpp @@ -0,0 +1,44 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2023 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 http://mozilla.org/MPL/2.0/. + +#pragma once + +// Traccc include(s) +#include "traccc/ambiguity_resolution/greedy_ambiguity_resolution_algorithm.hpp" +#include "traccc/clusterization/clusterization_algorithm.hpp" +#include "traccc/clusterization/spacepoint_formation_algorithm.hpp" +#include "traccc/definitions/primitives.hpp" +#include "traccc/finding/finding_algorithm.hpp" +#include "traccc/finding/finding_config.hpp" +#include "traccc/fitting/fitting_algorithm.hpp" +#include "traccc/fitting/fitting_config.hpp" +#include "traccc/seeding/seeding_algorithm.hpp" +#include "traccc/seeding/track_params_estimation.hpp" + +namespace ActsExamples::Traccc::Common { + +struct TracccChainConfig { + using ScalarType = traccc::scalar; + + using SeedfinderConfigType = typename traccc::seedfinder_config; + using SpacepointGridConfigType = typename traccc::spacepoint_grid_config; + using SeedfilterConfigType = typename traccc::seedfilter_config; + using FindingConfigType = typename traccc::finding_config; + using FittingConfigType = typename traccc::fitting_config; + using AmbiguityResolutionConfigType = + typename traccc::greedy_ambiguity_resolution_algorithm::config_t; + + SeedfinderConfigType seedfinderConfig; + SpacepointGridConfigType spacepointGridConfig{seedfinderConfig}; + SeedfilterConfigType seedfilterConfig; + FindingConfigType findingConfig; + FittingConfigType fittingConfig; + AmbiguityResolutionConfigType ambiguityResolutionConfig; +}; + +} // namespace ActsExamples::Traccc::Common diff --git a/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Util/IndexMap.hpp b/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Util/IndexMap.hpp new file mode 100644 index 00000000000..8408954312c --- /dev/null +++ b/Examples/Algorithms/Traccc/Common/include/ActsExamples/Traccc/Common/Util/IndexMap.hpp @@ -0,0 +1,127 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2023 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 http://mozilla.org/MPL/2.0/. + +#pragma once + +// System include(s). +#include +#include +#include +#include +#include +#include +#include + +namespace ActsExamples::Traccc::Common::Util { + +/// @brief +/// @tparam T +/// @tparam A +/// @param out the index into the candidate indices vector. +/// Taking this index into the candidate indices vector will get the index in . +/// @param element +/// @param candidateIdxs +/// @param candidateVec +/// @param eqFn +/// @return +template +auto findMatchIdx(std::size_t* out, const T& element, + const std::vector& candidateIdxs, + const std::vector& candidateVec, + const std::function& eqFn) { + for (std::size_t i = 0; i < candidateIdxs.size(); i++) { + auto idx = candidateIdxs[i]; + if (eqFn(element, candidateVec[idx])) { + *out = i; + return true; + } + } + return false; +} + +/// @brief Determines which pairs of indices in the two vectors contain items that are equal. +/// Each item in the vector 'from̈́' must be equal to at least 1 item in the +/// vector 'to'. Furthermore, if the flag 'bijection' is enabled each element in +/// ̈́'to' and 'from' can only be paired with exactly 1 element. +/// @note When 'bijection' is corresponds to the assumption that the two vectors contain exactly the same elements. +/// The ordering in the vectors may however be different (determining the +/// difference in the order is where this function can be helpful). +/// @param from a vector (the retutned map's domain). +/// @param to a vector (the returned map's codomain). +/// @param lshFn the hashing function used for locality sensitive hashing. Any items that could potential be equal should have the same hash value. +/// @param eqFn the function for determining if two items are equal. +/// @param bijection flag indicatiing whether the map should be a bijection. +/// @return a map: index ('from' vector) -> index ('to' vector). +template +inline auto matchMap(const std::vector& from, + const std::vector& to, + const std::function& lshFn, + const std::function& eqFn, + const bool bijection = true) { + // By composition of functions, we can combine the maps "index ('from' vector) + // -> hash value" and "hash value -> index ('to' vector)" to obtain "index + // ('from' vector) -> index ('to' vector)". + + if (bijection && from.size() != to.size()) { + throw std::runtime_error( + "Cannot create a bijection as domain and codomain do not have the same " + "cardinality"); + } + + // We start by creating the map "hash value -> index ('to' vector)". + + // Since there can be collisions with the hash values + // each hash value maps to a bucket of indices rather than a single index. + + std::unordered_map> map1; + for (std::size_t toIdx = 0; toIdx < to.size(); toIdx++) { + auto& toElement = to[toIdx]; + auto toElementHash = lshFn(toElement); + map1[toElementHash].push_back(toIdx); + } + + // We can build the map "index in 'from' -> index in 'to'" directly. + std::map res; + for (std::size_t fromIdx = 0; fromIdx < from.size(); fromIdx++) { + auto& fromElement = from[fromIdx]; + auto fromElementHash = lshFn(fromElement); + // We now find the exact element to match fromElement with in the bucket. + auto& candidateIdxs = map1[fromElementHash]; + std::size_t idx; + if (candidateIdxs.empty() || + !findMatchIdx(&idx, fromElement, candidateIdxs, to, eqFn)) { + throw std::runtime_error("Could not find a match for an element"); + } + res[fromIdx] = candidateIdxs[idx]; + if (bijection) { + candidateIdxs.erase(candidateIdxs.begin() + idx); + } + } + return res; +} + +/// @brief Creates a map from elements in one vector to another. +/// The resulting map holds the elements by reference. +/// @param from the first collection. +/// @param to the second collection. +/// @param indexMap a map of indices in the first collection to indices in the second collection. +/// @returns the map: element in first collection -> element in second collection. +template +std::map referenceMap( + const std::vector& from, const std::vector& to, + const std::map& indexMap) { + assert(from.size() == to.size()); + std::map res; + for (const auto [i, j] : indexMap) { + res.emplace(std::piecewise_construct, std::forward_as_tuple(from[i]), + std::forward_as_tuple(to[j])); + } + return res; +} + +} // namespace ActsExamples::Traccc::Common::Util \ No newline at end of file diff --git a/Examples/Algorithms/Traccc/Common/src/Conversion/CellMapConversion.cpp b/Examples/Algorithms/Traccc/Common/src/Conversion/CellMapConversion.cpp new file mode 100644 index 00000000000..8cdaf21ed81 --- /dev/null +++ b/Examples/Algorithms/Traccc/Common/src/Conversion/CellMapConversion.cpp @@ -0,0 +1,83 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2023 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 http://mozilla.org/MPL/2.0/. + +// Acts include(s) +#include "Acts/Geometry/GeometryIdentifier.hpp" + +// Acts Examples include(s) +#include "ActsExamples/EventData/Cluster.hpp" +#include "ActsExamples/Traccc/Common/Conversion/CellMapConversion.hpp" + +// Traccc include(s) +#include "traccc/edm/cell.hpp" + +// System include(s). +#include +#include +#include +#include + +namespace ActsExamples::Traccc::Common::Conversion { + +/// @brief Gets the time of the cell. +/// @note Currently, it always returns 0. +inline float getTime(const Cluster::Cell& /*cell*/) { + return 0.f; +} + +/// @brief Gets the activation of the cell. +inline float getActivation(const Cluster::Cell& cell) { + return static_cast(cell.activation); +} + +/// @brief Gets the row of the cell. +inline unsigned int getRow(const Cluster::Cell& cell) { + if (cell.bin[0] > UINT_MAX) { + throw std::runtime_error( + "Overflow will occur when casting to unsigned int."); + } + return static_cast(cell.bin[0]); +} + +/// @brief Gets the column of the cell. +inline unsigned int getColumn(const Cluster::Cell& cell) { + if (cell.bin[0] > UINT_MAX) { + throw std::runtime_error( + "Overflow will occur when casting to unsigned int."); + } + return static_cast(cell.bin[1]); +} + +/// @brief Creates a traccc cell from a generic cell type. +/// @param cell the cell. +/// @param moduleLink the module link value to set for the traccc cell that is created. +/// @returns a traccc cell. +/// @note the functions getRow(cell_t), getColumn(cell_t), getActivation(cell_t), getTime(cell_t) are expected. +inline traccc::cell tracccCell(const Cluster::Cell& cell, + const traccc::cell::link_type moduleLink = 0) { + return traccc::cell{getRow(cell), getColumn(cell), getActivation(cell), + getTime(cell), moduleLink}; +} + +/// @brief Converts a "geometry ID -> generic cell collection type" map to a "geometry ID -> traccc cell collection" map. +/// @note The function sets the module link of the cells in the output to 0. +/// @return Map from geometry ID to its cell data (as a vector of traccc cell data) +std::map> tracccCellsMap( + const std::map>& map) { + std::map> tracccCellMap; + for (const auto& [geometryID, cells] : map) { + std::vector tracccCells; + for (const auto& cell : cells) { + tracccCells.push_back(tracccCell(cell)); + } + tracccCellMap.insert({geometryID.value(), std::move(tracccCells)}); + } + return tracccCellMap; +} + +} // namespace ActsExamples::Traccc::Common::Conversion diff --git a/Examples/Algorithms/Traccc/Common/src/Conversion/DigitizationConversion.cpp b/Examples/Algorithms/Traccc/Common/src/Conversion/DigitizationConversion.cpp new file mode 100644 index 00000000000..dcd7e616dfe --- /dev/null +++ b/Examples/Algorithms/Traccc/Common/src/Conversion/DigitizationConversion.cpp @@ -0,0 +1,48 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2023 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 http://mozilla.org/MPL/2.0/. + +// Acts include(s) +#include "Acts/Geometry/GeometryHierarchyMap.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Utilities/BinUtility.hpp" + +// Acts Examples include(s) +#include "ActsExamples/Digitization/DigitizationConfig.hpp" +#include "ActsExamples/Traccc/Common/Conversion/DigitizationConversion.hpp" + +// Traccc include(s) +#include "traccc/io/digitization_config.hpp" + +// System include(s). +#include +#include + +namespace ActsExamples::Traccc::Common::Conversion { + +/// @brief Get the segmentation from a DigiComponentsConfig. +inline Acts::BinUtility getSegmentation(const DigiComponentsConfig& dcc) { + return dcc.geometricDigiConfig.segmentation; +} + +/// @brief Creates a traccc digitalization config from an Acts geometry hierarchy map +/// that contains the digitization configuration. +/// @param config the Acts geometry hierarchy map that contains the digitization configuration. +/// @return a traccc digitization config. +traccc::digitization_config tracccConfig( + const Acts::GeometryHierarchyMap& config) { + using ElementType = + std::pair; + std::vector vec; + for (auto& e : config.getElements()) { + vec.push_back({e.first, traccc::module_digitization_config{ + getSegmentation(e.second)}}); + } + return traccc::digitization_config(vec); +} + +} // namespace ActsExamples::Traccc::Common::Conversion diff --git a/Examples/Algorithms/Traccc/Common/src/Conversion/MeasurementConversion.cpp b/Examples/Algorithms/Traccc/Common/src/Conversion/MeasurementConversion.cpp new file mode 100644 index 00000000000..d759770a324 --- /dev/null +++ b/Examples/Algorithms/Traccc/Common/src/Conversion/MeasurementConversion.cpp @@ -0,0 +1,44 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2023 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 http://mozilla.org/MPL/2.0/. + +// Acts include(s) +#include "Acts/Definitions/TrackParametrization.hpp" + +// Acts Examples include(s) +#include "ActsExamples/Traccc/Common/Conversion/MeasurementConversion.hpp" + +// Traccc include(s) +#include "traccc/definitions/track_parametrization.hpp" + +namespace ActsExamples::Traccc::Common::Conversion { + +/// @brief Converts a traccc bound index to an Acts bound index. +/// @param tracccBoundIndex the traccc bound index. +/// @returns an Acts bound index. +Acts::BoundIndices boundIndex(const traccc::bound_indices tracccBoundIndex) { + switch (tracccBoundIndex) { + case traccc::bound_indices::e_bound_loc0: + return Acts::BoundIndices::eBoundLoc0; + case traccc::bound_indices::e_bound_loc1: + return Acts::BoundIndices::eBoundLoc1; + case traccc::bound_indices::e_bound_phi: + return Acts::BoundIndices::eBoundPhi; + case traccc::bound_indices::e_bound_theta: + return Acts::BoundIndices::eBoundTheta; + case traccc::bound_indices::e_bound_qoverp: + return Acts::BoundIndices::eBoundQOverP; + case traccc::bound_indices::e_bound_time: + return Acts::BoundIndices::eBoundTime; + case traccc::bound_indices::e_bound_size: + return Acts::BoundIndices::eBoundSize; + default: + throw std::runtime_error("Could not convert traccc bound index"); + } +} + +} // namespace ActsExamples::Traccc::Common::Conversion diff --git a/Examples/Algorithms/Traccc/Common/src/Debug/Debug.cpp b/Examples/Algorithms/Traccc/Common/src/Debug/Debug.cpp new file mode 100644 index 00000000000..4da7868fb55 --- /dev/null +++ b/Examples/Algorithms/Traccc/Common/src/Debug/Debug.cpp @@ -0,0 +1,117 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2023 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 http://mozilla.org/MPL/2.0/. + +// Acts include(s) +#include "Acts/Definitions/Algebra.hpp" + +// Acts Examples include(s) +#include "ActsExamples/EventData/Measurement.hpp" +#include "ActsExamples/Traccc/Common/Conversion/MeasurementConversion.hpp" + +// System include(s). +#include +#include +#include +#include +#include + +// This file is for debugging and for getting the matching between two +// collections of measurements as a string. + +namespace ActsExamples::Traccc::Common::Measurement { + +namespace { + +/// @returns a nicely formated string of a vector representing a point. +std::string toString(const Acts::ActsVector<2>& vec) { + std::stringstream ss; + ss << "(" << vec[0] << ", " << vec[1] << ")"; + return ss.str(); +} + +/// @brief Structure to hold table data +struct MeasurementMatchRow { + std::size_t idx1; + Acts::ActsVector<2> local1; + Acts::ActsVector<2> variance1; + + std::size_t idx2; + Acts::ActsVector<2> local2; + Acts::ActsVector<2> variance2; + + Acts::ActsScalar distanceLocal; +}; + +/// @brief Creates a table with data and measurements aligned according to the index map. +/// @param measurements1 the measurements (1). +/// @param measurements2 the measurements (2). +/// @param indexMap the index map: measurements1 indices -> measurement2 indices. +/// The index map describes which elements are related in the two measurement +/// collections. +/// @return a vector of MeasurementMatchRow. +auto createTable( + const std::vector& measurements1, + const std::vector& measurements2, + const std::map& indexMap) { + std::vector table; + for (std::size_t idx1 = 0; idx1 < measurements1.size(); ++idx1) { + MeasurementMatchRow row; + auto measurement1 = measurements1[idx1]; + row.idx1 = idx1; + row.local1 = Conversion::getLocal(measurement1); + row.variance1 = Conversion::getVariance(measurement1); + + auto idx2 = indexMap.at(idx1); + auto measurement2 = measurements2[idx2]; + row.idx2 = idx2; + row.local2 = Conversion::getLocal(measurement2); + row.variance2 = Conversion::getVariance(measurement2); + + row.distanceLocal = (row.local1 - row.local2).norm(); + table.push_back(row); + } + return table; +} + +} // namespace + +/// @brief Creates a string with the data of the measurements and their relation according to the index map. +/// @param measurements1 the measurements (1). +/// @param measurements2 the measurements (2). +/// @param indexMap the index map: measurements1 indices -> measurement2 indices. +/// The index map describes which elements are related in the two measurement +/// collections. +/// @return a string formatted as a table. +std::string pairingStatistics( + const std::vector& measurements1, + const std::vector& measurements2, + const std::map& indexMap) { + auto table = createTable(measurements1, measurements2, indexMap); + + std::stringstream ss; + + // Column headers + ss << std::setw(6) << "Idx1" << std::setw(25) << "Local1" << std::setw(35) + << "Variance1" << std::setw(20) << "Idx2" << std::setw(25) << "Local2" + << std::setw(35) << "Variance2" << std::setw(25) << "Distance Local" + << std::endl; + + // Line separator + ss << std::string(173, '-') << std::endl; + + // Print each row + for (const auto& row : table) { + ss << std::setw(6) << row.idx1 << std::setw(25) << toString(row.local1) + << std::setw(35) << toString(row.variance1) << std::setw(20) << row.idx2 + << std::setw(25) << toString(row.local2) << std::setw(35) + << toString(row.variance2) << std::setw(25) << std::fixed + << std::setprecision(2) << row.distanceLocal << std::endl; + } + return ss.str(); +} +} // namespace ActsExamples::Traccc::Common::Measurement \ No newline at end of file diff --git a/Examples/Algorithms/Traccc/Common/src/TracccChainAlgorithmBase.cpp b/Examples/Algorithms/Traccc/Common/src/TracccChainAlgorithmBase.cpp new file mode 100644 index 00000000000..b9bf4813253 --- /dev/null +++ b/Examples/Algorithms/Traccc/Common/src/TracccChainAlgorithmBase.cpp @@ -0,0 +1,76 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2020 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 http://mozilla.org/MPL/2.0/. + +// Traccc plugin include(s) +#include "ActsExamples/Traccc/Common/TracccChainAlgorithmBase.hpp" + +// Acts include(s) +#include "Acts/Utilities/Logger.hpp" +#include "ActsExamples/Framework/IAlgorithm.hpp" + +// Detray include(s). +#include "detray/core/detector.hpp" +#include "detray/io/frontend/detector_reader.hpp" + +// VecMem include(s). +#include + +// System include(s) +#include +#include + +namespace { + +// Temporarily used to get the corresponding detray detector for the Acts +// geometry. Will be replaced when the detray plugin containing geometry +// conversion is complete. +template +inline auto readDetector(vecmem::memory_resource* mr, + const std::string& detectorFilePath, + const std::string& materialFilePath = "", + const std::string& gridFilePath = "") { + // Set up the detector reader configuration. + detray::io::detector_reader_config cfg; + cfg.add_file(detectorFilePath); + if (!materialFilePath.empty()) { + cfg.add_file(materialFilePath); + } + if (!gridFilePath.empty()) { + cfg.add_file(gridFilePath); + } + + // Read the detector. + auto [det, names] = detray::io::read_detector(*mr, cfg); + return std::move(det); +} + +} // namespace + +/// Construct the traccc algorithm. +/// +/// @param cfg is the algorithm configuration +/// @param lvl is the logging level +ActsExamples::Traccc::Common::TracccChainAlgorithmBase:: + TracccChainAlgorithmBase(Config cfg, Acts::Logging::Level lvl) + : ActsExamples::IAlgorithm("TracccChainAlgorithm", lvl), + m_cfg(std::move(cfg)), + detector((TestValidConfig(), readDetector( + &hostMemoryResource, + "/home/frederik/Desktop/CERN-TECH/input/" + "odd-detray_geometry_detray.json"))), + field(Acts::CovfiePlugin::covfieField(*m_cfg.field)), + converter{*m_cfg.trackingGeometry, + detector, + Conversion::tracccConfig(m_cfg.digitizationConfigs), + traccc::io::alt_read_geometry(detector), + Acts::TracccPlugin::createBarcodeMap(detector), + logger()} { + m_inputCells.initialize(m_cfg.inputCells); + m_inputMeasurements.initialize(m_cfg.inputMeasurements); + m_outputTracks.initialize(m_cfg.outputTracks); +} diff --git a/Examples/Algorithms/Traccc/Host/CMakeLists.txt b/Examples/Algorithms/Traccc/Host/CMakeLists.txt new file mode 100644 index 00000000000..afad5a72094 --- /dev/null +++ b/Examples/Algorithms/Traccc/Host/CMakeLists.txt @@ -0,0 +1,20 @@ +add_library( + ActsExamplesTracccHost SHARED + src/TracccChainAlgorithm.cpp +) + +target_include_directories( + ActsExamplesTracccHost + PUBLIC $ +) + +target_link_libraries( + ActsExamplesTracccHost + PUBLIC + ActsExamplesTracccCommon +) + +install( + TARGETS ActsExamplesTracccHost + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} +) diff --git a/Examples/Algorithms/Traccc/Host/include/ActsExamples/Traccc/Host/TracccChainAlgorithm.hpp b/Examples/Algorithms/Traccc/Host/include/ActsExamples/Traccc/Host/TracccChainAlgorithm.hpp new file mode 100644 index 00000000000..84469bb59c7 --- /dev/null +++ b/Examples/Algorithms/Traccc/Host/include/ActsExamples/Traccc/Host/TracccChainAlgorithm.hpp @@ -0,0 +1,50 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2020 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 http://mozilla.org/MPL/2.0/. + +#pragma once + +// Traccc plugin include(s) +#include "ActsExamples/Traccc/Common/TracccChainAlgorithmBase.hpp" +#include "ActsExamples/Traccc/Host/Types.hpp" + +// VecMem include(s). +#include + +namespace ActsExamples::Traccc::Host { + +class TracccChainAlgorithm final : public Common::TracccChainAlgorithmBase { + public: + /// Construct the traccc algorithm. + /// + /// @param cfg is the algorithm configuration + /// @param lvl is the logging level + TracccChainAlgorithm(Config cfg, Acts::Logging::Level lvl); + + /// Run the algorithm. + /// + /// @param ctx is the algorithm context with event information + /// @return a process code indication success or failure + ProcessCode execute(const AlgorithmContext& ctx) const override; + + private: + using HostTypes = + typename ActsExamples::Chain::Host::Types; + + typename HostTypes::ClusterizationAlgorithmType clusterizationAlgorithm; + typename HostTypes::SpacepointFormationAlgorithmType + spacepointFormationAlgorithm; + typename HostTypes::SeedingAlgorithmType seedingAlgorithm; + typename HostTypes::TrackParametersEstimationAlgorithmType + trackParametersEstimationAlgorithm; + typename HostTypes::FindingAlgorithmType findingAlgorithm; + typename HostTypes::FittingAlgorithmType fittingAlgorithm; + typename HostTypes::AmbiguityResolutionAlgorithmType + ambiguityResolutionAlgorithm; +}; + +} // namespace ActsExamples::Traccc::Host \ No newline at end of file diff --git a/Examples/Algorithms/Traccc/Host/include/ActsExamples/Traccc/Host/Types.hpp b/Examples/Algorithms/Traccc/Host/include/ActsExamples/Traccc/Host/Types.hpp new file mode 100644 index 00000000000..d3c904a66e7 --- /dev/null +++ b/Examples/Algorithms/Traccc/Host/include/ActsExamples/Traccc/Host/Types.hpp @@ -0,0 +1,51 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2023 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 http://mozilla.org/MPL/2.0/. + +#pragma once + +// Traccc include(s) +#include "traccc/ambiguity_resolution/greedy_ambiguity_resolution_algorithm.hpp" +#include "traccc/clusterization/clusterization_algorithm.hpp" +#include "traccc/clusterization/spacepoint_formation_algorithm.hpp" +#include "traccc/finding/finding_algorithm.hpp" +#include "traccc/finding/finding_config.hpp" +#include "traccc/fitting/fitting_algorithm.hpp" +#include "traccc/fitting/fitting_config.hpp" +#include "traccc/seeding/seeding_algorithm.hpp" +#include "traccc/seeding/track_params_estimation.hpp" + +// Detray include(s). +#include "detray/core/detector.hpp" +#include "detray/propagator/rk_stepper.hpp" + +namespace ActsExamples::Chain::Host { + +template +struct Types { + using DetectorType = + detray::detector; + using StepperType = + detray::rk_stepper>; + using NavigatorType = detray::navigator; + using FitterType = traccc::kalman_fitter; + + using ClusterizationAlgorithmType = traccc::host::clusterization_algorithm; + using SpacepointFormationAlgorithmType = + traccc::host::spacepoint_formation_algorithm; + using SeedingAlgorithmType = traccc::seeding_algorithm; + using TrackParametersEstimationAlgorithmType = + traccc::track_params_estimation; + using FindingAlgorithmType = + traccc::finding_algorithm; + using FittingAlgorithmType = traccc::fitting_algorithm; + using AmbiguityResolutionAlgorithmType = + traccc::greedy_ambiguity_resolution_algorithm; +}; + +} // namespace ActsExamples::Chain::Host diff --git a/Examples/Algorithms/Traccc/Host/src/TracccChainAlgorithm.cpp b/Examples/Algorithms/Traccc/Host/src/TracccChainAlgorithm.cpp new file mode 100644 index 00000000000..fe8e9b310b6 --- /dev/null +++ b/Examples/Algorithms/Traccc/Host/src/TracccChainAlgorithm.cpp @@ -0,0 +1,98 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2020 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 http://mozilla.org/MPL/2.0/. + +// Acts examples include(s) +#include "ActsExamples/Traccc/Host/TracccChainAlgorithm.hpp" + +// System include(s). +#include +#include +#include +#include +#include +#include +#include +#include + +ActsExamples::Traccc::Host::TracccChainAlgorithm::TracccChainAlgorithm( + Config cfg, Acts::Logging::Level lvl) + : ActsExamples::Traccc::Common::TracccChainAlgorithmBase(std::move(cfg), + std::move(lvl)), + clusterizationAlgorithm(hostMemoryResource), + spacepointFormationAlgorithm(hostMemoryResource), + seedingAlgorithm(m_cfg.chainConfig->seedfinderConfig, + m_cfg.chainConfig->spacepointGridConfig, + m_cfg.chainConfig->seedfilterConfig, hostMemoryResource), + trackParametersEstimationAlgorithm(hostMemoryResource), + findingAlgorithm(m_cfg.chainConfig->findingConfig), + fittingAlgorithm(m_cfg.chainConfig->fittingConfig), + ambiguityResolutionAlgorithm( + m_cfg.chainConfig->ambiguityResolutionConfig) {} + +ActsExamples::ProcessCode +ActsExamples::Traccc::Host::TracccChainAlgorithm::execute( + const ActsExamples::AlgorithmContext& ctx) const { + vecmem::host_memory_resource mr; + + typename HostTypes::ClusterizationAlgorithmType::output_type measurements{ + &mr}; + typename HostTypes::SpacepointFormationAlgorithmType::output_type spacepoints{ + &mr}; + typename HostTypes::SeedingAlgorithmType::output_type seeds{&mr}; + typename HostTypes::TrackParametersEstimationAlgorithmType::output_type + params{&mr}; + typename HostTypes::FindingAlgorithmType::output_type trackCandidates{&mr}; + typename HostTypes::FittingAlgorithmType::output_type trackStates{&mr}; + typename HostTypes::AmbiguityResolutionAlgorithmType::output_type + resolvedTrackStates{&mr}; + + const auto cellsMap = m_inputCells(ctx); + + auto [cells, modules] = converter.convertCells(cellsMap, &mr); + + measurements = clusterizationAlgorithm(vecmem::get_data(cells), + vecmem::get_data(modules)); + + ACTS_INFO("Ran the clusterization algorithm"); + + spacepoints = spacepointFormationAlgorithm(vecmem::get_data(measurements), + vecmem::get_data(modules)); + + ACTS_INFO("Ran the spacepoint formation algorithm"); + + seeds = seedingAlgorithm(spacepoints); + + ACTS_INFO("Ran the seeding algorithm"); + + const typename FieldType::view_t fieldView(field); + + // Traccc expects a field vector of a constant field. + params = trackParametersEstimationAlgorithm(spacepoints, seeds, + fieldView.at(0.f, 0.f, 0.f)); + + ACTS_INFO("Ran the parameters estimation algorithm"); + + trackCandidates = findingAlgorithm(detector, field, measurements, params); + + ACTS_INFO("Ran the finding algorithm"); + + trackStates = fittingAlgorithm(detector, field, trackCandidates); + + ACTS_INFO("Ran the fitting algorithm"); + + resolvedTrackStates = ambiguityResolutionAlgorithm(trackStates); + + ACTS_INFO("Ran the ambiguity resolution algorithm"); + + const auto actsMeasurements = m_inputMeasurements(ctx); + auto result = converter.convertTracks(resolvedTrackStates, measurements, + actsMeasurements); + + m_outputTracks(ctx, std::move(result)); + return ActsExamples::ProcessCode::SUCCESS; +} diff --git a/Examples/Python/python/acts/examples/reconstruction.py b/Examples/Python/python/acts/examples/reconstruction.py index f486c9f9c3a..33bf6d1317b 100644 --- a/Examples/Python/python/acts/examples/reconstruction.py +++ b/Examples/Python/python/acts/examples/reconstruction.py @@ -2061,3 +2061,70 @@ def addSingleSeedVertexFinding( ) return s + + + +def addTracccChain( + s: acts.examples.Sequencer, + trackingGeometry: acts.TrackingGeometry, + field: acts.MagneticFieldProvider, + digiConfigFile: Union[Path, str], + chainConfig, + inputCells: Optional[str]= "cells", #"InputCells", + inputMeasurements: Optional[str]= "measurements", + outputTracks: Optional[str]="traccc_tracks", + outputDirRoot: Optional[Union[Path, str]] = None, + outputDirCsv: Optional[Union[Path, str]] = None, + logLevel: Optional[acts.logging.Level] = None, + writeTrajectories: bool = True, + writeCovMat=False, +) -> None: + from acts.examples import TracccChainAlgorithmHost + + customLogLevel = acts.examples.defaultLogging(s, logLevel) + + alg = TracccChainAlgorithmHost( + level=customLogLevel(), + inputCells=inputCells, + inputMeasurements=inputMeasurements, + outputTracks=outputTracks, + trackingGeometry=trackingGeometry, + field=field, + digitizationConfigs=acts.examples.readDigiConfigFromJson( + str(digiConfigFile), + ), + chainConfig=chainConfig + ) + + s.addAlgorithm(alg) + s.addWhiteboardAlias("tracks", alg.config.outputTracks) + + matchAlg = acts.examples.TrackTruthMatcher( + level=customLogLevel(), + inputTracks=alg.config.outputTracks, + inputParticles="particles", + inputMeasurementParticlesMap="measurement_particles_map", + outputTrackParticleMatching="track_particle_matching", + outputParticleTrackMatching="particle_track_matching", + ) + s.addAlgorithm(matchAlg) + s.addWhiteboardAlias( + "track_particle_matching", matchAlg.config.outputTrackParticleMatching + ) + s.addWhiteboardAlias( + "particle_track_matching", matchAlg.config.outputParticleTrackMatching + ) + + addTrackWriters( + s, + name="traccc", + tracks=alg.config.outputTracks, + outputDirCsv=outputDirCsv, + outputDirRoot=outputDirRoot, + writeStates=writeTrajectories, + writeSummary=writeTrajectories, + writeCKFperformance=False, + logLevel=logLevel, + writeCovMat=writeCovMat, + ) + return s \ No newline at end of file diff --git a/Examples/Python/python/acts/examples/simulation.py b/Examples/Python/python/acts/examples/simulation.py index 76cf0685aa8..f23a692a375 100644 --- a/Examples/Python/python/acts/examples/simulation.py +++ b/Examples/Python/python/acts/examples/simulation.py @@ -773,6 +773,7 @@ def addDigitization( outputDirRoot: Optional[Union[Path, str]] = None, rnd: Optional[acts.examples.RandomNumbers] = None, doMerge: Optional[bool] = None, + mergeCommonCorner: Optional[bool] = None, minEnergyDeposit: Optional[float] = None, logLevel: Optional[acts.logging.Level] = None, ) -> acts.examples.Sequencer: @@ -812,6 +813,7 @@ def addDigitization( outputMeasurementParticlesMap="measurement_particles_map", outputMeasurementSimHitsMap="measurement_simhits_map", doMerge=doMerge, + mergeCommonCorner=mergeCommonCorner, ) # Not sure how to do this in our style diff --git a/Examples/Python/src/Digitization.cpp b/Examples/Python/src/Digitization.cpp index 54ec8934ac1..b173edefa61 100644 --- a/Examples/Python/src/Digitization.cpp +++ b/Examples/Python/src/Digitization.cpp @@ -70,12 +70,12 @@ void addDigitization(Context& ctx) { ACTS_PYTHON_MEMBER(surfaceByIdentifier); ACTS_PYTHON_MEMBER(randomNumbers); ACTS_PYTHON_MEMBER(doMerge); + ACTS_PYTHON_MEMBER(mergeCommonCorner); ACTS_PYTHON_MEMBER(minEnergyDeposit); ACTS_PYTHON_MEMBER(digitizationConfigs); ACTS_PYTHON_STRUCT_END(); c.def_readonly("mergeNsigma", &Config::mergeNsigma); - c.def_readonly("mergeCommonCorner", &Config::mergeCommonCorner); patchKwargsConstructor(c); diff --git a/Examples/Python/src/ModuleEntry.cpp b/Examples/Python/src/ModuleEntry.cpp index 406894fda82..f5273d39414 100644 --- a/Examples/Python/src/ModuleEntry.cpp +++ b/Examples/Python/src/ModuleEntry.cpp @@ -79,6 +79,9 @@ void addObj(Context& ctx); void addOnnx(Context& ctx); void addOnnxNeuralCalibrator(Context& ctx); void addCovfie(Context& ctx); +void addTracccChainConfig(Context& ctx); +void addTracccChainHost(Context& ctx); + } // namespace Acts::Python @@ -142,4 +145,6 @@ PYBIND11_MODULE(ActsPythonBindings, m) { addOnnx(ctx); addOnnxNeuralCalibrator(ctx); addCovfie(ctx); + addTracccChainConfig(ctx); + addTracccChainHost(ctx); } diff --git a/Examples/Python/src/TracccChainConfig.cpp b/Examples/Python/src/TracccChainConfig.cpp new file mode 100644 index 00000000000..338167369ac --- /dev/null +++ b/Examples/Python/src/TracccChainConfig.cpp @@ -0,0 +1,184 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2021 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 http://mozilla.org/MPL/2.0/. + +#include "Acts/Plugins/Python/Utilities.hpp" +#include "Acts/Utilities/TypeTraits.hpp" +#include "ActsExamples/EventData/Index.hpp" +#include "ActsExamples/Traccc/Common/TracccChainConfig.hpp" + +#include + +#include +#include + +namespace py = pybind11; + +namespace Acts::Python { + +void addSeedFinderConfig(pybind11::module_ m){ + using Config = typename ActsExamples::Traccc::Common::TracccChainConfig::SeedfinderConfigType; + + auto c = py::class_(m, "SeedFinderConfig") + .def(py::init<>()); + + ACTS_PYTHON_STRUCT_BEGIN(c, Config); + ACTS_PYTHON_MEMBER(zMin); + ACTS_PYTHON_MEMBER(zMax); + ACTS_PYTHON_MEMBER(rMax); + ACTS_PYTHON_MEMBER(rMin); + ACTS_PYTHON_MEMBER(collisionRegionMin); + ACTS_PYTHON_MEMBER(collisionRegionMax); + ACTS_PYTHON_MEMBER(phiMin); + ACTS_PYTHON_MEMBER(phiMax); + ACTS_PYTHON_MEMBER(minPt); + ACTS_PYTHON_MEMBER(cotThetaMax); + ACTS_PYTHON_MEMBER(deltaRMin); + ACTS_PYTHON_MEMBER(deltaRMax); + ACTS_PYTHON_MEMBER(impactMax); + ACTS_PYTHON_MEMBER(sigmaScattering); + ACTS_PYTHON_MEMBER(maxPtScattering); + ACTS_PYTHON_MEMBER(maxSeedsPerSpM); + ACTS_PYTHON_MEMBER(bFieldInZ); + ACTS_PYTHON_MEMBER(beamPos); + ACTS_PYTHON_MEMBER(radLengthPerSeed); + ACTS_PYTHON_MEMBER(zAlign); + ACTS_PYTHON_MEMBER(rAlign); + ACTS_PYTHON_MEMBER(sigmaError); + ACTS_PYTHON_MEMBER(highland); + ACTS_PYTHON_MEMBER(maxScatteringAngle2); + ACTS_PYTHON_MEMBER(pTPerHelixRadius); + ACTS_PYTHON_MEMBER(minHelixDiameter2); + ACTS_PYTHON_MEMBER(pT2perRadius); + ACTS_PYTHON_MEMBER(phiBinDeflectionCoverage); + ACTS_PYTHON_MEMBER(neighbor_scope); + ACTS_PYTHON_STRUCT_END(); +} + +void addSpacePointGridConfig(py::module_ m) { + using Config = typename ActsExamples::Traccc::Common::TracccChainConfig::SpacepointGridConfigType; + + auto c = py::class_(m, "SpacePointGridConfig") + .def(py::init()); + + ACTS_PYTHON_STRUCT_BEGIN(c, Config); + ACTS_PYTHON_MEMBER(bFieldInZ); + ACTS_PYTHON_MEMBER(minPt); + ACTS_PYTHON_MEMBER(rMax); + ACTS_PYTHON_MEMBER(zMax); + ACTS_PYTHON_MEMBER(zMin); + ACTS_PYTHON_MEMBER(deltaRMax); + ACTS_PYTHON_MEMBER(cotThetaMax); + ACTS_PYTHON_MEMBER(impactMax); + ACTS_PYTHON_MEMBER(phiMin); + ACTS_PYTHON_MEMBER(phiMax); + ACTS_PYTHON_MEMBER(phiBinDeflectionCoverage); + ACTS_PYTHON_STRUCT_END(); +} + +void addSeedFilterConfig(py::module_ m) { + using Config = typename ActsExamples::Traccc::Common::TracccChainConfig::SeedfilterConfigType; + + auto c = py::class_(m, "SeedFilterConfig") + .def(py::init<>()); + + ACTS_PYTHON_STRUCT_BEGIN(c, Config); + ACTS_PYTHON_MEMBER(deltaInvHelixDiameter); + ACTS_PYTHON_MEMBER(impactWeightFactor); + ACTS_PYTHON_MEMBER(compatSeedWeight); + ACTS_PYTHON_MEMBER(deltaRMin); + ACTS_PYTHON_MEMBER(maxSeedsPerSpM); + ACTS_PYTHON_MEMBER(compatSeedLimit); + ACTS_PYTHON_MEMBER(max_triplets_per_spM); + ACTS_PYTHON_MEMBER(good_spB_min_radius); + ACTS_PYTHON_MEMBER(good_spB_weight_increase); + ACTS_PYTHON_MEMBER(good_spT_max_radius); + ACTS_PYTHON_MEMBER(good_spT_weight_increase); + ACTS_PYTHON_MEMBER(good_spB_min_weight); + ACTS_PYTHON_MEMBER(seed_min_weight); + ACTS_PYTHON_MEMBER(spB_min_radius); + ACTS_PYTHON_STRUCT_END(); +} + +void addFindingConfig(py::module_ m) { + using Config = typename ActsExamples::Traccc::Common::TracccChainConfig::FindingConfigType; + + auto c = py::class_(m, "FindingConfig") + .def(py::init<>()); + + ACTS_PYTHON_STRUCT_BEGIN(c, Config); + ACTS_PYTHON_MEMBER(max_num_branches_per_seed); + ACTS_PYTHON_MEMBER(max_num_branches_per_surface); + ACTS_PYTHON_MEMBER(min_track_candidates_per_track); + ACTS_PYTHON_MEMBER(max_track_candidates_per_track); + ACTS_PYTHON_MEMBER(max_num_skipping_per_cand); + ACTS_PYTHON_MEMBER(min_step_length_for_next_surface); + ACTS_PYTHON_MEMBER(max_step_counts_for_next_surface); + ACTS_PYTHON_MEMBER(chi2_max); + ACTS_PYTHON_MEMBER(propagation); + ACTS_PYTHON_MEMBER(n_measurements_per_thread); + ACTS_PYTHON_MEMBER(navigation_buffer_size_scaler); + ACTS_PYTHON_STRUCT_END(); +} + +void addFittingConfig(py::module_ m) { + using Config = typename ActsExamples::Traccc::Common::TracccChainConfig::FittingConfigType; + + auto c = py::class_(m, "FittingConfig") + .def(py::init<>()); + + ACTS_PYTHON_STRUCT_BEGIN(c, Config); + ACTS_PYTHON_MEMBER(n_iterations); + ACTS_PYTHON_MEMBER(propagation); + ACTS_PYTHON_STRUCT_END(); +} + +void addGreedyAmbiguityResolutionAlgorithmConfig(py::module_ m) { + using Config = typename ActsExamples::Traccc::Common::TracccChainConfig::AmbiguityResolutionConfigType; + + auto c = py::class_(m, "GreedyAmbiguityResolutionAlgorithmConfig") + .def(py::init<>()); + + ACTS_PYTHON_STRUCT_BEGIN(c, Config); + ACTS_PYTHON_MEMBER(maximum_shared_hits); + ACTS_PYTHON_MEMBER(maximum_iterations); + ACTS_PYTHON_MEMBER(n_measurements_min); + ACTS_PYTHON_MEMBER(check_obvious_errs); + ACTS_PYTHON_MEMBER(measurement_id_0_warning_threshold); + ACTS_PYTHON_MEMBER(verbose_error); + ACTS_PYTHON_MEMBER(verbose_warning); + ACTS_PYTHON_MEMBER(verbose_info); + ACTS_PYTHON_MEMBER(verbose_debug); + ACTS_PYTHON_STRUCT_END(); +} + +void addTracccChainConfig(Context& ctx) { + auto m = ctx.get("examples"); + + addSeedFinderConfig(m); + addSpacePointGridConfig(m); + addSeedFilterConfig(m); + addFindingConfig(m); + addFittingConfig(m); + addGreedyAmbiguityResolutionAlgorithmConfig(m); + + using Config = typename ActsExamples::Traccc::Common::TracccChainConfig; + + auto c = py::class_>(m, "TracccChainConfig") + .def(py::init<>()); + + ACTS_PYTHON_STRUCT_BEGIN(c, Config); + ACTS_PYTHON_MEMBER(seedfinderConfig); + ACTS_PYTHON_MEMBER(spacepointGridConfig); + ACTS_PYTHON_MEMBER(seedfilterConfig); + ACTS_PYTHON_MEMBER(findingConfig); + ACTS_PYTHON_MEMBER(fittingConfig); + ACTS_PYTHON_MEMBER(ambiguityResolutionConfig); + ACTS_PYTHON_STRUCT_END(); +} + +} // namespace Acts::Python diff --git a/Examples/Python/src/TracccChainConfigStub.cpp b/Examples/Python/src/TracccChainConfigStub.cpp new file mode 100644 index 00000000000..01aead0e57c --- /dev/null +++ b/Examples/Python/src/TracccChainConfigStub.cpp @@ -0,0 +1,22 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2021 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 http://mozilla.org/MPL/2.0/. + +#include "Acts/Plugins/Python/Utilities.hpp" + +#include +#include + +namespace py = pybind11; +using namespace pybind11::literals; + +namespace Acts::Python { +void addTracccChainConfig(Context& /* ctx */) { + +} + +} // namespace Acts::Python diff --git a/Examples/Python/src/TracccChainHost.cpp b/Examples/Python/src/TracccChainHost.cpp new file mode 100644 index 00000000000..af9f1f01482 --- /dev/null +++ b/Examples/Python/src/TracccChainHost.cpp @@ -0,0 +1,32 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2021 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 http://mozilla.org/MPL/2.0/. + +#include "Acts/Plugins/Python/Utilities.hpp" +#include "Acts/Utilities/TypeTraits.hpp" +#include "ActsExamples/EventData/Index.hpp" +#include "ActsExamples/Traccc/Host/TracccChainAlgorithm.hpp" + +#include + +#include +#include + +namespace py = pybind11; + +namespace Acts::Python { + +void addTracccChainHost(Context& ctx) { + auto m = ctx.get("examples"); + + ACTS_PYTHON_DECLARE_ALGORITHM( + ActsExamples::Traccc::Host::TracccChainAlgorithm, m, + "TracccChainAlgorithmHost", inputCells, inputMeasurements, + outputTracks, trackingGeometry, field, digitizationConfigs, chainConfig); +} + +} // namespace Acts::Python diff --git a/Examples/Python/src/TracccChainHostStub.cpp b/Examples/Python/src/TracccChainHostStub.cpp new file mode 100644 index 00000000000..b470535af86 --- /dev/null +++ b/Examples/Python/src/TracccChainHostStub.cpp @@ -0,0 +1,16 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2021 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 http://mozilla.org/MPL/2.0/. + +#include "Acts/Plugins/Python/Utilities.hpp" + +namespace Acts::Python { +void addTracccChainHost(Context& /* ctx */) { + +} + +} // namespace Acts::Python diff --git a/Examples/Scripts/Python/full_chain_odd_traccc.py b/Examples/Scripts/Python/full_chain_odd_traccc.py new file mode 100755 index 00000000000..ccc1194ee25 --- /dev/null +++ b/Examples/Scripts/Python/full_chain_odd_traccc.py @@ -0,0 +1,267 @@ +#!/usr/bin/env python3 + +import os +import argparse +import pathlib + +import acts +import acts.examples +from acts.examples.simulation import ( + addParticleGun, + MomentumConfig, + EtaConfig, + PhiConfig, + ParticleConfig, + addPythia8, + addFatras, + addGeant4, + ParticleSelectorConfig, + addDigitization, + addParticleSelection, +) + +from acts.examples.dd4hep import ( + DD4hepDetector, + DD4hepDetectorOptions, + DD4hepGeometryService, +) + +from acts.examples.reconstruction import ( + addTracccChain, +) + +from acts.examples.odd import getOpenDataDetector, getOpenDataDetectorDirectory + +u = acts.UnitConstants + +parser = argparse.ArgumentParser(description="Sim-digi chain with the OpenDataDetector") +parser.add_argument( + "--output", + "-o", + help="Output directory", + type=pathlib.Path, + default=pathlib.Path.cwd() / "traccc_output", +) +parser.add_argument("--events", "-n", help="Number of events", type=int, default=100) +parser.add_argument("--skip", "-s", help="Number of events", type=int, default=0) +parser.add_argument( + "--geant4", help="Use Geant4 instead of fatras", action="store_true" +) +parser.add_argument( + "--ttbar", + help="Use Pythia8 (ttbar, pile-up 200) instead of particle gun", + action="store_true", +) +parser.add_argument( + "--ttbar-pu", + help="Number of pile-up events for ttbar", + type=int, + default=200, +) +parser.add_argument( + "--gun-particles", + help="Particle multiplicity of the particle gun", + type=int, + default=200, +) +parser.add_argument( + "--gun-vertices", + help="Vertex mulitplicity for the particle gun", + type=int, + default=1, +) +parser.add_argument( + "--gun-eta-range", + nargs="+", + help="Eta range of the particle gun", + type=float, + default=[-3.0, 3.0], +) +parser.add_argument( + "--gun-pt-range", + nargs="+", + help="Pt range of the particle gun (GeV)", + type=float, + default=[0.1 * u.GeV, 100 * u.GeV], +) +parser.add_argument( + "--rnd-seed", + help="Random seed", + type=int, + default=42, +) +parser.add_argument( + "--digi-config", + help="Digitization configuration file", + type=str, + default="", +) + +parser.add_argument( + "--mat-map", + help="Material map file", + type=str, + default="", +) + +parser.add_argument( + "--experimental", + action=argparse.BooleanOptionalAction, + help="Construct experimental geometry", +) + +args = parser.parse_args() + +decorators = None +if args.mat_map != "": + decorators = acts.IMaterialDecorator.fromFile(args.map) + +if args.experimental: + odd_xml = getOpenDataDetectorDirectory() / "xml" / "OpenDataDetector.xml" + + # Create the dd4hep geometry service and detector + dd4hepConfig = DD4hepGeometryService.Config() + dd4hepConfig.logLevel = acts.logging.INFO + dd4hepConfig.xmlFileNames = [str(odd_xml)] + dd4hepGeometryService = DD4hepGeometryService(dd4hepConfig) + detector = DD4hepDetector(dd4hepGeometryService) + + cOptions = DD4hepDetectorOptions(logLevel=acts.logging.INFO, emulateToGraph="") + cOptions.materialDecorator = decorators + + # Context and options + geoContext = acts.GeometryContext() + [recoGeometry, contextors, store] = detector.finalize(geoContext, cOptions) + + +else: + [detector, recoGeometry, decorators] = getOpenDataDetector(decorators) + + +outputDir = args.output +oddDigiConfig = args.digi_config +# Field specifications +field = acts.ConstantBField(acts.Vector3(0.0, 0.0, 2.0 * u.T)) + +rnd = acts.examples.RandomNumbers(seed=args.rnd_seed) + +s = acts.examples.Sequencer( + events=args.events, + skip=args.skip, + numThreads= 1 if args.geant4 else -1, + outputDir=str(outputDir), + trackFpes=False, +) + + +if not args.ttbar: + addParticleGun( + s, + MomentumConfig( + args.gun_pt_range[0] * u.GeV, + args.gun_pt_range[1] * u.GeV, + transverse=True, + ), + EtaConfig(args.gun_eta_range[0], args.gun_eta_range[1]), + PhiConfig(0.0, 360.0 * u.degree), + ParticleConfig( + args.gun_particles, 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), + ), + multiplicity=args.gun_vertices, + rnd=rnd, + ) +else: + addPythia8( + s, + hardProcess=["Top:qqbar2ttbar=on"], + npileup=args.ttbar_pu, + 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, 5.0 * u.ns), + ), + rnd=rnd, + outputDirRoot=outputDir, + # outputDirCsv=outputDir, + ) + +if args.geant4: + if s.config.numThreads != 1: + raise ValueError("Geant 4 simulation does not support multi-threading") + + # 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, + recoGeometry, + field, + preSelectParticles=ParticleSelectorConfig( + rho=(0.0, 24 * u.mm), + absZ=(0.0, 1.0 * u.m), + eta=(-3.0, 3.0), + pt=(150 * u.MeV, None), + removeNeutral=True, + ), + outputDirRoot=outputDir, + outputDirCsv=outputDir, + rnd=rnd, + killVolume=recoGeometry.worldVolume + if isinstance(recoGeometry, acts.TrackingGeometry) + else None, + killAfterTime=25 * u.ns, + ) +elif isinstance(recoGeometry, acts.TrackingGeometry): + addFatras( + s, + recoGeometry, + field, + preSelectParticles=ParticleSelectorConfig( + rho=(0.0, 24 * u.mm), + absZ=(0.0, 1.0 * u.m), + eta=(-3.0, 3.0), + pt=(150 * u.MeV, None), + removeNeutral=True, + ) + if args.ttbar + else ParticleSelectorConfig(), + enableInteractions=True, + outputDirRoot=outputDir, + outputDirCsv=outputDir, + rnd=rnd, + ) +else: + raise ValueError("Fatras simulation with Experimental::Detector not yet supported") + +addDigitization( + s, + recoGeometry, + field, + digiConfigFile=oddDigiConfig, + outputDirRoot=outputDir, + outputDirCsv=outputDir, + rnd=rnd, + minEnergyDeposit=0, + doMerge=True, + mergeCommonCorner=True, +) + +chainConfig = acts.examples.TracccChainConfig() + +addTracccChain( + s, + recoGeometry, + field, + digiConfigFile=oddDigiConfig, + inputCells="cells", + outputDirRoot=outputDir, + chainConfig=chainConfig, + logLevel=acts.logging.DEBUG + #outputDirCsv=outputDir, +) + +s.run()