diff --git a/Core/include/Acts/Seeding/EstimateTrackParamsFromSeed.hpp b/Core/include/Acts/Seeding/EstimateTrackParamsFromSeed.hpp index 5d6b4dbb97c..c59a55ad533 100644 --- a/Core/include/Acts/Seeding/EstimateTrackParamsFromSeed.hpp +++ b/Core/include/Acts/Seeding/EstimateTrackParamsFromSeed.hpp @@ -18,7 +18,6 @@ #include #include -#include #include #include #include @@ -126,8 +125,6 @@ FreeVector estimateTrackParamsFromSeed(spacepoint_range_t spRange, /// @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 @@ -135,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) { @@ -143,19 +140,6 @@ std::optional estimateTrackParamsFromSeed( return std::nullopt; } - // Convert bField to Tesla - ActsScalar bFieldStrength = bField.norm(); - // Check if magnetic field is too small - if (bFieldStrength < bFieldMin) { - // @todo shall we use straight-line estimation and use default q/pt in such - // case? - ACTS_WARNING( - "The magnetic field at the bottom space point: B = " - << bFieldStrength / UnitConstants::T << " T is smaller than |B|_min = " - << bFieldMin / UnitConstants::T << " 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()}; @@ -252,6 +236,7 @@ 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 / (bFieldStrength * R); diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationAlgorithm.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationAlgorithm.hpp index fd8937bd300..331408faa9a 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationAlgorithm.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationAlgorithm.hpp @@ -8,18 +8,14 @@ #pragma once -#include "Acts/Definitions/Algebra.hpp" -#include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/Geometry/GeometryContext.hpp" #include "Acts/Geometry/GeometryHierarchyMap.hpp" #include "Acts/Utilities/Logger.hpp" #include "ActsExamples/Digitization/DigitizationConfig.hpp" #include "ActsExamples/Digitization/MeasurementCreation.hpp" -#include "ActsExamples/Digitization/SmearingConfig.hpp" #include "ActsExamples/EventData/Cluster.hpp" -#include "ActsExamples/EventData/Index.hpp" #include "ActsExamples/EventData/Measurement.hpp" #include "ActsExamples/EventData/SimHit.hpp" +#include "ActsExamples/EventData/SimParticle.hpp" #include "ActsExamples/Framework/DataHandle.hpp" #include "ActsExamples/Framework/IAlgorithm.hpp" #include "ActsExamples/Framework/ProcessCode.hpp" @@ -29,28 +25,62 @@ #include "ActsFatras/Digitization/UncorrelatedHitSmearer.hpp" #include -#include #include -#include -#include #include #include -namespace ActsFatras { -class Barcode; -} // namespace ActsFatras - namespace ActsExamples { -struct AlgorithmContext; /// Algorithm that turns simulated hits into measurements by truth smearing. class DigitizationAlgorithm final : public IAlgorithm { public: + class Config { + public: + /// Input collection of simulated hits. + std::string inputSimHits = "simhits"; + /// Output measurements collection. + std::string outputMeasurements = "measurements"; + /// Output cells map (geoID -> collection of cells). + std::string outputCells = "cells"; + /// Output cluster collection. + std::string outputClusters = "clusters"; + /// Output collection to map measured hits to contributing particles. + std::string outputMeasurementParticlesMap = "measurement_particles_map"; + /// Output collection to map measured hits to simulated hits. + std::string outputMeasurementSimHitsMap = "measurement_simhits_map"; + + /// Map of surface by identifier to allow local - to global + std::unordered_map + surfaceByIdentifier; + /// Random numbers tool. + std::shared_ptr randomNumbers = nullptr; + /// Flag to determine whether cell data should be written to the + /// `outputCells` collection; if true, writes (rather voluminous) cell data. + bool doOutputCells = false; + /// Flag to determine whether or not to run the clusterization; if true, + /// clusters, measurements, and sim-hit-maps are output. + bool doClusterization = true; + /// Do we merge hits or not + bool doMerge = false; + /// How close do parameters have to be to consider merged + double mergeNsigma = 1.0; + /// Consider clusters that share a corner as merged (8-cell connectivity) + bool mergeCommonCorner = false; + /// Energy deposit threshold for accepting a hit + /// For a generic readout frontend we assume 1000 e/h pairs, in Si each + /// e/h-pair requiers on average an energy of 3.65 eV (PDG review 2023, + /// Table 35.10) + /// @NOTE The default is set to 0 because this works only well with Geant4 + double minEnergyDeposit = 0.0; // 1000 * 3.65 * Acts::UnitConstants::eV; + /// The digitizers per GeometryIdentifiers + Acts::GeometryHierarchyMap digitizationConfigs; + }; + /// Construct the smearing algorithm. /// /// @param config is the algorithm configuration /// @param level is the logging level - DigitizationAlgorithm(DigitizationConfig config, Acts::Logging::Level level); + DigitizationAlgorithm(Config config, Acts::Logging::Level level); /// Build measurement from simulation hits at input. /// @@ -59,7 +89,7 @@ class DigitizationAlgorithm final : public IAlgorithm { ProcessCode execute(const AlgorithmContext& ctx) const override; /// Get const access to the config - const DigitizationConfig& config() const { return m_cfg; } + const Config& config() const { return m_cfg; } private: /// Helper method for creating digitized parameters from clusters @@ -89,7 +119,7 @@ class DigitizationAlgorithm final : public IAlgorithm { CombinedDigitizer<4>>; /// Configuration of the Algorithm - DigitizationConfig m_cfg; + Config m_cfg; /// Digitizers within geometry hierarchy Acts::GeometryHierarchyMap m_digitizers; /// Geometric digtizer @@ -98,17 +128,17 @@ class DigitizationAlgorithm final : public IAlgorithm { using CellsMap = std::map>; - ReadDataHandle m_simContainerReadHandle{this, - "SimHitContainer"}; - - WriteDataHandle m_measurementWriteHandle{ - this, "Measurements"}; - WriteDataHandle m_cellsWriteHandle{this, "Cells"}; - WriteDataHandle m_clusterWriteHandle{this, "Clusters"}; - WriteDataHandle> - m_measurementParticlesMapWriteHandle{this, "MeasurementParticlesMap"}; - WriteDataHandle> m_measurementSimHitsMapWriteHandle{ - this, "MeasurementSimHitsMap"}; + ReadDataHandle m_inputHits{this, "InputHits"}; + + WriteDataHandle m_outputMeasurements{ + this, "OutputMeasurements"}; + WriteDataHandle m_outputCells{this, "OutputCells"}; + WriteDataHandle m_outputClusters{this, "OutputClusters"}; + + WriteDataHandle> m_outputMeasurementParticlesMap{ + this, "OutputMeasurementParticlesMap"}; + WriteDataHandle> m_outputMeasurementSimHitsMap{ + this, "OutputMeasurementSimHitsMap"}; /// Construct a fixed-size smearer from a configuration. /// diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfig.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfig.hpp index 6a933f50075..213abe4d322 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfig.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfig.hpp @@ -8,107 +8,12 @@ #pragma once -#include "Acts/Definitions/Algebra.hpp" -#include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/Definitions/Units.hpp" #include "Acts/Geometry/GeometryHierarchyMap.hpp" -#include "Acts/Utilities/BinUtility.hpp" -#include "Acts/Utilities/BinningType.hpp" -#include "Acts/Utilities/Logger.hpp" -#include "Acts/Utilities/Result.hpp" -#include "ActsExamples/Digitization/DigitizationConfig.hpp" -#include "ActsExamples/Digitization/Smearers.hpp" +#include "ActsExamples/Digitization/GeometricConfig.hpp" #include "ActsExamples/Digitization/SmearingConfig.hpp" -#include "ActsExamples/Framework/RandomNumbers.hpp" -#include "ActsFatras/Digitization/UncorrelatedHitSmearer.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Acts { -class GeometryIdentifier; -} // namespace Acts namespace ActsExamples { -/// Configuration struct for geometric digitization -/// -/// If this is defined, then the geometric digitization -/// will create clusters with cells. -/// The BinUtility defines the segmentation and which parameters -/// are defined by this. -/// -struct GeometricConfig { - // The dimensions of the measurement - std::vector indices = {}; - - // The (multidimensional) binning definition for the segmentation of the - // sensor - Acts::BinUtility segmentation; - - // The thickness of the sensor - double thickness = 0.; - - /// The charge smearer - ActsFatras::SingleParameterSmearFunction - chargeSmearer = Digitization::Exact(0); - - // The threshold below a cell activation is ignored - double threshold = 0.; - - // Whether to assume digital readout (activation is either 0 or 1) - bool digital = false; - - // Flag as strip - bool strip = false; - - /// The variances for this digitization - std::map> varianceMap = {}; - - /// Charge generation (configurable via the chargeSmearer) - Acts::ActsScalar charge(Acts::ActsScalar path, RandomEngine &rng) const { - if (!chargeSmearer) { - return path; - } - auto res = chargeSmearer(path, rng); - if (res.ok()) { - return std::max(0.0, res->first); - } else { - throw std::runtime_error(res.error().message()); - } - } - - /// This generates the variances for a given cluster - /// - /// @note either the variances are directly taken from a pre-read - /// variance map, or they are generated from the pitch size - /// - /// @param csizes is the cluster size in the different dimensions - /// @param cmins is the cluster minimum in the different dimensions - /// - /// @return a vector of variances for the cluster - std::vector variances( - const std::array &csizes, - const std::array &cmins) const; - - /// Drift generation (currently not implemented) - /// Takes as an argument the position, and a random engine - /// @return drift direction in local 3D coordinates - Acts::Vector3 drift(const Acts::Vector3 & /*position*/, - RandomEngine & /*rng*/) const { - return Acts::Vector3(0., 0., 0.); - }; -}; - /// Configuration struct for the Digitization algorithm /// /// It contains: @@ -116,63 +21,9 @@ struct GeometricConfig { /// - optional SmearingConfig struct DigiComponentsConfig { GeometricConfig geometricDigiConfig; - SmearingConfig smearingDigiConfig = {}; + SmearingConfig smearingDigiConfig; }; -class DigitizationConfig { - public: - DigitizationConfig(bool merge, double sigma, bool commonCorner) - : DigitizationConfig(merge, sigma, commonCorner, - Acts::GeometryHierarchyMap()) { - } - - DigitizationConfig( - bool doMerge, double mergeNsigma, bool mergeCommonCorner, - Acts::GeometryHierarchyMap &&digiCfgs); - - explicit DigitizationConfig( - Acts::GeometryHierarchyMap &&digiCfgs); +using DigiConfigContainer = Acts::GeometryHierarchyMap; - /// Input collection of simulated hits. - std::string inputSimHits = "simhits"; - /// Output measurements collection. - std::string outputMeasurements = "measurements"; - /// Output cells map (geoID -> collection of cells). - std::string outputCells = "cells"; - /// Output cluster collection. - std::string outputClusters = "clusters"; - /// Output collection to map measured hits to contributing particles. - std::string outputMeasurementParticlesMap = "measurement_particles_map"; - /// Output collection to map measured hits to simulated hits. - std::string outputMeasurementSimHitsMap = "measurement_simhits_map"; - /// Map of surface by identifier to allow local - to global - std::unordered_map - surfaceByIdentifier; - /// Random numbers tool. - std::shared_ptr randomNumbers = nullptr; - /// Flag to determine whether cell data should be written to the - /// `outputCells` collection; if true, writes (rather voluminous) cell data. - bool doOutputCells = false; - /// Flag to determine whether or not to run the clusterization; if true, - /// clusters, measurements, and sim-hit-maps are output. - bool doClusterization = true; - /// Do we merge hits or not - bool doMerge; - /// How close do parameters have to be to consider merged - const double mergeNsigma; - /// Consider clusters that share a corner as merged (8-cell connectivity) - const bool mergeCommonCorner; - /// Energy deposit threshold for accepting a hit - /// For a generic readout frontend we assume 1000 e/h pairs, in Si each - /// e/h-pair requiers on average an energy of 3.65 eV (PDG review 2023, - /// Table 35.10) - /// @NOTE The default is set to 0 because this works only well with Geant4 - double minEnergyDeposit = 0.0; // 1000 * 3.65 * Acts::UnitConstants::eV; - /// The digitizers per GeometryIdentifiers - Acts::GeometryHierarchyMap digitizationConfigs; - - std::vector< - std::pair>> - getBoundIndices() const; -}; } // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfigurator.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfigurator.hpp index 55754eb79f7..3e6d01dea0f 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfigurator.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationConfigurator.hpp @@ -11,21 +11,9 @@ #include "Acts/Geometry/GeometryHierarchyMap.hpp" #include "Acts/Geometry/GeometryIdentifier.hpp" #include "Acts/Geometry/TrackingGeometry.hpp" -#include "Acts/Surfaces/AnnulusBounds.hpp" -#include "Acts/Surfaces/DiscTrapezoidBounds.hpp" -#include "Acts/Surfaces/RadialBounds.hpp" -#include "Acts/Surfaces/RectangleBounds.hpp" -#include "Acts/Surfaces/SurfaceBounds.hpp" -#include "Acts/Surfaces/TrapezoidBounds.hpp" -#include "Acts/Utilities/BinUtility.hpp" -#include "Acts/Utilities/BinningData.hpp" -#include "ActsExamples/Digitization/DigitizationAlgorithm.hpp" #include "ActsExamples/Digitization/DigitizationConfig.hpp" #include -#include -#include -#include namespace Acts { class Surface; @@ -66,4 +54,5 @@ struct DigitizationConfigurator { /// it adds an appropriate entry into the digitisation configuration void operator()(const Acts::Surface* surface); }; + } // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationCoordinatesConverter.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationCoordinatesConverter.hpp index 21c4f619b8a..382e113844f 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationCoordinatesConverter.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/DigitizationCoordinatesConverter.hpp @@ -8,6 +8,7 @@ #pragma once +#include "ActsExamples/Digitization/DigitizationAlgorithm.hpp" #include "ActsExamples/Digitization/DigitizationConfig.hpp" namespace ActsExamples { @@ -18,10 +19,11 @@ class DigitizationCoordinatesConverter final { /// Construct the converter /// /// @param config is the configuration - explicit DigitizationCoordinatesConverter(DigitizationConfig config); + explicit DigitizationCoordinatesConverter( + DigitizationAlgorithm::Config config); /// Get const access to the config - const DigitizationConfig& config() const { return m_cfg; } + const DigitizationAlgorithm::Config& config() const { return m_cfg; } /// Convert the hit coordinates to the local frame. std::tuple globalToLocal(std::uint64_t moduleId, double x, @@ -33,7 +35,7 @@ class DigitizationCoordinatesConverter final { private: /// Configuration - DigitizationConfig m_cfg; + DigitizationAlgorithm::Config m_cfg; }; } // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/GeometricConfig.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/GeometricConfig.hpp new file mode 100644 index 00000000000..6b4348e20f6 --- /dev/null +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/GeometricConfig.hpp @@ -0,0 +1,98 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Definitions/TrackParametrization.hpp" +#include "Acts/Utilities/BinUtility.hpp" +#include "Acts/Utilities/Result.hpp" +#include "ActsExamples/Digitization/Smearers.hpp" +#include "ActsExamples/Framework/RandomNumbers.hpp" +#include "ActsFatras/Digitization/UncorrelatedHitSmearer.hpp" + +#include +#include +#include +#include +#include +#include +#include + +namespace ActsExamples { + +/// Configuration struct for geometric digitization +/// +/// If this is defined, then the geometric digitization +/// will create clusters with cells. +/// The BinUtility defines the segmentation and which parameters +/// are defined by this. +/// +struct GeometricConfig { + // The dimensions of the measurement + std::vector indices = {}; + + // The (multidimensional) binning definition for the segmentation of the + // sensor + Acts::BinUtility segmentation; + + // The thickness of the sensor + double thickness = 0.; + + /// The charge smearer + ActsFatras::SingleParameterSmearFunction + chargeSmearer = Digitization::Exact(0); + + // The threshold below a cell activation is ignored + double threshold = 0.; + + // Whether to assume digital readout (activation is either 0 or 1) + bool digital = false; + + // Flag as strip + bool strip = false; + + /// The variances for this digitization + std::map> varianceMap = {}; + + /// Charge generation (configurable via the chargeSmearer) + Acts::ActsScalar charge(Acts::ActsScalar path, RandomEngine &rng) const { + if (!chargeSmearer) { + return path; + } + auto res = chargeSmearer(path, rng); + if (res.ok()) { + return std::max(0.0, res->first); + } else { + throw std::runtime_error(res.error().message()); + } + } + + /// This generates the variances for a given cluster + /// + /// @note either the variances are directly taken from a pre-read + /// variance map, or they are generated from the pitch size + /// + /// @param csizes is the cluster size in the different dimensions + /// @param cmins is the cluster minimum in the different dimensions + /// + /// @return a vector of variances for the cluster + std::vector variances( + const std::array &csizes, + const std::array &cmins) const; + + /// Drift generation (currently not implemented) + /// Takes as an argument the position, and a random engine + /// @return drift direction in local 3D coordinates + Acts::Vector3 drift(const Acts::Vector3 & /*position*/, + RandomEngine & /*rng*/) const { + return Acts::Vector3(0., 0., 0.); + }; +}; + +} // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/ModuleClusters.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/ModuleClusters.hpp index 675f86af07d..452111db2eb 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/ModuleClusters.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/ModuleClusters.hpp @@ -16,10 +16,8 @@ #include "ActsExamples/EventData/Cluster.hpp" #include "ActsExamples/EventData/SimHit.hpp" -#include #include #include -#include #include #include #include @@ -69,4 +67,5 @@ class ModuleClusters { std::vector> mergeParameters( std::vector values); }; + } // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/Smearers.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/Smearers.hpp index c51b8e26b64..8d0130831ae 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/Smearers.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/Smearers.hpp @@ -12,13 +12,10 @@ #include "Acts/Utilities/Result.hpp" #include "ActsExamples/Framework/RandomNumbers.hpp" #include "ActsFatras/Digitization/DigitizationError.hpp" -#include "ActsFatras/Digitization/UncorrelatedHitSmearer.hpp" #include #include #include -#include -#include #include namespace ActsExamples::Digitization { diff --git a/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp b/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp index 72f3905ab57..07019be74ca 100644 --- a/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp +++ b/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp @@ -11,35 +11,24 @@ #include "Acts/Definitions/Algebra.hpp" #include "Acts/Definitions/TrackParametrization.hpp" #include "Acts/Geometry/GeometryIdentifier.hpp" -#include "Acts/Geometry/TrackingGeometry.hpp" -#include "Acts/Surfaces/Surface.hpp" #include "Acts/Utilities/BinUtility.hpp" -#include "Acts/Utilities/Result.hpp" #include "ActsExamples/Digitization/ModuleClusters.hpp" -#include "ActsExamples/EventData/GeometryContainers.hpp" -#include "ActsExamples/EventData/Index.hpp" -#include "ActsExamples/EventData/SimHit.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" -#include "ActsExamples/Utilities/GroupBy.hpp" -#include "ActsExamples/Utilities/Range.hpp" #include "ActsFatras/EventData/Barcode.hpp" -#include "ActsFatras/EventData/Hit.hpp" #include #include -#include -#include #include #include -#include #include #include #include -ActsExamples::DigitizationAlgorithm::DigitizationAlgorithm( - DigitizationConfig config, Acts::Logging::Level level) - : ActsExamples::IAlgorithm("DigitizationAlgorithm", level), - m_cfg(std::move(config)) { +namespace ActsExamples { + +DigitizationAlgorithm::DigitizationAlgorithm(Config config, + Acts::Logging::Level level) + : IAlgorithm("DigitizationAlgorithm", level), m_cfg(std::move(config)) { if (m_cfg.inputSimHits.empty()) { throw std::invalid_argument("Missing simulated hits input collection"); } @@ -69,12 +58,11 @@ ActsExamples::DigitizationAlgorithm::DigitizationAlgorithm( "Missing hit-to-simulated-hits map output collection"); } - m_measurementWriteHandle.initialize(m_cfg.outputMeasurements); - m_clusterWriteHandle.initialize(m_cfg.outputClusters); - m_measurementParticlesMapWriteHandle.initialize( + m_outputMeasurements.initialize(m_cfg.outputMeasurements); + m_outputClusters.initialize(m_cfg.outputClusters); + m_outputMeasurementParticlesMap.initialize( m_cfg.outputMeasurementParticlesMap); - m_measurementSimHitsMapWriteHandle.initialize( - m_cfg.outputMeasurementSimHitsMap); + m_outputMeasurementSimHitsMap.initialize(m_cfg.outputMeasurementSimHitsMap); } if (m_cfg.doOutputCells) { @@ -82,10 +70,10 @@ ActsExamples::DigitizationAlgorithm::DigitizationAlgorithm( throw std::invalid_argument("Missing cell output collection"); } - m_cellsWriteHandle.initialize(m_cfg.outputCells); + m_outputCells.initialize(m_cfg.outputCells); } - m_simContainerReadHandle.initialize(m_cfg.inputSimHits); + m_inputHits.initialize(m_cfg.inputSimHits); // Create the digitizers from the configuration std::vector> digitizerInput; @@ -139,16 +127,16 @@ ActsExamples::DigitizationAlgorithm::DigitizationAlgorithm( m_digitizers = Acts::GeometryHierarchyMap(digitizerInput); } -ActsExamples::ProcessCode ActsExamples::DigitizationAlgorithm::execute( - const AlgorithmContext& ctx) const { +ProcessCode DigitizationAlgorithm::execute(const AlgorithmContext& ctx) const { // Retrieve input - const auto& simHits = m_simContainerReadHandle(ctx); + const auto& simHits = m_inputHits(ctx); ACTS_DEBUG("Loaded " << simHits.size() << " sim hits"); // Prepare output containers // need list here for stable addresses MeasurementContainer measurements; ClusterContainer clusters; + IndexMultimap measurementParticlesMap; IndexMultimap measurementSimHitsMap; measurements.reserve(simHits.size()); @@ -271,7 +259,7 @@ ActsExamples::ProcessCode ActsExamples::DigitizationAlgorithm::execute( // Store the cell data into a map. if (m_cfg.doOutputCells) { std::vector cells; - for (const auto& [dParameters, simhits] : + for (const auto& [dParameters, simHitsIdxs] : digitizeParametersResult) { for (const auto& cell : dParameters.cluster.channels) { cells.push_back(cell); @@ -281,21 +269,18 @@ ActsExamples::ProcessCode ActsExamples::DigitizationAlgorithm::execute( } if (m_cfg.doClusterization) { - for (auto& [dParameters, simhits] : digitizeParametersResult) { - // The measurement container is unordered and the index under - // which the measurement will be stored is known before adding it. - Index measurementIdx = measurements.size(); - - createMeasurement(measurements, moduleGeoId, dParameters); + for (auto& [dParameters, simHitsIdxs] : digitizeParametersResult) { + auto measurement = + createMeasurement(measurements, moduleGeoId, dParameters); clusters.emplace_back(std::move(dParameters.cluster)); - // this digitization does hit merging so there can be more than - // one mapping entry for each digitized hit. - for (auto simHitIdx : simhits) { + + for (auto [i, simHitIdx] : Acts::enumerate(simHitsIdxs)) { measurementParticlesMap.emplace_hint( - measurementParticlesMap.end(), measurementIdx, + measurementParticlesMap.end(), measurement.index(), simHits.nth(simHitIdx)->particleId()); measurementSimHitsMap.emplace_hint(measurementSimHitsMap.end(), - measurementIdx, simHitIdx); + measurement.index(), + simHitIdx); } } } @@ -309,23 +294,22 @@ ActsExamples::ProcessCode ActsExamples::DigitizationAlgorithm::execute( << " skipped in Digitization. Enable DEBUG mode to see more details."); } - if (m_cfg.doOutputCells) { - m_cellsWriteHandle(ctx, std::move(cellsMap)); + if (m_cfg.doClusterization) { + m_outputMeasurements(ctx, std::move(measurements)); + m_outputClusters(ctx, std::move(clusters)); + + m_outputMeasurementParticlesMap(ctx, std::move(measurementParticlesMap)); + m_outputMeasurementSimHitsMap(ctx, std::move(measurementSimHitsMap)); } - if (m_cfg.doClusterization) { - m_measurementWriteHandle(ctx, std::move(measurements)); - m_clusterWriteHandle(ctx, std::move(clusters)); - m_measurementParticlesMapWriteHandle(ctx, - std::move(measurementParticlesMap)); - m_measurementSimHitsMapWriteHandle(ctx, std::move(measurementSimHitsMap)); + if (m_cfg.doOutputCells) { + m_outputCells(ctx, std::move(cellsMap)); } return ProcessCode::SUCCESS; } -ActsExamples::DigitizedParameters -ActsExamples::DigitizationAlgorithm::localParameters( +DigitizedParameters DigitizationAlgorithm::localParameters( const GeometricConfig& geoCfg, const std::vector& channels, RandomEngine& rng) const { @@ -377,3 +361,5 @@ ActsExamples::DigitizationAlgorithm::localParameters( return dParameters; } + +} // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/src/DigitizationConfig.cpp b/Examples/Algorithms/Digitization/src/DigitizationConfig.cpp index e19452d1e7a..8c23ba729d1 100644 --- a/Examples/Algorithms/Digitization/src/DigitizationConfig.cpp +++ b/Examples/Algorithms/Digitization/src/DigitizationConfig.cpp @@ -8,59 +8,9 @@ #include "ActsExamples/Digitization/DigitizationConfig.hpp" -#include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/Geometry/GeometryIdentifier.hpp" -#include "ActsExamples/Digitization/SmearingConfig.hpp" +namespace ActsExamples { -namespace { - -enum SmearingTypes : int { - eGauss = 0, - eGaussTruncated = 1, - eGaussClipped = 2, - eUniform = 3, - eDigital = 4, -}; - -} // namespace - -ActsExamples::DigitizationConfig::DigitizationConfig( - bool merge, double sigma, bool commonCorner, - Acts::GeometryHierarchyMap&& digiCfgs) - : doMerge(merge), mergeNsigma(sigma), mergeCommonCorner(commonCorner) { - digitizationConfigs = std::move(digiCfgs); -} - -ActsExamples::DigitizationConfig::DigitizationConfig( - Acts::GeometryHierarchyMap&& digiCfgs) - : doMerge(false), mergeNsigma(1.0), mergeCommonCorner(false) { - digitizationConfigs = std::move(digiCfgs); -} - -std::vector< - std::pair>> -ActsExamples::DigitizationConfig::getBoundIndices() const { - std::vector< - std::pair>> - bIndexInput; - - for (std::size_t ibi = 0; ibi < digitizationConfigs.size(); ++ibi) { - Acts::GeometryIdentifier geoID = digitizationConfigs.idAt(ibi); - const auto dCfg = digitizationConfigs.valueAt(ibi); - std::vector boundIndices; - boundIndices.insert(boundIndices.end(), - dCfg.geometricDigiConfig.indices.begin(), - dCfg.geometricDigiConfig.indices.end()); - // we assume nobody will add multiple smearers to a single bound index - for (const auto& c : dCfg.smearingDigiConfig) { - boundIndices.push_back(c.index); - } - bIndexInput.push_back({geoID, boundIndices}); - } - return bIndexInput; -} - -std::vector ActsExamples::GeometricConfig::variances( +std::vector GeometricConfig::variances( const std::array& csizes, const std::array& cmins) const { std::vector rVariances; @@ -80,3 +30,5 @@ std::vector ActsExamples::GeometricConfig::variances( } return rVariances; } + +} // namespace ActsExamples diff --git a/Examples/Algorithms/Digitization/src/DigitizationConfigurator.cpp b/Examples/Algorithms/Digitization/src/DigitizationConfigurator.cpp index e7bd2ddfa09..bbf6ec7583b 100644 --- a/Examples/Algorithms/Digitization/src/DigitizationConfigurator.cpp +++ b/Examples/Algorithms/Digitization/src/DigitizationConfigurator.cpp @@ -9,7 +9,6 @@ #include "ActsExamples/Digitization/DigitizationConfigurator.hpp" #include "Acts/Definitions/Algebra.hpp" -#include "Acts/Definitions/TrackParametrization.hpp" #include "Acts/Surfaces/AnnulusBounds.hpp" #include "Acts/Surfaces/DiscTrapezoidBounds.hpp" #include "Acts/Surfaces/RadialBounds.hpp" @@ -25,9 +24,9 @@ #include #include -#include namespace { + /// @note This does not really compare if the configs are equal, therefore /// it is no operator==. The contained std::function types cannot really /// be checked for equality. @@ -47,6 +46,7 @@ bool digiConfigMaybeEqual(ActsExamples::DigiComponentsConfig &a, ag.thickness == bg.thickness && ag.threshold == bg.threshold && ag.digital == bg.digital); } + } // namespace void ActsExamples::DigitizationConfigurator::operator()( diff --git a/Examples/Algorithms/Digitization/src/DigitizationCoordinatesConverter.cpp b/Examples/Algorithms/Digitization/src/DigitizationCoordinatesConverter.cpp index e83e7be995b..b996306fb13 100644 --- a/Examples/Algorithms/Digitization/src/DigitizationCoordinatesConverter.cpp +++ b/Examples/Algorithms/Digitization/src/DigitizationCoordinatesConverter.cpp @@ -10,21 +10,22 @@ #include "Acts/Definitions/Algebra.hpp" #include "Acts/Geometry/GeometryContext.hpp" +#include "ActsExamples/Digitization/DigitizationAlgorithm.hpp" -#include #include #include -ActsExamples::DigitizationCoordinatesConverter:: - DigitizationCoordinatesConverter(DigitizationConfig config) +namespace ActsExamples { + +DigitizationCoordinatesConverter::DigitizationCoordinatesConverter( + DigitizationAlgorithm::Config config) : m_cfg(std::move(config)) { if (m_cfg.surfaceByIdentifier.empty()) { throw std::invalid_argument("Missing Surface-GeometryID association map"); } } -std::tuple -ActsExamples::DigitizationCoordinatesConverter::globalToLocal( +std::tuple DigitizationCoordinatesConverter::globalToLocal( std::uint64_t moduleId, double x, double y, double z) const { const Acts::GeometryIdentifier moduleGeoId = moduleId; auto surfaceItr = m_cfg.surfaceByIdentifier.find(moduleGeoId); @@ -44,8 +45,8 @@ ActsExamples::DigitizationCoordinatesConverter::globalToLocal( } std::tuple -ActsExamples::DigitizationCoordinatesConverter::localToGlobal( - std::uint64_t moduleId, double x, double y) const { +DigitizationCoordinatesConverter::localToGlobal(std::uint64_t moduleId, + double x, double y) const { const Acts::GeometryIdentifier moduleGeoId = moduleId; auto surfaceItr = m_cfg.surfaceByIdentifier.find(moduleGeoId); if (surfaceItr == m_cfg.surfaceByIdentifier.end()) { @@ -61,3 +62,5 @@ ActsExamples::DigitizationCoordinatesConverter::localToGlobal( return {pos2Global.x(), pos2Global.y(), pos2Global.z()}; } + +} // namespace ActsExamples diff --git a/Examples/Algorithms/TrackFinding/src/TrackParamsEstimationAlgorithm.cpp b/Examples/Algorithms/TrackFinding/src/TrackParamsEstimationAlgorithm.cpp index c8a30c7147d..dfb0269a56d 100644 --- a/Examples/Algorithms/TrackFinding/src/TrackParamsEstimationAlgorithm.cpp +++ b/Examples/Algorithms/TrackFinding/src/TrackParamsEstimationAlgorithm.cpp @@ -112,10 +112,16 @@ ProcessCode TrackParamsEstimationAlgorithm::execute( } Acts::Vector3 field = *fieldRes; + if (field.norm() < m_cfg.bFieldMin) { + ACTS_WARNING("Magnetic field at seed " << iseed << " is too small " + << field.norm()); + continue; + } + // Estimate the track parameters from seed auto optParams = Acts::estimateTrackParamsFromSeed( ctx.geoContext, seed.sp().begin(), seed.sp().end(), *surface, field, - m_cfg.bFieldMin, logger()); + logger()); if (!optParams.has_value()) { ACTS_WARNING("Estimation of track parameters for seed " << iseed << " failed."); diff --git a/Examples/Algorithms/TrackFindingExaTrkX/src/PrototracksToParameters.cpp b/Examples/Algorithms/TrackFindingExaTrkX/src/PrototracksToParameters.cpp index c8d34f71bd2..9ffe49ae460 100644 --- a/Examples/Algorithms/TrackFindingExaTrkX/src/PrototracksToParameters.cpp +++ b/Examples/Algorithms/TrackFindingExaTrkX/src/PrototracksToParameters.cpp @@ -154,16 +154,21 @@ ProcessCode PrototracksToParameters::execute( .geometryId(); const auto &surface = *m_cfg.geometry->findSurface(geoId); - auto field = m_cfg.magneticField->getField( + auto fieldRes = m_cfg.magneticField->getField( {bottomSP->x(), bottomSP->y(), bottomSP->z()}, bCache); - if (!field.ok()) { - ACTS_ERROR("Field lookup error: " << field.error()); + if (!fieldRes.ok()) { + ACTS_ERROR("Field lookup error: " << fieldRes.error()); return ProcessCode::ABORT; } + Acts::Vector3 field = *fieldRes; + + if (field.norm() < m_cfg.bFieldMin) { + ACTS_WARNING("Magnetic field at seed is too small " << field.norm()); + continue; + } auto pars = Acts::estimateTrackParamsFromSeed( - ctx.geoContext, seed.sp().begin(), seed.sp().end(), surface, *field, - m_cfg.bFieldMin); + ctx.geoContext, seed.sp().begin(), seed.sp().end(), surface, field); if (not pars) { ACTS_WARNING("Skip track because of bad params"); diff --git a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp index cfc62ab9da9..4c09134ef20 100644 --- a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp +++ b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp @@ -10,21 +10,15 @@ #include "Acts/Definitions/Algebra.hpp" #include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/EventData/ParticleHypothesis.hpp" #include "Acts/Seeding/EstimateTrackParamsFromSeed.hpp" #include "Acts/Surfaces/PerigeeSurface.hpp" #include "Acts/Surfaces/Surface.hpp" -#include "Acts/Utilities/Helpers.hpp" #include "Acts/Utilities/detail/periodic.hpp" #include "ActsExamples/EventData/SimParticle.hpp" #include "ActsExamples/EventData/Track.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" #include "ActsExamples/Framework/RandomNumbers.hpp" -#include "ActsExamples/Utilities/GroupBy.hpp" -#include "ActsExamples/Utilities/Range.hpp" -#include "ActsFatras/EventData/Particle.hpp" -#include #include #include #include diff --git a/Examples/Framework/include/ActsExamples/EventData/Cluster.hpp b/Examples/Framework/include/ActsExamples/EventData/Cluster.hpp index 3eb850b1214..bfd81c9f130 100644 --- a/Examples/Framework/include/ActsExamples/EventData/Cluster.hpp +++ b/Examples/Framework/include/ActsExamples/EventData/Cluster.hpp @@ -8,10 +8,10 @@ #pragma once +#include "Acts/Definitions/Algebra.hpp" #include "ActsFatras/Digitization/Segmentizer.hpp" #include -#include #include namespace ActsExamples { diff --git a/Examples/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/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/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/Output.cpp b/Examples/Python/src/Output.cpp index 5adead2a9b4..5f174777429 100644 --- a/Examples/Python/src/Output.cpp +++ b/Examples/Python/src/Output.cpp @@ -12,8 +12,7 @@ #include "Acts/Utilities/Logger.hpp" #include "Acts/Visualization/IVisualization3D.hpp" #include "Acts/Visualization/ViewConfig.hpp" -#include "ActsExamples/Digitization/DigitizationConfig.hpp" -#include "ActsExamples/Framework/ProcessCode.hpp" +#include "ActsExamples/Digitization/DigitizationAlgorithm.hpp" #include "ActsExamples/Io/Csv/CsvBFieldWriter.hpp" #include "ActsExamples/Io/Csv/CsvExaTrkXGraphWriter.hpp" #include "ActsExamples/Io/Csv/CsvMeasurementWriter.hpp" @@ -50,10 +49,8 @@ #include "ActsExamples/Plugins/Obj/ObjPropagationStepsWriter.hpp" #include "ActsExamples/Plugins/Obj/ObjTrackingGeometryWriter.hpp" -#include #include #include -#include #include #include @@ -268,13 +265,6 @@ void addOutput(Context& ctx) { auto c = py::class_(w, "Config").def(py::init<>()); - c.def("addBoundIndicesFromDigiConfig", - [](Writer::Config& self, const DigitizationConfig& digiCfg) { - self.boundIndices = - Acts::GeometryHierarchyMap>( - digiCfg.getBoundIndices()); - }); - ACTS_PYTHON_STRUCT_BEGIN(c, Writer::Config); ACTS_PYTHON_MEMBER(inputMeasurements); ACTS_PYTHON_MEMBER(inputClusters); @@ -282,7 +272,6 @@ void addOutput(Context& ctx) { ACTS_PYTHON_MEMBER(inputMeasurementSimHitsMap); ACTS_PYTHON_MEMBER(filePath); ACTS_PYTHON_MEMBER(fileMode); - ACTS_PYTHON_MEMBER(boundIndices); ACTS_PYTHON_MEMBER(surfaceByIdentifier); ACTS_PYTHON_STRUCT_END(); } diff --git a/Examples/Python/tests/conftest.py b/Examples/Python/tests/conftest.py index b2015c3f6a0..71c0899fe3f 100644 --- a/Examples/Python/tests/conftest.py +++ b/Examples/Python/tests/conftest.py @@ -357,8 +357,8 @@ def _factory(s): s.addAlgorithm(simAlg) # Digitization - digiCfg = acts.examples.DigitizationConfig( - acts.examples.readDigiConfigFromJson( + digiCfg = acts.examples.DigitizationAlgorithm.Config( + digitizationConfigs=acts.examples.readDigiConfigFromJson( str( Path(__file__).parent.parent.parent.parent / "Examples/Algorithms/Digitization/share/default-smearing-config-generic.json" diff --git a/Examples/Python/tests/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_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/Tests/UnitTests/Core/Seeding/EstimateTrackParamsFromSeedTest.cpp b/Tests/UnitTests/Core/Seeding/EstimateTrackParamsFromSeedTest.cpp index e39a6a1a900..9aab6c1c70b 100644 --- a/Tests/UnitTests/Core/Seeding/EstimateTrackParamsFromSeedTest.cpp +++ b/Tests/UnitTests/Core/Seeding/EstimateTrackParamsFromSeedTest.cpp @@ -176,7 +176,7 @@ BOOST_AUTO_TEST_CASE(trackparameters_estimation_test) { // Test the bound track parameters estimator auto fullParamsOpt = estimateTrackParamsFromSeed( geoCtx, spacePointPtrs.begin(), spacePointPtrs.end(), - *bottomSurface, bField, 0.1_T, *logger); + *bottomSurface, bField, *logger); BOOST_REQUIRE(fullParamsOpt.has_value()); const auto& estFullParams = fullParamsOpt.value(); BOOST_TEST_INFO(