ATLAS Offline Software
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
11 #include "ISFFluxRecorder.h"
12 
14 
15 // ISF classes
16 #include "ISF_Event/ISFParticle.h"
18 
19 // Athena classes
21 
24 
25 // HepMC classes
26 #include "AtlasHepMC/GenParticle.h"
27 
28 // Geant4 classes
29 #include "G4LorentzVector.hh"
30 #include "G4PrimaryVertex.hh"
31 #include "G4PrimaryParticle.hh"
32 #include "G4Trajectory.hh"
33 #include "G4Geantino.hh"
34 #include "G4ChargedGeantino.hh"
35 #include "G4ParticleTable.hh"
36 #include "G4StateManager.hh"
37 #include "G4TransportationManager.hh"
38 #include "G4UImanager.hh"
39 #include "G4ScoringManager.hh"
40 #include "G4Timer.hh"
41 #include "G4SDManager.hh"
42 #include "G4VUserPhysicsList.hh"
43 #include "G4VModularPhysicsList.hh"
44 #include "G4ParallelWorldPhysics.hh"
45 #include "G4Timer.hh"
46 
48 
49 // call_once mutexes
50 #include <mutex>
51 static std::once_flag initializeOnceFlag;
52 static std::once_flag finalizeOnceFlag;
53 
54 //________________________________________________________________________
56  const std::string& name,
57  const IInterface* parent )
58  : ISF::BaseSimulatorTool(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 //________________________________________________________________________
102 void 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 
121  m_pRunMgr->SetRecordFlux( m_recordFlux, std::make_unique<ISFFluxRecorder>() );
122  m_pRunMgr->SetLogLevel( int(msg().level()) ); // Synch log levels
123  m_pRunMgr->SetDetGeoSvc( m_detGeoSvc.typeAndName() );
124  m_pRunMgr->SetFastSimMasterTool(m_fastSimTool.typeAndName() );
125  m_pRunMgr->SetPhysListSvc(m_physListSvc.typeAndName() );
126  m_pRunMgr->SetQuietMode( m_quietMode );
127  std::unique_ptr<G4AtlasActionInitialization> actionInitialization =
128  std::make_unique<G4AtlasActionInitialization>(&*m_userActionSvc);
129  m_pRunMgr->SetUserInitialization(actionInitialization.release());
130 
131  G4UImanager *ui = G4UImanager::GetUIpointer();
132 
133  if (!m_libList.empty()) {
134  ATH_MSG_INFO("G4AtlasAlg specific libraries requested ") ;
135  std::string temp="/load "+m_libList;
136  ui->ApplyCommand(temp);
137  }
138 
139  if (!m_physList.empty()) {
140  ATH_MSG_INFO("requesting a specific physics list "<< m_physList) ;
141  std::string temp="/Physics/GetPhysicsList "+m_physList;
142  ui->ApplyCommand(temp);
143  }
144 
145  if (!m_fieldMap.empty()) {
146  ATH_MSG_INFO("requesting a specific field map "<< m_fieldMap) ;
147  ATH_MSG_INFO("the field is initialized straight away") ;
148  std::string temp="/MagneticField/Select "+m_fieldMap;
149  ui->ApplyCommand(temp);
150  ui->ApplyCommand("/MagneticField/Initialize");
151  }
152 
153  // Send UI commands
154  ATH_MSG_DEBUG("G4 Command: Trying at the end of initializeOnce()");
155  for (const auto& g4command : m_g4commands) {
156  int returnCode = ui->ApplyCommand( g4command );
157  commandLog(returnCode, g4command);
158  }
159 
160  // Code from G4AtlasSvc
161  auto* rm = G4RunManager::GetRunManager();
162  if(!rm) {
163  throw std::runtime_error("Run manager retrieval has failed");
164  }
165  rm->Initialize(); // Initialization differs slightly in multi-threading.
166  // TODO: add more details about why this is here.
167  if(!m_useMT && rm->ConfirmBeamOnCondition()) {
168  rm->RunInitialization();
169  }
170 
171  ATH_MSG_INFO( "retireving the Detector Geometry Service" );
172  if(m_detGeoSvc.retrieve().isFailure()) {
173  throw std::runtime_error("Could not initialize ATLAS DetectorGeometrySvc!");
174  }
175 
176  if(m_userLimitsSvc.retrieve().isFailure()) {
177  throw std::runtime_error("Could not initialize ATLAS UserLimitsSvc!");
178  }
179 
180  if (m_activateParallelGeometries) {
181  G4VModularPhysicsList* thePhysicsList=dynamic_cast<G4VModularPhysicsList*>(m_physListSvc->GetPhysicsList());
182  if (!thePhysicsList) {
183  throw std::runtime_error("Failed dynamic_cast!! this is not a G4VModularPhysicsList!");
184  }
185 #if G4VERSION_NUMBER >= 1010
186  std::vector<std::string>& parallelWorldNames=m_detGeoSvc->GetParallelWorldNames();
187  for (auto& it: parallelWorldNames) {
188  thePhysicsList->RegisterPhysics(new G4ParallelWorldPhysics(it,true));
189  }
190 #endif
191  }
192 
193  return;
194 }
195 
196 //________________________________________________________________________
198 {
199  ATH_MSG_VERBOSE("++++++++++++ ISF G4 G4LegacyTransportTool finalized ++++++++++++");
200 
201  // One time finalization
202  try {
203  std::call_once(finalizeOnceFlag, &iGeant4::G4LegacyTransportTool::finalizeOnce, this);
204  }
205  catch(const std::exception& e) {
206  ATH_MSG_ERROR("Failure in iGeant4::G4LegacyTransportTool::finalizeOnce: " << e.what());
207  return StatusCode::FAILURE;
208  }
209 
210  if (m_doTiming) {
211  m_runTimer->Stop();
212  float runTime=m_runTimer->GetUserElapsed()+m_runTimer->GetSystemElapsed();
213  float avgTimePerEvent=(m_nrOfEntries>1) ? m_accumulatedEventTime/(m_nrOfEntries-1.) : runTime;
214  float sigma=( m_nrOfEntries>2) ? std::sqrt((m_accumulatedEventTimeSq/float(m_nrOfEntries-1)-
215  avgTimePerEvent*avgTimePerEvent)/float(m_nrOfEntries-2)) : 0;
216  ATH_MSG_INFO("*****************************************"<<endmsg<<
217  "** **"<<endmsg<<
218  " End of run - time spent is "<<std::setprecision(4) <<
219  runTime<<endmsg<<
220  " Average time per event was "<<std::setprecision(4) <<
221  avgTimePerEvent <<" +- "<< std::setprecision(4) << sigma<<endmsg<<
222  "** **"<<endmsg<<
223  "*****************************************");
224  }
225 
226  return StatusCode::SUCCESS;
227 }
228 
229 //________________________________________________________________________
231 {
232  ATH_MSG_DEBUG("\t terminating the current G4 run");
233 
234  m_pRunMgr->RunTermination();
235 
236  return;
237 }
238 
239 //________________________________________________________________________
241 
242  // give a screen output that you entered Geant4SimSvc
243  ATH_MSG_VERBOSE( "Particle " << isp << " received for simulation." );
244 
246  // wrap the given ISFParticle into a STL vector of ISFParticles with length 1
247  // (minimizing code duplication)
248  const ISF::ISFParticleVector ispVector(1, &isp);
249  StatusCode success = this->simulateVector(ctx, ispVector, secondaries, mcEventCollection);
250  ATH_MSG_VERBOSE( "Simulation done" );
251 
252  // Geant4 call done
253  return success;
254 }
255 
256 //________________________________________________________________________
258 
259  ATH_MSG_DEBUG (name() << ".simulateVector(...) : Received a vector of " << particles.size() << " particles for simulation.");
261  G4Event* inputEvent = m_inputConverter->ISF_to_G4Event(ctx, particles, genEvent(mcEventCollection));
262  if (!inputEvent) {
263  ATH_MSG_ERROR("ISF Event conversion failed ");
264  return StatusCode::FAILURE;
265  }
266 
267  ATH_MSG_DEBUG("Calling ISF_Geant4 ProcessEvent");
268  bool abort = m_pRunMgr->ProcessEvent(inputEvent);
269 
270  if (abort) {
271  ATH_MSG_WARNING("Event was aborted !! ");
272  //ATH_MSG_WARNING("Simulation will now go on to the next event ");
273  //ATH_MSG_WARNING("setFilterPassed is now False");
274  //setFilterPassed(false);
275  return StatusCode::FAILURE;
276  }
277 
278 
279  // const DataHandle <TrackRecordCollection> tracks;
280 
281  // StatusCode sc = evtStore()->retrieve(tracks,m_trackCollName);
282 
283  // if (sc.isFailure()) {
284  // ATH_MSG_WARNING(" Cannot retrieve TrackRecordCollection " << m_trackCollName);
285  // }
286 
287  // not implemented yet... need to get particle stack from Geant4 and convert to ISFParticle
288  ATH_MSG_VERBOSE( "Simulation done" );
289 
290  Slot& slot = *m_slots;
291  Slot::lock_t lock (slot.m_mutex);
292 
293  for (auto* cisp : particles) {
294  // return any secondaries associated with this particle
295  auto searchResult = slot.m_secondariesMap.find( cisp );
296  if ( searchResult == slot.m_secondariesMap.end() ) {
297 
298  ATH_MSG_VERBOSE( "Found no secondaries" );
299 
300  } else {
301 
302  ATH_MSG_VERBOSE( "Found secondaries: " << searchResult->second.size() );
303  secondaries.splice( end(secondaries), std::move(searchResult->second) ); //append vector
304  slot.m_secondariesMap.erase( searchResult );
305  }
306  }
307  // Geant4 call done
308  return StatusCode::SUCCESS;
309 }
310 
311 //________________________________________________________________________
313 {
314  ATH_MSG_DEBUG ( "setup Event" );
315 
316  // Set the RNG to use for this event. We need to reset it for MT jobs
317  // because of the mismatch between Gaudi slot-local and G4 thread-local RNG.
318  ATHRNG::RNGWrapper* rngWrapper = m_rndmGenSvc->getEngine(this, m_randomStreamName);
319  rngWrapper->setSeed( m_randomStreamName, ctx );
320  G4Random::setTheEngine(rngWrapper->getEngine(ctx));
321 
322  ATH_CHECK(m_senDetTool->BeginOfAthenaEvent());
323 
324  m_nrOfEntries++;
325  if (m_doTiming) m_eventTimer->Start();
326 
327  // make sure SD collections are properly initialized in every Athena event
328  G4SDManager::GetSDMpointer()->PrepareNewEvent();
329 
330  return StatusCode::SUCCESS;
331 }
332 
333 //________________________________________________________________________
335 {
336  ATH_MSG_DEBUG ( "release Event" );
339  /* todo: ELLI: the following is copied in from the PyG4AtlasAlg:
340  -> this somehow needs to be moved into C++
341  and put into releaseEvent() ( or setupEvent() ?)
342 
343  from ISF_Geant4Example import AtlasG4Eng
344  from ISF_Geant4Example.ISF_SimFlags import simFlags
345  if self.doFirstEventG4SeedsCheck :
346  if simFlags.SeedsG4.statusOn:
347  rnd = AtlasG4Eng.G4Eng.menu_G4RandomNrMenu()
348  rnd.set_Seed(simFlags.SeedsG4.get_Value())
349  self.doFirstEventG4SeedsCheck = False
350  if self.RndG4Menu.SaveStatus:
351  self.RndG4Menu.Menu.saveStatus('G4Seeds.txt')
352  */
353 
354  // print per-event timing info if enabled
355  if (m_doTiming) {
356  m_eventTimer->Stop();
357 
358  double eventTime=m_eventTimer->GetUserElapsed()+m_eventTimer->GetSystemElapsed();
359  if (m_nrOfEntries>1) {
360  m_accumulatedEventTime +=eventTime;
361  m_accumulatedEventTimeSq+=eventTime*eventTime;
362  }
363 
364  float avgTimePerEvent=(m_nrOfEntries>1) ? m_accumulatedEventTime/(m_nrOfEntries-1.) : eventTime;
365  float sigma=(m_nrOfEntries>2) ? std::sqrt((m_accumulatedEventTimeSq/float(m_nrOfEntries-1)-
366  avgTimePerEvent*avgTimePerEvent)/float(m_nrOfEntries-2)) : 0.;
367 
368  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) <<
369  eventTime << " s. New average " << std::setprecision(4) <<
370  avgTimePerEvent<<" +- "<<std::setprecision(4) << sigma);
371  }
372 
373  ATH_CHECK(m_senDetTool->EndOfAthenaEvent());
374  ATH_CHECK(m_fastSimTool->EndOfAthenaEvent());
375 
376  return StatusCode::SUCCESS;
377 }
378 
379 //________________________________________________________________________
380 HepMC::GenEvent* iGeant4::G4LegacyTransportTool::genEvent(McEventCollection* mcEventCollection) const
381 {
382 
383  if(!mcEventCollection) {
384  // retrieve McEventCollection from storegate
385  if (evtStore()->contains<McEventCollection>(m_mcEventCollectionName)) {
386  if (evtStore()->retrieve( mcEventCollection, m_mcEventCollectionName).isFailure()) {
387  ATH_MSG_ERROR( "Unable to retrieve McEventCollection with name=" << m_mcEventCollectionName
388  << ".");
389  return nullptr;
390  }
391  else {
392  ATH_MSG_WARNING( "Fallback. Sucessfully retrieved McEventCollection with name=" << m_mcEventCollectionName);
393  }
394  }
395  else { return nullptr; }
396  }
397  // collect last GenEvent from McEventCollection
398  return mcEventCollection->back();
399 }
400 
401 //________________________________________________________________________
402 void iGeant4::G4LegacyTransportTool::commandLog(int returnCode, const std::string& commandString) const
403 {
404  switch(returnCode) {
405  case 0: { ATH_MSG_DEBUG("G4 Command: " << commandString << " - Command Succeeded"); } break;
406  case 100: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Command Not Found!"); } break;
407  case 200: {
408  auto* stateManager = G4StateManager::GetStateManager();
409  ATH_MSG_DEBUG("G4 Command: " << commandString << " - Illegal Application State (" <<
410  stateManager->GetStateString(stateManager->GetCurrentState()) << ")!");
411  } break;
412  case 300: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Parameter Out of Range!"); } break;
413  case 400: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Parameter Unreadable!"); } break;
414  case 500: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Parameter Out of Candidates!"); } break;
415  case 600: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Alias Not Found!"); } break;
416  default: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Unknown Status!"); } break;
417  }
418 
419 }
420 
ISF::ISFParticleContainer
std::list< ISF::ISFParticle * > ISFParticleContainer
generic ISFParticle container (not necessarily a std::list!)
Definition: ISFParticleContainer.h:23
python.PyKernel.retrieve
def retrieve(aClass, aKey=None)
Definition: PyKernel.py:110
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
ATHRNG::RNGWrapper::setSeed
void setSeed(const std::string &algName, const EventContext &ctx)
Set the random seed using a string (e.g.
Definition: RNGWrapper.h:169
ATLAS_NOT_THREAD_SAFE
void iGeant4::G4LegacyTransportTool::initializeOnce ATLAS_NOT_THREAD_SAFE()
Install fatal handler with default options.
Definition: G4LegacyTransportTool.cxx:102
pdg_comparison.sigma
sigma
Definition: pdg_comparison.py:324
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
iGeant4::G4LegacyTransportTool::G4LegacyTransportTool
G4LegacyTransportTool(const std::string &, const std::string &, const IInterface *)
Constructor.
Definition: G4LegacyTransportTool.cxx:55
G4AtlasActionInitialization.h
ISFFluxRecorder.h
skel.it
it
Definition: skel.GENtoEVGEN.py:396
ISF::ISFParticle
Definition: ISFParticle.h:42
iGeant4::G4LegacyTransportTool::finalizeOnce
void finalizeOnce()
G4 finalization called only by the first tool instance.
Definition: G4LegacyTransportTool.cxx:230
iGeant4::G4LegacyTransportTool::finalize
virtual StatusCode finalize() override final
AlgTool finalize method.
Definition: G4LegacyTransportTool.cxx:197
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
iGeant4::G4LegacyTransportTool::Slot
Definition: G4LegacyTransportTool.h:113
iGeant4::G4LegacyTransportTool::initialize
virtual StatusCode initialize() override final
AlgTool initialize method.
Definition: G4LegacyTransportTool.cxx:65
GenParticle.h
mergePhysValFiles.end
end
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:93
python.iconfTool.models.loaders.level
level
Definition: loaders.py:20
iGeant4::G4LegacyTransportTool::setupEvent
virtual StatusCode setupEvent(const EventContext &) override
Setup Event chain - in case of a begin-of event action is needed.
Definition: G4LegacyTransportTool.cxx:312
ISFParticleContainer.h
iGeant4::G4LegacyTransportTool::Slot::m_secondariesMap
std::unordered_map< ISF::ISFParticle const *, ISF::ISFParticleContainer > m_secondariesMap
Definition: G4LegacyTransportTool.h:114
G4AtlasRunManager.h
ISFParticle.h
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
McEventCollection.h
iGeant4::G4LegacyTransportTool::commandLog
void commandLog(int returnCode, const std::string &commandString) const
This command prints a message about a G4Command depending on its returnCode.
Definition: G4LegacyTransportTool.cxx:402
endmsg
#define endmsg
Definition: AnalysisConfig_Ntuple.cxx:63
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
ISF::ISFParticleVector
std::vector< ISF::ISFParticle * > ISFParticleVector
ISFParticle vector.
Definition: ISFParticleContainer.h:26
calibdata.exception
exception
Definition: calibdata.py:496
test_pyathena.parent
parent
Definition: test_pyathena.py:15
iGeant4::G4LegacyTransportTool::simulateVector
virtual StatusCode simulateVector(const EventContext &ctx, const ISF::ISFParticleVector &particles, ISF::ISFParticleContainer &secondaries, McEventCollection *mcEventCollection, McEventCollection *shadowTruth=nullptr) override
Simulation call for vectors of particles.
Definition: G4LegacyTransportTool.cxx:257
AtlasRegionHelper.h
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
McEventCollection
This defines the McEventCollection, which is really just an ObjectVector of McEvent objects.
Definition: McEventCollection.h:33
DataVector::back
const T * back() const
Access the last element in the collection as an rvalue.
G4LegacyTransportTool.h
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:228
ATHRNG::RNGWrapper
A wrapper class for event-slot-local random engines.
Definition: RNGWrapper.h:56
iGeant4::G4LegacyTransportTool::Slot::m_mutex
mutex_t m_mutex
Definition: G4LegacyTransportTool.h:117
ATHRNG::RNGWrapper::getEngine
CLHEP::HepRandomEngine * getEngine(const EventContext &ctx) const
Retrieve the random engine corresponding to the provided EventContext.
Definition: RNGWrapper.h:134
RNGWrapper.h
ISF::BaseSimulatorTool::initialize
virtual StatusCode initialize() override
Definition: BaseSimulatorTool.h:57
AtlasG4EventUserInfo.h
ISF
ISFParticleOrderedQueue.
Definition: PrimaryParticleInformation.h:13
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
iGeant4::G4LegacyTransportTool::simulate
virtual StatusCode simulate(const EventContext &ctx, ISF::ISFParticle &isp, ISF::ISFParticleContainer &secondaries, McEventCollection *mcEventCollection) override
Definition: G4LegacyTransportTool.cxx:240
iGeant4::G4LegacyTransportTool::Slot::lock_t
std::lock_guard< mutex_t > lock_t
Definition: G4LegacyTransportTool.h:116
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
PrimaryParticleInformation.h
LArG4FSStartPointFilter.particles
list particles
Definition: LArG4FSStartPointFilter.py:84
python.AutoConfigFlags.msg
msg
Definition: AutoConfigFlags.py:7
iGeant4::G4LegacyTransportTool::genEvent
HepMC::GenEvent * genEvent(McEventCollection *mcEventCollection) const
Definition: G4LegacyTransportTool.cxx:380
iGeant4::G4LegacyTransportTool::releaseEvent
virtual StatusCode releaseEvent(const EventContext &) override
Release Event chain - in case of an end-of event action is needed.
Definition: G4LegacyTransportTool.cxx:334