ATLAS Offline Software
Loading...
Searching...
No Matches
G4RunTool Class Reference

Front-end service for initializing and interacting with the Geant4 run. More...

#include <G4RunTool.h>

Inheritance diagram for G4RunTool:
Collaboration diagram for G4RunTool:

Public Member Functions

virtual StatusCode initialize () override final
 Initialize and start the Geant4 main thread, then wait until Geant4 is ready to start the run.
virtual StatusCode finalize () override final
virtual void NotifyBeginRun () override
 Notify Athena that Geant4 is ready to start a run.
virtual StatusCode WaitBeginRun () override
 Wait for BeginOfRun, or return failure if the Geant4 thread stops first.
virtual size_t Size () const override
virtual void PushEvent (UPEvent ev) override
virtual UPEvent GetEvent () override
 Get an event from the queue (called from Geant4 threads).

Private Member Functions

void Geant4main () noexcept
 Geant4 main thread function, this is executed in a separate thread and blocks on BeamOn.
void Geant4mainImpl (G4MTRunManager &runManager)
 Implementation called inside the Geant4 main thread exception boundary.
void commandLog (int returnCode, const std::string &commandString) const
 This command prints a message about a G4Command depending on its returnCode.

Private Attributes

ServiceHandle< IPhysicsListSvcm_physicsListSvc {this, "PhysicsListSvc", "PhysicsListSvc"}
ServiceHandle< IUserLimitsSvcm_userLimitsSvc {this, "UserLimitsSvc", "UserLimitsSvc"}
ServiceHandle< G4UA::IUserActionSvcm_userActionSvc {this, "UserActionSvc", "G4UA::UserActionSvc"}
ToolHandle< IDetectorConstructionToolm_detConstruction {this, "DetectorConstruction", "", "Tool handle of the DetectorConstruction"}
ToolHandleArray< G4UA::IUserActionToolm_actionTools {this, "UserActionTools", {}, "User action tools to be added to the G4 Action service."}
PublicToolHandleArray< IPhysicsInitializationToolm_physicsInitializationTools {this, "PhysicsInitializationTools", {}, "Physics initialization happening after Geant4 initialization"}
Gaudi::Property< bool > m_activateParallelGeometries {this, "ActivateParallelWorlds", false, "Toggle on/off the G4 parallel geometry system"}
Gaudi::Property< std::string > m_libList {this, "Dll", "", ""}
Gaudi::Property< std::string > m_physList {this, "Physics", "", ""}
Gaudi::Property< std::string > m_fieldMap {this, "FieldMap", "", ""}
Gaudi::Property< std::vector< std::string > > m_g4commands {this, "G4Commands", {}, "Commands to be sent to Geant4 UI at initialization"}
Gaudi::Property< int > m_nG4threads {this, "NG4threads", 1, "Number of parallel G4 worker threads to launch"}
Gaudi::Property< int > m_nG4eventsPerRun {this, "NG4eventsPerRun", 100000, "Number of G4 events foreseen for each Run"}
std::unique_ptr< std::thread > m_thread
G4RunToolStateSynchronization m_statusSync
G4RunToolEventQueue m_eventQueue

Detailed Description

Front-end service for initializing and interacting with the Geant4 run.

This public tool will initialize Geant4 in a separate thread which will block until the end of the job. All the services constructing Geant4 objects (detector construction, physics list, etc.) are retrieved from the Geant4 main thread during initialize().

This tool's initialize() will spawn the Geant4 main thread, but doesn't wait for Geant4 to be initialized before returning. The reason is that the Geant4 main thread needs to initialize tools, and Gaudi tool initialization is protected by a recursive mutex, which would lead to a deadlock. Algorithms using this tool should call WaitBeginRun() in their initialize function to ensure Geant4 is ready.

Athena can push events to Geant4 using the PushEvent method, and Geant4 will retrieve them using GetEvent in the generator action.

Author
Julien Esseiva julie.nosp@m.n.es.nosp@m.seiva.nosp@m.@cer.nosp@m.n.ch

Definition at line 48 of file G4RunTool.h.

Member Function Documentation

