Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-12 08:24:36

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   Geant4Kernel* s_main_instance = nullptr;
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 )   {
0139     s_main_instance = nullptr;
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 )   {
0165     G4AutoLock protection_lock(&kernel_mutex);    {
0166       if ( nullptr == s_main_instance )   { // Need to check again!
0167         /// Install here the termination handler
0168         std::set_terminate(description_unexpected);
0169         s_main_instance = new Geant4Kernel(description);
0170       }
0171     }
0172   }
0173   return *s_main_instance;
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 /// Run dd4hep plugin
0370 long Geant4Kernel::runPlugin( const std::string& plugin, const std::vector<std::string>& args )  {
0371   std::vector<const char*> arguments;
0372   arguments.reserve( args.size()+1 );
0373   for( const auto& a : args )
0374     arguments.push_back( a.c_str() );
0375   arguments.push_back( nullptr );
0376   return m_detDesc->apply( plugin.c_str(), args.size(), (char**) &arguments.at(0) );
0377 }
0378 
0379 /// Register configure callback
0380 void Geant4Kernel::register_configure(const std::function<void()>& callback)  {
0381   m_actionConfigure.push_back(callback);
0382 }
0383 
0384 /// Register initialize callback
0385 void Geant4Kernel::register_initialize(const std::function<void()>& callback)  {
0386   m_actionInitialize.push_back(callback);
0387 }
0388 
0389 /// Register terminate callback
0390 void Geant4Kernel::register_terminate(const std::function<void()>& callback)  {
0391   m_actionTerminate.push_back(callback);
0392 }
0393 
0394 /// Configure Geant4 kernel object
0395 int Geant4Kernel::configure() {
0396   int status = Geant4Exec::configure(*this);
0397   if ( status )   {
0398     for(auto& call : m_actionConfigure) call();
0399     return status;
0400   }
0401   except("Geant4Kernel","++ FAILED to configure DDG4 executive");
0402   return status;
0403 }
0404 
0405 /// Initialize Geant4 kernel object
0406 int Geant4Kernel::initialize() {
0407   int status = Geant4Exec::initialize(*this);
0408   if ( status )   {
0409     for(auto& call : m_actionInitialize) call();
0410     return status;
0411   }
0412   except("Geant4Kernel","++ FAILED to initialize DDG4 executive");
0413   return status;
0414 }
0415 
0416 /// Run Geant4
0417 int Geant4Kernel::run() {
0418   try  {
0419     auto result = Geant4Exec::run(*this);
0420     // flush the geant4 stream buffer
0421     G4cout << G4endl;
0422     return result;
0423   }
0424   catch(const std::exception& e)   {
0425     printout(FATAL,"Geant4Kernel","+++ Exception while simulating:%s",e.what());
0426   }
0427   catch(...)   {
0428     printout(FATAL,"Geant4Kernel","+++ UNKNOWN exception while simulating.");
0429   }
0430   return 0;
0431 }
0432 
0433 int Geant4Kernel::runEvents(int num_events) {
0434   m_numEvent = num_events;
0435   return Geant4Exec::run(*this);
0436 }
0437 
0438 int Geant4Kernel::terminate() {
0439   const Geant4Kernel* ptr = s_main_instance;
0440   printout(INFO,"Geant4Kernel","++ Terminate Geant4 and delete associated actions.");
0441   if ( ptr == this )  {
0442     auto calls = std::move(m_actionTerminate);
0443     for(auto& call : calls) call();
0444     Geant4Exec::terminate(*this);
0445     m_actionTerminate = std::move(calls);
0446   }
0447   destroyPhases();
0448   detail::releaseObjects(m_globalFilters);
0449   detail::releaseObjects(m_globalActions);
0450   if ( ptr == this )  {
0451     detail::deletePtr(m_runManager);
0452   }
0453   Geant4ActionContainer::terminate();
0454   if ( ptr == this && m_detDesc )  {
0455     //m_detDesc->removeExtension < Geant4Kernel > (false);
0456     m_detDesc->destroyInstance();
0457     m_detDesc = 0;
0458   }
0459   return 1;
0460 }
0461 
0462 /// Register action by name to be retrieved when setting up and connecting action objects
0463 /** Note: registered actions MUST be unique.
0464  *  However, not all actions need to registered....
0465  *  Only register those, you later need to retrieve by name.
0466  */
0467 Geant4Kernel& Geant4Kernel::registerGlobalAction(Geant4Action* action) {
0468   if( action ) {
0469     const std::string& nam = action->name();
0470     if( auto i=m_globalActions.find(nam); i == m_globalActions.end() ) {
0471       action->addRef();
0472       m_globalActions[nam] = action;
0473       printout(INFO,"Geant4Kernel","++ Registered global action %s of type %s",
0474                nam.c_str(),typeName(typeid(*action)).c_str());
0475       return *this;
0476     }
0477     except("Geant4Kernel", "DDG4: The action '%s' is already globally "
0478            "registered. [Action-Already-Registered]", nam.c_str());
0479   }
0480   except("Geant4Kernel",
0481          "DDG4: Attempt to globally register an invalid action. [Action-Invalid]");
0482   return *this;
0483 }
0484 
0485 /// Retrieve action from repository
0486 Geant4Action* Geant4Kernel::globalAction(const std::string& nam, bool throw_if_not_present) {
0487   if( auto i=m_globalActions.find(nam); i != m_globalActions.end() )
0488     return (*i).second;
0489   if( throw_if_not_present )   {
0490     except("Geant4Kernel", "DDG4: The action '%s' is not globally "
0491            "registered. [Action-Missing]", nam.c_str());
0492   }
0493   return nullptr;
0494 }
0495 
0496 /// Register filter by name to be retrieved when setting up and connecting filter objects
0497 /** Note: registered filters MUST be unique.
0498  *  However, not all filters need to registered....
0499  *  Only register those, you later need to retrieve by name.
0500  */
0501 Geant4Kernel& Geant4Kernel::registerGlobalFilter(Geant4Action* filter) {
0502   if( filter )   {
0503     const std::string& nam = filter->name();
0504     if( auto i=m_globalFilters.find(nam); i == m_globalFilters.end()) {
0505       filter->addRef();
0506       m_globalFilters[nam] = filter;
0507       return *this;
0508     }
0509     except("Geant4Kernel", "DDG4: The filter '%s' is already globally "
0510            "registered. [Filter-Already-Registered]", nam.c_str());
0511   }
0512   except("Geant4Kernel",
0513          "DDG4: Attempt to globally register an invalid filter. [Filter-Invalid]");
0514   return *this;
0515 }
0516 
0517 /// Retrieve filter from repository
0518 Geant4Action* Geant4Kernel::globalFilter(const std::string& filter_name, bool throw_if_not_present) {
0519   if( auto i=m_globalFilters.find(filter_name); i != m_globalFilters.end())
0520     return (*i).second;
0521   if (throw_if_not_present) {
0522     except("Geant4Kernel", "DDG4: The filter '%s' is not already globally "
0523            "registered. [Filter-Missing]", filter_name.c_str());
0524   }
0525   return nullptr;
0526 }
0527 
0528 /// Execute phase action if it exists
0529 bool Geant4Kernel::executePhase(const std::string& nam, const void** arguments)  const   {
0530   if( auto i=m_phases.find(nam); i != m_phases.end() )   {
0531     (*i).second->execute(arguments);
0532     return true;
0533   }
0534   return false;
0535 }
0536 
0537 /// Access phase by name
0538 Geant4ActionPhase* Geant4Kernel::getPhase(const std::string& nam)   {
0539   if( auto i=m_phases.find(nam); i != m_phases.end() )
0540     return (*i).second;
0541   except("Geant4Kernel", "DDG4: The Geant4 action phase '%s' does not exist. [No-Entry]", nam.c_str());
0542   return nullptr;
0543 }
0544 
0545 /// Add a new phase to the phase
0546 Geant4ActionPhase* Geant4Kernel::addSimplePhase(const std::string& name, bool throw_on_exist)   {
0547   return addPhase(name,typeid(void),typeid(void),typeid(void),throw_on_exist);
0548 }
0549 
0550 /// Add a new phase
0551 Geant4ActionPhase* Geant4Kernel::addPhase(const std::string& nam,
0552                                           const std::type_info& arg0,
0553                                           const std::type_info& arg1,
0554                                           const std::type_info& arg2,
0555                                           bool throw_on_exist)
0556 {
0557   if( auto i=m_phases.find(nam); i == m_phases.end() )   {
0558     Geant4ActionPhase* p = new Geant4ActionPhase(workerContext(), nam, arg0, arg1, arg2);
0559     m_phases.emplace(nam, p);
0560     return p;
0561   }
0562   else if (throw_on_exist) {
0563     except("Geant4Kernel", "DDG4: The Geant4 action phase %s already exists. [Already-Exists]", nam.c_str());
0564   }
0565   return nullptr;
0566 }
0567 
0568 /// Remove an existing phase from the phase. If not existing returns false
0569 bool Geant4Kernel::removePhase(const std::string& nam) {
0570   if( auto i=m_phases.find(nam); i != m_phases.end() )   {
0571     delete (*i).second;
0572     m_phases.erase(i);
0573     return true;
0574   }
0575   return false;
0576 }
0577 
0578 /// Destroy all phases. To be called only at shutdown
0579 void Geant4Kernel::destroyPhases() {
0580   detail::destroyObjects(m_phases);
0581 }