From 52681f7a7fd6ad96667aa4c8e47b2991d09027be Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Sat, 2 Nov 2024 09:42:09 +0100 Subject: [PATCH 1/2] refactor: Remove `TruthSeedSelector` from Examples (#3808) After removing `TruthSeedRanges` with https://github.com/acts-project/acts/pull/3742 we can also safely remove `TruthSeedSelector` which does very much the same as the `ParticleSelector` by now. --- .../TruthTracking/TruthSeedSelector.cpp | 89 ------------------ .../TruthTracking/TruthSeedSelector.hpp | 92 ------------------- .../Algorithms/TruthTracking/CMakeLists.txt | 1 - .../python/acts/examples/reconstruction.py | 15 --- Examples/Python/src/TruthTracking.cpp | 46 ---------- Examples/Python/tests/test_algorithms.py | 2 - 6 files changed, 245 deletions(-) delete mode 100644 Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TruthSeedSelector.cpp delete mode 100644 Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TruthSeedSelector.hpp diff --git a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TruthSeedSelector.cpp b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TruthSeedSelector.cpp deleted file mode 100644 index 49640e5079f..00000000000 --- a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TruthSeedSelector.cpp +++ /dev/null @@ -1,89 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 CERN for the benefit of the ACTS project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -#include "ActsExamples/TruthTracking/TruthSeedSelector.hpp" - -#include "Acts/Utilities/MultiIndex.hpp" -#include "Acts/Utilities/VectorHelpers.hpp" -#include "ActsExamples/EventData/Index.hpp" -#include "ActsExamples/EventData/SimParticle.hpp" -#include "ActsExamples/Utilities/Range.hpp" -#include "ActsFatras/EventData/Barcode.hpp" -#include "ActsFatras/EventData/Particle.hpp" - -#include -#include -#include - -namespace ActsExamples { -struct AlgorithmContext; -} // namespace ActsExamples - -using namespace ActsExamples; - -TruthSeedSelector::TruthSeedSelector(const Config& config, - Acts::Logging::Level level) - : IAlgorithm("TruthSeedSelector", level), m_cfg(config) { - if (m_cfg.inputParticles.empty()) { - throw std::invalid_argument("Missing input truth particles collection"); - } - if (m_cfg.inputMeasurementParticlesMap.empty()) { - throw std::invalid_argument("Missing input hit-particles map collection"); - } - if (m_cfg.outputParticles.empty()) { - throw std::invalid_argument("Missing output truth particles collection"); - } - - m_inputParticles.initialize(m_cfg.inputParticles); - m_inputMeasurementParticlesMap.initialize(m_cfg.inputMeasurementParticlesMap); - m_outputParticles.initialize(m_cfg.outputParticles); -} - -ProcessCode TruthSeedSelector::execute(const AlgorithmContext& ctx) const { - // prepare input collections - const auto& inputParticles = m_inputParticles(ctx); - const auto& hitParticlesMap = m_inputMeasurementParticlesMap(ctx); - // compute particle_id -> {hit_id...} map from the - // hit_id -> {particle_id...} map on the fly. - const auto& particleHitsMap = invertIndexMultimap(hitParticlesMap); - - // prepare output collection - SimParticleContainer selectedParticles; - selectedParticles.reserve(inputParticles.size()); - - auto within = [](double x, double min, double max) { - return (min <= x) && (x < max); - }; - auto isValidparticle = [&](const auto& p) { - const auto eta = Acts::VectorHelpers::eta(p.direction()); - const auto phi = Acts::VectorHelpers::phi(p.direction()); - const auto rho = Acts::VectorHelpers::perp(p.position()); - // find the corresponding hits for this particle - const auto& hits = makeRange(particleHitsMap.equal_range(p.particleId())); - // number of recorded hits - std::size_t nHits = hits.size(); - return within(rho, 0., m_cfg.rhoMax) && - within(p.position().z(), m_cfg.zMin, m_cfg.zMax) && - within(std::abs(eta), m_cfg.absEtaMin, m_cfg.absEtaMax) && - within(eta, m_cfg.etaMin, m_cfg.etaMax) && - within(phi, m_cfg.phiMin, m_cfg.phiMax) && - within(p.transverseMomentum(), m_cfg.ptMin, m_cfg.ptMax) && - within(nHits, m_cfg.nHitsMin, m_cfg.nHitsMax) && - (m_cfg.keepNeutral || (p.charge() != 0)); - }; - - // create prototracks for all input particles - for (const auto& particle : inputParticles) { - if (isValidparticle(particle)) { - selectedParticles.insert(particle); - } - } - - m_outputParticles(ctx, std::move(selectedParticles)); - return ProcessCode::SUCCESS; -} diff --git a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TruthSeedSelector.hpp b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TruthSeedSelector.hpp deleted file mode 100644 index 1bb12042aa3..00000000000 --- a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TruthSeedSelector.hpp +++ /dev/null @@ -1,92 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 CERN for the benefit of the ACTS project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -#pragma once - -#include "Acts/Utilities/Logger.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" - -#include -#include -#include - -namespace ActsFatras { -class Barcode; -} // namespace ActsFatras - -namespace ActsExamples { -struct AlgorithmContext; - -/// Select truth particles to be used as 'seeds' of reconstruction algorithms, -/// e.g. track fitting and track finding. -/// -/// This pre-selection could help guarantee quality of the 'seeds', i.e. to -/// avoid empty proto track (no recorded hits for the particle). In addition, it -/// could help save unnecessary reconstruction time. For instance, when -/// investigating performance of CombinatorialKalmanFilter (CKF), we might be -/// interested in its performance for only truth particles with pT and number of -/// recorded hits (on sensitive detectors) safistying provided criteria (input -/// measurements of CKF are still recorded hits from all possible particles). -/// Then we could use particles only satisfying provided criteria as the 'seeds' -/// of CKF instead of handling all the truth particles. -// -class TruthSeedSelector final : public IAlgorithm { - public: - struct Config { - /// The input truth particles that should be used to create proto tracks. - std::string inputParticles; - /// The input hit-particles map collection. - std::string inputMeasurementParticlesMap; - /// The output proto tracks collection. - std::string outputParticles; - /// Maximum distance from the origin in the transverse plane - double rhoMin = 0.; - double rhoMax = std::numeric_limits::max(); - /// Minimum/Maximum absolute distance from the origin along z - double zMin = std::numeric_limits::lowest(); - double zMax = std::numeric_limits::max(); - // Truth particle kinematic cuts - double phiMin = std::numeric_limits::lowest(); - double phiMax = std::numeric_limits::max(); - double etaMin = std::numeric_limits::lowest(); - double etaMax = std::numeric_limits::max(); - double absEtaMin = std::numeric_limits::lowest(); - double absEtaMax = std::numeric_limits::max(); - double ptMin = 0.0; - double ptMax = std::numeric_limits::max(); - /// Keep neutral particles - bool keepNeutral = false; - /// Requirement on number of recorded hits - //@TODO: implement detector-specific requirements - std::size_t nHitsMin = 0; - std::size_t nHitsMax = std::numeric_limits::max(); - }; - - TruthSeedSelector(const Config& config, Acts::Logging::Level level); - - ProcessCode execute(const AlgorithmContext& ctx) const final; - - /// Get readonly access to the config parameters - const Config& config() const { return m_cfg; } - - private: - Config m_cfg; - - ReadDataHandle m_inputParticles{this, "InputParticles"}; - ReadDataHandle m_inputMeasurementParticlesMap{ - this, "InputMeasurementParticlesMap"}; - - WriteDataHandle m_outputParticles{this, - "OutputParticles"}; -}; - -} // namespace ActsExamples diff --git a/Examples/Algorithms/TruthTracking/CMakeLists.txt b/Examples/Algorithms/TruthTracking/CMakeLists.txt index 7c1eff1ed51..4594cdb7480 100644 --- a/Examples/Algorithms/TruthTracking/CMakeLists.txt +++ b/Examples/Algorithms/TruthTracking/CMakeLists.txt @@ -6,7 +6,6 @@ add_library( ActsExamples/TruthTracking/TrackParameterSelector.cpp ActsExamples/TruthTracking/TrackModifier.cpp ActsExamples/TruthTracking/TrackTruthMatcher.cpp - ActsExamples/TruthTracking/TruthSeedSelector.cpp ActsExamples/TruthTracking/TruthTrackFinder.cpp ActsExamples/TruthTracking/TruthVertexFinder.cpp ActsExamples/TruthTracking/TruthSeedingAlgorithm.cpp diff --git a/Examples/Python/python/acts/examples/reconstruction.py b/Examples/Python/python/acts/examples/reconstruction.py index fd02c6bddac..846de8995f2 100644 --- a/Examples/Python/python/acts/examples/reconstruction.py +++ b/Examples/Python/python/acts/examples/reconstruction.py @@ -1741,21 +1741,6 @@ def addExaTrkX( ) -> None: customLogLevel = acts.examples.defaultLogging(s, logLevel) - # Run the particle selection - # The pre-selection will select truth particles satisfying provided criteria - # from all particles read in by particle reader for further processing. It - # has no impact on the truth hits themselves - s.addAlgorithm( - acts.examples.TruthSeedSelector( - level=customLogLevel(), - ptMin=500 * u.MeV, - nHitsMin=9, - inputParticles="particles_initial", - inputMeasurementParticlesMap="measurement_particles_map", - outputParticles="particles_seed_selected", - ) - ) - # Create space points s.addAlgorithm( acts.examples.SpacePointMaker( diff --git a/Examples/Python/src/TruthTracking.cpp b/Examples/Python/src/TruthTracking.cpp index 2c43b3cfc4d..7278b3f821f 100644 --- a/Examples/Python/src/TruthTracking.cpp +++ b/Examples/Python/src/TruthTracking.cpp @@ -13,15 +13,11 @@ #include "ActsExamples/TruthTracking/TrackModifier.hpp" #include "ActsExamples/TruthTracking/TrackParameterSelector.hpp" #include "ActsExamples/TruthTracking/TrackTruthMatcher.hpp" -#include "ActsExamples/TruthTracking/TruthSeedSelector.hpp" #include "ActsExamples/TruthTracking/TruthSeedingAlgorithm.hpp" #include "ActsExamples/TruthTracking/TruthTrackFinder.hpp" #include "ActsExamples/TruthTracking/TruthVertexFinder.hpp" #include "ActsExamples/Utilities/HitSelector.hpp" -#include "ActsExamples/Utilities/Range.hpp" -#include -#include #include #include @@ -45,48 +41,6 @@ void addTruthTracking(Context& ctx) { ActsExamples::TruthTrackFinder, mex, "TruthTrackFinder", inputParticles, inputMeasurementParticlesMap, outputProtoTracks); - { - using Alg = ActsExamples::TruthSeedSelector; - using Config = Alg::Config; - - auto alg = py::class_>( - mex, "TruthSeedSelector") - .def(py::init(), - py::arg("config"), py::arg("level")) - .def_property_readonly("config", &Alg::config); - - auto c = py::class_(alg, "Config").def(py::init<>()); - - ACTS_PYTHON_STRUCT_BEGIN(c, Config); - ACTS_PYTHON_MEMBER(inputParticles); - ACTS_PYTHON_MEMBER(inputMeasurementParticlesMap); - ACTS_PYTHON_MEMBER(outputParticles); - ACTS_PYTHON_MEMBER(rhoMin); - ACTS_PYTHON_MEMBER(rhoMax); - ACTS_PYTHON_MEMBER(zMin); - ACTS_PYTHON_MEMBER(zMax); - ACTS_PYTHON_MEMBER(phiMin); - ACTS_PYTHON_MEMBER(phiMax); - ACTS_PYTHON_MEMBER(etaMin); - ACTS_PYTHON_MEMBER(etaMax); - ACTS_PYTHON_MEMBER(absEtaMin); - ACTS_PYTHON_MEMBER(absEtaMax); - ACTS_PYTHON_MEMBER(ptMin); - ACTS_PYTHON_MEMBER(ptMax); - ACTS_PYTHON_MEMBER(keepNeutral); - ACTS_PYTHON_MEMBER(nHitsMin); - ACTS_PYTHON_MEMBER(nHitsMax); - ACTS_PYTHON_STRUCT_END(); - - pythonRangeProperty(c, "rho", &Config::rhoMin, &Config::rhoMax); - pythonRangeProperty(c, "z", &Config::zMin, &Config::zMax); - pythonRangeProperty(c, "phi", &Config::phiMin, &Config::phiMax); - pythonRangeProperty(c, "eta", &Config::etaMin, &Config::etaMax); - pythonRangeProperty(c, "absEta", &Config::absEtaMin, &Config::absEtaMax); - pythonRangeProperty(c, "pt", &Config::ptMin, &Config::ptMax); - pythonRangeProperty(c, "nHits", &Config::nHitsMin, &Config::nHitsMax); - } - ACTS_PYTHON_DECLARE_ALGORITHM( ActsExamples::ParticleSmearing, mex, "ParticleSmearing", inputParticles, outputTrackParameters, sigmaD0, sigmaD0PtA, sigmaD0PtB, sigmaZ0, diff --git a/Examples/Python/tests/test_algorithms.py b/Examples/Python/tests/test_algorithms.py index ede2610f604..4cca7199291 100644 --- a/Examples/Python/tests/test_algorithms.py +++ b/Examples/Python/tests/test_algorithms.py @@ -11,7 +11,6 @@ EventGenerator, FatrasSimulation, MaterialMapping, - TruthSeedSelector, TruthTrackFinder, ParticleSelector, TruthVertexFinder, @@ -42,7 +41,6 @@ EventGenerator, FatrasSimulation, MaterialMapping, - TruthSeedSelector, TruthTrackFinder, ParticleSelector, TruthVertexFinder, From a3b81d51786ee95736516bc0347b0324800ffd8b Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Tue, 5 Nov 2024 10:19:39 +0100 Subject: [PATCH 2/2] feat: Log-uniform p/pt distributions for Examples (#3790) Allows for log-uniform p/pt distributions in the Examples framework --- .../EventData/detail/GenerateParameters.hpp | 20 ++- .../ParametricParticleGenerator.cpp | 124 ++++++++++-------- .../ParametricParticleGenerator.hpp | 27 ++-- .../Python/python/acts/examples/simulation.py | 9 +- Examples/Python/src/Generators.cpp | 1 + 5 files changed, 112 insertions(+), 69 deletions(-) diff --git a/Core/include/Acts/EventData/detail/GenerateParameters.hpp b/Core/include/Acts/EventData/detail/GenerateParameters.hpp index 1b591dbcd7a..64e7bc3405b 100644 --- a/Core/include/Acts/EventData/detail/GenerateParameters.hpp +++ b/Core/include/Acts/EventData/detail/GenerateParameters.hpp @@ -143,6 +143,9 @@ struct GenerateQoverPOptions { /// Indicate if the momentum referse to transverse momentum bool pTransverse = true; + /// Indicate if the momentum should be uniformly distributed in log space. + bool pLogUniform = false; + /// Charge of the parameters. double charge = 1; @@ -157,6 +160,19 @@ inline double generateQoverP(generator_t& rng, using UniformIndex = std::uniform_int_distribution; using UniformReal = std::uniform_real_distribution; + auto drawP = [&options](generator_t& rng_, double theta_) -> double { + const double pTransverseScaling = + options.pTransverse ? 1. / std::sin(theta_) : 1.; + + if (options.pLogUniform) { + UniformReal pLogDist(std::log(options.pMin), std::log(options.pMax)); + return std::exp(pLogDist(rng_)) * pTransverseScaling; + } + + UniformReal pDist(options.pMin, options.pMax); + return pDist(rng_) * pTransverseScaling; + }; + // choose between particle/anti-particle if requested // the upper limit of the distribution is inclusive UniformIndex particleTypeChoice(0u, options.randomizeCharge ? 1u : 0u); @@ -165,14 +181,12 @@ inline double generateQoverP(generator_t& rng, options.charge, -options.charge, }; - UniformReal pDist(options.pMin, options.pMax); // draw parameters const std::uint8_t type = particleTypeChoice(rng); const double q = qChoices[type]; - const double p = - pDist(rng) * (options.pTransverse ? 1. / std::sin(theta) : 1.); + const double p = drawP(rng, theta); const double qOverP = (q != 0) ? q / p : 1 / p; return qOverP; diff --git a/Examples/Algorithms/Generators/ActsExamples/Generators/ParametricParticleGenerator.cpp b/Examples/Algorithms/Generators/ActsExamples/Generators/ParametricParticleGenerator.cpp index dcc7ac573f3..240669274b0 100644 --- a/Examples/Algorithms/Generators/ActsExamples/Generators/ParametricParticleGenerator.cpp +++ b/Examples/Algorithms/Generators/ActsExamples/Generators/ParametricParticleGenerator.cpp @@ -9,15 +9,12 @@ #include "ActsExamples/Generators/ParametricParticleGenerator.hpp" #include "Acts/Definitions/Algebra.hpp" -#include "Acts/Definitions/Common.hpp" #include "Acts/Definitions/ParticleData.hpp" #include "Acts/Utilities/AngleHelpers.hpp" #include "ActsFatras/EventData/Barcode.hpp" #include "ActsFatras/EventData/Particle.hpp" -#include #include -#include #include namespace ActsExamples { @@ -25,41 +22,71 @@ namespace ActsExamples { ParametricParticleGenerator::ParametricParticleGenerator(const Config& cfg) : m_cfg(cfg), m_charge(cfg.charge.value_or(Acts::findCharge(m_cfg.pdg).value_or(0))), - m_mass(cfg.mass.value_or(Acts::findMass(m_cfg.pdg).value_or(0))), - // since we want to draw the direction uniform on the unit sphere, we must - // draw from cos(theta) instead of theta. see e.g. - // https://mathworld.wolfram.com/SpherePointPicking.html - m_cosThetaMin(std::cos(m_cfg.thetaMin)), - // ensure upper bound is included. see e.g. - // https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution - m_cosThetaMax(std::nextafter(std::cos(m_cfg.thetaMax), - std::numeric_limits::max())), - // in case we force uniform eta generation - m_etaMin(Acts::AngleHelpers::etaFromTheta(m_cfg.thetaMin)), - m_etaMax(Acts::AngleHelpers::etaFromTheta(m_cfg.thetaMax)) {} - -std::pair -ParametricParticleGenerator::operator()(RandomEngine& rng) { - using UniformIndex = std::uniform_int_distribution; - using UniformReal = std::uniform_real_distribution; - - // choose between particle/anti-particle if requested - // the upper limit of the distribution is inclusive - UniformIndex particleTypeChoice(0u, m_cfg.randomizeCharge ? 1u : 0u); - // (anti-)particle choice is one random draw but defines two properties - const Acts::PdgParticle pdgChoices[] = { + m_mass(cfg.mass.value_or(Acts::findMass(m_cfg.pdg).value_or(0))) { + m_pdgChoices = { m_cfg.pdg, static_cast(-m_cfg.pdg), }; - const double qChoices[] = { + m_qChoices = { m_charge, -m_charge, }; - UniformReal phiDist(m_cfg.phiMin, m_cfg.phiMax); - UniformReal cosThetaDist(m_cosThetaMin, m_cosThetaMax); - UniformReal etaDist(m_etaMin, m_etaMax); - UniformReal pDist(m_cfg.pMin, m_cfg.pMax); + // choose between particle/anti-particle if requested + // the upper limit of the distribution is inclusive + m_particleTypeChoice = UniformIndex(0u, m_cfg.randomizeCharge ? 1u : 0u); + m_phiDist = UniformReal(m_cfg.phiMin, m_cfg.phiMax); + + if (m_cfg.etaUniform) { + double etaMin = Acts::AngleHelpers::etaFromTheta(m_cfg.thetaMin); + double etaMax = Acts::AngleHelpers::etaFromTheta(m_cfg.thetaMax); + + UniformReal etaDist(etaMin, etaMax); + + m_sinCosThetaDist = + [=](RandomEngine& rng) mutable -> std::pair { + const double eta = etaDist(rng); + const double theta = Acts::AngleHelpers::thetaFromEta(eta); + return {std::sin(theta), std::cos(theta)}; + }; + } else { + // since we want to draw the direction uniform on the unit sphere, we must + // draw from cos(theta) instead of theta. see e.g. + // https://mathworld.wolfram.com/SpherePointPicking.html + double cosThetaMin = std::cos(m_cfg.thetaMin); + // ensure upper bound is included. see e.g. + // https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution + double cosThetaMax = std::nextafter(std::cos(m_cfg.thetaMax), + std::numeric_limits::max()); + + UniformReal cosThetaDist(cosThetaMin, cosThetaMax); + + m_sinCosThetaDist = + [=](RandomEngine& rng) mutable -> std::pair { + const double cosTheta = cosThetaDist(rng); + return {std::sqrt(1 - cosTheta * cosTheta), cosTheta}; + }; + } + + if (m_cfg.pLogUniform) { + // distributes p or pt uniformly in log space + UniformReal dist(std::log(m_cfg.pMin), std::log(m_cfg.pMax)); + + m_somePDist = [=](RandomEngine& rng) mutable -> double { + return std::exp(dist(rng)); + }; + } else { + // distributes p or pt uniformly + UniformReal dist(m_cfg.pMin, m_cfg.pMax); + + m_somePDist = [=](RandomEngine& rng) mutable -> double { + return dist(rng); + }; + } +} + +std::pair +ParametricParticleGenerator::operator()(RandomEngine& rng) { SimVertexContainer::sequence_type vertices; SimParticleContainer::sequence_type particles; @@ -74,33 +101,22 @@ ParametricParticleGenerator::operator()(RandomEngine& rng) { primaryVertex.outgoing.insert(pid); // draw parameters - const unsigned int type = particleTypeChoice(rng); - const Acts::PdgParticle pdg = pdgChoices[type]; - const double q = qChoices[type]; - const double phi = phiDist(rng); - double p = pDist(rng); - - // we already have sin/cos theta. they can be used directly to - Acts::Vector3 dir; - double cosTheta = 0.; - double sinTheta = 0.; - if (!m_cfg.etaUniform) { - cosTheta = cosThetaDist(rng); - sinTheta = std::sqrt(1 - cosTheta * cosTheta); - } else { - const double eta = etaDist(rng); - const double theta = Acts::AngleHelpers::thetaFromEta(eta); - sinTheta = std::sin(theta); - cosTheta = std::cos(theta); - } - dir[Acts::eMom0] = sinTheta * std::cos(phi); - dir[Acts::eMom1] = sinTheta * std::sin(phi); - dir[Acts::eMom2] = cosTheta; + const unsigned int type = m_particleTypeChoice(rng); + const Acts::PdgParticle pdg = m_pdgChoices[type]; + const double q = m_qChoices[type]; + const double phi = m_phiDist(rng); + const double someP = m_somePDist(rng); + + const auto [sinTheta, cosTheta] = m_sinCosThetaDist(rng); + // we already have sin/cos theta. they can be used directly + const Acts::Vector3 dir = {sinTheta * std::cos(phi), + sinTheta * std::sin(phi), cosTheta}; + + const double p = someP * (m_cfg.pTransverse ? 1. / sinTheta : 1.); // construct the particle; ActsFatras::Particle particle(pid, pdg, q, m_mass); particle.setDirection(dir); - p *= m_cfg.pTransverse ? 1. / sinTheta : 1.; particle.setAbsoluteMomentum(p); // generated particle ids are already ordered and should end up at the end diff --git a/Examples/Algorithms/Generators/ActsExamples/Generators/ParametricParticleGenerator.hpp b/Examples/Algorithms/Generators/ActsExamples/Generators/ParametricParticleGenerator.hpp index a7d9bfe3e08..0efc47a0c5c 100644 --- a/Examples/Algorithms/Generators/ActsExamples/Generators/ParametricParticleGenerator.hpp +++ b/Examples/Algorithms/Generators/ActsExamples/Generators/ParametricParticleGenerator.hpp @@ -15,10 +15,10 @@ #include "ActsExamples/Generators/EventGenerator.hpp" #include -#include #include #include #include +#include namespace ActsExamples { @@ -49,8 +49,10 @@ class ParametricParticleGenerator : public EventGenerator::ParticlesGenerator { /// Low, high (exclusive) for absolute/transverse momentum. double pMin = 1 * Acts::UnitConstants::GeV; double pMax = 10 * Acts::UnitConstants::GeV; - /// Indicate if the momentum referse to transverse momentum + /// Indicate if the momentum refers to transverse momentum. bool pTransverse = false; + /// Indicate if the momentum should be uniformly distributed in log space. + bool pLogUniform = false; /// (Absolute) PDG particle number to identify the particle type. Acts::PdgParticle pdg = Acts::PdgParticle::eMuon; /// Randomize the charge and flip the PDG particle number sign accordingly. @@ -71,14 +73,23 @@ class ParametricParticleGenerator : public EventGenerator::ParticlesGenerator { RandomEngine& rng) override; private: + using UniformIndex = std::uniform_int_distribution; + using UniformReal = std::uniform_real_distribution; + Config m_cfg; + // will be automatically set from PDG data tables - double m_charge; - double m_mass; - double m_cosThetaMin; - double m_cosThetaMax; - double m_etaMin; - double m_etaMax; + double m_charge{}; + double m_mass{}; + + // (anti-)particle choice is one random draw but defines two properties + std::array m_pdgChoices{}; + std::array m_qChoices{}; + + UniformIndex m_particleTypeChoice; + UniformReal m_phiDist; + std::function(RandomEngine& rng)> m_sinCosThetaDist; + std::function m_somePDist; }; } // namespace ActsExamples diff --git a/Examples/Python/python/acts/examples/simulation.py b/Examples/Python/python/acts/examples/simulation.py index 15883f4c648..b72d1f456df 100644 --- a/Examples/Python/python/acts/examples/simulation.py +++ b/Examples/Python/python/acts/examples/simulation.py @@ -18,8 +18,8 @@ # Examples/Algorithms/Generators/ActsExamples/Generators/ParametricParticleGenerator.hpp MomentumConfig = namedtuple( "MomentumConfig", - ["min", "max", "transverse"], - defaults=[None, None, None], + ["min", "max", "transverse", "logUniform"], + defaults=[None, None, None, None], ) EtaConfig = namedtuple( "EtaConfig", ["min", "max", "uniform"], defaults=[None, None, None] @@ -80,8 +80,8 @@ def addParticleGun( the output folder for the Csv output, None triggers no output outputDirRoot : Path|str, path, None the output folder for the Root output, None triggers no output - momentumConfig : MomentumConfig(min, max, transverse) - momentum configuration: minimum momentum, maximum momentum, transverse + momentumConfig : MomentumConfig(min, max, transverse, logUniform) + momentum configuration: minimum momentum, maximum momentum, transverse, log-uniform etaConfig : EtaConfig(min, max, uniform) pseudorapidity configuration: eta min, eta max, uniform phiConfig : PhiConfig(min, max) @@ -118,6 +118,7 @@ def addParticleGun( **acts.examples.defaultKWArgs( p=(momentumConfig.min, momentumConfig.max), pTransverse=momentumConfig.transverse, + pLogUniform=momentumConfig.logUniform, eta=(etaConfig.min, etaConfig.max), phi=(phiConfig.min, phiConfig.max), etaUniform=etaConfig.uniform, diff --git a/Examples/Python/src/Generators.cpp b/Examples/Python/src/Generators.cpp index 800c912aa89..454227ddbf6 100644 --- a/Examples/Python/src/Generators.cpp +++ b/Examples/Python/src/Generators.cpp @@ -176,6 +176,7 @@ void addGenerators(Context& ctx) { .def_readwrite("pMin", &Config::pMin) .def_readwrite("pMax", &Config::pMax) .def_readwrite("pTransverse", &Config::pTransverse) + .def_readwrite("pLogUniform", &Config::pLogUniform) .def_readwrite("pdg", &Config::pdg) .def_readwrite("randomizeCharge", &Config::randomizeCharge) .def_readwrite("numParticles", &Config::numParticles)