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