Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-03-13 08:20:15

0001 //==========================================================================
0002 //  AIDA Detector description implementation 
0003 //--------------------------------------------------------------------------
0004 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0005 // All rights reserved.
0006 //
0007 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0008 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0009 //
0010 // Author     : M.Frank
0011 //
0012 //==========================================================================
0013 
0014 // Framework include files
0015 #include <DD4hep/Detector.h>
0016 #include <DD4hep/Memory.h>
0017 #include <DD4hep/Plugins.h>
0018 #include <DD4hep/Printout.h>
0019 #include <DD4hep/Primitives.h>
0020 #include <DD4hep/InstanceCount.h>
0021 
0022 #include <DDG4/Geant4Kernel.h>
0023 #include <DDG4/Geant4Context.h>
0024 #include <DDG4/Geant4Interrupts.h>
0025 #include <DDG4/Geant4ActionPhase.h>
0026 
0027 // Geant4 include files
0028 #include <G4RunManager.hh>
0029 #include <G4ScoringManager.hh>
0030 #include <G4UIdirectory.hh>
0031 #include <G4Threading.hh>
0032 #include <G4AutoLock.hh>
0033 
0034 // C/C++ include files
0035 #include <algorithm>
0036 #include <pthread.h>
0037 #include <csignal>
0038 #include <memory>
0039 
0040 using namespace dd4hep::sim;
0041 
0042 namespace {
0043 
0044   G4Mutex kernel_mutex = G4MUTEX_INITIALIZER;
0045   std::unique_ptr<Geant4Kernel> s_main_instance;
0046   void description_unexpected()    {
0047     try  {
0048       throw;
0049     }
0050     catch( std::exception& e )  {
0051       std::cout << "\n"
0052            << "**************************************************** \n"
0053            << "*  A runtime error has occured :                     \n"
0054            << "*    " << e.what()   <<  std::endl
0055            << "*  the program will have to be terminated - sorry.   \n"
0056            << "**************************************************** \n"
0057            <<  std::endl;
0058       // this provokes ROOT seg fault and stack trace (comment out to avoid it)
0059       ::exit(1) ;
0060     }
0061   }
0062 }
0063 
0064 /// Standard constructor
0065 Geant4Kernel::PhaseSelector::PhaseSelector(Geant4Kernel* kernel)
0066   : m_kernel(kernel) {
0067 }
0068 
0069 /// Copy constructor
0070 Geant4Kernel::PhaseSelector::PhaseSelector(const PhaseSelector& c)
0071   : m_kernel(c.m_kernel) {
0072 }
0073 
0074 /// Assignment operator
0075 Geant4Kernel::PhaseSelector& Geant4Kernel::PhaseSelector::operator=(const PhaseSelector& c) {
0076   if ( this != &c )  {
0077     m_kernel = c.m_kernel;
0078   }
0079   return *this;
0080 }
0081 
0082 /// Phase access to the map
0083 Geant4ActionPhase& Geant4Kernel::PhaseSelector::operator[](const std::string& nam) const {
0084   if( Geant4ActionPhase* action_phase = m_kernel->getPhase(nam) )
0085     return *action_phase;
0086   throw except("Geant4Kernel", "Attempt to access the nonexisting phase '%s'", nam.c_str());
0087 }
0088 
0089 /// Standard constructor
0090 Geant4Kernel::Geant4Kernel(Detector& description_ref)
0091   : Geant4ActionContainer(), m_detDesc(&description_ref), 
0092     m_id(Geant4Kernel::thread_self()), m_master(this), phase(this)
0093 {
0094   m_ident = -1;
0095   declareProperty("UI",                   m_uiName);
0096   declareProperty("OutputLevel",          m_outputLevel = DEBUG);
0097   declareProperty("NumEvents",            m_numEvent = 10);
0098   declareProperty("OutputLevels",         m_clientLevels);
0099   declareProperty("NumberOfThreads",      m_numThreads = 0);
0100   declareProperty("HaveScoringManager",   m_haveScoringMgr = false);
0101   declareProperty("SensitiveTypes",       m_sensitiveDetectorTypes);
0102   declareProperty("RunManagerType",       m_runManagerType = "G4RunManager");
0103   declareProperty("DefaultSensitiveType", m_dfltSensitiveDetectorType = "Geant4SensDet");
0104   m_interrupts = new Geant4Interrupts(*this);
0105   m_controlName = "/ddg4/";
0106   m_control = new G4UIdirectory(m_controlName.c_str());
0107   m_control->SetGuidance("Control for named Geant4 actions");
0108   setContext(new Geant4Context(this));
0109   InstanceCount::increment(this);
0110 }
0111 
0112 /// Standard constructor
0113 Geant4Kernel::Geant4Kernel(Geant4Kernel* krnl, unsigned long ident)
0114   : Geant4ActionContainer(), m_id(ident), m_master(krnl), phase(this)
0115 {
0116   char text[64];
0117   m_numThreads     = 1; // Slave instance for one single thread
0118   m_detDesc        = m_master->m_detDesc;
0119   m_world          = m_master->m_world;
0120   m_ident          = m_master->m_workers.size();
0121   m_numEvent       = m_master->m_numEvent;
0122   m_runManagerType = m_master->m_runManagerType;
0123   m_sensitiveDetectorTypes      = m_master->m_sensitiveDetectorTypes;
0124   m_dfltSensitiveDetectorType   = m_master->m_dfltSensitiveDetectorType;
0125   declareProperty("UI",m_uiName = m_master->m_uiName);
0126   declareProperty("OutputLevel",  m_outputLevel  = m_master->m_outputLevel);
0127   declareProperty("OutputLevels", m_clientLevels = m_master->m_clientLevels);
0128   ::snprintf(text, sizeof(text), "/ddg4.%d/", (int)(m_master->m_workers.size()));
0129   m_controlName = text;
0130   m_control = new G4UIdirectory(m_controlName.c_str());
0131   m_control->SetGuidance("Control for thread specific Geant4 actions");
0132   setContext(new Geant4Context(this));
0133   InstanceCount::increment(this);
0134 }
0135 
0136 /// Default destructor
0137 Geant4Kernel::~Geant4Kernel() {
0138   if ( this == s_main_instance.get() )   {
0139     s_main_instance.release();
0140   }
0141   detail::destroyObjects(m_workers);
0142   if ( isMaster() )  {
0143     detail::releaseObjects(m_globalFilters);
0144     detail::releaseObjects(m_globalActions);
0145     detail::deletePtr(m_interrupts);
0146   }
0147   destroyPhases();
0148   detail::deletePtr(m_runManager);
0149   Geant4ActionContainer::terminate();
0150   if ( m_detDesc && isMaster() )  {
0151     try  {
0152       //m_detDesc->removeExtension < Geant4Kernel > (false);
0153       m_detDesc->destroyInstance();
0154       m_detDesc = 0;
0155     }
0156     catch(...)  {
0157     }
0158   }
0159   InstanceCount::decrement(this);
0160 }
0161 
0162 /// Instance accessor
0163 Geant4Kernel& Geant4Kernel::instance(Detector& description) {
0164   if ( nullptr == s_main_instance.get() )   {
0165     G4AutoLock protection_lock(&kernel_mutex);    {
0166       if ( nullptr == s_main_instance.get() )   { // Need to check again!
0167         /// Install here the termination handler
0168         std::set_terminate(description_unexpected);
0169         s_main_instance.reset(new Geant4Kernel(description));
0170       }
0171     }
0172   }
0173   return *(s_main_instance.get());
0174 }
0175 
0176 /// Access interrupt handler. Will be created on the first call
0177 Geant4Interrupts& Geant4Kernel::interruptHandler()  const  {
0178   if ( isMaster() )
0179     return *this->m_interrupts; 
0180   return this->m_master->interruptHandler();
0181 }
0182 
0183 /// Trigger smooth end-of-event-loop with finishing currently processing event
0184 void Geant4Kernel::triggerStop()  {
0185   printout(INFO, "Geant4Kernel",
0186        "+++ Stop signal seen. Will finish after current event(s) have been processed.");
0187   printout(INFO, "Geant4Kernel",
0188        "+++ Depending on the complexity of the simulation, this may take some time ...");
0189   this->m_master->m_processEvents = EVENTLOOP_HALT;
0190 }
0191 
0192 /// Access flag if event loop is enabled
0193 bool Geant4Kernel::processEvents()  const  {
0194   return this->m_master->m_processEvents == EVENTLOOP_RUNNING;
0195 }
0196 
0197 /// Install DDG4 default handler for a given signal. If no handler: return false
0198 bool Geant4Kernel::registerInterruptHandler(int sig_num)   {
0199   if ( sig_num == SIGINT )  {
0200     return interruptHandler().registerHandler_SIGINT();
0201   }
0202   return false;
0203 }
0204 
0205 /// (Re-)apply registered interrupt handlers to override potentially later registrations by other libraries
0206 void Geant4Kernel::applyInterruptHandlers()  {
0207   interruptHandler().applyHandlers();
0208 }
0209 
0210 /// Access thread identifier
0211 unsigned long int Geant4Kernel::thread_self()    {
0212   unsigned long int thr_id = (unsigned long int)::pthread_self();
0213   return thr_id;
0214 }
0215 
0216 /// Create identified worker instance
0217 Geant4Kernel& Geant4Kernel::createWorker()   {
0218   if ( isMaster() )   {
0219     unsigned long identifier = thread_self();
0220     Geant4Kernel* w = new Geant4Kernel(this, identifier);
0221     m_workers[identifier] = w;
0222     printout(INFO, "Geant4Kernel", "+++ Created worker instance id=%ul",identifier);
0223     return *w;
0224   }
0225   except("Geant4Kernel", "DDG4: Only the master instance may create workers.");
0226   throw std::runtime_error("Geant4Kernel::createWorker");
0227 }
0228 
0229 /// Access worker instance by its identifier
0230 Geant4Kernel& Geant4Kernel::worker(unsigned long identifier, bool create_if)    {
0231   if ( Workers::iterator i=m_workers.find(identifier); i != m_workers.end() )   {
0232     return *((*i).second);
0233   }
0234   else if ( identifier == m_id )  {
0235     return *this;
0236   }
0237   else if ( !isMultiThreaded() )  {
0238     unsigned long self = thread_self();
0239     if ( identifier == self )  {
0240       return *this;
0241     }
0242   }
0243   else if( create_if )  {
0244     return createWorker();
0245   }
0246   except("Geant4Kernel", "DDG4: The Kernel object 0x%p does not exists!",(void*)identifier);
0247   throw std::runtime_error("Geant4Kernel::worker");
0248 }
0249 
0250 /// Access number of workers
0251 int Geant4Kernel::numWorkers() const   {
0252   return m_workers.size();
0253 }
0254 
0255 /// Access to geometry world
0256 G4VPhysicalVolume* Geant4Kernel::world()  const   {
0257   if( this != m_master ) return m_master->world();
0258   return m_world;
0259 }
0260 
0261 /// Set the geometry world
0262 void Geant4Kernel::setWorld(G4VPhysicalVolume* volume)  {
0263   if( this == m_master ) m_world = volume;
0264   else m_master->setWorld(volume);
0265 }
0266 
0267 /// Add new sensitive type to factory list
0268 void Geant4Kernel::defineSensitiveDetectorType(const std::string& type, const std::string& factory)  {
0269   auto iter = m_sensitiveDetectorTypes.find(type);
0270   if( iter == m_sensitiveDetectorTypes.end() )  {
0271     printout(INFO,"Geant4Kernel","+++ Define sensitive type: %s -> %s", type.c_str(), factory.c_str());
0272     m_sensitiveDetectorTypes.emplace(type, factory);
0273     return;
0274   }
0275   else if( iter->first == type && iter->second == factory )  {
0276     return;
0277   }
0278   except("Geant4Kernel",
0279          "+++ The sensitive type %s is already defined and used %s. Cannot overwrite with %s",
0280          type.c_str(), iter->second.c_str(), factory.c_str());
0281 }
0282 
0283 void Geant4Kernel::printProperties()  const  {
0284   printout(ALWAYS,"Geant4Kernel","OutputLevel:  %d",  m_outputLevel);
0285   printout(ALWAYS,"Geant4Kernel","UI:           %s",  m_uiName.c_str());
0286   printout(ALWAYS,"Geant4Kernel","NumEvents:    %ld", m_numEvent);
0287   printout(ALWAYS,"Geant4Kernel","NumThreads:   %d",  m_numThreads);
0288   for( const auto& [name, level] : m_clientLevels )
0289     printout(ALWAYS,"Geant4Kernel","OutputLevel[%s]:  %d", name.c_str(), level);
0290 }
0291 
0292 /// Check property for existence
0293 bool Geant4Kernel::hasProperty(const std::string& name) const    {
0294   return m_properties.exists(name);
0295 }
0296 
0297 /// Access single property
0298 dd4hep::Property& Geant4Kernel::property(const std::string& name)   {
0299   return properties()[name];
0300 }
0301 
0302 /// Fill cache with the global output level of a named object. Must be set before instantiation
0303 void Geant4Kernel::setOutputLevel(const std::string object, PrintLevel new_level)   {
0304   m_clientLevels[object] = new_level;
0305 }
0306 
0307 /// Retrieve the global output level of a named object.
0308 dd4hep::PrintLevel Geant4Kernel::getOutputLevel(const std::string object) const   {
0309   if( auto i=m_clientLevels.find(object); i != m_clientLevels.end() )
0310     return (PrintLevel)(*i).second;
0311   return dd4hep::PrintLevel(dd4hep::printLevel()-1);
0312 }
0313 
0314 /// Set the output level; returns previous value
0315 dd4hep::PrintLevel Geant4Kernel::setOutputLevel(PrintLevel new_level)  {
0316   int old = m_outputLevel;
0317   m_outputLevel = new_level;
0318   return (PrintLevel)old;
0319 }
0320 
0321 /// Access to the Geant4 run manager
0322 G4RunManager& Geant4Kernel::runManager() {
0323   if ( m_runManager )  {
0324     return *m_runManager;
0325   }
0326   else if ( isMaster() )   {
0327     Geant4Action* mgr =
0328       PluginService::Create<Geant4Action*>(m_runManagerType,
0329                                            m_context,
0330                                            std::string("Geant4RunManager"));
0331     if ( !mgr )   {
0332       except("Geant4Kernel",
0333              "+++ Invalid Geant4RunManager class: %s. Aborting.",
0334              m_runManagerType.c_str());
0335     }
0336     mgr->property("NumberOfThreads").set(m_numThreads);
0337     mgr->enableUI();
0338     if ( this->m_haveScoringMgr )  {
0339       if ( nullptr == G4ScoringManager::GetScoringManager() )  {
0340         except("Geant4Kernel", "+++ FAILED to create the G4ScoringManager instance.");
0341       }
0342     }
0343     m_runManager = dynamic_cast<G4RunManager*>(mgr);
0344     if ( m_runManager )  {
0345       return *m_runManager;
0346     }
0347     except("Geant4Kernel",
0348            "+++ Invalid Geant4RunManager action: %s. Invalid inheritance.",
0349            m_runManagerType.c_str());
0350   }
0351   except("Geant4Kernel", 
0352          "+++ Only the master thread may instantiate a G4RunManager object!");
0353   throw std::runtime_error("Is never called -- just to satisfy compiler!");
0354 }
0355 
0356 /// Construct detector geometry using description plugin
0357 void Geant4Kernel::loadGeometry(const std::string& compact_file) {
0358   char* arg = (char*) compact_file.c_str();
0359   m_detDesc->apply("DD4hep_XMLLoader", 1, &arg);
0360   //return *this;
0361 }
0362 
0363 // Utility function to load XML files
0364 void Geant4Kernel::loadXML(const char* fname) {
0365   const char* args[] = { fname, 0 };
0366   m_detDesc->apply("DD4hep_XMLLoader", 1, (char**) args);
0367 }
0368 
0369 /// Register configure callback
0370 void Geant4Kernel::register_configure(const std::function<void()>& callback)  {
0371   m_actionConfigure.push_back(callback);
0372 }
0373 
0374 /// Register initialize callback
0375 void Geant4Kernel::register_initialize(const std::function<void()>& callback)  {
0376   m_actionInitialize.push_back(callback);
0377 }
0378 
0379 /// Register terminate callback
0380 void Geant4Kernel::register_terminate(const std::function<void()>& callback)  {
0381   m_actionTerminate.push_back(callback);
0382 }
0383 
0384 /// Configure Geant4 kernel object
0385 int Geant4Kernel::configure() {
0386   int status = Geant4Exec::configure(*this);
0387   if ( status )   {
0388     for(auto& call : m_actionConfigure) call();
0389     return status;
0390   }
0391   except("Geant4Kernel","++ FAILED to configure DDG4 executive");
0392   return status;
0393 }
0394 
0395 /// Initialize Geant4 kernel object
0396 int Geant4Kernel::initialize() {
0397   int status = Geant4Exec::initialize(*this);
0398   if ( status )   {
0399     for(auto& call : m_actionInitialize) call();
0400     return status;
0401   }
0402   except("Geant4Kernel","++ FAILED to initialize DDG4 executive");
0403   return status;
0404 }
0405 
0406 /// Run Geant4
0407 int Geant4Kernel::run() {
0408   try  {
0409     auto result = Geant4Exec::run(*this);
0410     // flush the geant4 stream buffer
0411     G4cout << G4endl;
0412     return result;
0413   }
0414   catch(const std::exception& e)   {
0415     printout(FATAL,"Geant4Kernel","+++ Exception while simulating:%s",e.what());
0416   }
0417   catch(...)   {
0418     printout(FATAL,"Geant4Kernel","+++ UNKNOWN exception while simulating.");
0419   }
0420   return 0;
0421 }
0422 
0423 int Geant4Kernel::runEvents(int num_events) {
0424   m_numEvent = num_events;
0425   return Geant4Exec::run(*this);
0426 }
0427 
0428 int Geant4Kernel::terminate() {
0429   const Geant4Kernel* ptr = s_main_instance.get();
0430   printout(INFO,"Geant4Kernel","++ Terminate Geant4 and delete associated actions.");
0431   if ( ptr == this )  {
0432     auto calls = std::move(m_actionTerminate);
0433     for(auto& call : calls) call();
0434     Geant4Exec::terminate(*this);
0435     m_actionTerminate = std::move(calls);
0436   }
0437   destroyPhases();
0438   detail::releaseObjects(m_globalFilters);
0439   detail::releaseObjects(m_globalActions);
0440   if ( ptr == this )  {
0441     detail::deletePtr(m_runManager);
0442   }
0443   Geant4ActionContainer::terminate();
0444   if ( ptr == this && m_detDesc )  {
0445     //m_detDesc->removeExtension < Geant4Kernel > (false);
0446     m_detDesc->destroyInstance();
0447     m_detDesc = 0;
0448   }
0449   return 1;
0450 }
0451 
0452 /// Register action by name to be retrieved when setting up and connecting action objects
0453 /** Note: registered actions MUST be unique.
0454  *  However, not all actions need to registered....
0455  *  Only register those, you later need to retrieve by name.
0456  */
0457 Geant4Kernel& Geant4Kernel::registerGlobalAction(Geant4Action* action) {
0458   if( action ) {
0459     const std::string& nam = action->name();
0460     if( auto i=m_globalActions.find(nam); i == m_globalActions.end() ) {
0461       action->addRef();
0462       m_globalActions[nam] = action;
0463       printout(INFO,"Geant4Kernel","++ Registered global action %s of type %s",
0464                nam.c_str(),typeName(typeid(*action)).c_str());
0465       return *this;
0466     }
0467     except("Geant4Kernel", "DDG4: The action '%s' is already globally "
0468            "registered. [Action-Already-Registered]", nam.c_str());
0469   }
0470   except("Geant4Kernel",
0471          "DDG4: Attempt to globally register an invalid action. [Action-Invalid]");
0472   return *this;
0473 }
0474 
0475 /// Retrieve action from repository
0476 Geant4Action* Geant4Kernel::globalAction(const std::string& nam, bool throw_if_not_present) {
0477   if( auto i=m_globalActions.find(nam); i != m_globalActions.end() )
0478     return (*i).second;
0479   if( throw_if_not_present )   {
0480     except("Geant4Kernel", "DDG4: The action '%s' is not globally "
0481            "registered. [Action-Missing]", nam.c_str());
0482   }
0483   return nullptr;
0484 }
0485 
0486 /// Register filter by name to be retrieved when setting up and connecting filter objects
0487 /** Note: registered filters MUST be unique.
0488  *  However, not all filters need to registered....
0489  *  Only register those, you later need to retrieve by name.
0490  */
0491 Geant4Kernel& Geant4Kernel::registerGlobalFilter(Geant4Action* filter) {
0492   if( filter )   {
0493     const std::string& nam = filter->name();
0494     if( auto i=m_globalFilters.find(nam); i == m_globalFilters.end()) {
0495       filter->addRef();
0496       m_globalFilters[nam] = filter;
0497       return *this;
0498     }
0499     except("Geant4Kernel", "DDG4: The filter '%s' is already globally "
0500            "registered. [Filter-Already-Registered]", nam.c_str());
0501   }
0502   except("Geant4Kernel",
0503          "DDG4: Attempt to globally register an invalid filter. [Filter-Invalid]");
0504   return *this;
0505 }
0506 
0507 /// Retrieve filter from repository
0508 Geant4Action* Geant4Kernel::globalFilter(const std::string& filter_name, bool throw_if_not_present) {
0509   if( auto i=m_globalFilters.find(filter_name); i != m_globalFilters.end())
0510     return (*i).second;
0511   if (throw_if_not_present) {
0512     except("Geant4Kernel", "DDG4: The filter '%s' is not already globally "
0513            "registered. [Filter-Missing]", filter_name.c_str());
0514   }
0515   return nullptr;
0516 }
0517 
0518 /// Execute phase action if it exists
0519 bool Geant4Kernel::executePhase(const std::string& nam, const void** arguments)  const   {
0520   if( auto i=m_phases.find(nam); i != m_phases.end() )   {
0521     (*i).second->execute(arguments);
0522     return true;
0523   }
0524   return false;
0525 }
0526 
0527 /// Access phase by name
0528 Geant4ActionPhase* Geant4Kernel::getPhase(const std::string& nam)   {
0529   if( auto i=m_phases.find(nam); i != m_phases.end() )
0530     return (*i).second;
0531   except("Geant4Kernel", "DDG4: The Geant4 action phase '%s' does not exist. [No-Entry]", nam.c_str());
0532   return nullptr;
0533 }
0534 
0535 /// Add a new phase to the phase
0536 Geant4ActionPhase* Geant4Kernel::addSimplePhase(const std::string& name, bool throw_on_exist)   {
0537   return addPhase(name,typeid(void),typeid(void),typeid(void),throw_on_exist);
0538 }
0539 
0540 /// Add a new phase
0541 Geant4ActionPhase* Geant4Kernel::addPhase(const std::string& nam,
0542                                           const std::type_info& arg0,
0543                                           const std::type_info& arg1,
0544                                           const std::type_info& arg2,
0545                                           bool throw_on_exist)
0546 {
0547   if( auto i=m_phases.find(nam); i == m_phases.end() )   {
0548     Geant4ActionPhase* p = new Geant4ActionPhase(workerContext(), nam, arg0, arg1, arg2);
0549     m_phases.emplace(nam, p);
0550     return p;
0551   }
0552   else if (throw_on_exist) {
0553     except("Geant4Kernel", "DDG4: The Geant4 action phase %s already exists. [Already-Exists]", nam.c_str());
0554   }
0555   return nullptr;
0556 }
0557 
0558 /// Remove an existing phase from the phase. If not existing returns false
0559 bool Geant4Kernel::removePhase(const std::string& nam) {
0560   if( auto i=m_phases.find(nam); i != m_phases.end() )   {
0561     delete (*i).second;
0562     m_phases.erase(i);
0563     return true;
0564   }
0565   return false;
0566 }
0567 
0568 /// Destroy all phases. To be called only at shutdown
0569 void Geant4Kernel::destroyPhases() {
0570   detail::destroyObjects(m_phases);
0571 }