Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ParticleTrackingAction.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file ParticleTrackingAction.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2021 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
10 
18 
19 #include <cassert>
20 #include <cstddef>
21 #include <ostream>
22 #include <unordered_map>
23 #include <utility>
24 
25 #include <G4ParticleDefinition.hh>
26 #include <G4RunManager.hh>
27 #include <G4Track.hh>
28 #include <G4UnitsTable.hh>
29 
31  const Config& cfg, std::unique_ptr<const Acts::Logger> logger)
32  : G4UserTrackingAction(), m_cfg(cfg), m_logger(std::move(logger)) {}
33 
35  const G4Track* aTrack) {
36  // If this is not the case, there are unhandled cases of particle stopping in
37  // the SensitiveSteppingAction
38  // TODO We could also merge the remaining hits to a hit here, but it would be
39  // nicer to investigate, if we can handle all particle stop conditions in the
40  // SensitiveSteppingAction... This seems to happen O(1) times in a ttbar
41  // event, so seems not to be too problematic
42  if (not eventStore().hitBuffer.empty()) {
43  eventStore().hitBuffer.clear();
44  ACTS_WARNING("Hit buffer not empty after track");
45  }
46 
47  auto barcode = makeParticleId(aTrack->GetTrackID(), aTrack->GetParentID());
48 
49  // There is already a warning printed in the makeParticleId function if this
50  // indicates a failure
51  if (not barcode) {
52  return;
53  }
54 
55  auto particle = convert(*aTrack, *barcode);
56  auto [it, success] = eventStore().particlesInitial.insert(particle);
57 
58  // Only register particle at the initial state AND if there is no particle ID
59  // collision
60  if (success) {
61  eventStore().trackIdMapping[aTrack->GetTrackID()] = particle.particleId();
62  } else {
63  eventStore().particleIdCollisionsInitial++;
64  ACTS_WARNING("Particle ID collision with "
65  << particle.particleId()
66  << " detected for initial particles. Skip particle");
67  }
68 }
69 
71  const G4Track* aTrack) {
72  // The initial particle maybe was not registered because a particle ID
73  // collision
74  if (eventStore().trackIdMapping.find(aTrack->GetTrackID()) ==
75  eventStore().trackIdMapping.end()) {
76  ACTS_WARNING("Particle ID for track ID " << aTrack->GetTrackID()
77  << " not registered. Skip");
78  return;
79  }
80 
81  const auto barcode = eventStore().trackIdMapping.at(aTrack->GetTrackID());
82 
83  auto hasHits = eventStore().particleHitCount.find(barcode) !=
84  eventStore().particleHitCount.end() and
85  eventStore().particleHitCount.at(barcode) > 0;
86 
87  if (not m_cfg.keepParticlesWithoutHits and not hasHits) {
88  [[maybe_unused]] auto n = eventStore().particlesInitial.erase(
90  assert(n == 1);
91  return;
92  }
93 
94  auto particle = convert(*aTrack, barcode);
95  auto [it, success] = eventStore().particlesFinal.insert(particle);
96 
97  if (not success) {
98  eventStore().particleIdCollisionsFinal++;
99  ACTS_WARNING("Particle ID collision with "
100  << particle.particleId()
101  << " detected for final particles. Skip particle");
102  }
103 }
104 
106  const G4Track& aTrack, SimBarcode particleId) const {
107  // Unit conversions G4->::ACTS
108  constexpr double convertTime = Acts::UnitConstants::ns / CLHEP::ns;
109  constexpr double convertLength = Acts::UnitConstants::mm / CLHEP::mm;
110  constexpr double convertEnergy = Acts::UnitConstants::GeV / CLHEP::GeV;
111 
112  // Get all the information from the Track
113  const G4ParticleDefinition* particleDef = aTrack.GetParticleDefinition();
114  G4int pdg = particleDef->GetPDGEncoding();
115  G4double charge = particleDef->GetPDGCharge();
116  G4double mass = convertEnergy * particleDef->GetPDGMass();
117  G4ThreeVector pPosition = convertLength * aTrack.GetPosition();
118  G4double pTime = convertTime * aTrack.GetGlobalTime();
119  G4ThreeVector pDirection = aTrack.GetMomentumDirection();
120  G4double p = convertEnergy * aTrack.GetKineticEnergy();
121 
122  // Now create the Particle
123  ActsExamples::SimParticle aParticle(particleId, Acts::PdgParticle(pdg),
124  charge, mass);
125  aParticle.setPosition4(pPosition[0], pPosition[1], pPosition[2], pTime);
126  aParticle.setDirection(pDirection[0], pDirection[1], pDirection[2]);
127  aParticle.setAbsoluteMomentum(p);
128  return aParticle;
129 }
130 
131 std::optional<ActsExamples::SimBarcode>
133  G4int parentId) const {
134  // We already have this particle registered (it is one of the input particles
135  // or we are making a final particle state)
136  if (eventStore().trackIdMapping.find(trackId) !=
137  eventStore().trackIdMapping.end()) {
138  return std::nullopt;
139  }
140 
141  if (eventStore().trackIdMapping.find(parentId) ==
142  eventStore().trackIdMapping.end()) {
143  ACTS_DEBUG("Parent particle " << parentId
144  << " not registered, cannot build barcode");
145  eventStore().parentIdNotFound++;
146  return std::nullopt;
147  }
148 
149  auto pid = eventStore().trackIdMapping.at(parentId).makeDescendant();
150 
152  key.set(0, pid.vertexPrimary())
153  .set(1, pid.vertexSecondary())
154  .set(2, pid.particle())
155  .set(3, pid.generation());
156  pid.setSubParticle(++eventStore().subparticleMap[key]);
157 
158  return pid;
159 }