ATLAS Offline Software
Loading...
Searching...
No Matches
G4RunTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "G4RunTool.h"
7
8// Gaudi includes
9#include "GaudiKernel/ServiceHandle.h"
10
11// header files from Geant4
12#include "G4MTRunManager.hh"
13#include "G4StateManager.hh"
14#include "G4UImanager.hh"
15#include "G4EventManager.hh"
16
18
19// Standard library
20#include <exception>
21#include <memory>
22#include <stdexcept>
23
26
27 // Gaudi will automatically initialize child tools once this tool is initialized.
28 // We want these child tools to be initialized in the Geant4 main thread,
29 // disable() will tell Gaudi not to initialize them now.
30 // Ideally we'd move the initialization that needs to happen in the Geant4 main thread out of initialize
31 // and into a separate method called from Geant4main.
32 m_detConstruction.disable();
33 for(auto& tool : m_actionTools) {
34 tool.disable();
35 }
36
37 m_thread = std::make_unique<std::thread>(&G4RunTool::Geant4main, this);
38 ATH_MSG_DEBUG("Geant4main thread created, id=" << m_thread->get_id() << ", now waiting for G4 run manager");
39 return StatusCode::SUCCESS;
40}
41
43 // Signal finalization to G4 threads
44 m_statusSync.RequestFinalize();
45
46 // Wake every worker blocked waiting for an Athena event. GetEvent() returns
47 // nullptr once the queue is closed, causing SyncEventAction to abort the run.
48 m_eventQueue.Close();
49
50 if (m_thread) {
51 try {
52 if(m_thread->joinable()) {
53 m_thread->join();
54 ATH_MSG_INFO("Geant4 main thread ended");
55 }
56
57 }
58 catch(const std::exception& e) {
59 ATH_MSG_ERROR("Failure in G4RunTool::finalize, joining Geant4 main thread:" << e.what());
60 }
61 }
62
63 return StatusCode::SUCCESS;
64}
65
66//---------------------------------------------------------------------------
67// Status management
68//---------------------------------------------------------------------------
69
70// Notify Athena that Geant4 is ready to start a run (called by Geant4 BeginOfRunAction).
72 m_statusSync.NotifyBeginRun();
73}
74
75// Wait until Geant4 is ready to start a run (called by Athena initialize).
77 std::string failureMessage;
78 if (!m_statusSync.WaitBeginRun(failureMessage)) {
79 ATH_MSG_ERROR("Geant4 failed to start: " << failureMessage);
80 return StatusCode::FAILURE;
81 }
82 return StatusCode::SUCCESS;
83}
84
85//---------------------------------------------------------------------------
86// Queue management
87//---------------------------------------------------------------------------
88
89// Check the size of the event queue
90size_t G4RunTool::Size() const {
91 return m_eventQueue.Size();
92}
93
94// Push an event to the queue (called from Athena threads)
95void G4RunTool::PushEvent(UPEvent ev) {
96 m_eventQueue.PushEvent(std::move(ev));
97}
98
100auto G4RunTool::GetEvent() -> UPEvent {
101 return m_eventQueue.GetEvent();
102}
103
104//---------------------------------------------------------------------------
105// Geant4 thread function
106//---------------------------------------------------------------------------
107
108// G4 main thread management
109void G4RunTool::Geant4main() noexcept {
110 std::unique_ptr<G4MTRunManager> runManager;
111 try {
112 // Keep ownership outside the exception boundary. On failure, the event
113 // queue must be closed before the run manager tries to join workers that
114 // may still be blocked in GetEvent().
115 runManager = std::make_unique<G4MTRunManager>();
116 Geant4mainImpl(*runManager);
117 }
118 catch(const std::exception& error) {
119 m_statusSync.Fail(error.what());
120 ATH_MSG_ERROR("Exception in Geant4 main thread: " << error.what());
121 }
122 catch(...) {
123 m_statusSync.Fail("Unknown exception in Geant4 main thread");
124 ATH_MSG_ERROR("Unknown exception in Geant4 main thread");
125 }
126
127 // Teardown ordering is significant: wake blocked workers, join them while
128 // destroying the run manager, publish the terminal lifecycle state, and
129 // only then release Athena event waiters and their associated resources.
130 m_eventQueue.Close();
131 runManager.reset();
132 m_statusSync.NotifyThreadExit();
133 m_eventQueue.CompleteOutstandingEvents();
134}
135
136void G4RunTool::Geant4mainImpl(G4MTRunManager& runManager) {
137
138 ATH_MSG_INFO("Geant4 main thread starts with id " << std::this_thread::get_id());
139
140 runManager.SetNumberOfThreads(m_nG4threads);
141 constexpr int seedFirstEventOnly = 1; // name the magic number
142 // we will take care of reseeding each event, turn off Geant4 reseeding
143 runManager.SetSeedOncePerCommunication(seedFirstEventOnly);
144
145 if(m_detConstruction.retrieve().isFailure()) {
146 ATH_MSG_ERROR("Failed to retrieve DetectorGeometryService");
147 m_statusSync.Fail("Failed to retrieve DetectorGeometryService");
148 return;
149 }
150
151 if(m_physicsListSvc.retrieve().isFailure()) {
152 ATH_MSG_ERROR("Failed to retrieve PhysicsListService");
153 m_statusSync.Fail("Failed to retrieve PhysicsListService");
154 return;
155 }
156
157 if(m_userActionSvc.retrieve().isFailure()) {
158 ATH_MSG_ERROR("Failed to retrieve UserActionService");
159 m_statusSync.Fail("Failed to retrieve UserActionService");
160 return;
161 }
162
163 if(m_actionTools.retrieve().isFailure()) {
164 ATH_MSG_ERROR("Failed to retrieve ActionTools");
165 m_statusSync.Fail("Failed to retrieve ActionTools");
166 return;
167 }
168
169 // Initialize action tools for G4RunTool
170 for (const auto& action_tool : m_actionTools) {
171 ATH_MSG_INFO("retrieving action tool " + action_tool.name());
172 if (m_userActionSvc->addActionTool(action_tool).isFailure()) {
173 throw std::runtime_error("Failed to add action tool " + action_tool.name());
174 }
175 }
176 // Set the user action service for the G4UA service
177 // Having a ServiceHandle<IG4RunTool> would be a circular dependency which is not supported...
178 m_userActionSvc->G4RunTool(this);
179
180 // Many of the objects created here must be created in the same thread as the run manager
181 runManager.SetUserInitialization(m_detConstruction->GetDetectorConstruction().release());
182
183 // The actual physics list object must be created in the same thread as the run manager
184 runManager.SetUserInitialization(m_physicsListSvc->GetPhysicsList());
185
186 // Set global physics-list options as soon as the list has been created and
187 // before any pre-initialization UI commands are applied.
188 m_physicsListSvc->SetPhysicsListOptions();
189
190 runManager.SetUserInitialization(
191 std::make_unique<G4RunToolWorkerThreadInitialization>().release());
192 runManager.SetUserInitialization(
193 std::make_unique<G4AtlasActionInitialization>(m_userActionSvc.get()).release());
194
195 // G4 user interface commands
196 G4UImanager *ui = G4UImanager::GetUIpointer();
197
198 // Load custom libraries
199 if (!m_libList.empty()) {
200 ATH_MSG_INFO("G4AtlasAlg specific libraries requested ");
201 std::string temp="/load "+m_libList;
202 ui->ApplyCommand(temp);
203 }
204 // Load custom physics
205 if (!m_physList.empty()) {
206 ATH_MSG_INFO("requesting a specific physics list "<< m_physList);
207 std::string temp="/Physics/GetPhysicsList "+m_physList;
208 ui->ApplyCommand(temp);
209 }
210 // Load custom magnetic field
211 if (!m_fieldMap.empty()) {
212 ATH_MSG_INFO("requesting a specific field map "<< m_fieldMap);
213 ATH_MSG_INFO("the field is initialized straight away");
214 std::string temp="/MagneticField/Select "+m_fieldMap;
215 ui->ApplyCommand(temp);
216 ui->ApplyCommand("/MagneticField/Initialize");
217 }
218
219 // Send UI commands
220 ATH_MSG_DEBUG("G4 Command: Trying at the end of initializeOnce()");
221 for (const auto& g4command : m_g4commands) {
222 int returnCode = ui->ApplyCommand( g4command );
223 commandLog(returnCode, g4command);
224 }
225
226 // Initialize run
227 runManager.Initialize();
228
229 // Process-specific UI commands require the processes to exist first. They
230 // are forwarded to the workers with the command stack at the next BeamOn.
231 m_physicsListSvc->SetPhysicsProcessOptions();
232
233 ATH_MSG_INFO("Initializing " << m_physicsInitializationTools.size() << " physics initialization tools");
234 for(auto& physicsTool : m_physicsInitializationTools) {
235 if (physicsTool->initializePhysics().isFailure()) {
236 throw std::runtime_error("Failed to initialize physics with tool " + physicsTool.name());
237 }
238 }
239 // Retrieve core services needed for G4 main thread
240 if(m_userLimitsSvc.retrieve().isFailure()) {
241 throw std::runtime_error("Could not initialize ATLAS UserLimitsSvc!");
242 }
243
244 ATH_MSG_INFO("Geant4 initialization done, BeamOn...");
245
246 // Repeat BeamOn as long as athena event loop is not finished
247 while (!m_statusSync.StopRequested()) {
248 runManager.BeamOn(m_nG4eventsPerRun);
249 }
250}
251
252void G4RunTool::commandLog(int returnCode, const std::string& commandString) const
253{
254 switch(returnCode) {
255 case 0: { ATH_MSG_DEBUG("G4 Command: " << commandString << " - Command Succeeded"); } break;
256 case 100: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Command Not Found!"); } break;
257 case 200: {
258 auto* stateManager = G4StateManager::GetStateManager();
259 ATH_MSG_DEBUG("G4 Command: " << commandString << " - Illegal Application State (" <<
260 stateManager->GetStateString(stateManager->GetCurrentState()) << ")!");
261 } break;
262 case 300: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Parameter Out of Range!"); } break;
263 case 400: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Parameter Unreadable!"); } break;
264 case 500: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Parameter Out of Candidates!"); } break;
265 case 600: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Alias Not Found!"); } break;
266 default: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Unknown Status!"); } break;
267 }
268
269}
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_INFO(x,...)
ServiceHandle< IPhysicsListSvc > m_physicsListSvc
Definition G4RunTool.h:77
virtual StatusCode finalize() override final
Definition G4RunTool.cxx:42
std::unique_ptr< std::thread > m_thread
Definition G4RunTool.h:96
Gaudi::Property< std::vector< std::string > > m_g4commands
Definition G4RunTool.h:90
Gaudi::Property< int > m_nG4threads
Definition G4RunTool.h:92
Gaudi::Property< int > m_nG4eventsPerRun
Definition G4RunTool.h:93
virtual void NotifyBeginRun() override
Notify Athena that Geant4 is ready to start a run.
Definition G4RunTool.cxx:71
ServiceHandle< IUserLimitsSvc > m_userLimitsSvc
Definition G4RunTool.h:78
void Geant4mainImpl(G4MTRunManager &runManager)
Implementation called inside the Geant4 main thread exception boundary.
void Geant4main() noexcept
Geant4 main thread function, this is executed in a separate thread and blocks on BeamOn.
G4RunToolStateSynchronization m_statusSync
Definition G4RunTool.h:99
virtual UPEvent GetEvent() override
Get an event from the queue (called from Geant4 threads).
Gaudi::Property< std::string > m_libList
Definition G4RunTool.h:87
ToolHandleArray< G4UA::IUserActionTool > m_actionTools
Definition G4RunTool.h:82
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:25
virtual size_t Size() const override
Definition G4RunTool.cxx:90
virtual void PushEvent(UPEvent ev) override
Definition G4RunTool.cxx:95
PublicToolHandleArray< IPhysicsInitializationTool > m_physicsInitializationTools
Definition G4RunTool.h:83
virtual StatusCode WaitBeginRun() override
Wait for BeginOfRun, or return failure if the Geant4 thread stops first.
Definition G4RunTool.cxx:76
Gaudi::Property< std::string > m_fieldMap
Definition G4RunTool.h:89
ServiceHandle< G4UA::IUserActionSvc > m_userActionSvc
Definition G4RunTool.h:79
ToolHandle< IDetectorConstructionTool > m_detConstruction
Definition G4RunTool.h:81
void commandLog(int returnCode, const std::string &commandString) const
This command prints a message about a G4Command depending on its returnCode.
G4RunToolEventQueue m_eventQueue
Definition G4RunTool.h:102
Gaudi::Property< std::string > m_physList
Definition G4RunTool.h:88
static std::string release
Definition computils.h:50
int ev
Definition globals.cxx:25