File indexing completed on 2025-09-16 08:27:47
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 }