ATLAS Offline Software
Loading...
Searching...
No Matches
G4RunTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "G4RunTool.h"
6
7// Gaudi includes
8#include "GaudiKernel/ServiceHandle.h"
9
10// header files from Geant4
11#include "G4MTRunManager.hh"
12#include "G4StateManager.hh"
13#include "G4UImanager.hh"
14#include "G4GeometryManager.hh"
15#include "G4PhysicalVolumeStore.hh"
16#include "G4EventManager.hh"
17
19
20// Standard library
21#include <memory>
22
25
26 // Gaudi will automatically initialize child tools once this tool is initialized.
27 // We want these child tools to be initialized in the Geant4 main thread,
28 // disable() will tell Gaudi not to initialize them now.
29 // Ideally we'd move the initialization that needs to happen in the Geant4 main thread out of initialize
30 // and into a separate method called from Geant4main.
31 m_detConstruction.disable();
32 for(auto& tool : m_actionTools) {
33 tool.disable();
34 }
35
36 m_thread = std::make_unique<std::thread>(&G4RunTool::Geant4main, this);
37 ATH_MSG_DEBUG("Geant4main thread created, id=" << m_thread->get_id() << ", now waiting for G4 run manager");
38 return StatusCode::SUCCESS;
39}
40
42 // Signal finalization to G4 threads
44
45 // G4 worker threads should be waiting for the next event to simulate at this state
46 // Pushing empty event, will cause one worker thread to realize we are done and call AbortRun for G4
47 for(int i = 0; i < m_nG4threads; ++i) {
48 PushEvent(nullptr);
49 }
50
51 if (m_thread) {
52 try {
53 if(m_thread->joinable()) m_thread->join();
54 }
55 catch(const std::exception& e) {
56 ATH_MSG_ERROR("Failure in G4RunTool::finalize, joining Geant4 main thread:" << e.what());
57 }
58 }
59
60 return StatusCode::SUCCESS;
61}
62
63//---------------------------------------------------------------------------
64// Status management
65//---------------------------------------------------------------------------
66
67// Notify Athena that Geant4 is ready to start a run (called by Geant4 BeginOfRunAction).
71
72// Wait until Geant4 is ready to start a run (called by Athena initialize).
76
78 {
79 std::scoped_lock lk(m_mutex);
80 m_status = status;
81 }
82 m_cv.notify_all();
83}
84
86 std::unique_lock lk(m_mutex);
87 m_cv.wait(lk, [this, status]{ return m_status == status; });
88}
89
90//---------------------------------------------------------------------------
91// Queue management
92//---------------------------------------------------------------------------
93
94// Check the size of the event queue
95size_t G4RunTool::Size() const {
96 std::scoped_lock lk(m_eventQueueSync.m_mutex);
97 return m_eventQueueSync.m_events.size();
98}
99
100// Push an event to the queue (called from Athena threads)
102 {
103 std::scoped_lock lk(m_eventQueueSync.m_mutex);
104 m_eventQueueSync.m_events.push(std::move(ev));
105 }
106 m_eventQueueSync.m_cv.notify_one();
107}
108
110auto G4RunTool::GetEvent() -> UPEvent {
111
112 std::unique_lock lk(m_eventQueueSync.m_mutex);
113 m_eventQueueSync.m_cv.wait(lk, [this]{ return m_eventQueueSync.m_events.size() > 0; });
114 UPEvent ev = std::move(m_eventQueueSync.m_events.front());
115 m_eventQueueSync.m_events.pop();
116 return ev;
117}
118
119//---------------------------------------------------------------------------
120// Geant4 thread function
121//---------------------------------------------------------------------------
122
123// G4 main thread management
125
126 ATH_MSG_INFO("Geant4 main thread starts with id " << std::this_thread::get_id());
127
128 // Construct the default run manager
129 auto runManager = std::make_unique<G4MTRunManager>();
130
131 runManager->SetNumberOfThreads(m_nG4threads);
132 constexpr int seedFirstEventOnly = 1; // name the magic number
133 // we will take care of reseeding each event, turn off Geant4 reseeding
134 runManager->SetSeedOncePerCommunication(seedFirstEventOnly);
135
136 if(m_detConstruction.retrieve().isFailure()) {
137 ATH_MSG_ERROR("Failed to retrieve DetectorGeometryService");
138 return;
139 }
140
141 if(m_physicsListSvc.retrieve().isFailure()) {
142 ATH_MSG_ERROR("Failed to retrieve PhysicsListService");
143 return;
144 }
145
146 if(m_userActionSvc.retrieve().isFailure()) {
147 ATH_MSG_ERROR("Failed to retrieve UserActionService");
148 return;
149 }
150
151 if(m_actionTools.retrieve().isFailure()) {
152 ATH_MSG_ERROR("Failed to retrieve ActionTools");
153 return;
154 }
155
156 // Initialize action tools for G4RunTool
157 for (const auto& action_tool : m_actionTools) {
158 ATH_MSG_INFO("retrieving action tool " + action_tool.name());
159 if (m_userActionSvc->addActionTool(action_tool).isFailure()) {
160 throw std::runtime_error("Failed to add action tool " + action_tool.name());
161 }
162 }
163 // Set the user action service for the G4UA service
164 // Having a ServiceHandle<IG4RunTool> would be a circular dependency which is not supported...
165 m_userActionSvc->G4RunTool(this);
166
167 // Many of the objects created here must be created in the same thread as the run manager
168 runManager->SetUserInitialization(m_detConstruction->GetDetectorConstruction().release());
169
170 // The actual physics list object must be created in the same thread as the run manager
171 runManager->SetUserInitialization(m_physicsListSvc->GetPhysicsList());
172
173 runManager->SetUserInitialization(std::make_unique<G4AtlasActionInitialization>(m_userActionSvc.get()).release());
174
175 // G4 user interface commands
176 G4UImanager *ui = G4UImanager::GetUIpointer();
177
178 // Load custom libraries
179 if (!m_libList.empty()) {
180 ATH_MSG_INFO("G4AtlasAlg specific libraries requested ");
181 std::string temp="/load "+m_libList;
182 ui->ApplyCommand(temp);
183 }
184 // Load custom physics
185 if (!m_physList.empty()) {
186 ATH_MSG_INFO("requesting a specific physics list "<< m_physList);
187 std::string temp="/Physics/GetPhysicsList "+m_physList;
188 ui->ApplyCommand(temp);
189 }
190 // Load custom magnetic field
191 if (!m_fieldMap.empty()) {
192 ATH_MSG_INFO("requesting a specific field map "<< m_fieldMap);
193 ATH_MSG_INFO("the field is initialized straight away");
194 std::string temp="/MagneticField/Select "+m_fieldMap;
195 ui->ApplyCommand(temp);
196 ui->ApplyCommand("/MagneticField/Initialize");
197 }
198
199 // Send UI commands
200 ATH_MSG_DEBUG("G4 Command: Trying at the end of initializeOnce()");
201 for (const auto& g4command : m_g4commands) {
202 int returnCode = ui->ApplyCommand( g4command );
203 commandLog(returnCode, g4command);
204 }
205
206 // Initialize run
207 runManager->Initialize();
208
209 m_physicsListSvc->SetPhysicsOptions();
210
211 ATH_MSG_INFO("Initializing " << m_physicsInitializationTools.size() << " physics initialization tools");
212 for(auto& physicsTool : m_physicsInitializationTools) {
213 if (physicsTool->initializePhysics().isFailure()) {
214 throw std::runtime_error("Failed to initialize physics with tool " + physicsTool.name());
215 }
216 }
217 // Retrieve core services needed for G4 main thread
218 if(m_userLimitsSvc.retrieve().isFailure()) {
219 throw std::runtime_error("Could not initialize ATLAS UserLimitsSvc!");
220 }
221
222 ATH_MSG_INFO("Geant4 initialization done, BeamOn...");
223
224 // Repeat BeamOn as long as athena event loop is not finished
226 runManager->BeamOn(m_nG4eventsPerRun);
227 }
228
229 // Clean up geometry
230 G4GeometryManager::GetInstance()->OpenGeometry();
231 G4PhysicalVolumeStore::GetInstance()->Clean();
232 ATH_MSG_INFO("Geant4 main thread ended");
233}
234
235void G4RunTool::commandLog(int returnCode, const std::string& commandString) const
236{
237 switch(returnCode) {
238 case 0: { ATH_MSG_DEBUG("G4 Command: " << commandString << " - Command Succeeded"); } break;
239 case 100: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Command Not Found!"); } break;
240 case 200: {
241 auto* stateManager = G4StateManager::GetStateManager();
242 ATH_MSG_DEBUG("G4 Command: " << commandString << " - Illegal Application State (" <<
243 stateManager->GetStateString(stateManager->GetCurrentState()) << ")!");
244 } break;
245 case 300: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Parameter Out of Range!"); } break;
246 case 400: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Parameter Unreadable!"); } break;
247 case 500: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Parameter Out of Candidates!"); } break;
248 case 600: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Alias Not Found!"); } break;
249 default: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Unknown Status!"); } break;
250 }
251
252}
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
ServiceHandle< IPhysicsListSvc > m_physicsListSvc
Definition G4RunTool.h:74
virtual StatusCode finalize() override final
Definition G4RunTool.cxx:41
virtual void WaitBeginRun() override
Definition G4RunTool.cxx:73
EventQueueSynchronization m_eventQueueSync
Definition G4RunTool.h:121
std::unique_ptr< std::thread > m_thread
Definition G4RunTool.h:115
void Geant4main()
Geant4 main thread function, this is executed in a separate thread and blocks on BeamOn.
Gaudi::Property< std::vector< std::string > > m_g4commands
Definition G4RunTool.h:87
Gaudi::Property< int > m_nG4threads
Definition G4RunTool.h:89
Gaudi::Property< int > m_nG4eventsPerRun
Definition G4RunTool.h:90
virtual void NotifyBeginRun() override
Notify Athena that Geant4 is ready to start a run.
Definition G4RunTool.cxx:68
ServiceHandle< IUserLimitsSvc > m_userLimitsSvc
Definition G4RunTool.h:75
virtual UPEvent GetEvent() override
Get an event from the queue (called from Geant4 threads)
Gaudi::Property< std::string > m_libList
Definition G4RunTool.h:84
ToolHandleArray< G4UA::IUserActionTool > m_actionTools
Definition G4RunTool.h:79
virtual StatusCode initialize() override final
Initialize and start the Geant4 main thread, then wait until Geant4 is ready to start the run.
Definition G4RunTool.cxx:24
virtual size_t Size() const override
Definition G4RunTool.cxx:95
virtual void PushEvent(UPEvent ev) override
PublicToolHandleArray< IPhysicsInitializationTool > m_physicsInitializationTools
Definition G4RunTool.h:80
Gaudi::Property< std::string > m_fieldMap
Definition G4RunTool.h:86
ServiceHandle< G4UA::IUserActionSvc > m_userActionSvc
Definition G4RunTool.h:76
StateSynchronization m_statusSync
Definition G4RunTool.h:118
ToolHandle< IDetectorConstructionTool > m_detConstruction
Definition G4RunTool.h:78
void commandLog(int returnCode, const std::string &commandString) const
This command prints a message about a G4Command depending on its returnCode.
Gaudi::Property< std::string > m_physList
Definition G4RunTool.h:85
int ev
Definition globals.cxx:25
void SetStatus(const Status &)
Definition G4RunTool.cxx:77
std::condition_variable m_cv
Definition G4RunTool.h:104
void WaitStatus(const Status &)
Definition G4RunTool.cxx:85