File indexing completed on 2025-12-16 09:41:49
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
0057 Particle(const Particle &) = default;
0058
0059 Particle(Particle &&) = default;
0060
0061
0062 Particle &operator=(const Particle &) = default;
0063
0064
0065 Particle &operator=(Particle &&) = default;
0066
0067
0068
0069
0070
0071
0072
0073
0074 Particle withParticleId(Barcode particleId) const {
0075 Particle p = *this;
0076 p.m_particleId = particleId;
0077 return p;
0078 }
0079
0080
0081
0082
0083 Particle &setProcess(ProcessType proc) {
0084 m_process = proc;
0085 return *this;
0086 }
0087
0088
0089
0090 Particle setPdg(Acts::PdgParticle pdg) {
0091 m_pdg = pdg;
0092 return *this;
0093 }
0094
0095
0096
0097 Particle setCharge(double charge) {
0098 m_charge = charge;
0099 return *this;
0100 }
0101
0102
0103
0104 Particle setMass(double mass) {
0105 m_mass = mass;
0106 return *this;
0107 }
0108
0109
0110
0111 Particle &setParticleId(Barcode barcode) {
0112 m_particleId = barcode;
0113 return *this;
0114 }
0115
0116
0117
0118 Particle &setPosition4(const Acts::Vector4 &pos4) {
0119 m_position4 = pos4;
0120 return *this;
0121 }
0122
0123
0124
0125
0126 Particle &setPosition4(const Acts::Vector3 &position, double time) {
0127 m_position4.segment<3>(Acts::ePos0) = position;
0128 m_position4[Acts::eTime] = time;
0129 return *this;
0130 }
0131
0132
0133
0134
0135
0136
0137 Particle &setPosition4(double x, double y, double z, double time) {
0138 m_position4[Acts::ePos0] = x;
0139 m_position4[Acts::ePos1] = y;
0140 m_position4[Acts::ePos2] = z;
0141 m_position4[Acts::eTime] = time;
0142 return *this;
0143 }
0144
0145
0146
0147 Particle &setDirection(const Acts::Vector3 &direction) {
0148 m_direction = direction;
0149 m_direction.normalize();
0150 return *this;
0151 }
0152
0153
0154
0155
0156
0157 Particle &setDirection(double dx, double dy, double dz) {
0158 m_direction[Acts::ePos0] = dx;
0159 m_direction[Acts::ePos1] = dy;
0160 m_direction[Acts::ePos2] = dz;
0161 m_direction.normalize();
0162 return *this;
0163 }
0164
0165
0166
0167 Particle &setAbsoluteMomentum(double absMomentum) {
0168 m_absMomentum = absMomentum;
0169 return *this;
0170 }
0171
0172
0173
0174
0175
0176
0177
0178
0179 Particle &correctEnergy(double delta) {
0180 const auto newEnergy = std::hypot(m_mass, m_absMomentum) + delta;
0181 if (newEnergy <= m_mass) {
0182 m_absMomentum = 0.;
0183 } else {
0184 m_absMomentum = std::sqrt(newEnergy * newEnergy - m_mass * m_mass);
0185 }
0186 return *this;
0187 }
0188
0189
0190
0191 Barcode particleId() const { return m_particleId; }
0192
0193
0194 ProcessType process() const { return m_process; }
0195
0196
0197 Acts::PdgParticle pdg() const { return m_pdg; }
0198
0199
0200 Acts::PdgParticle absolutePdg() const {
0201 return Acts::makeAbsolutePdgParticle(pdg());
0202 }
0203
0204
0205 double charge() const { return m_charge; }
0206
0207
0208 double absoluteCharge() const { return std::abs(m_charge); }
0209
0210
0211 double mass() const { return m_mass; }
0212
0213
0214
0215 Acts::ParticleHypothesis hypothesis() const {
0216 return Acts::ParticleHypothesis(
0217 absolutePdg(), static_cast<float>(mass()),
0218 Acts::AnyCharge{static_cast<float>(absoluteCharge())});
0219 }
0220
0221
0222 double qOverP() const {
0223 return hypothesis().qOverP(absoluteMomentum(), charge());
0224 }
0225
0226
0227
0228 const Acts::Vector4 &fourPosition() const { return m_position4; }
0229
0230
0231 auto position() const { return m_position4.segment<3>(Acts::ePos0); }
0232
0233
0234 double time() const { return m_position4[Acts::eTime]; }
0235
0236
0237 Acts::Vector4 fourMomentum() const {
0238 Acts::Vector4 mom4;
0239
0240 mom4[Acts::eMom0] = m_absMomentum * m_direction[Acts::ePos0];
0241 mom4[Acts::eMom1] = m_absMomentum * m_direction[Acts::ePos1];
0242 mom4[Acts::eMom2] = m_absMomentum * m_direction[Acts::ePos2];
0243 mom4[Acts::eEnergy] = energy();
0244 return mom4;
0245 }
0246
0247
0248 const Acts::Vector3 &direction() const { return m_direction; }
0249
0250
0251 double theta() const { return Acts::VectorHelpers::theta(direction()); }
0252
0253
0254 double phi() const { return Acts::VectorHelpers::phi(direction()); }
0255
0256
0257 double transverseMomentum() const {
0258 return m_absMomentum * m_direction.segment<2>(Acts::eMom0).norm();
0259 }
0260
0261
0262 double absoluteMomentum() const { return m_absMomentum; }
0263
0264
0265 Acts::Vector3 momentum() const { return absoluteMomentum() * direction(); }
0266
0267
0268 double energy() const { return std::hypot(m_mass, m_absMomentum); }
0269
0270
0271
0272 bool isAlive() const { return 0. < m_absMomentum; }
0273
0274
0275
0276 bool isSecondary() const {
0277 return particleId().vertexSecondary() != 0 ||
0278 particleId().generation() != 0 || particleId().subParticle() != 0;
0279 }
0280
0281
0282
0283
0284
0285
0286
0287 Particle &setProperTime(double properTime) {
0288 m_properTime = properTime;
0289 return *this;
0290 }
0291
0292
0293 double properTime() const { return m_properTime; }
0294
0295
0296
0297
0298
0299
0300 Particle &setMaterialPassed(double pathInX0, double pathInL0) {
0301 m_pathInX0 = pathInX0;
0302 m_pathInL0 = pathInL0;
0303 return *this;
0304 }
0305
0306
0307 double pathInX0() const { return m_pathInX0; }
0308
0309
0310 double pathInL0() const { return m_pathInL0; }
0311
0312
0313
0314
0315
0316 Particle &setReferenceSurface(const Acts::Surface *surface) {
0317 m_referenceSurface = surface;
0318 return *this;
0319 }
0320
0321
0322
0323 const Acts::Surface *referenceSurface() const { return m_referenceSurface; }
0324
0325
0326
0327 bool hasReferenceSurface() const { return m_referenceSurface != nullptr; }
0328
0329
0330
0331
0332 Acts::Result<Acts::BoundTrackParameters> boundParameters(
0333 const Acts::GeometryContext &gctx) const {
0334 if (!hasReferenceSurface()) {
0335 return Acts::Result<Acts::BoundTrackParameters>::failure(
0336 std::error_code());
0337 }
0338 Acts::Result<Acts::Vector2> localResult =
0339 m_referenceSurface->globalToLocal(gctx, position(), direction());
0340 if (!localResult.ok()) {
0341 return localResult.error();
0342 }
0343 Acts::BoundVector params;
0344 params << localResult.value(), phi(), theta(), qOverP(), time();
0345 return Acts::BoundTrackParameters(referenceSurface()->getSharedPtr(),
0346 params, std::nullopt, hypothesis());
0347 }
0348
0349
0350 Acts::BoundTrackParameters curvilinearParameters() const {
0351 return Acts::BoundTrackParameters::createCurvilinear(
0352 fourPosition(), direction(), qOverP(), std::nullopt, hypothesis());
0353 }
0354
0355
0356
0357
0358
0359 Particle &setNumberOfHits(std::uint32_t nHits) {
0360 m_numberOfHits = nHits;
0361 return *this;
0362 }
0363
0364
0365
0366 std::uint32_t numberOfHits() const { return m_numberOfHits; }
0367
0368
0369
0370
0371
0372 Particle &setOutcome(ParticleOutcome outcome) {
0373 m_outcome = outcome;
0374 return *this;
0375 }
0376
0377
0378
0379 ParticleOutcome outcome() const { return m_outcome; }
0380
0381 private:
0382
0383
0384 Barcode m_particleId;
0385
0386 ProcessType m_process = ProcessType::eUndefined;
0387
0388 Acts::PdgParticle m_pdg = Acts::PdgParticle::eInvalid;
0389
0390 double m_charge = 0.;
0391 double m_mass = 0.;
0392
0393 Acts::Vector3 m_direction = Acts::Vector3::UnitZ();
0394 double m_absMomentum = 0.;
0395 Acts::Vector4 m_position4 = Acts::Vector4::Zero();
0396
0397 double m_properTime = 0.;
0398
0399 double m_pathInX0 = 0.;
0400 double m_pathInL0 = 0.;
0401
0402 std::uint32_t m_numberOfHits = 0;
0403
0404 const Acts::Surface *m_referenceSurface{nullptr};
0405
0406 ParticleOutcome m_outcome = ParticleOutcome::Alive;
0407 };
0408
0409 std::ostream &operator<<(std::ostream &os, const Particle &particle);
0410
0411 }