Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-26 08:38:34

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #pragma once
0010 
0011 #include "ActsExamples/Utilities/GroupBy.hpp"
0012 #include "ActsFatras/EventData/Particle.hpp"
0013 #include "ActsFatras/EventData/SimulationOutcome.hpp"
0014 
0015 #include <boost/container/flat_set.hpp>
0016 
0017 namespace ActsExamples {
0018 
0019 using SimBarcode = ::ActsFatras::Barcode;
0020 using SimBarcodeContainer = ::boost::container::flat_set<SimBarcode>;
0021 
0022 using SimParticleState = ::ActsFatras::Particle;
0023 
0024 class SimParticle final {
0025  public:
0026   /// Construct a default particle with invalid identity.
0027   SimParticle() = default;
0028 
0029   /// Construct a particle at rest with explicit mass and charge.
0030   ///
0031   /// @param particleId Particle identifier within an event
0032   /// @param pdg PDG id
0033   /// @param charge Particle charge in native units
0034   /// @param mass Particle mass in native units
0035   ///
0036   /// @warning It is the users responsibility that charge and mass match
0037   ///          the PDG particle number.
0038   SimParticle(SimBarcode particleId, Acts::PdgParticle pdg, double charge,
0039               double mass)
0040       : m_initial(particleId, pdg, charge, mass),
0041         m_final(particleId, pdg, charge, mass) {}
0042 
0043   /// Construct a particle at rest from a PDG particle number.
0044   ///
0045   /// @param particleId Particle identifier within an event
0046   /// @param pdg PDG particle number
0047   ///
0048   /// Charge and mass are retrieved from the particle data table.
0049   SimParticle(SimBarcode particleId, Acts::PdgParticle pdg)
0050       : m_initial(particleId, pdg), m_final(particleId, pdg) {}
0051 
0052   SimParticle(const SimParticleState& initial,
0053               const SimParticleState& finalState)
0054       : m_initial(initial), m_final(finalState) {
0055     if (m_initial.particleId() != m_final.particleId()) {
0056       throw std::invalid_argument("Particle id mismatch");
0057     }
0058   }
0059 
0060   const SimParticleState& initialState() const { return m_initial; }
0061   const SimParticleState& finalState() const { return m_final; }
0062 
0063   SimParticleState& initialState() { return m_initial; }
0064   SimParticleState& finalState() { return m_final; }
0065 
0066   /// Construct a new particle with a new identifier but same kinematics.
0067   ///
0068   /// @note This is intentionally not a regular setter. The particle id
0069   ///       is used to identify the whole particle. Setting it on an existing
0070   ///       particle is usually a mistake.
0071   SimParticle withParticleId(SimBarcode particleId) const {
0072     SimParticle copy(initialState().withParticleId(particleId),
0073                      finalState().withParticleId(particleId));
0074     copy.setParentParticleId(parentParticleId());
0075     return copy;
0076   }
0077 
0078   /// Set the process type that generated this particle.
0079   SimParticle& setProcess(ActsFatras::GenerationProcess proc) {
0080     initialState().setProcess(proc);
0081     finalState().setProcess(proc);
0082     return *this;
0083   }
0084   /// Set the pdg.
0085   SimParticle& setPdg(Acts::PdgParticle pdg) {
0086     initialState().setPdg(pdg);
0087     finalState().setPdg(pdg);
0088     return *this;
0089   }
0090   /// Set the charge.
0091   SimParticle& setCharge(double charge) {
0092     initialState().setCharge(charge);
0093     finalState().setCharge(charge);
0094     return *this;
0095   }
0096   /// Set the mass.
0097   SimParticle& setMass(double mass) {
0098     initialState().setMass(mass);
0099     finalState().setMass(mass);
0100     return *this;
0101   }
0102   /// Set the particle ID.
0103   SimParticle& setParticleId(SimBarcode barcode) {
0104     initialState().setParticleId(barcode);
0105     finalState().setParticleId(barcode);
0106     return *this;
0107   }
0108   /// Set the parent particle id on both initial and final state.
0109   SimParticle& setParentParticleId(SimBarcode parentId) {
0110     initialState().setParentParticleId(parentId);
0111     finalState().setParentParticleId(parentId);
0112     return *this;
0113   }
0114 
0115   /// Particle identifier within an event.
0116   SimBarcode particleId() const { return initialState().particleId(); }
0117   /// Parent particle id, or default-constructed @c SimBarcode if unknown.
0118   SimBarcode parentParticleId() const {
0119     return initialState().parentParticleId();
0120   }
0121   /// Which type of process generated this particle.
0122   ActsFatras::GenerationProcess process() const {
0123     return initialState().process();
0124   }
0125   /// PDG particle number that identifies the type.
0126   Acts::PdgParticle pdg() const { return initialState().pdg(); }
0127   /// Absolute PDG particle number that identifies the type.
0128   Acts::PdgParticle absolutePdg() const { return initialState().absolutePdg(); }
0129   /// Particle charge.
0130   double charge() const { return initialState().charge(); }
0131   /// Particle absolute charge.
0132   double absoluteCharge() const { return initialState().absoluteCharge(); }
0133   /// Particle mass.
0134   double mass() const { return initialState().mass(); }
0135 
0136   /// Check if this is a secondary particle.
0137   bool isSecondary() const { return initialState().isSecondary(); }
0138 
0139   /// Particle hypothesis.
0140   Acts::ParticleHypothesis hypothesis() const {
0141     return initialState().hypothesis();
0142   }
0143   /// Particl qOverP.
0144   double qOverP() const { return initialState().qOverP(); }
0145 
0146   /// Space-time position four-vector.
0147   const Acts::Vector4& fourPosition() const {
0148     return initialState().fourPosition();
0149   }
0150   /// Three-position, i.e. spatial coordinates without the time.
0151   auto position() const { return initialState().position(); }
0152   /// Time coordinate.
0153   double time() const { return initialState().time(); }
0154   /// Energy-momentum four-vector.
0155   Acts::Vector4 fourMomentum() const { return initialState().fourMomentum(); }
0156   /// Unit three-direction, i.e. the normalized momentum three-vector.
0157   const Acts::Vector3& direction() const { return initialState().direction(); }
0158   /// Polar angle.
0159   double theta() const { return initialState().theta(); }
0160   /// Azimuthal angle.
0161   double phi() const { return initialState().phi(); }
0162   /// Absolute momentum in the x-y plane.
0163   double transverseMomentum() const {
0164     return initialState().transverseMomentum();
0165   }
0166   /// Absolute momentum.
0167   double absoluteMomentum() const { return initialState().absoluteMomentum(); }
0168   /// Absolute momentum.
0169   Acts::Vector3 momentum() const { return initialState().momentum(); }
0170   /// Total energy, i.e. norm of the four-momentum.
0171   double energy() const { return initialState().energy(); }
0172 
0173   /// Energy loss over the particles lifetime or simulation time.
0174   double energyLoss() const {
0175     return initialState().energy() - finalState().energy();
0176   }
0177 
0178   /// Accumulated path within material measured in radiation lengths.
0179   double pathInX0() const { return finalState().pathInX0(); }
0180   /// Accumulated path within material measured in interaction lengths.
0181   double pathInL0() const { return finalState().pathInL0(); }
0182 
0183   /// Number of hits.
0184   std::uint32_t numberOfHits() const { return finalState().numberOfHits(); }
0185 
0186   /// Particle outcome.
0187   ActsFatras::SimulationOutcome outcome() const {
0188     return finalState().outcome();
0189   }
0190 
0191  private:
0192   SimParticleState m_initial;
0193   SimParticleState m_final;
0194 };
0195 
0196 std::ostream& operator<<(std::ostream& os, const SimParticle& particle);
0197 
0198 namespace detail {
0199 struct CompareParticleId {
0200   using is_transparent = void;
0201   bool operator()(const SimParticleState& lhs,
0202                   const SimParticleState& rhs) const {
0203     return lhs.particleId() < rhs.particleId();
0204   }
0205   bool operator()(const SimParticle& lhs, const SimParticle& rhs) const {
0206     return lhs.particleId() < rhs.particleId();
0207   }
0208   bool operator()(SimBarcode lhs, const SimParticleState& rhs) const {
0209     return lhs < rhs.particleId();
0210   }
0211   bool operator()(SimBarcode lhs, const SimParticle& rhs) const {
0212     return lhs < rhs.particleId();
0213   }
0214   bool operator()(const SimParticleState& lhs, SimBarcode rhs) const {
0215     return lhs.particleId() < rhs;
0216   }
0217   bool operator()(const SimParticle& lhs, SimBarcode rhs) const {
0218     return lhs.particleId() < rhs;
0219   }
0220 };
0221 struct PrimaryVertexIdGetter {
0222   SimBarcode operator()(const SimParticleState& particle) const {
0223     return SimBarcode().withVertexPrimary(
0224         particle.particleId().vertexPrimary());
0225   }
0226   SimBarcode operator()(const SimParticle& particle) const {
0227     return SimBarcode().withVertexPrimary(
0228         particle.particleId().vertexPrimary());
0229   }
0230 };
0231 struct SecondaryVertexIdGetter {
0232   SimBarcode operator()(const SimParticleState& particle) const {
0233     return SimBarcode()
0234         .withVertexPrimary(particle.particleId().vertexPrimary())
0235         .withVertexSecondary(particle.particleId().vertexSecondary());
0236   }
0237   SimBarcode operator()(const SimParticle& particle) const {
0238     return SimBarcode()
0239         .withVertexPrimary(particle.particleId().vertexPrimary())
0240         .withVertexSecondary(particle.particleId().vertexSecondary());
0241   }
0242 };
0243 struct VertexIdGetter {
0244   SimBarcode operator()(const SimParticleState& particle) const {
0245     return particle.particleId().vertexId();
0246   }
0247   SimBarcode operator()(const SimParticle& particle) const {
0248     return particle.particleId().vertexId();
0249   }
0250 };
0251 }  // namespace detail
0252 
0253 using SimParticleStateContainer =
0254     ::boost::container::flat_set<SimParticleState, detail::CompareParticleId>;
0255 
0256 /// Store particles ordered by particle identifier.
0257 using SimParticleContainer =
0258     ::boost::container::flat_set<SimParticle, detail::CompareParticleId>;
0259 
0260 /// Iterate over groups of particles belonging to the same primary vertex.
0261 inline GroupBy<SimParticleContainer::const_iterator,
0262                detail::PrimaryVertexIdGetter>
0263 groupByPrimaryVertex(const SimParticleContainer& container) {
0264   return makeGroupBy(container, detail::PrimaryVertexIdGetter());
0265 }
0266 
0267 /// Iterate over groups of particles belonging to the same secondary vertex.
0268 ///
0269 /// For each primary vertex, this yields one group of particles belonging
0270 /// directly to the secondary vertex and a group for each secondary vertex.
0271 inline GroupBy<SimParticleContainer::const_iterator,
0272                detail::SecondaryVertexIdGetter>
0273 groupBySecondaryVertex(const SimParticleContainer& container) {
0274   return makeGroupBy(container, detail::SecondaryVertexIdGetter());
0275 }
0276 
0277 /// Iterate over groups of particles belonging to the same vertex.
0278 ///
0279 /// For each vertex, this yields one group of particles belonging
0280 /// directly to the vertex and a group for each secondary vertex.
0281 inline GroupBy<SimParticleContainer::const_iterator, detail::VertexIdGetter>
0282 groupByVertexId(const SimParticleContainer& container) {
0283   return makeGroupBy(container, detail::VertexIdGetter());
0284 }
0285 
0286 }  // namespace ActsExamples