ATLAS Offline Software
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 
5 #include "G4CaloTransportTool.h"
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 
18 thread_local std::unique_ptr<G4PropagatorInField, G4CaloTransportTool::Deleter> G4CaloTransportTool::s_propagator;
19 
20 void 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 
75  if (m_useSimplifiedGeo) {
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(
80  m_simplifiedWorldLogName.value());
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 
101 G4PropagatorInField* G4CaloTransportTool::makePropagator() {
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 
115 void 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 
152 std::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 }
G4CaloTransportTool::finalize
virtual StatusCode finalize() override final
Definition: G4CaloTransportTool.cxx:30
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
G4CaloTransportTool::m_transportLimitVolume
Gaudi::Property< std::string > m_transportLimitVolume
Definition: G4CaloTransportTool.h:58
G4CaloTransportTool::m_simplifiedWorldLogName
Gaudi::Property< std::string > m_simplifiedWorldLogName
Definition: G4CaloTransportTool.h:56
G4CaloTransportTool::m_worldVolume
G4VPhysicalVolume * m_worldVolume
Definition: G4CaloTransportTool.h:51
dbg::ptr
void * ptr(T *p)
Definition: SGImplSvc.cxx:74
python.CaloAddPedShiftConfig.type
type
Definition: CaloAddPedShiftConfig.py:42
G4CaloTransportTool::m_maxSteps
Gaudi::Property< unsigned int > m_maxSteps
Definition: G4CaloTransportTool.h:60
G4CaloTransportTool::s_propagator
static thread_local std::unique_ptr< G4PropagatorInField, Deleter > s_propagator
Definition: G4CaloTransportTool.h:62
G4CaloTransportTool::Deleter::operator()
void operator()(G4PropagatorInField *) const
Definition: G4CaloTransportTool.cxx:20
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
test_pyathena.parent
parent
Definition: test_pyathena.py:15
G4CaloTransportTool::G4CaloTransportTool
G4CaloTransportTool(const std::string &, const std::string &, const IInterface *)
Definition: G4CaloTransportTool.cxx:25
G4CaloTransportTool.h
G4CaloTransportTool::transport
virtual std::vector< G4FieldTrack > transport(const G4Track &G4InputTrack) override final
Definition: G4CaloTransportTool.cxx:152
G4CaloTransportTool::makePropagator
G4PropagatorInField * makePropagator()
Definition: G4CaloTransportTool.cxx:101
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
runIDPVM.pdgId
pdgId
Definition: runIDPVM.py:91
G4CaloTransportTool::getWorldVolume
G4VPhysicalVolume * getWorldVolume()
Definition: G4CaloTransportTool.cxx:73
G4CaloTransportTool::initializePropagator
StatusCode initializePropagator() override final
Definition: G4CaloTransportTool.cxx:39
G4CaloTransportTool::doStep
void doStep(G4FieldTrack &fieldTrack)
Definition: G4CaloTransportTool.cxx:115
G4CaloTransportTool::m_useSimplifiedGeo
Gaudi::Property< bool > m_useSimplifiedGeo
Definition: G4CaloTransportTool.h:54
python.SystemOfUnits.m
float m
Definition: SystemOfUnits.py:106
description
std::string description
glabal timer - how long have I taken so far?
Definition: hcg.cxx:91