File indexing completed on 2025-03-13 08:20:15
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
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
0028 #include <G4RunManager.hh>
0029 #include <G4ScoringManager.hh>
0030 #include <G4UIdirectory.hh>
0031 #include <G4Threading.hh>
0032 #include <G4AutoLock.hh>
0033
0034
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
0059 ::exit(1) ;
0060 }
0061 }
0062 }
0063
0064
0065 Geant4Kernel::PhaseSelector::PhaseSelector(Geant4Kernel* kernel)
0066 : m_kernel(kernel) {
0067 }
0068
0069
0070 Geant4Kernel::PhaseSelector::PhaseSelector(const PhaseSelector& c)
0071 : m_kernel(c.m_kernel) {
0072 }
0073
0074
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
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
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
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;
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
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
0153 m_detDesc->destroyInstance();
0154 m_detDesc = 0;
0155 }
0156 catch(...) {
0157 }
0158 }
0159 InstanceCount::decrement(this);
0160 }
0161
0162
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() ) {
0167
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
0177 Geant4Interrupts& Geant4Kernel::interruptHandler() const {
0178 if ( isMaster() )
0179 return *this->m_interrupts;
0180 return this->m_master->interruptHandler();
0181 }
0182
0183
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
0193 bool Geant4Kernel::processEvents() const {
0194 return this->m_master->m_processEvents == EVENTLOOP_RUNNING;
0195 }
0196
0197
0198 bool Geant4Kernel::registerInterruptHandler(int sig_num) {
0199 if ( sig_num == SIGINT ) {
0200 return interruptHandler().registerHandler_SIGINT();
0201 }
0202 return false;
0203 }
0204
0205
0206 void Geant4Kernel::applyInterruptHandlers() {
0207 interruptHandler().applyHandlers();
0208 }
0209
0210
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
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
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
0251 int Geant4Kernel::numWorkers() const {
0252 return m_workers.size();
0253 }
0254
0255
0256 G4VPhysicalVolume* Geant4Kernel::world() const {
0257 if( this != m_master ) return m_master->world();
0258 return m_world;
0259 }
0260
0261
0262 void Geant4Kernel::setWorld(G4VPhysicalVolume* volume) {
0263 if( this == m_master ) m_world = volume;
0264 else m_master->setWorld(volume);
0265 }
0266
0267
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
0293 bool Geant4Kernel::hasProperty(const std::string& name) const {
0294 return m_properties.exists(name);
0295 }
0296
0297
0298 dd4hep::Property& Geant4Kernel::property(const std::string& name) {
0299 return properties()[name];
0300 }
0301
0302
0303 void Geant4Kernel::setOutputLevel(const std::string object, PrintLevel new_level) {
0304 m_clientLevels[object] = new_level;
0305 }
0306
0307
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
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
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
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
0361 }
0362
0363
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
0370 void Geant4Kernel::register_configure(const std::function<void()>& callback) {
0371 m_actionConfigure.push_back(callback);
0372 }
0373
0374
0375 void Geant4Kernel::register_initialize(const std::function<void()>& callback) {
0376 m_actionInitialize.push_back(callback);
0377 }
0378
0379
0380 void Geant4Kernel::register_terminate(const std::function<void()>& callback) {
0381 m_actionTerminate.push_back(callback);
0382 }
0383
0384
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
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
0407 int Geant4Kernel::run() {
0408 try {
0409 auto result = Geant4Exec::run(*this);
0410
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
0446 m_detDesc->destroyInstance();
0447 m_detDesc = 0;
0448 }
0449 return 1;
0450 }
0451
0452
0453
0454
0455
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
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
0487
0488
0489
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
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
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
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
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
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
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
0569 void Geant4Kernel::destroyPhases() {
0570 detail::destroyObjects(m_phases);
0571 }