File indexing completed on 2025-01-18 09:11:36
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/Geant4/ParticleTrackingAction.hpp"
0010
0011 #include "Acts/Definitions/PdgParticle.hpp"
0012 #include "Acts/Definitions/Units.hpp"
0013 #include "Acts/Utilities/MultiIndex.hpp"
0014 #include "ActsExamples/EventData/SimParticle.hpp"
0015 #include "ActsExamples/Geant4/EventStore.hpp"
0016 #include "ActsFatras/EventData/Barcode.hpp"
0017
0018 #include <cassert>
0019 #include <ostream>
0020 #include <unordered_map>
0021 #include <utility>
0022
0023 #include <G4ParticleDefinition.hh>
0024 #include <G4RunManager.hh>
0025 #include <G4Track.hh>
0026 #include <G4UnitsTable.hh>
0027
0028 namespace ActsExamples::Geant4 {
0029
0030 ParticleTrackingAction::ParticleTrackingAction(
0031 const Config& cfg, std::unique_ptr<const Acts::Logger> logger)
0032 : G4UserTrackingAction(), m_cfg(cfg), m_logger(std::move(logger)) {}
0033
0034 void ParticleTrackingAction::PreUserTrackingAction(const G4Track* aTrack) {
0035
0036
0037
0038
0039
0040
0041 if (!eventStore().hitBuffer.empty()) {
0042 eventStore().hitBuffer.clear();
0043 ACTS_WARNING("Hit buffer not empty after track");
0044 }
0045
0046 auto barcode = makeParticleId(aTrack->GetTrackID(), aTrack->GetParentID());
0047
0048
0049
0050 if (!barcode) {
0051 return;
0052 }
0053
0054 auto fatrasParticle = convert(*aTrack, *barcode);
0055 SimParticle particle(fatrasParticle, fatrasParticle);
0056 auto [it, success] = eventStore().particlesInitial.insert(particle);
0057
0058
0059
0060 if (success) {
0061 eventStore().trackIdMapping[aTrack->GetTrackID()] = particle.particleId();
0062 } else {
0063 eventStore().particleIdCollisionsInitial++;
0064 ACTS_WARNING("Particle ID collision with "
0065 << particle.particleId()
0066 << " detected for initial particles. Skip particle");
0067 }
0068 }
0069
0070 void ParticleTrackingAction::PostUserTrackingAction(const G4Track* aTrack) {
0071
0072
0073 if (!eventStore().trackIdMapping.contains(aTrack->GetTrackID())) {
0074 ACTS_WARNING("Particle ID for track ID " << aTrack->GetTrackID()
0075 << " not registered. Skip");
0076 return;
0077 }
0078
0079 const auto barcode = eventStore().trackIdMapping.at(aTrack->GetTrackID());
0080
0081 auto hasHits = eventStore().particleHitCount.contains(barcode) &&
0082 eventStore().particleHitCount.at(barcode) > 0;
0083
0084 if (!m_cfg.keepParticlesWithoutHits && !hasHits) {
0085 [[maybe_unused]] auto n = eventStore().particlesSimulated.erase(
0086 SimParticle(barcode, Acts::PdgParticle::eInvalid));
0087 assert(n == 1);
0088 return;
0089 }
0090
0091 auto particleIt = eventStore().particlesInitial.find(barcode);
0092 if (particleIt == eventStore().particlesInitial.end()) {
0093 ACTS_WARNING("Particle ID " << barcode
0094 << " not found in initial particles");
0095 return;
0096 }
0097 SimParticle particle = *particleIt;
0098 particle.final() = convert(*aTrack, barcode);
0099
0100 auto [it, success] = eventStore().particlesSimulated.insert(particle);
0101
0102 if (!success) {
0103 eventStore().particleIdCollisionsFinal++;
0104 ACTS_WARNING("Particle ID collision with "
0105 << particle.particleId()
0106 << " detected for final particles. Skip particle");
0107 }
0108 }
0109
0110 SimParticleState ParticleTrackingAction::convert(const G4Track& aTrack,
0111 SimBarcode particleId) const {
0112
0113 constexpr double convertTime = Acts::UnitConstants::ns / CLHEP::ns;
0114 constexpr double convertLength = Acts::UnitConstants::mm / CLHEP::mm;
0115 constexpr double convertEnergy = Acts::UnitConstants::GeV / CLHEP::GeV;
0116
0117
0118 const G4ParticleDefinition* particleDef = aTrack.GetParticleDefinition();
0119 G4int pdg = particleDef->GetPDGEncoding();
0120 G4double charge = particleDef->GetPDGCharge();
0121 G4double mass = convertEnergy * particleDef->GetPDGMass();
0122 G4ThreeVector pPosition = convertLength * aTrack.GetPosition();
0123 G4double pTime = convertTime * aTrack.GetGlobalTime();
0124 G4ThreeVector pDirection = aTrack.GetMomentumDirection();
0125 G4double p = convertEnergy * aTrack.GetKineticEnergy();
0126
0127 std::uint32_t numberOfHits = 0;
0128 if (auto it = eventStore().particleHitCount.find(particleId);
0129 it != eventStore().particleHitCount.end()) {
0130 numberOfHits = it->second;
0131 }
0132
0133 ActsFatras::ParticleOutcome particleOutcome =
0134 ActsFatras::ParticleOutcome::Alive;
0135 if (auto it = eventStore().particleOutcome.find(particleId);
0136 it != eventStore().particleOutcome.end()) {
0137 particleOutcome = it->second;
0138 }
0139
0140
0141 SimParticleState aParticle(particleId, Acts::PdgParticle{pdg}, charge, mass);
0142 aParticle.setPosition4(pPosition[0], pPosition[1], pPosition[2], pTime);
0143 aParticle.setDirection(pDirection[0], pDirection[1], pDirection[2]);
0144 aParticle.setAbsoluteMomentum(p);
0145 aParticle.setNumberOfHits(numberOfHits);
0146 aParticle.setOutcome(particleOutcome);
0147 return aParticle;
0148 }
0149
0150 std::optional<SimBarcode> ParticleTrackingAction::makeParticleId(
0151 G4int trackId, G4int parentId) const {
0152
0153
0154 if (eventStore().trackIdMapping.contains(trackId)) {
0155 return std::nullopt;
0156 }
0157
0158 if (!eventStore().trackIdMapping.contains(parentId)) {
0159 ACTS_DEBUG("Parent particle " << parentId
0160 << " not registered, cannot build barcode");
0161 eventStore().parentIdNotFound++;
0162 return std::nullopt;
0163 }
0164
0165 auto pid = eventStore().trackIdMapping.at(parentId).makeDescendant();
0166
0167 auto key = EventStore::BarcodeWithoutSubparticle::Zeros();
0168 key.set(0, pid.vertexPrimary())
0169 .set(1, pid.vertexSecondary())
0170 .set(2, pid.particle())
0171 .set(3, pid.generation());
0172 pid.setSubParticle(++eventStore().subparticleMap[key]);
0173
0174 return pid;
0175 }
0176
0177 }