Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SimParticleTranslation.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file SimParticleTranslation.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 
20 
21 #include <ostream>
22 #include <string>
23 #include <unordered_map>
24 #include <utility>
25 
26 #include <G4ChargedGeantino.hh>
27 #include <G4Event.hh>
28 #include <G4Geantino.hh>
29 #include <G4ParticleDefinition.hh>
30 #include <G4ParticleTable.hh>
31 #include <G4PrimaryParticle.hh>
32 #include <G4PrimaryVertex.hh>
33 #include <G4UnitsTable.hh>
34 
35 namespace ActsExamples {
36 class WhiteBoard;
37 } // namespace ActsExamples
38 
40  const Config& cfg, std::unique_ptr<const Acts::Logger> logger)
41  : G4VUserPrimaryGeneratorAction(),
42  m_cfg(cfg),
43  m_logger(std::move(logger)) {}
44 
46 
48  anEvent->SetEventID(m_eventNr++);
49  unsigned int eventID = anEvent->GetEventID();
50 
51  ACTS_DEBUG("Primary Generator Action for Event: " << eventID);
52 
53  if (eventStore().store == nullptr) {
54  ACTS_WARNING("No WhiteBoard instance could be found for this event!");
55  return;
56  }
57 
58  if (eventStore().inputParticles == nullptr) {
59  ACTS_WARNING("No input particle handle found");
60  return;
61  }
62 
63  // Get the number of input particles
64  const auto inputParticles =
65  (*eventStore().inputParticles)(*eventStore().store);
66 
67  // Reserve hopefully enough hit space
68  eventStore().hits.reserve(inputParticles.size() *
69  m_cfg.reserveHitsPerParticle);
70 
71  // Default particle kinematic
72  G4ParticleTable* particleTable = G4ParticleTable::GetParticleTable();
73  G4PrimaryVertex* pVertex = nullptr;
74 
75  // We are looping through the particles and flush per vertex
76  std::optional<Acts::Vector4> lastVertex;
77 
78  constexpr double convertLength = CLHEP::mm / Acts::UnitConstants::mm;
79  constexpr double convertTime = CLHEP::ns / Acts::UnitConstants::ns;
80  constexpr double convertEnergy = CLHEP::GeV / Acts::UnitConstants::GeV;
81 
82  unsigned int pCounter = 0;
83  unsigned int trackId = 1;
84  // Loop over the input partilces and run
85  for (const auto& part : inputParticles) {
86  auto currentVertex = part.fourPosition();
87  if (not lastVertex or not currentVertex.isApprox(*lastVertex)) {
88  // Add the vertex to the event
89  if (pVertex != nullptr) {
90  anEvent->AddPrimaryVertex(pVertex);
91  ACTS_DEBUG("Flushing " << pCounter
92  << " particles associated with vertex "
93  << lastVertex->transpose());
94  pCounter = 0;
95  }
96  lastVertex = currentVertex;
97  pVertex = new G4PrimaryVertex(
98  currentVertex[0] * convertLength, currentVertex[1] * convertLength,
99  currentVertex[2] * convertLength, currentVertex[3] * convertTime);
100  }
101 
102  // Add a new primary to the vertex
103 
104  Acts::Vector4 mom4 = part.fourMomentum() * convertEnergy;
105 
106  // Particle properties, may be forced to specific value
107  G4int particlePdgCode = m_cfg.forcedPdgCode.value_or(part.pdg());
108  G4double particleCharge = m_cfg.forcedCharge.value_or(part.charge());
109  G4double particleMass =
110  m_cfg.forcedMass.value_or(part.mass() * convertEnergy);
111 
112  // Check if it is a Geantino / ChargedGeantino
113  G4ParticleDefinition* particleDefinition =
114  particleTable->FindParticle(particlePdgCode);
115  if (particleDefinition == nullptr) {
116  if (particlePdgCode == 0 && particleMass == 0 && particleCharge == 0) {
117  particleDefinition = G4Geantino::Definition();
118  }
119  if (particlePdgCode == 0 && particleMass == 0 && particleCharge != 0) {
120  if (particleCharge != 1) {
121  ACTS_ERROR("invalid charged geantino charge " << particleCharge
122  << ". should be 1");
123  }
124  particleDefinition = G4ChargedGeantino::Definition();
125  }
126  }
127 
128  // Skip if translation failed
129  if (particleDefinition == nullptr) {
130  ACTS_DEBUG(
131  "Could not translate particle with PDG code : " << particlePdgCode);
132  continue;
133  }
134 
135  ACTS_VERBOSE("Adding particle with name '"
136  << particleDefinition->GetParticleName()
137  << "' and properties:");
138  ACTS_VERBOSE(" -> mass: " << particleMass);
139  ACTS_VERBOSE(" -> charge: " << particleCharge);
140  ACTS_VERBOSE(" -> momentum: " << mom4.transpose());
141 
142  // G4 will delete this
143  G4PrimaryParticle* particle = new G4PrimaryParticle(particleDefinition);
144 
145  particle->SetMass(particleMass);
146  particle->SetCharge(particleCharge);
147  particle->Set4Momentum(mom4[0], mom4[1], mom4[2], mom4[3]);
148  particle->SetTrackID(trackId++);
149 
150  // Add the primary to the vertex
151  pVertex->SetPrimary(particle);
152 
153  eventStore().particlesInitial.insert(part);
154  eventStore().trackIdMapping[particle->GetTrackID()] = part.particleId();
155 
156  ++pCounter;
157  }
158  // Final vertex to be added
159  if (pVertex != nullptr) {
160  anEvent->AddPrimaryVertex(pVertex);
161  ACTS_DEBUG("Flushing " << pCounter << " particles associated with vertex "
162  << lastVertex->transpose());
163  }
164 }