ATLAS Offline Software
Loading...
Searching...
No Matches
G4LegacyTransportTool.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// class header
7
8//package includes
13#include "ISFFluxRecorder.h"
14
15// ISF classes
18
19// Athena classes
25
26// HepMC classes
28
29// Geant4 classes
30#include "G4ChargedGeantino.hh"
31#include "G4Event.hh"
32#include "G4Geantino.hh"
33#include "G4LorentzVector.hh"
34#include "G4ParallelWorldPhysics.hh"
35#include "G4ParticleTable.hh"
36#include "G4PrimaryParticle.hh"
37#include "G4PrimaryVertex.hh"
38#include "G4SDManager.hh"
39#include "G4ScoringManager.hh"
40#include "G4StateManager.hh"
41#include "G4Timer.hh"
42#include "G4Trajectory.hh"
43#include "G4TransportationManager.hh"
44#include "G4UImanager.hh"
45#include "G4VModularPhysicsList.hh"
46#include "G4VUserPhysicsList.hh"
47
48// standard library
49#include <memory>
50#include <mutex>
51static std::once_flag initializeOnceFlag;
52static std::once_flag finalizeOnceFlag;
53
54//________________________________________________________________________
56 const std::string& name,
57 const IInterface* parent )
58 : ISF::BaseSimulatorG4Tool(type, name, parent)
59{
60 //declareProperty("KillAllNeutrinos", m_KillAllNeutrinos=true);
61 //declareProperty("KillLowEPhotons", m_KillLowEPhotons=-1.);
62}
63
64//________________________________________________________________________
66{
67 ATH_MSG_VERBOSE("initialize");
68
70
71 // create G4Timers if enabled
72 if (m_doTiming) {
73 m_runTimer = new G4Timer();
74 m_eventTimer = new G4Timer();
75 m_runTimer->Start();
76 }
77
78 // Create the scoring manager if requested
79 if (m_recordFlux) G4ScoringManager::GetScoringManager();
80
81 // One-time initialization
82 try {
83 std::call_once(initializeOnceFlag, &iGeant4::G4LegacyTransportTool::initializeOnce, this);
84 }
85 catch(const std::exception& e) {
86 ATH_MSG_ERROR("Failure in iGeant4::G4LegacyTransportTool::initializeOnce: " << e.what());
87 return StatusCode::FAILURE;
88 }
89
90 ATH_CHECK( m_rndmGenSvc.retrieve() );
91 ATH_CHECK( m_userActionSvc.retrieve() );
92
93 ATH_CHECK(m_senDetTool.retrieve());
94 ATH_CHECK(m_fastSimTool.retrieve());
95
96 ATH_CHECK(m_inputConverter.retrieve());
97
98 return StatusCode::SUCCESS;
99}
100
101//________________________________________________________________________
102void iGeant4::G4LegacyTransportTool::initializeOnce ATLAS_NOT_THREAD_SAFE ()
103{
104 // get G4AtlasRunManager
105 ATH_MSG_DEBUG("initialize G4AtlasRunManager");
106
107 if (m_g4RunManagerHelper.retrieve().isFailure()) {
108 throw std::runtime_error("Could not initialize G4RunManagerHelper!");
109 }
110 ATH_MSG_DEBUG("retrieved "<<m_g4RunManagerHelper);
111 m_pRunMgr = m_g4RunManagerHelper ? m_g4RunManagerHelper->g4RunManager() : nullptr;
112 if (!m_pRunMgr) {
113 throw std::runtime_error("G4RunManagerHelper::g4RunManager() returned nullptr.");
114 }
115
116 if(m_physListSvc.retrieve().isFailure()) {
117 throw std::runtime_error("Could not initialize ATLAS PhysicsListSvc!");
118 }
119 m_physListSvc->SetPhysicsList();
120 ATH_MSG_INFO( "retireving the Detector Construction tool" );
121 if(m_detConstruction.retrieve().isFailure()) {
122 throw std::runtime_error("Could not initialize ATLAS DetectorConstruction!");
123 }
124
125 m_pRunMgr->SetRecordFlux( m_recordFlux, std::make_unique<ISFFluxRecorder>() );
126 m_pRunMgr->SetLogLevel( int(msg().level()) ); // Synch log levels
127 m_pRunMgr->SetDetConstructionTool( m_detConstruction.get() );
128 m_pRunMgr->SetPhysListSvc(m_physListSvc.typeAndName() );
129 m_pRunMgr->SetQuietMode( m_quietMode );
130 std::unique_ptr<G4AtlasActionInitialization> actionInitialization =
131 std::make_unique<G4AtlasActionInitialization>(&*m_userActionSvc);
132 m_pRunMgr->SetUserInitialization(actionInitialization.release());
133
134 G4UImanager *ui = G4UImanager::GetUIpointer();
135
136 if (!m_libList.empty()) {
137 ATH_MSG_INFO("G4AtlasAlg specific libraries requested ") ;
138 std::string temp="/load "+m_libList;
139 ui->ApplyCommand(temp);
140 }
141
142 if (!m_physList.empty()) {
143 ATH_MSG_INFO("requesting a specific physics list "<< m_physList) ;
144 std::string temp="/Physics/GetPhysicsList "+m_physList;
145 ui->ApplyCommand(temp);
146 }
147
148 if (!m_fieldMap.empty()) {
149 ATH_MSG_INFO("requesting a specific field map "<< m_fieldMap) ;
150 ATH_MSG_INFO("the field is initialized straight away") ;
151 std::string temp="/MagneticField/Select "+m_fieldMap;
152 ui->ApplyCommand(temp);
153 ui->ApplyCommand("/MagneticField/Initialize");
154 }
155
156 // Send UI commands
157 ATH_MSG_DEBUG("G4 Command: Trying at the end of initializeOnce()");
158 for (const auto& g4command : m_g4commands) {
159 int returnCode = ui->ApplyCommand( g4command );
160 commandLog(returnCode, g4command);
161 }
162
163 // Code from G4AtlasSvc
164 auto* rm = G4RunManager::GetRunManager();
165 if(!rm) {
166 throw std::runtime_error("Run manager retrieval has failed");
167 }
168 rm->Initialize(); // Initialization differs slightly in multi-threading.
169 // TODO: add more details about why this is here.
170 if(!m_useMT && rm->ConfirmBeamOnCondition()) {
171 rm->RunInitialization();
172 }
173
174 ATH_MSG_INFO("Initializing " << m_physicsInitializationTools.size() << " physics initialization tools");
175 for(auto& physicsTool : m_physicsInitializationTools) {
176 if (physicsTool->initializePhysics().isFailure()) {
177 throw std::runtime_error("Failed to initialize physics with tool " + physicsTool.name());
178 }
179 }
180
181 if(m_userLimitsSvc.retrieve().isFailure()) {
182 throw std::runtime_error("Could not initialize ATLAS UserLimitsSvc!");
183 }
184
185 if (m_activateParallelGeometries) {
186 G4VModularPhysicsList* thePhysicsList=dynamic_cast<G4VModularPhysicsList*>(m_physListSvc->GetPhysicsList());
187 if (!thePhysicsList) {
188 throw std::runtime_error("Failed dynamic_cast!! this is not a G4VModularPhysicsList!");
189 }
190#if G4VERSION_NUMBER >= 1010
191 std::vector<std::string>& parallelWorldNames=m_detConstruction->GetParallelWorldNames();
192 for (auto& it: parallelWorldNames) {
193 thePhysicsList->RegisterPhysics(new G4ParallelWorldPhysics(it,true));
194 }
195#endif
196 }
197
198 return;
199}
200
201//________________________________________________________________________
203{
204 ATH_MSG_VERBOSE("++++++++++++ ISF G4 G4LegacyTransportTool finalized ++++++++++++");
205
206 // One time finalization
207 try {
209 }
210 catch(const std::exception& e) {
211 ATH_MSG_ERROR("Failure in iGeant4::G4LegacyTransportTool::finalizeOnce: " << e.what());
212 return StatusCode::FAILURE;
213 }
214
215 if (m_doTiming) {
216 m_runTimer->Stop();
217 float runTime=m_runTimer->GetUserElapsed()+m_runTimer->GetSystemElapsed();
218 float avgTimePerEvent=(m_nrOfEntries>1) ? m_accumulatedEventTime/(m_nrOfEntries-1.) : runTime;
219 float sigma=( m_nrOfEntries>2) ? std::sqrt((m_accumulatedEventTimeSq/float(m_nrOfEntries-1)-
220 avgTimePerEvent*avgTimePerEvent)/float(m_nrOfEntries-2)) : 0;
221 ATH_MSG_INFO("*****************************************"<<endmsg<<
222 "** **"<<endmsg<<
223 " End of run - time spent is "<<std::setprecision(4) <<
224 runTime<<endmsg<<
225 " Average time per event was "<<std::setprecision(4) <<
226 avgTimePerEvent <<" +- "<< std::setprecision(4) << sigma<<endmsg<<
227 "** **"<<endmsg<<
228 "*****************************************");
229 }
230
231 return StatusCode::SUCCESS;
232}
233
234//________________________________________________________________________
236{
237 ATH_MSG_DEBUG("\t terminating the current G4 run");
238
239 m_pRunMgr->RunTermination();
240
241 return;
242}
243
244//________________________________________________________________________
246 const EventContext& ctx, ISF::ISFParticle& isp,
247 ISF::ISFParticleContainer& secondaries,
248 McEventCollection* mcEventCollection, std::shared_ptr<HitCollectionMap> hitCollections) {
249
250 // give a screen output that you entered Geant4SimSvc
251 ATH_MSG_VERBOSE( "Particle " << isp << " received for simulation." );
252
254 // wrap the given ISFParticle into a STL vector of ISFParticles with length 1
255 // (minimizing code duplication)
256 const ISF::ISFParticleVector ispVector(1, &isp);
257 StatusCode success = this->simulateVector(ctx, ispVector, secondaries,
258 mcEventCollection, hitCollections);
259 ATH_MSG_VERBOSE( "Simulation done" );
260
261 // Geant4 call done
262 return success;
263}
264
265//________________________________________________________________________
267 const EventContext& ctx, const ISF::ISFParticleVector& particles,
268 ISF::ISFParticleContainer& secondaries,
269 McEventCollection* mcEventCollection, std::shared_ptr<HitCollectionMap> hitCollections,
271
272 ATH_MSG_DEBUG (name() << ".simulateVector(...) : Received a vector of " << particles.size() << " particles for simulation.");
274 // Lambda prevents using the unique_ptr
275 bool abort = [&] ATLAS_NOT_THREAD_SAFE {
276 auto eventInfo = std::make_unique<AtlasG4EventUserInfo>(ctx);
277 eventInfo->SetHitCollectionMap(hitCollections);
278
279 auto inputEvent = std::make_unique<G4Event>(ctx.eventID().event_number());
280 inputEvent->SetUserInformation(eventInfo.release());
281
282 m_inputConverter->ISF_to_G4Event(*inputEvent, particles,
283 genEvent(mcEventCollection));
284
285 ATH_MSG_DEBUG("Calling ISF_Geant4 ProcessEvent");
286 return m_pRunMgr->ProcessEvent(inputEvent.release());
287 }();
288
289 if (abort) {
290 ATH_MSG_WARNING("Event was aborted !! ");
291 return StatusCode::FAILURE;
292 }
293
294
295 // not implemented yet... need to get particle stack from Geant4 and convert to ISFParticle
296 ATH_MSG_VERBOSE( "Simulation done" );
297
298 Slot& slot = *m_slots;
299 Slot::lock_t lock (slot.m_mutex);
300
301 for (auto* cisp : particles) {
302 // return any secondaries associated with this particle
303 auto searchResult = slot.m_secondariesMap.find( cisp );
304 if ( searchResult == slot.m_secondariesMap.end() ) {
305
306 ATH_MSG_VERBOSE( "Found no secondaries" );
307
308 } else {
309
310 ATH_MSG_VERBOSE( "Found secondaries: " << searchResult->second.size() );
311 secondaries.splice( end(secondaries), std::move(searchResult->second) ); //append vector
312 slot.m_secondariesMap.erase( searchResult );
313 }
314 }
315 // Geant4 call done
316 return StatusCode::SUCCESS;
317}
318
319//________________________________________________________________________
321 const EventContext& ctx, HitCollectionMap& hitCollections) {
322 ATH_MSG_DEBUG ( "setup Event" );
323
324 // Set the RNG to use for this event. We need to reset it for MT jobs
325 // because of the mismatch between Gaudi slot-local and G4 thread-local RNG.
326 ATHRNG::RNGWrapper* rngWrapper = m_rndmGenSvc->getEngine(this, m_randomStreamName);
327 rngWrapper->setSeed( m_randomStreamName, ctx );
328 G4Random::setTheEngine(rngWrapper->getEngine(ctx));
329 ATH_CHECK(m_senDetTool->BeginOfAthenaEvent(hitCollections));
330 ATH_CHECK(m_userActionSvc->BeginOfAthenaEvent(hitCollections));
331
333 if (m_doTiming) m_eventTimer->Start();
334
335 // make sure SD collections are properly initialized in every Athena event
336 G4SDManager::GetSDMpointer()->PrepareNewEvent();
337
338 return StatusCode::SUCCESS;
339}
340
341//________________________________________________________________________
343 const EventContext& ctx, HitCollectionMap& hitCollections) {
344 ATH_MSG_DEBUG ( "release Event" );
346
347 /* todo: ELLI: the following is copied in from the PyG4AtlasAlg:
348 -> this somehow needs to be moved into C++
349 and put into releaseEvent() ( or setupEvent() ?)
350
351 from ISF_Geant4Example import AtlasG4Eng
352 from ISF_Geant4Example.ISF_SimFlags import simFlags
353 if self.doFirstEventG4SeedsCheck :
354 if simFlags.SeedsG4.statusOn:
355 rnd = AtlasG4Eng.G4Eng.menu_G4RandomNrMenu()
356 rnd.set_Seed(simFlags.SeedsG4.get_Value())
357 self.doFirstEventG4SeedsCheck = False
358 if self.RndG4Menu.SaveStatus:
359 self.RndG4Menu.Menu.saveStatus('G4Seeds.txt')
360 */
361
362 // print per-event timing info if enabled
363 if (m_doTiming) {
364 m_eventTimer->Stop();
365
366 double eventTime=m_eventTimer->GetUserElapsed()+m_eventTimer->GetSystemElapsed();
367 if (m_nrOfEntries>1) {
368 m_accumulatedEventTime +=eventTime;
369 m_accumulatedEventTimeSq+=eventTime*eventTime;
370 }
371
372 float avgTimePerEvent=(m_nrOfEntries>1) ? m_accumulatedEventTime/(m_nrOfEntries-1.) : eventTime;
373 float sigma=(m_nrOfEntries>2) ? std::sqrt((m_accumulatedEventTimeSq/float(m_nrOfEntries-1)-
374 avgTimePerEvent*avgTimePerEvent)/float(m_nrOfEntries-2)) : 0.;
375
376 ATH_MSG_INFO("\t Run:Event "<<ctx.eventID().run_number()<<":"<<ctx.eventID().event_number() << "\t ("<<m_nrOfEntries<<"th event for this worker) took " << std::setprecision(4) <<
377 eventTime << " s. New average " << std::setprecision(4) <<
378 avgTimePerEvent<<" +- "<<std::setprecision(4) << sigma);
379 }
380
381 ATH_CHECK(m_senDetTool->EndOfAthenaEvent(hitCollections));
382 ATH_CHECK(m_userActionSvc->EndOfAthenaEvent(hitCollections));
383 ATH_CHECK(m_fastSimTool->EndOfAthenaEvent());
384
385 return StatusCode::SUCCESS;
386}
387
388//________________________________________________________________________
389HepMC::GenEvent* iGeant4::G4LegacyTransportTool::genEvent(McEventCollection* mcEventCollection) const
390{
391
392 if(!mcEventCollection) {
393 // retrieve McEventCollection from storegate
395 if (evtStore()->retrieve( mcEventCollection, m_mcEventCollectionName).isFailure()) {
396 ATH_MSG_ERROR( "Unable to retrieve McEventCollection with name=" << m_mcEventCollectionName
397 << ".");
398 return nullptr;
399 }
400 else {
401 ATH_MSG_WARNING( "Fallback. Sucessfully retrieved McEventCollection with name=" << m_mcEventCollectionName);
402 }
403 }
404 else { return nullptr; }
405 }
406 // collect last GenEvent from McEventCollection
407 return mcEventCollection->back();
408}
409
410//________________________________________________________________________
411void iGeant4::G4LegacyTransportTool::commandLog(int returnCode, const std::string& commandString) const
412{
413 switch(returnCode) {
414 case 0: { ATH_MSG_DEBUG("G4 Command: " << commandString << " - Command Succeeded"); } break;
415 case 100: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Command Not Found!"); } break;
416 case 200: {
417 auto* stateManager = G4StateManager::GetStateManager();
418 ATH_MSG_DEBUG("G4 Command: " << commandString << " - Illegal Application State (" <<
419 stateManager->GetStateString(stateManager->GetCurrentState()) << ")!");
420 } break;
421 case 300: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Parameter Out of Range!"); } break;
422 case 400: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Parameter Unreadable!"); } break;
423 case 500: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Parameter Out of Candidates!"); } break;
424 case 600: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Alias Not Found!"); } break;
425 default: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Unknown Status!"); } break;
426 }
427
428}
429
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
static std::once_flag initializeOnceFlag
static std::once_flag finalizeOnceFlag
Define macros for attributes used to control the static checker.
#define ATLAS_NOT_THREAD_SAFE
getNoisyStrip() Find noisy strips from hitmaps and write out into xml/db formats
A wrapper class for event-slot-local random engines.
Definition RNGWrapper.h:56
void setSeed(const std::string &algName, const EventContext &ctx)
Set the random seed using a string (e.g.
Definition RNGWrapper.h:169
CLHEP::HepRandomEngine * getEngine(const EventContext &ctx) const
Retrieve the random engine corresponding to the provided EventContext.
Definition RNGWrapper.h:134
const T * back() const
Access the last element in the collection as an rvalue.
Small wrapper around hit collection map to facilitate accessing the hit collection.
virtual StatusCode initialize() override
The generic ISF particle definition,.
Definition ISFParticle.h:42
This defines the McEventCollection, which is really just an ObjectVector of McEvent objectsFile: Gene...
virtual StatusCode setupEvent(const EventContext &, HitCollectionMap &) override
Create data containers for an event.
virtual StatusCode simulate(const EventContext &ctx, ISF::ISFParticle &isp, ISF::ISFParticleContainer &secondaries, McEventCollection *mcEventCollection, std::shared_ptr< HitCollectionMap >) override
Simulation call for individual particles.
void commandLog(int returnCode, const std::string &commandString) const
This command prints a message about a G4Command depending on its returnCode.
ServiceHandle< ISF::IInputConverter > m_inputConverter
Service to convert ISF_Particles into a G4Event.
PublicToolHandle< ISensitiveDetectorMasterTool > m_senDetTool
Sensitive Detector Master Tool.
PublicToolHandle< IFastSimulationMasterTool > m_fastSimTool
Fast Simulation Master Tool.
virtual StatusCode finalize() override final
AlgTool finalize method.
void finalizeOnce()
G4 finalization called only by the first tool instance.
void initializeOnce ATLAS_NOT_THREAD_SAFE()
G4 initialization called only by the first tool instance.
G4LegacyTransportTool(const std::string &, const std::string &, const IInterface *)
Constructor.
ServiceHandle< G4UA::IUserActionSvc > m_userActionSvc
user action service
virtual StatusCode initialize() override final
AlgTool initialize method.
HepMC::GenEvent * genEvent(McEventCollection *mcEventCollection) const
Gaudi::Property< std::string > m_randomStreamName
Random Stream Name.
virtual StatusCode simulateVector(const EventContext &ctx, const ISF::ISFParticleVector &particles, ISF::ISFParticleContainer &secondaries, McEventCollection *mcEventCollection, std::shared_ptr< HitCollectionMap > hitCollections, McEventCollection *shadowTruth=nullptr) override
Simulation call for vectors of particles.
Gaudi::Property< std::string > m_mcEventCollectionName
virtual StatusCode releaseEvent(const EventContext &, HitCollectionMap &) override
Finalise data containers for an event.
ServiceHandle< IAthRNGSvc > m_rndmGenSvc
bool contains(const std::string &s, const std::string &regx)
does a string contain the substring
Definition hcg.cxx:114
ISFParticleOrderedQueue.
std::list< ISF::ISFParticle * > ISFParticleContainer
generic ISFParticle container (not necessarily a std::list!)
std::vector< ISF::ISFParticle * > ISFParticleVector
ISFParticle vector.
std::unordered_map< ISF::ISFParticle const *, ISF::ISFParticleContainer > m_secondariesMap
MsgStream & msg
Definition testRead.cxx:32