ATLAS Offline Software
Loading...
Searching...
No Matches
G4CaloTransportTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <memory>
8
9// Geant4 includes for for particle extrapolation
10#include "G4FieldTrack.hh"
11#include "G4FieldTrackUpdator.hh"
12#include "G4LogicalVolumeStore.hh"
13#include "G4Navigator.hh"
14#include "G4PVPlacement.hh"
15#include "G4PathFinder.hh"
16#include "G4TransportationManager.hh"
17
18thread_local std::unique_ptr<G4PropagatorInField, G4CaloTransportTool::Deleter> G4CaloTransportTool::s_propagator;
19
20void G4CaloTransportTool::Deleter::operator()(G4PropagatorInField* ptr) const {
21 delete ptr->GetNavigatorForPropagating();
22 delete ptr;
23}
24
26 const std::string& name,
27 const IInterface* parent)
28 : base_class(type, name, parent) {}
29
31
32 // Delete the world volume if we created it
34 delete m_worldVolume;
35
36 return StatusCode::SUCCESS;
37}
38
40 ATH_MSG_INFO("Initializing G4PropagatorInField for thread "
41 << G4Threading::G4GetThreadId());
42
43 if (!m_worldVolume) {
44 // If not set, get either the simplified or full world volume
46
47 if (!m_worldVolume) {
48 G4Exception("G4CaloTransportTool", "FailedToGetWorldVolume",
49 FatalException,
50 "G4CaloTransportTool: Failed to get world volume.");
51 abort();
52 }
53 ATH_MSG_INFO("Using world volume: " << m_worldVolume->GetName());
54 ATH_MSG_INFO("Transport will be stopped at volume: "
55 << m_transportLimitVolume.value());
56 ATH_MSG_INFO("Maximum allowed number of steps in particle transport: "
57 << m_maxSteps.value());
58 }
59
60 // Check if we already have propagator set up for the current thread
61 // If not, we create one
62 if (!s_propagator) {
63 s_propagator = std::unique_ptr<G4PropagatorInField, Deleter>(makePropagator());
64 } else {
66 "G4CaloTransportTool::initializePropagator() Propagator already "
67 "initialized!");
68 }
69
70 return StatusCode::SUCCESS;
71}
72
74
76
77 ATH_MSG_INFO("Creating simplified world volume for particle transport");
78 // Get the logical world volume of the simplified geometry by name
79 G4LogicalVolume* logVol = G4LogicalVolumeStore::GetInstance()->GetVolume(
81
82 // Create the physical volume of the simplified world
83 return new G4PVPlacement(
84 nullptr, // no rotation
85 G4ThreeVector(0, 0, 0), // world centre at (0,0,0)
86 logVol, // logical volume
87 "simplifiedWorldPhysVol", // name of physical volume
88 nullptr, // mother volume
89 false, // not used
90 999, // copy number
91 false); // overlap check
92
93 } else {
94 ATH_MSG_INFO("Using full geometry for particle transport");
95 return G4TransportationManager::GetTransportationManager()
96 ->GetNavigatorForTracking()
97 ->GetWorldVolume();
98 }
99}
100
102 // Create a new navigator
103 G4Navigator* navigator = new G4Navigator();
104 // Set world volume in which the navigator will operate
105 navigator->SetWorldVolume(m_worldVolume);
106 // Get the global field manager
107 G4FieldManager* fieldMgr =
108 G4TransportationManager::GetTransportationManager()->GetFieldManager();
109 // Create a new magnetic field propagator
110 G4PropagatorInField* propagator =
111 new G4PropagatorInField(navigator, fieldMgr);
112 return propagator;
113}
114
115void G4CaloTransportTool::doStep(G4FieldTrack& fieldTrack) {
116
117 // Get the propagator and navigator for the current thread
118 auto navigator = s_propagator->GetNavigatorForPropagating();
119
120 G4double retSafety = -1.0;
121 G4double currentMinimumStep = 10.0 * CLHEP::m;
122
123 G4VPhysicalVolume* currentPhysVol =
124 navigator->LocateGlobalPointAndSetup(fieldTrack.GetPosition(), nullptr);
125
126 G4ThreeVector direction = fieldTrack.GetMomentumDirection();
127 // Must be called before calling the computeStep method
128 navigator->LocateGlobalPointAndSetup(fieldTrack.GetPosition(), &direction);
129
130 if (fieldTrack.GetCharge() == 0) {
131 /* Neutral particles: transport with navigator */
132
133 // Compute the step length
134 G4double stepLength = navigator->ComputeStep(
135 fieldTrack.GetPosition(), fieldTrack.GetMomentumDirection(),
136 currentMinimumStep, retSafety);
137
138 // Update the position of the track from the computed step length
139 fieldTrack.SetPosition(fieldTrack.GetPosition() +
140 stepLength *
141 fieldTrack.GetMomentumDirection().unit());
142
143 } else {
144 /* Charged particles: transport with magnetic field propagator */
145 s_propagator->ComputeStep(fieldTrack, currentMinimumStep, retSafety,
146 currentPhysVol);
147 }
148
149 return;
150}
151
152std::vector<G4FieldTrack> G4CaloTransportTool::transport(
153 const G4Track& G4InputTrack) {
154
155 // Get the PDG ID of the particle
156 int pdgId = G4InputTrack.GetDefinition()->GetPDGEncoding();
157
158 // Get the navigator for the current thread
159 auto navigator = s_propagator->GetNavigatorForPropagating();
160
161 // Create a vector to store the output steps
162 std::vector<G4FieldTrack> outputStepVector;
163
164 // Initialize the tmpFieldTrack with the input track
165 G4FieldTrack tmpFieldTrack('0');
166 G4FieldTrackUpdator::Update(&tmpFieldTrack, &G4InputTrack);
167 // Fill with the initial particle position
168 outputStepVector.push_back(tmpFieldTrack);
169
170 // Iterate until we reach the maximum number of steps or the requested volume
171 for (unsigned int iStep = 0; iStep < m_maxSteps; iStep++) {
172 // Save preStep information
173 G4ThreeVector preStepPos = tmpFieldTrack.GetPosition();
174 G4ThreeVector preStepMom = tmpFieldTrack.GetMomentum();
175
176 // Perform a single Geant4 step
177 doStep(tmpFieldTrack);
178
179 // Fill the output vector with the updated track
180 outputStepVector.push_back(tmpFieldTrack);
181
182 // Get the name of the volume in which the particle is located
183 auto volume = navigator->LocateGlobalPointAndSetup(
184 tmpFieldTrack.GetPosition(), nullptr);
185
186 if (volume != nullptr) {
187 // Get the name of the current volume
188 std::string volName = volume->GetName();
189
190 // We stop the track navigation once we have reached the provided volume
191 if (volName.find(m_transportLimitVolume) != std::string::npos) {
192 break;
193 }
194 } else {
195 G4ExceptionDescription description;
197 << "Transport failure for particle PID: " << pdgId << " at step "
198 << iStep << "/" << m_maxSteps << G4endl
199 << " - PreStep position: " << preStepPos << G4endl
200 << " - PreStep momentum: " << preStepMom << G4endl
201 << " - PostStep position: " << tmpFieldTrack.GetPosition() << G4endl
202 << " - PostStep momentum: " << tmpFieldTrack.GetMomentum() << G4endl
203 << "Possible cause: The transport is likely outside the world volume."
204 << G4endl
205 << "Check if an envelope volume is defined and properly set up."
206 << G4endl << "This issue should not occur during normal operation.";
207 G4Exception("G4CaloTransportTool::transport",
208 "LocateGlobalPointAndSetup failed: Particle may be "
209 "transported outside the world volume.",
210 JustWarning, description);
211 break;
212 }
213 }
214
215 return outputStepVector;
216}
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
void doStep(G4FieldTrack &fieldTrack)
StatusCode initializePropagator() override final
Gaudi::Property< bool > m_useSimplifiedGeo
Gaudi::Property< std::string > m_transportLimitVolume
virtual StatusCode finalize() override final
static thread_local std::unique_ptr< G4PropagatorInField, Deleter > s_propagator
G4VPhysicalVolume * m_worldVolume
Gaudi::Property< std::string > m_simplifiedWorldLogName
virtual std::vector< G4FieldTrack > transport(const G4Track &G4InputTrack) override final
G4VPhysicalVolume * getWorldVolume()
G4CaloTransportTool(const std::string &, const std::string &, const IInterface *)
Gaudi::Property< unsigned int > m_maxSteps
G4PropagatorInField * makePropagator()
std::string description
glabal timer - how long have I taken so far?
Definition hcg.cxx:91
void operator()(G4PropagatorInField *) const