File indexing completed on 2025-11-03 09:14:55
0001 
0002 
0003 
0004 
0005 
0006 
0007 
0008 
0009 #pragma once
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/Common.hpp"
0013 #include "Acts/Definitions/PdgParticle.hpp"
0014 #include "Acts/Definitions/TrackParametrization.hpp"
0015 #include "Acts/EventData/ParticleHypothesis.hpp"
0016 #include "Acts/EventData/TrackParameters.hpp"
0017 #include "Acts/Geometry/GeometryContext.hpp"
0018 #include "Acts/Surfaces/Surface.hpp"
0019 #include "Acts/Utilities/VectorHelpers.hpp"
0020 #include "ActsFatras/EventData/Barcode.hpp"
0021 #include "ActsFatras/EventData/ParticleOutcome.hpp"
0022 #include "ActsFatras/EventData/ProcessType.hpp"
0023 
0024 #include <cmath>
0025 #include <iosfwd>
0026 #include <optional>
0027 
0028 namespace ActsFatras {
0029 
0030 
0031 
0032 
0033 class Particle {
0034  public:
0035   
0036   Particle() = default;
0037   
0038   
0039   
0040   
0041   
0042   
0043   
0044   
0045   
0046   Particle(Barcode particleId, Acts::PdgParticle pdg, double charge,
0047            double mass)
0048       : m_particleId(particleId), m_pdg(pdg), m_charge(charge), m_mass(mass) {}
0049   
0050   
0051   
0052   
0053   
0054   
0055   Particle(Barcode particleId, Acts::PdgParticle pdg);
0056   Particle(const Particle &) = default;
0057   Particle(Particle &&) = default;
0058   Particle &operator=(const Particle &) = default;
0059   Particle &operator=(Particle &&) = default;
0060 
0061   
0062   
0063   
0064   
0065   
0066   Particle withParticleId(Barcode particleId) const {
0067     Particle p = *this;
0068     p.m_particleId = particleId;
0069     return p;
0070   }
0071 
0072   
0073   Particle &setProcess(ProcessType proc) {
0074     m_process = proc;
0075     return *this;
0076   }
0077   
0078   Particle setPdg(Acts::PdgParticle pdg) {
0079     m_pdg = pdg;
0080     return *this;
0081   }
0082   
0083   Particle setCharge(double charge) {
0084     m_charge = charge;
0085     return *this;
0086   }
0087   
0088   Particle setMass(double mass) {
0089     m_mass = mass;
0090     return *this;
0091   }
0092   
0093   Particle &setParticleId(Barcode barcode) {
0094     m_particleId = barcode;
0095     return *this;
0096   }
0097   
0098   Particle &setPosition4(const Acts::Vector4 &pos4) {
0099     m_position4 = pos4;
0100     return *this;
0101   }
0102   
0103   Particle &setPosition4(const Acts::Vector3 &position, double time) {
0104     m_position4.segment<3>(Acts::ePos0) = position;
0105     m_position4[Acts::eTime] = time;
0106     return *this;
0107   }
0108   
0109   Particle &setPosition4(double x, double y, double z, double time) {
0110     m_position4[Acts::ePos0] = x;
0111     m_position4[Acts::ePos1] = y;
0112     m_position4[Acts::ePos2] = z;
0113     m_position4[Acts::eTime] = time;
0114     return *this;
0115   }
0116   
0117   Particle &setDirection(const Acts::Vector3 &direction) {
0118     m_direction = direction;
0119     m_direction.normalize();
0120     return *this;
0121   }
0122   
0123   Particle &setDirection(double dx, double dy, double dz) {
0124     m_direction[Acts::ePos0] = dx;
0125     m_direction[Acts::ePos1] = dy;
0126     m_direction[Acts::ePos2] = dz;
0127     m_direction.normalize();
0128     return *this;
0129   }
0130   
0131   Particle &setAbsoluteMomentum(double absMomentum) {
0132     m_absMomentum = absMomentum;
0133     return *this;
0134   }
0135 
0136   
0137   
0138   
0139   
0140   
0141   Particle &correctEnergy(double delta) {
0142     const auto newEnergy = std::hypot(m_mass, m_absMomentum) + delta;
0143     if (newEnergy <= m_mass) {
0144       m_absMomentum = 0.;
0145     } else {
0146       m_absMomentum = std::sqrt(newEnergy * newEnergy - m_mass * m_mass);
0147     }
0148     return *this;
0149   }
0150 
0151   
0152   Barcode particleId() const { return m_particleId; }
0153   
0154   ProcessType process() const { return m_process; }
0155   
0156   Acts::PdgParticle pdg() const { return m_pdg; }
0157   
0158   Acts::PdgParticle absolutePdg() const {
0159     return Acts::makeAbsolutePdgParticle(pdg());
0160   }
0161   
0162   double charge() const { return m_charge; }
0163   
0164   double absoluteCharge() const { return std::abs(m_charge); }
0165   
0166   double mass() const { return m_mass; }
0167 
0168   
0169   Acts::ParticleHypothesis hypothesis() const {
0170     return Acts::ParticleHypothesis(absolutePdg(), mass(), absoluteCharge());
0171   }
0172   
0173   double qOverP() const {
0174     return hypothesis().qOverP(absoluteMomentum(), charge());
0175   }
0176 
0177   
0178   const Acts::Vector4 &fourPosition() const { return m_position4; }
0179   
0180   auto position() const { return m_position4.segment<3>(Acts::ePos0); }
0181   
0182   double time() const { return m_position4[Acts::eTime]; }
0183   
0184   Acts::Vector4 fourMomentum() const {
0185     Acts::Vector4 mom4;
0186     
0187     mom4[Acts::eMom0] = m_absMomentum * m_direction[Acts::ePos0];
0188     mom4[Acts::eMom1] = m_absMomentum * m_direction[Acts::ePos1];
0189     mom4[Acts::eMom2] = m_absMomentum * m_direction[Acts::ePos2];
0190     mom4[Acts::eEnergy] = energy();
0191     return mom4;
0192   }
0193   
0194   const Acts::Vector3 &direction() const { return m_direction; }
0195   
0196   double theta() const { return Acts::VectorHelpers::theta(direction()); }
0197   
0198   double phi() const { return Acts::VectorHelpers::phi(direction()); }
0199   
0200   double transverseMomentum() const {
0201     return m_absMomentum * m_direction.segment<2>(Acts::eMom0).norm();
0202   }
0203   
0204   double absoluteMomentum() const { return m_absMomentum; }
0205   
0206   Acts::Vector3 momentum() const { return absoluteMomentum() * direction(); }
0207   
0208   double energy() const { return std::hypot(m_mass, m_absMomentum); }
0209 
0210   
0211   bool isAlive() const { return 0. < m_absMomentum; }
0212 
0213   
0214   bool isSecondary() const {
0215     return particleId().vertexSecondary() != 0 ||
0216            particleId().generation() != 0 || particleId().subParticle() != 0;
0217   }
0218 
0219   
0220 
0221   
0222   
0223   
0224   Particle &setProperTime(double properTime) {
0225     m_properTime = properTime;
0226     return *this;
0227   }
0228   
0229   double properTime() const { return m_properTime; }
0230 
0231   
0232   
0233   
0234   
0235   Particle &setMaterialPassed(double pathInX0, double pathInL0) {
0236     m_pathInX0 = pathInX0;
0237     m_pathInL0 = pathInL0;
0238     return *this;
0239   }
0240   
0241   double pathInX0() const { return m_pathInX0; }
0242   
0243   double pathInL0() const { return m_pathInL0; }
0244 
0245   
0246   
0247   
0248   Particle &setReferenceSurface(const Acts::Surface *surface) {
0249     m_referenceSurface = surface;
0250     return *this;
0251   }
0252 
0253   
0254   const Acts::Surface *referenceSurface() const { return m_referenceSurface; }
0255 
0256   
0257   bool hasReferenceSurface() const { return m_referenceSurface != nullptr; }
0258 
0259   
0260   Acts::Result<Acts::BoundTrackParameters> boundParameters(
0261       const Acts::GeometryContext &gctx) const {
0262     if (!hasReferenceSurface()) {
0263       return Acts::Result<Acts::BoundTrackParameters>::failure(
0264           std::error_code());
0265     }
0266     Acts::Result<Acts::Vector2> localResult =
0267         m_referenceSurface->globalToLocal(gctx, position(), direction());
0268     if (!localResult.ok()) {
0269       return localResult.error();
0270     }
0271     Acts::BoundVector params;
0272     params << localResult.value(), phi(), theta(), qOverP(), time();
0273     return Acts::BoundTrackParameters(referenceSurface()->getSharedPtr(),
0274                                       params, std::nullopt, hypothesis());
0275   }
0276 
0277   Acts::CurvilinearTrackParameters curvilinearParameters() const {
0278     return Acts::CurvilinearTrackParameters(
0279         fourPosition(), direction(), qOverP(), std::nullopt, hypothesis());
0280   }
0281 
0282   
0283   
0284   
0285   Particle &setNumberOfHits(std::uint32_t nHits) {
0286     m_numberOfHits = nHits;
0287     return *this;
0288   }
0289 
0290   
0291   std::uint32_t numberOfHits() const { return m_numberOfHits; }
0292 
0293   
0294   
0295   
0296   Particle &setOutcome(ParticleOutcome outcome) {
0297     m_outcome = outcome;
0298     return *this;
0299   }
0300 
0301   
0302   ParticleOutcome outcome() const { return m_outcome; }
0303 
0304  private:
0305   
0306   
0307   Barcode m_particleId;
0308   
0309   ProcessType m_process = ProcessType::eUndefined;
0310   
0311   Acts::PdgParticle m_pdg = Acts::PdgParticle::eInvalid;
0312   
0313   double m_charge = 0.;
0314   double m_mass = 0.;
0315   
0316   Acts::Vector3 m_direction = Acts::Vector3::UnitZ();
0317   double m_absMomentum = 0.;
0318   Acts::Vector4 m_position4 = Acts::Vector4::Zero();
0319   
0320   double m_properTime = 0.;
0321   
0322   double m_pathInX0 = 0.;
0323   double m_pathInL0 = 0.;
0324   
0325   std::uint32_t m_numberOfHits = 0;
0326   
0327   const Acts::Surface *m_referenceSurface{nullptr};
0328   
0329   ParticleOutcome m_outcome = ParticleOutcome::Alive;
0330 };
0331 
0332 std::ostream &operator<<(std::ostream &os, const Particle &particle);
0333 
0334 }