ATLAS Offline Software
G4LegacyTransportTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2022 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  std::unique_ptr<G4AtlasActionInitialization> actionInitialization =
127  std::make_unique<G4AtlasActionInitialization>(&*m_userActionSvc);
128  m_pRunMgr->SetUserInitialization(actionInitialization.release());
129 
130  G4UImanager *ui = G4UImanager::GetUIpointer();
131 
132  if (!m_libList.empty()) {
133  ATH_MSG_INFO("G4AtlasAlg specific libraries requested ") ;
134  std::string temp="/load "+m_libList;
135  ui->ApplyCommand(temp);
136  }
137 
138  if (!m_physList.empty()) {
139  ATH_MSG_INFO("requesting a specific physics list "<< m_physList) ;
140  std::string temp="/Physics/GetPhysicsList "+m_physList;
141  ui->ApplyCommand(temp);
142  }
143 
144  if (!m_fieldMap.empty()) {
145  ATH_MSG_INFO("requesting a specific field map "<< m_fieldMap) ;
146  ATH_MSG_INFO("the field is initialized straight away") ;
147  std::string temp="/MagneticField/Select "+m_fieldMap;
148  ui->ApplyCommand(temp);
149  ui->ApplyCommand("/MagneticField/Initialize");
150  }
151 
152  // Send UI commands
153  ATH_MSG_DEBUG("G4 Command: Trying at the end of initializeOnce()");
154  for (const auto& g4command : m_g4commands) {
155  int returnCode = ui->ApplyCommand( g4command );
156  commandLog(returnCode, g4command);
157  }
158 
159  // Code from G4AtlasSvc
160  auto* rm = G4RunManager::GetRunManager();
161  if(!rm) {
162  throw std::runtime_error("Run manager retrieval has failed");
163  }
164  rm->Initialize(); // Initialization differs slightly in multi-threading.
165  // TODO: add more details about why this is here.
166  if(!m_useMT && rm->ConfirmBeamOnCondition()) {
167  rm->RunInitialization();
168  }
169 
170  ATH_MSG_INFO( "retireving the Detector Geometry Service" );
171  if(m_detGeoSvc.retrieve().isFailure()) {
172  throw std::runtime_error("Could not initialize ATLAS DetectorGeometrySvc!");
173  }
174 
175  if(m_userLimitsSvc.retrieve().isFailure()) {
176  throw std::runtime_error("Could not initialize ATLAS UserLimitsSvc!");
177  }
178 
179  if (m_activateParallelGeometries) {
180  G4VModularPhysicsList* thePhysicsList=dynamic_cast<G4VModularPhysicsList*>(m_physListSvc->GetPhysicsList());
181  if (!thePhysicsList) {
182  throw std::runtime_error("Failed dynamic_cast!! this is not a G4VModularPhysicsList!");
183  }
184 #if G4VERSION_NUMBER >= 1010
185  std::vector<std::string>& parallelWorldNames=m_detGeoSvc->GetParallelWorldNames();
186  for (auto& it: parallelWorldNames) {
187  thePhysicsList->RegisterPhysics(new G4ParallelWorldPhysics(it,true));
188  }
189 #endif
190  }
191 
192  return;
193 }
194 
195 //________________________________________________________________________
197 {
198  ATH_MSG_VERBOSE("++++++++++++ ISF G4 G4LegacyTransportTool finalized ++++++++++++");
199 
200  // One time finalization
201  try {
202  std::call_once(finalizeOnceFlag, &iGeant4::G4LegacyTransportTool::finalizeOnce, this);
203  }
204  catch(const std::exception& e) {
205  ATH_MSG_ERROR("Failure in iGeant4::G4LegacyTransportTool::finalizeOnce: " << e.what());
206  return StatusCode::FAILURE;
207  }
208 
209  if (m_doTiming) {
210  m_runTimer->Stop();
211  float runTime=m_runTimer->GetUserElapsed()+m_runTimer->GetSystemElapsed();
212  float avgTimePerEvent=(m_nrOfEntries>1) ? m_accumulatedEventTime/(m_nrOfEntries-1.) : runTime;
213  float sigma=( m_nrOfEntries>2) ? std::sqrt((m_accumulatedEventTimeSq/float(m_nrOfEntries-1)-
214  avgTimePerEvent*avgTimePerEvent)/float(m_nrOfEntries-2)) : 0;
215  ATH_MSG_INFO("*****************************************"<<endmsg<<
216  "** **"<<endmsg<<
217  " End of run - time spent is "<<std::setprecision(4) <<
218  runTime<<endmsg<<
219  " Average time per event was "<<std::setprecision(4) <<
220  avgTimePerEvent <<" +- "<< std::setprecision(4) << sigma<<endmsg<<
221  "** **"<<endmsg<<
222  "*****************************************");
223  }
224 
225  return StatusCode::SUCCESS;
226 }
227 
228 //________________________________________________________________________
230 {
231  ATH_MSG_DEBUG("\t terminating the current G4 run");
232 
233  m_pRunMgr->RunTermination();
234 
235  return;
236 }
237 
238 //________________________________________________________________________
240 
241  // give a screen output that you entered Geant4SimSvc
242  ATH_MSG_VERBOSE( "Particle " << isp << " received for simulation." );
243 
245  // wrap the given ISFParticle into a STL vector of ISFParticles with length 1
246  // (minimizing code duplication)
247  const ISF::ISFParticleVector ispVector(1, &isp);
248  StatusCode success = this->simulateVector(ispVector, secondaries, mcEventCollection);
249  ATH_MSG_VERBOSE( "Simulation done" );
250 
251  // Geant4 call done
252  return success;
253 }
254 
255 //________________________________________________________________________
257 
258  ATH_MSG_DEBUG (name() << ".simulateVector(...) : Received a vector of " << particles.size() << " particles for simulation.");
260  G4Event* inputEvent = m_inputConverter->ISF_to_G4Event(particles, genEvent(mcEventCollection));
261  if (!inputEvent) {
262  ATH_MSG_ERROR("ISF Event conversion failed ");
263  return StatusCode::FAILURE;
264  }
265 
266  ATH_MSG_DEBUG("Calling ISF_Geant4 ProcessEvent");
267  bool abort = m_pRunMgr->ProcessEvent(inputEvent);
268 
269  if (abort) {
270  ATH_MSG_WARNING("Event was aborted !! ");
271  //ATH_MSG_WARNING("Simulation will now go on to the next event ");
272  //ATH_MSG_WARNING("setFilterPassed is now False");
273  //setFilterPassed(false);
274  return StatusCode::FAILURE;
275  }
276 
277 
278  // const DataHandle <TrackRecordCollection> tracks;
279 
280  // StatusCode sc = evtStore()->retrieve(tracks,m_trackCollName);
281 
282  // if (sc.isFailure()) {
283  // ATH_MSG_WARNING(" Cannot retrieve TrackRecordCollection " << m_trackCollName);
284  // }
285 
286  // not implemented yet... need to get particle stack from Geant4 and convert to ISFParticle
287  ATH_MSG_VERBOSE( "Simulation done" );
288 
289  Slot& slot = *m_slots;
290  Slot::lock_t lock (slot.m_mutex);
291 
292  for (auto* cisp : particles) {
293  // return any secondaries associated with this particle
294  auto searchResult = slot.m_secondariesMap.find( cisp );
295  if ( searchResult == slot.m_secondariesMap.end() ) {
296 
297  ATH_MSG_VERBOSE( "Found no secondaries" );
298 
299  } else {
300 
301  ATH_MSG_VERBOSE( "Found secondaries: " << searchResult->second.size() );
302  secondaries.splice( end(secondaries), std::move(searchResult->second) ); //append vector
303  slot.m_secondariesMap.erase( searchResult );
304  }
305  }
306  // Geant4 call done
307  return StatusCode::SUCCESS;
308 }
309 
310 //________________________________________________________________________
312 {
313  ATH_MSG_DEBUG ( "setup Event" );
314 
315  // Set the RNG to use for this event. We need to reset it for MT jobs
316  // because of the mismatch between Gaudi slot-local and G4 thread-local RNG.
317  ATHRNG::RNGWrapper* rngWrapper = m_rndmGenSvc->getEngine(this, m_randomStreamName);
318  rngWrapper->setSeed( m_randomStreamName, ctx );
319  G4Random::setTheEngine(rngWrapper->getEngine(ctx));
320 
321  ATH_CHECK(m_senDetTool->BeginOfAthenaEvent());
322 
323  m_nrOfEntries++;
324  if (m_doTiming) m_eventTimer->Start();
325 
326  // make sure SD collections are properly initialized in every Athena event
327  G4SDManager::GetSDMpointer()->PrepareNewEvent();
328 
329  return StatusCode::SUCCESS;
330 }
331 
332 //________________________________________________________________________
334 {
335  ATH_MSG_DEBUG ( "release Event" );
338  /* todo: ELLI: the following is copied in from the PyG4AtlasAlg:
339  -> this somehow needs to be moved into C++
340  and put into releaseEvent() ( or setupEvent() ?)
341 
342  from ISF_Geant4Example import AtlasG4Eng
343  from ISF_Geant4Example.ISF_SimFlags import simFlags
344  if self.doFirstEventG4SeedsCheck :
345  if simFlags.SeedsG4.statusOn:
346  rnd = AtlasG4Eng.G4Eng.menu_G4RandomNrMenu()
347  rnd.set_Seed(simFlags.SeedsG4.get_Value())
348  self.doFirstEventG4SeedsCheck = False
349  if self.RndG4Menu.SaveStatus:
350  self.RndG4Menu.Menu.saveStatus('G4Seeds.txt')
351  */
352 
353  // print per-event timing info if enabled
354  if (m_doTiming) {
355  m_eventTimer->Stop();
356 
357  double eventTime=m_eventTimer->GetUserElapsed()+m_eventTimer->GetSystemElapsed();
358  if (m_nrOfEntries>1) {
359  m_accumulatedEventTime +=eventTime;
360  m_accumulatedEventTimeSq+=eventTime*eventTime;
361  }
362 
363  float avgTimePerEvent=(m_nrOfEntries>1) ? m_accumulatedEventTime/(m_nrOfEntries-1.) : eventTime;
364  float sigma=(m_nrOfEntries>2) ? std::sqrt((m_accumulatedEventTimeSq/float(m_nrOfEntries-1)-
365  avgTimePerEvent*avgTimePerEvent)/float(m_nrOfEntries-2)) : 0.;
366 
367  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) <<
368  eventTime << " s. New average " << std::setprecision(4) <<
369  avgTimePerEvent<<" +- "<<std::setprecision(4) << sigma);
370  }
371 
372  ATH_CHECK(m_senDetTool->EndOfAthenaEvent());
373  ATH_CHECK(m_fastSimTool->EndOfAthenaEvent());
374 
375  return StatusCode::SUCCESS;
376 }
377 
378 //________________________________________________________________________
379 HepMC::GenEvent* iGeant4::G4LegacyTransportTool::genEvent(McEventCollection* mcEventCollection) const
380 {
381 
382  if(!mcEventCollection) {
383  // retrieve McEventCollection from storegate
384  if (evtStore()->contains<McEventCollection>(m_mcEventCollectionName)) {
385  if (evtStore()->retrieve( mcEventCollection, m_mcEventCollectionName).isFailure()) {
386  ATH_MSG_ERROR( "Unable to retrieve McEventCollection with name=" << m_mcEventCollectionName
387  << ".");
388  return nullptr;
389  }
390  else {
391  ATH_MSG_WARNING( "Fallback. Sucessfully retrieved McEventCollection with name=" << m_mcEventCollectionName);
392  }
393  }
394  else { return nullptr; }
395  }
396  // collect last GenEvent from McEventCollection
397  return mcEventCollection->back();
398 }
399 
400 //________________________________________________________________________
401 void iGeant4::G4LegacyTransportTool::commandLog(int returnCode, const std::string& commandString) const
402 {
403  switch(returnCode) {
404  case 0: { ATH_MSG_DEBUG("G4 Command: " << commandString << " - Command Succeeded"); } break;
405  case 100: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Command Not Found!"); } break;
406  case 200: {
407  auto* stateManager = G4StateManager::GetStateManager();
408  ATH_MSG_DEBUG("G4 Command: " << commandString << " - Illegal Application State (" <<
409  stateManager->GetStateString(stateManager->GetCurrentState()) << ")!");
410  } break;
411  case 300: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Parameter Out of Range!"); } break;
412  case 400: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Parameter Unreadable!"); } break;
413  case 500: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Parameter Out of Candidates!"); } break;
414  case 600: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Alias Not Found!"); } break;
415  default: { ATH_MSG_ERROR("G4 Command: " << commandString << " - Unknown Status!"); } break;
416  }
417 
418 }
419 
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
iGeant4::G4LegacyTransportTool::simulateVector
virtual StatusCode simulateVector(const ISF::ISFParticleVector &particles, ISF::ISFParticleContainer &secondaries, McEventCollection *mcEventCollection, McEventCollection *shadowTruth=nullptr) override
Simulation call for vectors of particles.
Definition: G4LegacyTransportTool.cxx:256
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:423
ISF::ISFParticle
Definition: ISFParticle.h:42
iGeant4::G4LegacyTransportTool::finalizeOnce
void finalizeOnce()
G4 finalization called only by the first tool instance.
Definition: G4LegacyTransportTool.cxx:229
iGeant4::G4LegacyTransportTool::finalize
virtual StatusCode finalize() override final
AlgTool finalize method.
Definition: G4LegacyTransportTool.cxx:196
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:311
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:401
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
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:195
iGeant4::G4LegacyTransportTool::simulate
virtual StatusCode simulate(ISF::ISFParticle &isp, ISF::ISFParticleContainer &secondaries, McEventCollection *mcEventCollection) override
Definition: G4LegacyTransportTool.cxx:239
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:59
DiTauMassTools::MaxHistStrategyV2::e
e
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:26
AtlasG4EventUserInfo.h
ISF
ISFParticleOrderedQueue.
Definition: PrimaryParticleInformation.h:13
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
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
CI_EMPFlowData22test.returnCode
returnCode
Definition: CI_EMPFlowData22test.py:16
python.AutoConfigFlags.msg
msg
Definition: AutoConfigFlags.py:7
iGeant4::G4LegacyTransportTool::genEvent
HepMC::GenEvent * genEvent(McEventCollection *mcEventCollection) const
Definition: G4LegacyTransportTool.cxx:379
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:333