Warning, file /include/ActsFatras/EventData/Particle.hpp was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
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/BoundTrackParameters.hpp"
0016 #include "Acts/EventData/ParticleHypothesis.hpp"
0017 #include "Acts/Geometry/GeometryContext.hpp"
0018 #include "Acts/Surfaces/Surface.hpp"
0019 #include "Acts/Utilities/MathHelpers.hpp"
0020 #include "Acts/Utilities/VectorHelpers.hpp"
0021 #include "ActsFatras/EventData/Barcode.hpp"
0022 #include "ActsFatras/EventData/GenerationProcess.hpp"
0023 #include "ActsFatras/EventData/SimulationOutcome.hpp"
0024
0025 #include <cmath>
0026 #include <iosfwd>
0027 #include <optional>
0028
0029 namespace ActsFatras {
0030
0031
0032
0033
0034 class Particle {
0035 public:
0036
0037 Particle() = default;
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 Particle(Barcode particleId, Acts::PdgParticle pdg, double charge,
0048 double mass)
0049 : m_particleId(particleId), m_pdg(pdg), m_charge(charge), m_mass(mass) {}
0050
0051
0052
0053
0054
0055
0056 Particle(Barcode particleId, Acts::PdgParticle pdg);
0057
0058 Particle(const Particle &) = default;
0059
0060 Particle(Particle &&) = default;
0061
0062
0063 Particle &operator=(const Particle &) = default;
0064
0065
0066 Particle &operator=(Particle &&) = default;
0067
0068
0069
0070
0071
0072
0073
0074
0075 Particle withParticleId(Barcode particleId) const {
0076 Particle p = *this;
0077 p.m_particleId = particleId;
0078 return p;
0079 }
0080
0081
0082
0083
0084 void killParticle(SimulationOutcome outcome) {
0085 if (outcome == SimulationOutcome::Alive) {
0086 throw std::invalid_argument("Cannot kill particle with outcome 'Alive'.");
0087 }
0088 m_outcome = outcome;
0089 }
0090
0091
0092
0093
0094 Particle &setProcess(GenerationProcess proc) {
0095 m_process = proc;
0096 return *this;
0097 }
0098
0099
0100
0101 Particle setPdg(Acts::PdgParticle pdg) {
0102 m_pdg = pdg;
0103 return *this;
0104 }
0105
0106
0107
0108 Particle setCharge(double charge) {
0109 m_charge = charge;
0110 return *this;
0111 }
0112
0113
0114
0115 Particle setMass(double mass) {
0116 m_mass = mass;
0117 return *this;
0118 }
0119
0120
0121
0122 Particle &setParticleId(Barcode barcode) {
0123 m_particleId = barcode;
0124 return *this;
0125 }
0126
0127
0128
0129 Particle &setPosition4(const Acts::Vector4 &pos4) {
0130 m_position4 = pos4;
0131 return *this;
0132 }
0133
0134
0135
0136
0137 Particle &setPosition4(const Acts::Vector3 &position, double time) {
0138 m_position4.segment<3>(Acts::ePos0) = position;
0139 m_position4[Acts::eTime] = time;
0140 return *this;
0141 }
0142
0143
0144
0145
0146
0147
0148 Particle &setPosition4(double x, double y, double z, double time) {
0149 m_position4[Acts::ePos0] = x;
0150 m_position4[Acts::ePos1] = y;
0151 m_position4[Acts::ePos2] = z;
0152 m_position4[Acts::eTime] = time;
0153 return *this;
0154 }
0155
0156
0157
0158 Particle &setDirection(const Acts::Vector3 &direction) {
0159 m_direction = direction;
0160 m_direction.normalize();
0161 return *this;
0162 }
0163
0164
0165
0166
0167
0168 Particle &setDirection(double dx, double dy, double dz) {
0169 m_direction[Acts::ePos0] = dx;
0170 m_direction[Acts::ePos1] = dy;
0171 m_direction[Acts::ePos2] = dz;
0172 m_direction.normalize();
0173 return *this;
0174 }
0175
0176
0177
0178
0179 Particle &setAbsoluteMomentum(double absMomentum) {
0180 if (absMomentum < 0) {
0181 throw std::invalid_argument("Absolute momentum cannot be negative.");
0182 }
0183 m_absMomentum = absMomentum;
0184 return *this;
0185 }
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195 Particle &loseEnergy(double delta, SimulationOutcome stoppedOutcome =
0196 SimulationOutcome::Alive) {
0197 const double newEnergy = energy() - delta;
0198 if (newEnergy <= m_mass) {
0199 if (stoppedOutcome == SimulationOutcome::Alive) {
0200 throw std::invalid_argument(
0201 "Energy loss cannot exceed the current energy of the particle if "
0202 "the particle is to remain alive.");
0203 }
0204 killParticle(stoppedOutcome);
0205 } else {
0206 m_absMomentum = Acts::fastCathetus(newEnergy, m_mass);
0207 }
0208 return *this;
0209 }
0210
0211
0212
0213 Barcode particleId() const { return m_particleId; }
0214
0215
0216 GenerationProcess process() const { return m_process; }
0217
0218
0219 Acts::PdgParticle pdg() const { return m_pdg; }
0220
0221
0222 Acts::PdgParticle absolutePdg() const {
0223 return Acts::makeAbsolutePdgParticle(pdg());
0224 }
0225
0226
0227 double charge() const { return m_charge; }
0228
0229
0230 double absoluteCharge() const { return std::abs(m_charge); }
0231
0232
0233 double mass() const { return m_mass; }
0234
0235
0236
0237 Acts::ParticleHypothesis hypothesis() const {
0238 return Acts::ParticleHypothesis(
0239 absolutePdg(), static_cast<float>(mass()),
0240 Acts::ChargeHypothesis{static_cast<float>(absoluteCharge())},
0241 charge() != 0 ? std::nullopt
0242 : std::optional<double>(absoluteMomentum()));
0243 }
0244
0245
0246 double qOverP() const {
0247 return hypothesis().qOverP(absoluteMomentum(), charge());
0248 }
0249
0250
0251
0252 const Acts::Vector4 &fourPosition() const { return m_position4; }
0253
0254
0255 auto position() const { return m_position4.segment<3>(Acts::ePos0); }
0256
0257
0258 double time() const { return m_position4[Acts::eTime]; }
0259
0260
0261 Acts::Vector4 fourMomentum() const {
0262 Acts::Vector4 mom4;
0263
0264 mom4[Acts::eMom0] = m_absMomentum * m_direction[Acts::ePos0];
0265 mom4[Acts::eMom1] = m_absMomentum * m_direction[Acts::ePos1];
0266 mom4[Acts::eMom2] = m_absMomentum * m_direction[Acts::ePos2];
0267 mom4[Acts::eEnergy] = energy();
0268 return mom4;
0269 }
0270
0271
0272 const Acts::Vector3 &direction() const { return m_direction; }
0273
0274
0275 double theta() const { return Acts::VectorHelpers::theta(direction()); }
0276
0277
0278 double phi() const { return Acts::VectorHelpers::phi(direction()); }
0279
0280
0281 double transverseMomentum() const {
0282 return m_absMomentum * m_direction.segment<2>(Acts::eMom0).norm();
0283 }
0284
0285
0286 double absoluteMomentum() const { return m_absMomentum; }
0287
0288
0289 Acts::Vector3 momentum() const { return absoluteMomentum() * direction(); }
0290
0291
0292 double energy() const { return std::hypot(m_mass, m_absMomentum); }
0293
0294
0295
0296 bool isAlive() const { return m_outcome == SimulationOutcome::Alive; }
0297
0298
0299
0300 bool isSecondary() const {
0301 return particleId().vertexSecondary() != 0 ||
0302 particleId().generation() != 0 || particleId().subParticle() != 0;
0303 }
0304
0305
0306
0307
0308
0309
0310
0311 Particle &setProperTime(double properTime) {
0312 m_properTime = properTime;
0313 return *this;
0314 }
0315
0316
0317 double properTime() const { return m_properTime; }
0318
0319
0320
0321
0322
0323
0324 Particle &setMaterialPassed(double pathInX0, double pathInL0) {
0325 m_pathInX0 = pathInX0;
0326 m_pathInL0 = pathInL0;
0327 return *this;
0328 }
0329
0330
0331 double pathInX0() const { return m_pathInX0; }
0332
0333
0334 double pathInL0() const { return m_pathInL0; }
0335
0336
0337
0338
0339
0340 Particle &setReferenceSurface(const Acts::Surface *surface) {
0341 m_referenceSurface = surface;
0342 return *this;
0343 }
0344
0345
0346
0347 const Acts::Surface *referenceSurface() const { return m_referenceSurface; }
0348
0349
0350
0351 bool hasReferenceSurface() const { return m_referenceSurface != nullptr; }
0352
0353
0354
0355
0356 Acts::Result<Acts::BoundTrackParameters> boundParameters(
0357 const Acts::GeometryContext &gctx) const {
0358 if (!hasReferenceSurface()) {
0359 return Acts::Result<Acts::BoundTrackParameters>::failure(
0360 std::error_code());
0361 }
0362 Acts::Result<Acts::Vector2> localResult =
0363 m_referenceSurface->globalToLocal(gctx, position(), direction());
0364 if (!localResult.ok()) {
0365 return localResult.error();
0366 }
0367 Acts::BoundVector params;
0368 params << localResult.value(), phi(), theta(), qOverP(), time();
0369 return Acts::BoundTrackParameters(referenceSurface()->getSharedPtr(),
0370 params, std::nullopt, hypothesis());
0371 }
0372
0373
0374 Acts::BoundTrackParameters curvilinearParameters() const {
0375 return Acts::BoundTrackParameters::createCurvilinear(
0376 fourPosition(), direction(), qOverP(), std::nullopt, hypothesis());
0377 }
0378
0379
0380
0381
0382
0383 Particle &setNumberOfHits(std::uint32_t nHits) {
0384 m_numberOfHits = nHits;
0385 return *this;
0386 }
0387
0388
0389
0390 std::uint32_t numberOfHits() const { return m_numberOfHits; }
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400 Particle &setParentParticleId(Barcode parentId) {
0401 m_parentParticleId = parentId;
0402 return *this;
0403 }
0404
0405
0406
0407 Barcode parentParticleId() const { return m_parentParticleId; }
0408
0409
0410
0411
0412
0413 Particle &setOutcome(SimulationOutcome outcome) {
0414 m_outcome = outcome;
0415 return *this;
0416 }
0417
0418
0419
0420 SimulationOutcome outcome() const { return m_outcome; }
0421
0422 private:
0423
0424
0425 Barcode m_particleId;
0426
0427 GenerationProcess m_process = GenerationProcess::eUndefined;
0428
0429 Acts::PdgParticle m_pdg = Acts::PdgParticle::eInvalid;
0430
0431 double m_charge = 0;
0432 double m_mass = 0;
0433
0434 Acts::Vector3 m_direction = Acts::Vector3::UnitZ();
0435 double m_absMomentum = 0;
0436 Acts::Vector4 m_position4 = Acts::Vector4::Zero();
0437
0438 double m_properTime = 0;
0439
0440 double m_pathInX0 = 0;
0441 double m_pathInL0 = 0;
0442
0443 std::uint32_t m_numberOfHits = 0;
0444
0445 Barcode m_parentParticleId{};
0446
0447 const Acts::Surface *m_referenceSurface{nullptr};
0448
0449 SimulationOutcome m_outcome = SimulationOutcome::Alive;
0450 };
0451
0452
0453
0454
0455
0456 std::ostream &operator<<(std::ostream &os, const Particle &particle);
0457
0458 }