ATLAS Offline Software
Loading...
Searching...
No Matches
G4LegacyTransportTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 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 //ATH_MSG_WARNING("Simulation will now go on to the next event ");
292 //ATH_MSG_WARNING("setFilterPassed is now False");
293 //setFilterPassed(false);
294 return StatusCode::FAILURE;
295 }
296
297
298 // const DataHandle <TrackRecordCollection> tracks;
299
300 // StatusCode sc = evtStore()->retrieve(tracks,m_trackCollName);
301
302 // if (sc.isFailure()) {
303 // ATH_MSG_WARNING(" Cannot retrieve TrackRecordCollection " << m_trackCollName);
304 // }
305
306 // not implemented yet... need to get particle stack from Geant4 and convert to ISFParticle
307 ATH_MSG_VERBOSE( "Simulation done" );
308
309 Slot& slot = *m_slots;
310 Slot::lock_t lock (slot.m_mutex);
311
312 for (auto* cisp : particles) {
313 // return any secondaries associated with this particle
314 auto searchResult = slot.m_secondariesMap.find( cisp );
315 if ( searchResult == slot.m_secondariesMap.end() ) {
316
317 ATH_MSG_VERBOSE( "Found no secondaries" );
318
319 } else {
320
321 ATH_MSG_VERBOSE( "Found secondaries: " << searchResult->second.size() );
322 secondaries.splice( end(secondaries), std::move(searchResult->second) ); //append vector
323 slot.m_secondariesMap.erase( searchResult );
324 }
325 }
326 // Geant4 call done
327 return StatusCode::SUCCESS;
328}
329
330//________________________________________________________________________
332 const EventContext& ctx, HitCollectionMap& hitCollections) {
333 ATH_MSG_DEBUG ( "setup Event" );
334
335 // Set the RNG to use for this event. We need to reset it for MT jobs
336 // because of the mismatch between Gaudi slot-local and G4 thread-local RNG.
337 ATHRNG::RNGWrapper* rngWrapper = m_rndmGenSvc->getEngine(this, m_randomStreamName);
338 rngWrapper->setSeed( m_randomStreamName, ctx );
339 G4Random::setTheEngine(rngWrapper->getEngine(ctx));
340 ATH_CHECK(m_senDetTool->BeginOfAthenaEvent(hitCollections));
341 ATH_CHECK(m_userActionSvc->BeginOfAthenaEvent(hitCollections));
342
344 if (m_doTiming) m_eventTimer->Start();
345
346 // make sure SD collections are properly initialized in every Athena event
347 G4SDManager::GetSDMpointer()->PrepareNewEvent();
348
349 return StatusCode::SUCCESS;
350}
351
352//________________________________________________________________________
354 const EventContext& ctx, HitCollectionMap& hitCollections) {
355 ATH_MSG_DEBUG ( "release Event" );
357
358 /* todo: ELLI: the following is copied in from the PyG4AtlasAlg:
359 -> this somehow needs to be moved into C++
360 and put into releaseEvent() ( or setupEvent() ?)
361
362 from ISF_Geant4Example import AtlasG4Eng
363 from ISF_Geant4Example.ISF_SimFlags import simFlags
364 if self.doFirstEventG4SeedsCheck :
365 if simFlags.SeedsG4.statusOn:
366 rnd = AtlasG4Eng.G4Eng.menu_G4RandomNrMenu()
367 rnd.set_Seed(simFlags.SeedsG4.get_Value())
368 self.doFirstEventG4SeedsCheck = False
369 if self.RndG4Menu.SaveStatus:
370 self.RndG4Menu.Menu.saveStatus('G4Seeds.txt')
371 */
372
373 // print per-event timing info if enabled
374 if (m_doTiming) {
375 m_eventTimer->Stop();
376
377 double eventTime=m_eventTimer->GetUserElapsed()+m_eventTimer->GetSystemElapsed();
378 if (m_nrOfEntries>1) {
379 m_accumulatedEventTime +=eventTime;
380 m_accumulatedEventTimeSq+=eventTime*eventTime;
381 }
382
383 float avgTimePerEvent=(m_nrOfEntries>1) ? m_accumulatedEventTime/(m_nrOfEntries-1.) : eventTime;
384 float sigma=(m_nrOfEntries>2) ? std::sqrt((m_accumulatedEventTimeSq/float(m_nrOfEntries-1)-
385 avgTimePerEvent*avgTimePerEvent)/float(m_nrOfEntries-2)) : 0.;
386
387 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) <<
388 eventTime << " s. New average " << std::setprecision(4) <<
389 avgTimePerEvent<<" +- "<<std::setprecision(4) << sigma);
390 }
391
392 ATH_CHECK(m_senDetTool->EndOfAthenaEvent(hitCollections));
393 ATH_CHECK(m_userActionSvc->EndOfAthenaEvent(hitCollections));
394 ATH_CHECK(m_fastSimTool->EndOfAthenaEvent());
395
396 return StatusCode::SUCCESS;
397}
398
399//________________________________________________________________________
400HepMC::GenEvent* iGeant4::G4LegacyTransportTool::genEvent(McEventCollection* mcEventCollection) const
401{
402
403 if(!mcEventCollection) {
404 // retrieve McEventCollection from storegate
406 if (evtStore()->retrieve( mcEventCollection, m_mcEventCollectionName).isFailure()) {
407 ATH_MSG_ERROR( "Unable to retrieve McEventCollection with name=" << m_mcEventCollectionName
408 << ".");
409 return nullptr;
410 }
411 else {
412 ATH_MSG_WARNING( "Fallback. Sucessfully retrieved McEventCollection with name=" << m_mcEventCollectionName);
413 }
414 }
415 else { return nullptr; }
416 }
417 // collect last GenEvent from McEventCollection
418 return mcEventCollection->back();
419}
420
421//________________________________________________________________________
422void iGeant4::G4LegacyTransportTool::commandLog(int returnCode, const std::string& commandString) const
423{
424 switch(returnCode) {
425 case 0: { ATH_MSG_DEBUG("G4 Command: " << commandString << " - Command Succeeded"); } break;
426 case 100: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Command Not Found!"); } break;
427 case 200: {
428 auto* stateManager = G4StateManager::GetStateManager();
429 ATH_MSG_DEBUG("G4 Command: " << commandString << " - Illegal Application State (" <<
430 stateManager->GetStateString(stateManager->GetCurrentState()) << ")!");
431 } break;
432 case 300: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Parameter Out of Range!"); } break;
433 case 400: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Parameter Unreadable!"); } break;
434 case 500: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Parameter Out of Candidates!"); } break;
435 case 600: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Alias Not Found!"); } break;
436 default: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Unknown Status!"); } break;
437 }
438
439}
440
#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