From 9e05869b75c27b36a5485bce34a714dbc60be23a Mon Sep 17 00:00:00 2001 From: Markus Frank <Markus.Frank@cern.ch> Date: Wed, 29 Nov 2017 20:21:04 +0100 Subject: [PATCH] Add user defined framework context to DDG4and make the G4RunManager instantiation a plugin this should consequently allow for user defined specializations. --- DDG4/include/DDG4/Geant4Context.h | 50 +++++++++++++++ DDG4/include/DDG4/Geant4Kernel.h | 19 ++++-- DDG4/plugins/Geant4RunManagers.cpp | 100 +++++++++++++++++++++++++++++ DDG4/plugins/Geant4SDActions.cpp | 31 ++++++++- DDG4/src/Geant4Context.cpp | 5 ++ DDG4/src/Geant4Kernel.cpp | 88 ++++++++++++------------- 6 files changed, 245 insertions(+), 48 deletions(-) create mode 100644 DDG4/plugins/Geant4RunManagers.cpp diff --git a/DDG4/include/DDG4/Geant4Context.h b/DDG4/include/DDG4/Geant4Context.h index 2500bc211..20b130b89 100644 --- a/DDG4/include/DDG4/Geant4Context.h +++ b/DDG4/include/DDG4/Geant4Context.h @@ -154,16 +154,62 @@ namespace dd4hep { /// Generic context to extend user, run and event information /** + * A valid instance of the Geant4Context is passed to every instance of a Geant4Action at + * creation time. + * + * The Geant4Context is the main thread specific accessor to the dd4hep, DDG4 and + * the user framework. + * - The access to the dd4hep objects is via the Geant4Context::detectorDescription() call, + * - the access to DDG4 as a whole is supported via Geant4Context::kernel() and + * - the access to the user gframework using a specialized implementation of: + * template <typename T> T& userFramework() const; + * + * A user defined implementations must be specialized somewhere in a compilation unit + * of the user framework, not in a header file. The framework object could host + * e.g. references for histogramming, logging, data access etc. + * + * This way any experiment/user related data processing framework can exhibit + * it's essential tools to DDG4 actions. + * + * A possible specialized implementations would look like the following: + * + * struct Gaudi { + * IMessageSvc* msg; + * IHistogramSvc* histos; + * .... + * }; + * + * template<> Gaudi& Geant4Context::userFramework<Gaudi>() const { + * UserFramework& fw = m_kernel->userFramework(); + * if ( fw.first && &typeid(T) == fw.second ) return *(T*)fw.first; + * throw std::runtime_error("No user specified framework context present!"); + * } + * + * To access the user framework then use the following call: + * Gaudi* fw = context->userFramework<Gaudi>(); + * + * of course after having initialized it: + * Gaudi * fw = ...; + * GaudiKernel& kernel = ...; + * kernel.setUserFramework(fw); + * * \author M.Frank * \version 1.0 * \ingroup DD4HEP_SIMULATION */ class Geant4Context { + public: friend class Geant4Kernel; + typedef std::pair<void*, const std::type_info*> UserFramework; + protected: + /// Reference to the kernel object Geant4Kernel* m_kernel; + /// Transient context variable - depending on the thread context: run reference Geant4Run* m_run; + /// Transient context variable - depending on the thread context: event reference Geant4Event* m_event; + /// Default constructor Geant4Context(Geant4Kernel* kernel); public: @@ -183,6 +229,10 @@ namespace dd4hep { Geant4Event* eventPtr() const { return m_event; } /// Access to the kernel object Geant4Kernel& kernel() const { return *m_kernel; } + /// Access to the user framework. Specialized function to be implemented by the client + template <typename T> T& framework() const; + /// Generic framework access + UserFramework& userFramework() const; /// Access to detector description Detector& detectorDescription() const; /// Access the tracking manager diff --git a/DDG4/include/DDG4/Geant4Kernel.h b/DDG4/include/DDG4/Geant4Kernel.h index 2648acd0b..09a342ecd 100644 --- a/DDG4/include/DDG4/Geant4Kernel.h +++ b/DDG4/include/DDG4/Geant4Kernel.h @@ -35,6 +35,8 @@ namespace dd4hep { /// Class, which allows all Geant4Action derivatives to access the DDG4 kernel structures. /** + * To implement access to a user specified framework please see class Geant4Context. + * * \author M.Frank * \version 1.0 * \ingroup DD4HEP_SIMULATION @@ -45,6 +47,7 @@ namespace dd4hep { typedef std::map<std::string, Geant4ActionPhase*> Phases; typedef std::map<std::string, Geant4Action*> GlobalActions; typedef std::map<std::string,int> ClientOutputLevels; + typedef std::pair<void*, const std::type_info*> UserFramework; protected: /// Reference to the run manager @@ -57,7 +60,8 @@ namespace dd4hep { Detector* m_detDesc; /// Property pool PropertyManager m_properties; - + /// Reference to the user framework + UserFramework m_userFramework; /// Action phases Phases m_phases; @@ -67,16 +71,18 @@ namespace dd4hep { GlobalActions m_globalActions; /// Globally registered filters of sensitive detectors GlobalActions m_globalFilters; + /// Property: Client output levels + ClientOutputLevels m_clientLevels; /// Property: Name of the G4UI command tree std::string m_controlName; /// Property: Name of the UI action. Must be member of the global actions std::string m_uiName; + /// Property: Name of the G4 run manager factory to be used. Default: Geant4RunManager + std::string m_runManagerType; /// Property: Number of events to be executed in batch mode long m_numEvent; /// Property: Output level int m_outputLevel; - /// Property: Client output levels - ClientOutputLevels m_clientLevels; /// Property: Running in multi threaded context //bool m_multiThreaded; @@ -159,7 +165,12 @@ namespace dd4hep { unsigned long id() const { return m_ident; } /// Access to the Geant4 run manager G4RunManager& runManager(); - + /// Generic framework access + UserFramework& userFramework() { return m_userFramework; } + /// Set the framework context to the kernel object + template <typename T> void setUserFramework(T* object) { + m_userFramework = UserFramework(object,&typeid(T)); + } /** Property access */ /// Access to the properties of the object PropertyManager& properties() { return m_properties; } diff --git a/DDG4/plugins/Geant4RunManagers.cpp b/DDG4/plugins/Geant4RunManagers.cpp new file mode 100644 index 000000000..818ae7362 --- /dev/null +++ b/DDG4/plugins/Geant4RunManagers.cpp @@ -0,0 +1,100 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== +#ifndef DDG4_GEANT4RUNMANAGER_H +#define DDG4_GEANT4RUNMANAGER_H 1 + +/// Framework include files +#include "DDG4/Geant4Action.h" + +/// Geant4 include files +#include "G4RunManager.hh" + +typedef G4RunManager G4__RunManager; + +/// Namespace for the AIDA detector description toolkit +namespace dd4hep { + + /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit + namespace sim { + + /// Geant4 run manager plugin class. + /** + * The plugin acts as a normal Geant4Action. However, it must support a + * dynamic_cast to G4RunManager. + * The templated class may be specialized by any user defined class + * which has G4RunManager as a super class. + * + * Current specializations are: + * - G4RunManager for single threaded applications + * - G4MTRunManager for multi threaded applications + * + * For convenience we name the factory instances according to the G4 classes. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + template <typename RUNMANAGER> + class Geant4RunManager : public Geant4Action, public RUNMANAGER { + public: + Geant4RunManager(Geant4Context* ctxt, const std::string& nam) + : Geant4Action(ctxt, nam), RUNMANAGER() + { + declareProperty("NumberOfThreads", m_numThreads); + } + virtual ~Geant4RunManager() { } + /// Enable and install UI messenger + virtual void enableUI(); + private: + /// global range cut for secondary productions + int m_numThreads; + }; + template <> void Geant4RunManager<G4RunManager>::enableUI() { + Geant4Action::enableUI(); + printout(WARNING,"Geant4RunManager","+++ Configured run manager of type: %s.", + typeName(typeid(G4RunManager)).c_str()); + printout(WARNING,"Geant4Kernel","+++ Multi-threaded mode requested, " + "but not supported by this compilation of Geant4."); + printout(WARNING,"Geant4Kernel","+++ Falling back to single threaded mode."); + m_numThreads = 0; + } + typedef Geant4RunManager<G4__RunManager> G4RunManager; + } +} +#endif // DDG4_GEANT4RUNMANAGER_H + +#include "DDG4/Factories.h" +using namespace dd4hep::sim; +DECLARE_GEANT4ACTION(G4RunManager) + +#ifdef G4MULTITHREADED +#include "G4MTRunManager.hh" +typedef G4MTRunManager G4__MTRunManager; + +/// Namespace for the AIDA detector description toolkit +namespace dd4hep { + /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit + namespace sim { + template <> void Geant4RunManager<G4MTRunManager>::enableUI() { + Geant4Action::enableUI(); + this->RUNMANAGER::SetNumberOfThreads(m_numThreads); + printout(WARNING,"Geant4RunManager","+++ Configured run manager of type: %s with %d threads.", + typeName(typeid(G4MTRunManager)).c_str(), m_numThreads); + } + typedef Geant4RunManager<G4__MTRunManager> G4MTRunManager; + } +} +DECLARE_GEANT4ACTION(G4MTRunManager) +#endif + + diff --git a/DDG4/plugins/Geant4SDActions.cpp b/DDG4/plugins/Geant4SDActions.cpp index 2bc1c0883..ef5f0d6e1 100644 --- a/DDG4/plugins/Geant4SDActions.cpp +++ b/DDG4/plugins/Geant4SDActions.cpp @@ -25,6 +25,33 @@ namespace dd4hep { /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit namespace sim { + namespace { + struct Geant4VoidSensitive {}; + } + // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Geant4SensitiveAction<Geant4VoidSensitive> + // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + /** \addtogroup Geant4SDActionPlugin + * + * @{ + * \package Geant4VoidSensitiveAction + * \brief Void Sensitive detector action to skip the processing of a detector + * without changing the entire DDG4 setup. + * + * @} + */ + + /// Define collections created by this sensitivie action object + template <> void Geant4SensitiveAction<Geant4VoidSensitive>::defineCollections() { + m_collectionID = -1; + } + + /// Method for generating hit(s) using the information of G4Step object. + template <> bool Geant4SensitiveAction<Geant4VoidSensitive>::process(G4Step* /*step*/,G4TouchableHistory* /*hist*/ ) { + return true; + } + typedef Geant4SensitiveAction<Geant4VoidSensitive> Geant4VoidSensitiveAction; + // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Geant4SensitiveAction<Geant4Tracker> // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -32,7 +59,6 @@ namespace dd4hep { * * @{ * \package Geant4TrackerAction - * * \brief Sensitive detector meant for tracking detectors, will produce one hit per step * * @} @@ -480,6 +506,9 @@ namespace dd4hep { using namespace dd4hep::sim; #include "DDG4/Factories.h" +// Special void entry point +DECLARE_GEANT4SENSITIVE(Geant4VoidSensitiveAction) +// Standard factories used for simulation DECLARE_GEANT4SENSITIVE(Geant4TrackerAction) DECLARE_GEANT4SENSITIVE(Geant4TrackerCombineAction) DECLARE_GEANT4SENSITIVE(Geant4CalorimeterAction) diff --git a/DDG4/src/Geant4Context.cpp b/DDG4/src/Geant4Context.cpp index 01c444f5b..ff303f2c8 100644 --- a/DDG4/src/Geant4Context.cpp +++ b/DDG4/src/Geant4Context.cpp @@ -89,6 +89,11 @@ Detector& Geant4Context::detectorDescription() const { return m_kernel->detectorDescription(); } +/// Generic framework access +Geant4Context::UserFramework& Geant4Context::userFramework() const { + return m_kernel->userFramework(); +} + /// Create a user trajectory G4VTrajectory* Geant4Context::createTrajectory(const G4Track* /* track */) const { string err = dd4hep::format("Geant4Kernel", "createTrajectory: Purely virtual method. requires overloading!"); diff --git a/DDG4/src/Geant4Kernel.cpp b/DDG4/src/Geant4Kernel.cpp index 3408d9a7a..103f99613 100644 --- a/DDG4/src/Geant4Kernel.cpp +++ b/DDG4/src/Geant4Kernel.cpp @@ -14,6 +14,7 @@ // Framework include files #include "DD4hep/Detector.h" #include "DD4hep/Memory.h" +#include "DD4hep/Plugins.h" #include "DD4hep/Printout.h" #include "DD4hep/Primitives.h" #include "DD4hep/InstanceCount.h" @@ -23,11 +24,7 @@ #include "DDG4/Geant4ActionPhase.h" // Geant4 include files -#ifdef G4MULTITHREADED -#include "G4MTRunManager.hh" -#else #include "G4RunManager.hh" -#endif #include "G4UIdirectory.hh" #include "G4Threading.hh" #include "G4AutoLock.hh" @@ -82,10 +79,11 @@ Geant4Kernel::Geant4Kernel(Detector& description_ref) m_detDesc->addExtension < Geant4Kernel > (this); m_ident = -1; declareProperty("UI",m_uiName); - declareProperty("OutputLevel", m_outputLevel = DEBUG); - declareProperty("NumEvents", m_numEvent = 10); - declareProperty("OutputLevels", m_clientLevels); - declareProperty("NumberOfThreads",m_numThreads); + declareProperty("OutputLevel", m_outputLevel = DEBUG); + declareProperty("NumEvents", m_numEvent = 10); + declareProperty("OutputLevels", m_clientLevels); + declareProperty("NumberOfThreads", m_numThreads); + declareProperty("RunManagerType", m_runManagerType = "G4RunManager"); m_controlName = "/ddg4/"; m_control = new G4UIdirectory(m_controlName.c_str()); m_control->SetGuidance("Control for named Geant4 actions"); @@ -101,9 +99,10 @@ Geant4Kernel::Geant4Kernel(Geant4Kernel* m, unsigned long ident) m_threadContext(0), phase(this) { char text[64]; - m_detDesc = m_master->m_detDesc; + m_detDesc = m_master->m_detDesc; m_ident = m_master->m_workers.size(); m_numEvent = m_master->m_numEvent; + m_runManagerType = m_master->m_runManagerType; declareProperty("UI",m_uiName = m_master->m_uiName); declareProperty("OutputLevel", m_outputLevel = m_master->m_outputLevel); declareProperty("OutputLevels",m_clientLevels = m_master->m_clientLevels); @@ -241,26 +240,28 @@ G4RunManager& Geant4Kernel::runManager() { return *m_runManager; } else if ( isMaster() ) { -#ifdef G4MULTITHREADED - if ( m_numThreads > 0 ) { - printout(WARNING,"Geant4Kernel","+++ Multi-threaded mode requested with %d worker threads.",m_numThreads); - G4MTRunManager* run_mgr = new G4MTRunManager; - run_mgr->SetNumberOfThreads(m_numThreads); - m_runManager = run_mgr; - return *m_runManager; + Geant4Action* mgr = + PluginService::Create<Geant4Action*>(m_runManagerType, + m_context, + string("Geant4RunManager")); + if ( !mgr ) { + except("Geant4Kernel", + "+++ Invalid Geant4RunManager class: %s. Aborting.", + m_runManagerType.c_str()); } -#endif - if ( m_numThreads > 0 ) { - printout(WARNING,"Geant4Kernel","+++ Multi-threaded mode requested, " - "but not supported by this compilation of Geant4."); - printout(WARNING,"Geant4Kernel","+++ Falling back to single threaded mode."); - m_numThreads = 0; + mgr->property("NumberOfThreads").set(m_numThreads); + mgr->enableUI(); + m_runManager = dynamic_cast<G4RunManager*>(mgr); + if ( m_runManager ) { + return *m_runManager; } - return *(m_runManager = new G4RunManager); + except("Geant4Kernel", + "+++ Invalid Geant4RunManager action: %s. Invalid inheritance.", + m_runManagerType.c_str()); } - throw runtime_error(format("Geant4Kernel", - "DDG4: Only the master thread may instantiate " - "a G4RunManager object!")); + except("Geant4Kernel", + "+++ Only the master thread may instantiate a G4RunManager object!"); + throw runtime_error("Is never called -- just to satisfy compiler!"); } /// Construct detector geometry using description plugin @@ -312,7 +313,7 @@ int Geant4Kernel::terminate() { detail::releaseObjects(m_globalFilters); detail::releaseObjects(m_globalActions); if ( ptr == this ) { - detail::deletePtr (m_runManager); + detail::deletePtr(m_runManager); } Geant4ActionContainer::terminate(); if ( ptr == this && m_detDesc ) { @@ -339,11 +340,12 @@ Geant4Kernel& Geant4Kernel::registerGlobalAction(Geant4Action* action) { nam.c_str(),typeName(typeid(*action)).c_str()); return *this; } - throw runtime_error(format("Geant4Kernel", "DDG4: The action '%s' is already globally " - "registered. [Action-Already-Registered]", nam.c_str())); + except("Geant4Kernel", "DDG4: The action '%s' is already globally " + "registered. [Action-Already-Registered]", nam.c_str()); } - throw runtime_error(format("Geant4Kernel", "DDG4: Attempt to globally register an invalid " - "action. [Action-Invalid]")); + except("Geant4Kernel", + "DDG4: Attempt to globally register an invalid action. [Action-Invalid]"); + return *this; } /// Retrieve action from repository @@ -351,8 +353,8 @@ Geant4Action* Geant4Kernel::globalAction(const std::string& action_name, bool th GlobalActions::iterator i = m_globalActions.find(action_name); if (i == m_globalActions.end()) { if (throw_if_not_present) { - throw runtime_error(format("Geant4Kernel", "DDG4: The action '%s' is not globally " - "registered. [Action-Missing]", action_name.c_str())); + except("Geant4Kernel", "DDG4: The action '%s' is not globally " + "registered. [Action-Missing]", action_name.c_str()); } return 0; } @@ -373,11 +375,12 @@ Geant4Kernel& Geant4Kernel::registerGlobalFilter(Geant4Action* filter) { m_globalFilters[nam] = filter; return *this; } - throw runtime_error(format("Geant4Kernel", "DDG4: The filter '%s' is already globally " - "registered. [Filter-Already-Registered]", nam.c_str())); + except("Geant4Kernel", "DDG4: The filter '%s' is already globally " + "registered. [Filter-Already-Registered]", nam.c_str()); } - throw runtime_error(format("Geant4Kernel", "DDG4: Attempt to globally register an invalid " - "filter. [Filter-Invalid]")); + except("Geant4Kernel", + "DDG4: Attempt to globally register an invalid filter. [Filter-Invalid]"); + return *this; } /// Retrieve filter from repository @@ -385,8 +388,8 @@ Geant4Action* Geant4Kernel::globalFilter(const std::string& filter_name, bool th GlobalActions::iterator i = m_globalFilters.find(filter_name); if (i == m_globalFilters.end()) { if (throw_if_not_present) { - throw runtime_error(format("Geant4Kernel", "DDG4: The filter '%s' is not already globally " - "registered. [Filter-Missing]", filter_name.c_str())); + except("Geant4Kernel", "DDG4: The filter '%s' is not already globally " + "registered. [Filter-Missing]", filter_name.c_str()); } return 0; } @@ -409,8 +412,8 @@ Geant4ActionPhase* Geant4Kernel::getPhase(const std::string& nam) { if (i != m_phases.end()) { return (*i).second; } - throw runtime_error(format("Geant4Kernel", "DDG4: The Geant4 action phase '%s' " - "does not exist. [No-Entry]", nam.c_str())); + except("Geant4Kernel", "DDG4: The Geant4 action phase '%s' does not exist. [No-Entry]", nam.c_str()); + return 0; } /// Add a new phase to the phase @@ -428,8 +431,7 @@ Geant4ActionPhase* Geant4Kernel::addPhase(const std::string& nam, const type_inf return p; } else if (throw_on_exist) { - throw runtime_error(format("Geant4Kernel", "DDG4: The Geant4 action phase %s " - "already exists. [Already-Exists]", nam.c_str())); + except("Geant4Kernel", "DDG4: The Geant4 action phase %s already exists. [Already-Exists]", nam.c_str()); } return (*i).second; } -- GitLab