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:

Classes

struct  EventQueueSynchronization
struct  StateSynchronization

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 void WaitBeginRun () override
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 ()
 Geant4 main thread function, this is executed in a separate thread and blocks on BeamOn.
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
StateSynchronization m_statusSync
EventQueueSynchronization m_eventQueueSync

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 235 of file G4RunTool.cxx.

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_DEBUG(x)

◆ finalize()

StatusCode G4RunTool::finalize ( )
finaloverridevirtual

Definition at line 41 of file G4RunTool.cxx.

41 {
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}
std::unique_ptr< std::thread > m_thread
Definition G4RunTool.h:115
Gaudi::Property< int > m_nG4threads
Definition G4RunTool.h:89
virtual void PushEvent(UPEvent ev) override
StateSynchronization m_statusSync
Definition G4RunTool.h:118

◆ Geant4main()

void G4RunTool::Geant4main ( )
private

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

Definition at line 124 of file G4RunTool.cxx.

124 {
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}
#define ATH_MSG_INFO(x)
ServiceHandle< IPhysicsListSvc > m_physicsListSvc
Definition G4RunTool.h:74
Gaudi::Property< std::vector< std::string > > m_g4commands
Definition G4RunTool.h:87
Gaudi::Property< int > m_nG4eventsPerRun
Definition G4RunTool.h:90
ServiceHandle< IUserLimitsSvc > m_userLimitsSvc
Definition G4RunTool.h:75
Gaudi::Property< std::string > m_libList
Definition G4RunTool.h:84
ToolHandleArray< G4UA::IUserActionTool > m_actionTools
Definition G4RunTool.h:79
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
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

◆ GetEvent()

auto G4RunTool::GetEvent ( )
overridevirtual

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

Definition at line 110 of file G4RunTool.cxx.

110 {
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}
EventQueueSynchronization m_eventQueueSync
Definition G4RunTool.h:121
int ev
Definition globals.cxx:25

◆ 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 24 of file G4RunTool.cxx.

24 {
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}
void Geant4main()
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 68 of file G4RunTool.cxx.

◆ PushEvent()

void G4RunTool::PushEvent ( UPEvent ev)
overridevirtual

Definition at line 101 of file G4RunTool.cxx.

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

◆ Size()

size_t G4RunTool::Size ( ) const
overridevirtual

Definition at line 95 of file G4RunTool.cxx.

95 {
96 std::scoped_lock lk(m_eventQueueSync.m_mutex);
97 return m_eventQueueSync.m_events.size();
98}

◆ WaitBeginRun()

void G4RunTool::WaitBeginRun ( )
overridevirtual

Definition at line 73 of file G4RunTool.cxx.

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 79 of file G4RunTool.h.

79{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 82 of file G4RunTool.h.

82{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 78 of file G4RunTool.h.

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

◆ m_eventQueueSync

EventQueueSynchronization G4RunTool::m_eventQueueSync
private

Definition at line 121 of file G4RunTool.h.

◆ m_fieldMap

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

Definition at line 86 of file G4RunTool.h.

86{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 87 of file G4RunTool.h.

87{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 84 of file G4RunTool.h.

84{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 90 of file G4RunTool.h.

90{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 89 of file G4RunTool.h.

89{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 80 of file G4RunTool.h.

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

◆ m_physicsListSvc

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

Definition at line 74 of file G4RunTool.h.

74{this, "PhysicsListSvc", "PhysicsListSvc"};

◆ m_physList

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

Definition at line 85 of file G4RunTool.h.

85{this, "Physics", "", ""};

◆ m_statusSync

StateSynchronization G4RunTool::m_statusSync
private

Definition at line 118 of file G4RunTool.h.

◆ m_thread

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

Definition at line 115 of file G4RunTool.h.

◆ m_userActionSvc

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

Definition at line 76 of file G4RunTool.h.

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

◆ m_userLimitsSvc

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

Definition at line 75 of file G4RunTool.h.

75{this, "UserLimitsSvc", "UserLimitsSvc"};

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