◆ commandLog()

void G4RunTool::commandLog ( int returnCode,
const std::string & commandString ) const
private

This command prints a message about a G4Command depending on its returnCode.

Definition at line 252 of file G4RunTool.cxx.

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,...)

◆ finalize()

StatusCode G4RunTool::finalize ( )
finaloverridevirtual

Definition at line 42 of file G4RunTool.cxx.

42 {
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}
#define ATH_MSG_INFO(x,...)
std::unique_ptr< std::thread > m_thread
Definition G4RunTool.h:96
G4RunToolStateSynchronization m_statusSync
Definition G4RunTool.h:99
G4RunToolEventQueue m_eventQueue
Definition G4RunTool.h:102

◆ Geant4main()

void G4RunTool::Geant4main ( )
privatenoexcept

Geant4 main thread function, this is executed in a separate thread and blocks on BeamOn.

Definition at line 109 of file G4RunTool.cxx.

109 {
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}
void Geant4mainImpl(G4MTRunManager &runManager)
Implementation called inside the Geant4 main thread exception boundary.

◆ Geant4mainImpl()

void G4RunTool::Geant4mainImpl ( G4MTRunManager & runManager)
private

Implementation called inside the Geant4 main thread exception boundary.

Definition at line 136 of file G4RunTool.cxx.

136 {
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}
ServiceHandle< IPhysicsListSvc > m_physicsListSvc
Definition G4RunTool.h:77
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
ServiceHandle< IUserLimitsSvc > m_userLimitsSvc
Definition G4RunTool.h:78
Gaudi::Property< std::string > m_libList
Definition G4RunTool.h:87
ToolHandleArray< G4UA::IUserActionTool > m_actionTools
Definition G4RunTool.h:82
PublicToolHandleArray< IPhysicsInitializationTool > m_physicsInitializationTools
Definition G4RunTool.h:83
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.
Gaudi::Property< std::string > m_physList
Definition G4RunTool.h:88
static std::string release
Definition computils.h:50

◆ GetEvent()

auto G4RunTool::GetEvent ( )
overridevirtual

Get an event from the queue (called from Geant4 threads).

Definition at line 100 of file G4RunTool.cxx.

100 {
101 return m_eventQueue.GetEvent();
102}

◆ initialize()

StatusCode G4RunTool::initialize ( )
finaloverridevirtual

Initialize and start the Geant4 main thread, then wait until Geant4 is ready to start the run.

Definition at line 25 of file G4RunTool.cxx.

25 {
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}
void Geant4main() noexcept
Geant4 main thread function, this is executed in a separate thread and blocks on BeamOn.

◆ NotifyBeginRun()

void G4RunTool::NotifyBeginRun ( )
overridevirtual

Notify Athena that Geant4 is ready to start a run.

Definition at line 71 of file G4RunTool.cxx.

71 {
72 m_statusSync.NotifyBeginRun();
73}

◆ PushEvent()

void G4RunTool::PushEvent ( UPEvent ev)
overridevirtual

Definition at line 95 of file G4RunTool.cxx.

95 {
96 m_eventQueue.PushEvent(std::move(ev));
97}
int ev
Definition globals.cxx:25

◆ Size()

size_t G4RunTool::Size ( ) const
overridevirtual

Definition at line 90 of file G4RunTool.cxx.

90 {
91 return m_eventQueue.Size();
92}

◆ WaitBeginRun()

StatusCode G4RunTool::WaitBeginRun ( )
overridevirtual

Wait for BeginOfRun, or return failure if the Geant4 thread stops first.

Definition at line 76 of file G4RunTool.cxx.

76 {
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}

Member Data Documentation

◆ m_actionTools

ToolHandleArray<G4UA::IUserActionTool> G4RunTool::m_actionTools {this, "UserActionTools", {}, "User action tools to be added to the G4 Action service."}
private

Definition at line 82 of file G4RunTool.h.

82{this, "UserActionTools", {}, "User action tools to be added to the G4 Action service."};

◆ m_activateParallelGeometries

Gaudi::Property<bool> G4RunTool::m_activateParallelGeometries {this, "ActivateParallelWorlds", false, "Toggle on/off the G4 parallel geometry system"}
private

Definition at line 85 of file G4RunTool.h.

85{this, "ActivateParallelWorlds", false, "Toggle on/off the G4 parallel geometry system"};

◆ m_detConstruction

ToolHandle<IDetectorConstructionTool> G4RunTool::m_detConstruction {this, "DetectorConstruction", "", "Tool handle of the DetectorConstruction"}
private

Definition at line 81 of file G4RunTool.h.

81{this, "DetectorConstruction", "", "Tool handle of the DetectorConstruction"};

◆ m_eventQueue

G4RunToolEventQueue G4RunTool::m_eventQueue
private

Definition at line 102 of file G4RunTool.h.

◆ m_fieldMap

Gaudi::Property<std::string> G4RunTool::m_fieldMap {this, "FieldMap", "", ""}
private

Definition at line 89 of file G4RunTool.h.

89{this, "FieldMap", "", ""};

◆ m_g4commands

Gaudi::Property<std::vector<std::string> > G4RunTool::m_g4commands {this, "G4Commands", {}, "Commands to be sent to Geant4 UI at initialization"}
private

Definition at line 90 of file G4RunTool.h.

90{this, "G4Commands", {}, "Commands to be sent to Geant4 UI at initialization"};

◆ m_libList

Gaudi::Property<std::string> G4RunTool::m_libList {this, "Dll", "", ""}
private

Definition at line 87 of file G4RunTool.h.

87{this, "Dll", "", ""};

◆ m_nG4eventsPerRun

Gaudi::Property<int> G4RunTool::m_nG4eventsPerRun {this, "NG4eventsPerRun", 100000, "Number of G4 events foreseen for each Run"}
private

Definition at line 93 of file G4RunTool.h.

93{this, "NG4eventsPerRun", 100000, "Number of G4 events foreseen for each Run"};

◆ m_nG4threads

Gaudi::Property<int> G4RunTool::m_nG4threads {this, "NG4threads", 1, "Number of parallel G4 worker threads to launch"}
private

Definition at line 92 of file G4RunTool.h.

92{this, "NG4threads", 1, "Number of parallel G4 worker threads to launch"};

◆ m_physicsInitializationTools

PublicToolHandleArray<IPhysicsInitializationTool> G4RunTool::m_physicsInitializationTools {this, "PhysicsInitializationTools", {}, "Physics initialization happening after Geant4 initialization"}
private

Definition at line 83 of file G4RunTool.h.

83{this, "PhysicsInitializationTools", {}, "Physics initialization happening after Geant4 initialization"};

◆ m_physicsListSvc

ServiceHandle<IPhysicsListSvc> G4RunTool::m_physicsListSvc {this, "PhysicsListSvc", "PhysicsListSvc"}
private

Definition at line 77 of file G4RunTool.h.

77{this, "PhysicsListSvc", "PhysicsListSvc"};

◆ m_physList

Gaudi::Property<std::string> G4RunTool::m_physList {this, "Physics", "", ""}
private

Definition at line 88 of file G4RunTool.h.

88{this, "Physics", "", ""};

◆ m_statusSync

G4RunToolStateSynchronization G4RunTool::m_statusSync
private

Definition at line 99 of file G4RunTool.h.

◆ m_thread

std::unique_ptr<std::thread> G4RunTool::m_thread
private

Definition at line 96 of file G4RunTool.h.

◆ m_userActionSvc

ServiceHandle<G4UA::IUserActionSvc> G4RunTool::m_userActionSvc {this, "UserActionSvc", "G4UA::UserActionSvc"}
private

Definition at line 79 of file G4RunTool.h.

79{this, "UserActionSvc", "G4UA::UserActionSvc"};

◆ m_userLimitsSvc

ServiceHandle<IUserLimitsSvc> G4RunTool::m_userLimitsSvc {this, "UserLimitsSvc", "UserLimitsSvc"}
private

Definition at line 78 of file G4RunTool.h.

78{this, "UserLimitsSvc", "UserLimitsSvc"};

The documentation for this class was generated from the following files: