diff --git a/CMakeLists.txt b/CMakeLists.txt index 39e38fd1d14476b6003a83f6a287dfa8ebc85708..5e65099568c9177102745a986b43643537ba4832 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,12 +73,17 @@ ELSE() MESSAGE( "All dependencies were found. Run 'make' to build SLIC and 'make install' to install to '${CMAKE_INSTALL_PREFIX}'." ) + # build user plugin library + FILE( GLOB_RECURSE plugin_sources ${PROJECT_SOURCE_DIR}/plugins/*.cc ) + ADD_LIBRARY( slicPlugins SHARED ${plugin_sources} ) + INSTALL( TARGETS slicPlugins DESTINATION ${CMAKE_INSTALL_PREFIX}/slic/lib ) + # set executable target ADD_EXECUTABLE( slic ${library_sources} slic.cc ) - # make slic depend on its external deps (is this necessary???) - ADD_DEPENDENCIES( slic extdeps ) - + # make slic depend on its external deps + ADD_DEPENDENCIES( slic extdeps slicPlugins ) + # local includes SET( SLIC_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include ) INCLUDE_DIRECTORIES( ${SLIC_INCLUDE_DIR} ) @@ -93,7 +98,7 @@ ELSE() INCLUDE_DIRECTORIES( ${XERCES_INCLUDE_DIR} ${LCIO_INCLUDE_DIRS} ${Geant4_INCLUDE_DIRS} ${GDML_INCLUDE_DIR} ${LCDD_INCLUDE_DIR} ${HEPPDT_INCLUDE_DIR} ) # libraries - TARGET_LINK_LIBRARIES( slic ${XERCES_LIBRARY} ${Geant4_LIBRARIES} ${GDML_LIBRARY} ${LCDD_LIBRARY} ${HEPPDT_LIBRARIES} ${LCIO_LIBRARIES} ) + TARGET_LINK_LIBRARIES( slic ${XERCES_LIBRARY} ${Geant4_LIBRARIES} ${GDML_LIBRARY} ${LCDD_LIBRARY} ${HEPPDT_LIBRARIES} ${LCIO_LIBRARIES} slicPlugins ) # link directories LINK_DIRECTORIES( ${GDML_LIBRARY_DIR} ${LCDD_LIBRARY_DIR} ${LCIO_LIBRARY_DIRS} ) diff --git a/include/EventAction.hh b/include/EventAction.hh index 092994b1dfab96f502710cfb4a341607542047c1..5690791408cac3a786161344deff8c82e2b362aa 100644 --- a/include/EventAction.hh +++ b/include/EventAction.hh @@ -3,6 +3,7 @@ // SLIC #include "Module.hh" +#include "PluginManagerAccessor.hh" // LCDD #include "lcdd/hits/CalorimeterHit.hh" @@ -21,7 +22,7 @@ namespace slic { * @brief Implementation of G4UserEventAction. * @note Calls actions of TrajectoryManager and LcioManager. */ -class EventAction: public G4UserEventAction, public Module { +class EventAction: public G4UserEventAction, public Module, public PluginManagerAccessor { public: diff --git a/include/PluginLoader.hh b/include/PluginLoader.hh new file mode 100644 index 0000000000000000000000000000000000000000..02bc4f0f719c2e36222b3889f73237b7d899f6e5 --- /dev/null +++ b/include/PluginLoader.hh @@ -0,0 +1,55 @@ +/** + * @file PluginLoader.h + * @brief Class which loads user simulation plugins from external shared libraries + * @author Jeremy McCormick, SLAC National Accelerator Laboratory + */ + +#ifndef SLIC_PLUGINLOADER_HH_ +#define SLIC_PLUGINLOADER_HH_ + +// LDMX +#include "UserActionPlugin.hh" + +namespace slic { + +/** + * @class PluginLoader + * @brief Loads user sim plugin classes from external shared libraries + */ +class PluginLoader { + + public: + + /** + * Create a user sim plugin with the given name from the supplied + * library name. + * @param pluginName The name of the plugin. + * @param libName The name of the shared library. + */ + UserActionPlugin* create(std::string pluginName, std::string libName); + + /** + * Destroy an existing user sim plugin. + * @param plugin The sim plugin to destroy. + */ + void destroy(UserActionPlugin* plugin); + + private: + + /** + * Get a handle for a plugin. + * @param pluginName The name of the plugin. + */ + void* getHandle(std::string pluginName); + + private: + + /** + * Map of plugins to their handles. + */ + std::map<UserActionPlugin*, void*> pluginHandles_; +}; + +} + +#endif diff --git a/include/PluginManager.hh b/include/PluginManager.hh new file mode 100644 index 0000000000000000000000000000000000000000..c11877d9cf2cd1886a8b9ed945c612a9f01f9edf --- /dev/null +++ b/include/PluginManager.hh @@ -0,0 +1,194 @@ +/** + * @file PluginManager.h + * @brief Class for managing the loading, activation and destruction of UserSimPlugin objects + * @author Jeremy McCormick, SLAC National Accelerator Laboratory + */ + +#ifndef SLIC_PLUGINMANAGER_HH_ +#define SLIC_PLUGINMANAGER_HH_ + +// LDMX +#include "PluginLoader.hh" +#include "UserActionPlugin.hh" + +// STL +#include <algorithm> +#include <ostream> + +// Geant4 +#include "G4ClassificationOfNewTrack.hh" + +namespace slic { + +/** + * @class PluginManager + * @brief Manages user sim plugins + * + * @note + * This class loads UserSimPlugin objects from dynamic libraries using a PluginLoader. + * It is also responsible for activating the user action hooks for all registered plugins. + * Only one instance of a given plugin can be loaded at a time. + * + * @see UserActionPlugin + * @see PluginLoader + */ +class PluginManager { + + public: + + /** + * Vector of plugins. + */ + typedef std::vector<UserActionPlugin*> PluginVec; + + /** + * Class constructor. + */ + PluginManager() { + } + + /** + * Class destructor. + * This will destroy all the currently registered plugins. + */ + virtual ~PluginManager(); + + /** + * Activate the begin run hook for registered plugins. + * @param aRun The Geant4 run that is beginning. + */ + void beginRun(const G4Run* aRun); + + /** + * Activate the end run hook of registered plugins. + * @param aRun The Geant4 run that is ending. + */ + void endRun(const G4Run* aRun); + + /** + * Activate the stepping hook of registered plugins. + * @param aStep The Geant4 step. + */ + void stepping(const G4Step* aStep); + + /** + * Activate the pre-tracking hook of registered plugins. + * @param aTrack The Geant4 track. + */ + void preTracking(const G4Track* aTrack); + + /** + * Activate the post-tracking hook of registered plugins. + * @param aTrack The Geant4 track. + */ + void postTracking(const G4Track* aTrack); + + /** + * Activate the begin event hook of registered plugins. + * @param anEvent The Geant4 event. + */ + void beginEvent(const G4Event* anEvent); + + /** + * Activate the end event hook of registered plugins. + * @param anEvent The Geant4 event. + */ + void endEvent(const G4Event* anEvent); + + /** + * Activate the generate primary hook of registered plugins. + * @param anEvent The Geant4 event. + */ + void generatePrimary(G4Event* anEvent); + + /** + * + * Activate the track classification hook of registered plugins. + * @param aTrack The Geant4 track. + * + * @brief Return a track classification from the user plugins that have stacking actions. + * + * @note + * The current classification will only be updated if a plugin actually provides a different classification + * than the current one. + */ + G4ClassificationOfNewTrack stackingClassifyNewTrack(const G4Track* aTrack); + + /** + * Activate the stacking new stage hook of registered plugins. + */ + void stackingNewStage(); + + /** + * Activate the prepare new event stacking hook of registered plugins. + */ + void stackingPrepareNewEvent(); + + /** + * Find a plugin by name. + * @param pluginName The name of the plugin. + * @return The plugin with the name or <i>nullptr</i> if does not exist. + */ + UserActionPlugin* findPlugin(const std::string& pluginName); + + /** + * Create a new plugin by name from the given library. + * @param pluginName The name of the plugin. + * @param libName The name of the shared library. + */ + void create(const std::string& pluginName, const std::string& libName); + + /** + * Destroy a plugin by name. + * @param pluginName The name of the plugin. + */ + void destroy(const std::string& pluginName); + + /** + * Print out information about registered plugins. + * @param os The output stream. + * @return The same output stream. + */ + std::ostream& print(std::ostream& os); + + private: + + /** + * Destroy a plugin. + * @param plugin Pointer to plugin that should be destroyed. + */ + void destroy(UserActionPlugin* plugin); + + /** + * Register a plugin. + * @param plugin Pointer to plugin that should be registered. + */ + void registerPlugin(UserActionPlugin* plugin); + + /** + * De-register a plugin. + * @param plugin Pointer to plugin that should be de-registered. + */ + void deregisterPlugin(UserActionPlugin* plugin); + + /** + * Destroy all registered plugins. + */ + void destroyPlugins(); + + private: + + /** + * The plugin loader for loading plugins from shared libraries. + */ + PluginLoader pluginLoader_; + + /** + * The list of registered plugins. + */ + PluginVec plugins_; +}; + +} + +#endif diff --git a/include/PluginManagerAccessor.hh b/include/PluginManagerAccessor.hh new file mode 100644 index 0000000000000000000000000000000000000000..3361e88951b33b6953a18c5e0d2d9c70897c92a1 --- /dev/null +++ b/include/PluginManagerAccessor.hh @@ -0,0 +1,50 @@ +/** + * @file PluginManagerAccessor.h + * @brief Mixin class for accessing the plugin manager + * @author Jeremy McCormick, SLAC National Accelerator Laboratory + */ + +#ifndef SLIC_PLUGINMANAGERACCESSOR_HH_ +#define SLIC_PLUGINMANAGERACCESSOR_HH_ + +// LDMX +#include "PluginManager.hh" + +namespace slic { + +/** + * @class PluginManagerAccessor + * @brief Mixin for accessing the PluginManager + * + * @note + * This class is used to assign a plugin manager to each of the user action classes. + */ +class PluginManagerAccessor { + + public: + + /** + * Set the plugin manager pointer. + * @param pluginManager Pointer to the plugin manager. + */ + void setPluginManager(PluginManager* pluginManager) { + m_pluginManager = pluginManager; + } + + /** + * Get the plugin manager. + * @return The plugin manager. + */ + PluginManager* getPluginManager() { + return m_pluginManager; + } + + protected: + + /* The plugin manager pointer; allow protected access for convenience of sub-classes. */ + PluginManager* m_pluginManager; +}; + +} + +#endif diff --git a/include/PluginMessenger.hh b/include/PluginMessenger.hh new file mode 100644 index 0000000000000000000000000000000000000000..7723dcfc3af01fb48424a54191f21f6e37bcb413 --- /dev/null +++ b/include/PluginMessenger.hh @@ -0,0 +1,74 @@ +/** + * @file PluginMessenger.h + * @brief Class defining a messenger for simulation plugins + * @author Jeremy McCormick, SLAC National Accelerator Laboratory + */ + +#ifndef SLIC_PLUGINMESSENGER_HH_ +#define SLIC_PLUGINMESSENGER_HH_ + +// Geant4 +#include "G4UImessenger.hh" + +// LDMX +#include "PluginManager.hh" + +namespace slic { + +/** + * @class PluginMessenger + * @brief Messenger class for loading and destroying user sim plugins using macro commands + */ +class PluginMessenger : public G4UImessenger { + + public: + + /** + * Class constructor. + * @param mgr The plugin manager. + */ + PluginMessenger(PluginManager* mgr); + + /** + * Class destructor. + */ + virtual ~PluginMessenger(); + + /** + * Process the macro command. + * @param[in] command The macro command. + * @param[in] newValues The argument values. + */ + void SetNewValue(G4UIcommand* command, G4String newValues); + + private: + + /** + * The plugin manager. + */ + PluginManager* pluginManager_; + + /** + * Directory for plugin commands. + */ + G4UIdirectory* pluginDir_; + + /** + * Command for loading a plugin by name. + */ + G4UIcommand* loadCmd_; + + /** + * Command for destroying a plugin by name. + */ + G4UIcommand* destroyCmd_; + + /** + * Command for listing currently registered plugins. + */ + G4UIcommand* listCmd_; +}; + +} + +#endif diff --git a/include/PrimaryGeneratorAction.hh b/include/PrimaryGeneratorAction.hh index 8cda9f1294f9805ea9477686dad1868074f110c3..37ccdbc3558221823e75d5324ebe064492e09103 100644 --- a/include/PrimaryGeneratorAction.hh +++ b/include/PrimaryGeneratorAction.hh @@ -4,6 +4,7 @@ // SLIC #include "EventSourceManager.hh" #include "Module.hh" +#include "PluginManagerAccessor.hh" // Geant4 #include "G4VUserPrimaryGeneratorAction.hh" @@ -17,7 +18,7 @@ namespace slic { * @class PrimaryGeneratorAction * @brief Implementation of G4VUserPrimaryGeneratorAction. */ -class PrimaryGeneratorAction: public G4VUserPrimaryGeneratorAction, public Module { +class PrimaryGeneratorAction: public G4VUserPrimaryGeneratorAction, public Module, public PluginManagerAccessor { public: diff --git a/include/RunAction.hh b/include/RunAction.hh index d04d0d11bf0fd2a95455d17fe6d374d4799e6fc5..22c7c2c3535a769071202c415337ca96651307a3 100644 --- a/include/RunAction.hh +++ b/include/RunAction.hh @@ -3,6 +3,7 @@ // slic #include "Module.hh" +#include "PluginManagerAccessor.hh" // geant4 #include "G4UserRunAction.hh" @@ -14,7 +15,7 @@ namespace slic { * @class RunAction * @brief Implementation of G4UserRunAction. */ -class RunAction: public G4UserRunAction, public Module { +class RunAction: public G4UserRunAction, public Module, public PluginManagerAccessor { public: diff --git a/include/RunManager.hh b/include/RunManager.hh index 30441c80f9c4f49c57a6398729b2c2779dcbe33c..15bed1133b455ad2dc3542efad128e84b209f19b 100644 --- a/include/RunManager.hh +++ b/include/RunManager.hh @@ -6,6 +6,7 @@ // slic #include "Module.hh" +#include "PluginManager.hh" #include "SlicApplication.hh" namespace slic { @@ -105,6 +106,7 @@ private: int m_numberOfEventsToRun; bool m_abortRun; + PluginManager* m_pluginManager; }; } diff --git a/include/StackingAction.hh b/include/StackingAction.hh index 46824aa33df67d29ef76d5823d6bb9b542de77d6..ef95e93a8129993399da68457703c479c74ce1a6 100644 --- a/include/StackingAction.hh +++ b/include/StackingAction.hh @@ -1,9 +1,13 @@ #ifndef SLIC_STACKINGACTION_HH_ #define SLIC_STACKINGACTION_HH_ 1 +#include "PluginManagerAccessor.hh" + #include "globals.hh" #include "G4UserStackingAction.hh" +namespace slic { + /** * @class StackingAction * @@ -15,7 +19,7 @@ * suspends backscattering tracks until the end * of shower development. */ -class StackingAction : public G4UserStackingAction { +class StackingAction : public G4UserStackingAction, public PluginManagerAccessor { public: StackingAction(); @@ -24,7 +28,13 @@ public: public: G4ClassificationOfNewTrack ClassifyNewTrack(const G4Track* aTrack); + + void NewStage(); + + void PrepareNewEvent(); }; +} + #endif diff --git a/include/SteppingAction.hh b/include/SteppingAction.hh index a7bcbe98e9d5081d123c3660a5004e7208b33fea..8bc8366d2daea001e913568b59b2a5faf603a63e 100644 --- a/include/SteppingAction.hh +++ b/include/SteppingAction.hh @@ -3,6 +3,7 @@ // SLIC #include "Module.hh" +#include "PluginManagerAccessor.hh" // Geant4 #include "G4UserSteppingAction.hh" @@ -18,7 +19,7 @@ namespace slic { * @class SteppingAction * @brief Implementation of G4UserSteppingAction. */ -class SteppingAction: public G4UserSteppingAction, Module { +class SteppingAction: public G4UserSteppingAction, public Module, public PluginManagerAccessor { public: diff --git a/include/TrackingAction.hh b/include/TrackingAction.hh index 57601489ed01aaf75177e28d4154c5d437a9f30b..1a57cbcaae035dac83e8d9cdf9839ffc274010a9 100644 --- a/include/TrackingAction.hh +++ b/include/TrackingAction.hh @@ -1,6 +1,8 @@ #ifndef SLIC_TRACKINGACTION_HH_ #define SLIC_TRACKINGACTION_HH_ 1 +#include "PluginManagerAccessor.hh" + // Geant4 #include "G4UserTrackingAction.hh" #include "G4TrackingManager.hh" @@ -13,7 +15,7 @@ class TrajectoryManager; * @class TrackingAction * @brief Implementation of G4UserTrackingAction */ -class TrackingAction: public G4UserTrackingAction { +class TrackingAction: public G4UserTrackingAction, public PluginManagerAccessor { public: diff --git a/include/UserActionPlugin.hh b/include/UserActionPlugin.hh new file mode 100644 index 0000000000000000000000000000000000000000..9324ecc1106a3ba94ad8f3489b841176f4b8edfd --- /dev/null +++ b/include/UserActionPlugin.hh @@ -0,0 +1,215 @@ +/** + * @file UserActionPlugin.h + * @brief Class defining an interface for a user simulation plugin + * @author Jeremy McCormick, SLAC National Accelerator Laboratory + */ + +#ifndef SLIC_USERACTIONPLUGIN_HH_ +#define SLIC_USERACTIONPLUGIN_HH_ + +// Geant4 +#include "G4Run.hh" +#include "G4Event.hh" +#include "G4Track.hh" +#include "G4Step.hh" +#include "G4ClassificationOfNewTrack.hh" + +namespace slic { + +/** + * @class UserActionPlugin + * @brief User simulation plugin + * + * @note + * This class defines a plugin interface to the Geant4 simulation engine + * which is activated in the "user action" hooks. An implementation + * class must define "create" and "destroy" functions as entry points for + * the dynamic library loading. By default, the plugin does not activate + * any of the user actions, and the user should override the methods + * which return boolean flags to activate these hooks. + * + * @par + * Here are examples of the static functions that should be defined for + * creating and destroying the plugin in the class's source file, assuming that + * the plugin is called %DummySimPlugin. + * + * @par + * Example create function: + * @snippet extern "C" sim::DummySimPlugin* createDummySimPlugin() { return new sim::DummySimPlugin; } + * + * @par + * Example destroy function: + * @snippet extern "C" void destroyDummySimPlugin(sim::DummySimPlugin* object) { delete object; } + */ +class UserActionPlugin { + + public: + + /** + * Class destructor. + */ + virtual ~UserActionPlugin() { + } + + /** + * Get the name of the plugin. + * The user must override this function. + * @return The name of the plugin. + */ + virtual std::string getName() = 0; + + /** + * Set the verbose level of the plugin (1-4). + * @param verbose The verbose level of the plugin. + */ + void setVerboseLevel(int verbose) { + verbose_ = verbose; + if (verbose_ < 1) { + verbose = 1; + } else if (verbose_ > 4) { + verbose = 4; + } + } + + /** + * Get the current verbose level. + * @return The current verbose level. + */ + int getVerboseLevel() { + return verbose_; + } + + /** + * Get whether this plugin implements the run action. + * @return True if the plugin implements the run action. + */ + virtual bool hasRunAction() { + return false; + } + + /** + * Get whether this plugin implements the stepping action. + * @return True if the plugin implements the stepping action. + */ + virtual bool hasSteppingAction() { + return false; + } + + /** + * Get whether this plugin implements the tracking action. + * @return True if the plugin implements the tracking action. + */ + virtual bool hasTrackingAction() { + return false; + } + + /** + * Get whether this plugin implements the event action. + * @return True if the plugin implements the event action. + */ + virtual bool hasEventAction() { + return false; + } + + /** + * Get whether this plugin implements the stacking action. + * @return True if the plugin implements the stacking action. + */ + virtual bool hasStackingAction() { + return false; + } + + /** + * Get whether this plugin implements the primary generator action. + * @return True if the plugin implements the primary generator action. + */ + virtual bool hasPrimaryGeneratorAction() { + return false; + } + + /** + * Begin of run action. + */ + virtual void beginRun(const G4Run*) { + } + + /** + * End of run action. + */ + virtual void endRun(const G4Run*) { + } + + /** + * Stepping action. + */ + virtual void stepping(const G4Step*) { + } + + /** + * Pre-tracking action. + */ + virtual void preTracking(const G4Track*) { + } + + /** + * Post-tracking action. + */ + virtual void postTracking(const G4Track*) { + } + + /** + * Begin of event action. + */ + virtual void beginEvent(const G4Event*) { + } + + /** + * End of event action. + */ + virtual void endEvent(const G4Event*) { + } + + /** + * Generate primary action. + */ + virtual void generatePrimary(G4Event*) { + } + + /** + * Classify a new track. + * @param currentTrackClass The current track classification. + * @return The current track classification returned by default. + */ + virtual G4ClassificationOfNewTrack stackingClassifyNewTrack(const G4Track*, const G4ClassificationOfNewTrack& currentTrackClass) { + return currentTrackClass; + } + + /** + * New stacking stage action. + */ + virtual void stackingNewStage() { + } + + /** + * New event stacking action. + */ + virtual void stackingPrepareNewEvent() { + } + + protected: + + /** Protected access to verbose level for convenience of sub-classes. */ + int verbose_ {1}; +}; + +} + +#define DECLARE_PLUGIN(NS, NAME) \ +extern "C" NS::NAME* create ## NAME() { \ + return new NS::NAME; \ +} \ +extern "C" void destroy ## NAME(NS::NAME* object) { \ + delete object; \ +} + +#endif diff --git a/include/UserActionPluginMessenger.hh b/include/UserActionPluginMessenger.hh new file mode 100644 index 0000000000000000000000000000000000000000..a6f089afaad3644f05ef9fbdbb027408993ceb14 --- /dev/null +++ b/include/UserActionPluginMessenger.hh @@ -0,0 +1,90 @@ +/** + * @file UserActionPluginMessenger.h + * @brief Class defining a macro messenger for a UserActionPlugin + * @author Jeremy McCormick, SLAC National Accelerator Laboratory + */ + +#ifndef SLIC_USERACTIONPLUGINMESSENGER_HH_ +#define SLIC_USERACTIONPLUGINMESSENGER_HH_ + +// LDMX +#include "UserActionPlugin.hh" + +// Geant4 +#include "G4UImessenger.hh" +#include "G4UIdirectory.hh" +#include "G4UIcommand.hh" + +namespace slic { + +/** + * @class UserActionPluginMessenger + * @brief Messenger for sending macro commands to a UserActionPlugin + * + * @note + * By default, this class creates a directory for the plugin and provides + * a command for setting of the verbose level. Users can override this + * class to provide additional commands for their specific plugins. + */ +class UserActionPluginMessenger : public G4UImessenger { + + public: + + /** + * Class constructor. + * @param userPlugin The associated UserActionPlugin. + */ + UserActionPluginMessenger(UserActionPlugin* userPlugin); + + /** + * Class destructor. + */ + virtual ~UserActionPluginMessenger() { + delete verboseCmd_; + delete pluginDir_; + } + + /** + * Process the macro command. + * @param[in] command The macro command. + * @param[in] newValue The argument values. + */ + void SetNewValue(G4UIcommand *command, G4String newValue); + + /** + * Get the command path (plugin's macro directory). + * @return The command path. + */ + const std::string& getPath() { + return pluginDir_->GetCommandPath(); + } + + /** + * Get the associated UserActionPlugin. + * @return The associated UserActionPlugin. + */ + UserActionPlugin* getPlugin() { + return userPlugin_; + } + + private: + + /** + * The associated UserActionPligin. + */ + UserActionPlugin* userPlugin_; + + /** + * The plugin's command directory. + */ + G4UIdirectory* pluginDir_; + + /** + * The command for setting verbose level. + */ + G4UIcommand* verboseCmd_; +}; + +} + +#endif diff --git a/plugins/DummySimPlugin.cc b/plugins/DummySimPlugin.cc new file mode 100644 index 0000000000000000000000000000000000000000..4b154e6e2d25cd9f98b9412c767da4d912f836d3 --- /dev/null +++ b/plugins/DummySimPlugin.cc @@ -0,0 +1,115 @@ +/** + * @file DummySimPlugin.h + * @brief Class that defines a dummy simulation plugin + * @author Jeremy McCormick, SLAC National Accelerator Laboratory + */ + +#ifndef SIMPLUGINS_DUMMYSIMPLUGIN_H_ +#define SIMPLUGINS_DUMMYSIMPLUGIN_H_ + +// LDMX +#include "UserActionPlugin.hh" + +namespace slic { + + /** + * @class DummySimPlugin + * @brief Dummy implementation of UserActionPlugin + */ + class DummySimPlugin : public UserActionPlugin { + + public: + + DummySimPlugin() { + std::cout << "DummySimPlugin::DummySimPlugin - Hello!" << std::endl; + } + + virtual ~DummySimPlugin() { + std::cout << "DummySimPlugin::~DummySimPlugin - Goodbye!" << std::endl; + } + + virtual std::string getName() { + return "DummySimPlugin"; + } + + bool hasRunAction() { + return true; + } + + bool hasSteppingAction() { + return true; + } + + bool hasTrackingAction() { + return true; + } + + bool hasEventAction() { + return true; + } + + bool hasStackingAction() { + return true; + } + + bool hasPrimaryGeneratorAction() { + return true; + } + + void beginRun(const G4Run* run) { + std::cout << "DummySimPlugin::beginRun - run " << run->GetRunID() << std::endl; + } + + void endRun(const G4Run* run) { + std::cout << "DummySimPlugin::endRun - run " << run->GetRunID() << std::endl; + } + + void stepping(const G4Step* step) { + std::cout << "DummySimPlugin::stepping - pre-point: " << step->GetPreStepPoint()->GetPosition() << ", post-point: "; + if (step->GetPostStepPoint()) { + std::cout << step->GetPostStepPoint()->GetPosition(); + } else { + std::cout << "NONE"; + } + std::cout << std::endl; + } + + void preTracking(const G4Track* track) { + std::cout << "DummySimPlugin::preTracking - track ID " << track->GetTrackID() << std::endl; + } + + void postTracking(const G4Track* track) { + std::cout << "DummySimPlugin::postTracking - track ID " << track->GetTrackID() << std::endl; + } + + void beginEvent(const G4Event* event) { + std::cout << "DummySimPlugin::beginEvent - event " << event->GetEventID() << std::endl; + } + + void endEvent(const G4Event* event) { + std::cout << "DummySimPlugin::endEvent - event " << event->GetEventID() << std::endl; + } + + G4ClassificationOfNewTrack stackingClassifyNewTrack(const G4Track* aTrack, const G4ClassificationOfNewTrack& currentTrackClass) { + std::cout << "DummySimPlugin::stackingClassifyNewTrack - track ID " << aTrack->GetTrackID() << " classified as " << currentTrackClass << std::endl; + return currentTrackClass; + } + + void stackingNewStage() { + std::cout << "DummySimPlugin::stackingNewStage" << std::endl; + } + + void stackingPrepareNewEvent() { + std::cout << "DummySimPlugin::stackingPrepareNewEvent" << std::endl; + } + + void generatePrimary(G4Event* event) { + std::cout << "DummySimPlugin::generatorPrimary - event " << event->GetEventID() << std::endl; + } + }; + +} + +DECLARE_PLUGIN(slic, DummySimPlugin) + +#endif diff --git a/scripts/slic-env.sh.in b/scripts/slic-env.sh.in index a5cb228e6d394847c53f1694737ff61a22bf0a0e..d2e03850185010dbf309dd37ded83b6ab71cc03b 100755 --- a/scripts/slic-env.sh.in +++ b/scripts/slic-env.sh.in @@ -1,13 +1,13 @@ #!/bin/sh -export LD_LIBRARY_PATH=@HEPPDT_DIR@/lib/:@GDML_DIR@/lib:@LCDD_DIR@/lib:@LCIO_DIR@/lib:@XERCES_DIR@/lib +export LD_LIBRARY_PATH=@HEPPDT_DIR@/lib/:@GDML_DIR@/lib:@LCDD_DIR@/lib:@LCIO_DIR@/lib:@XERCES_DIR@/lib:@CMAKE_INSTALL_PREFIX@/slic/lib if [ "@CMAKE_CXX_COMPILER@" != "/usr/bin/g++" ] then export LD_LIBRARY_PATH=$(dirname @CMAKE_CXX_COMPILER@)/../lib64:$LD_LIBRARY_PATH fi -export GDML_SCHEMA_DIR=@GDML_DIR@/schemas +#export GDML_SCHEMA_DIR=@GDML_DIR@/schemas . @Geant4_DIR@/../../bin/geant4.sh diff --git a/src/EventAction.cc b/src/EventAction.cc index f2b5ff7ab54796e18d188d33b2c2816644a00db6..9be2cd4b8cf67c26dc714f7ebf034aad8e3bc1f4 100644 --- a/src/EventAction.cc +++ b/src/EventAction.cc @@ -27,9 +27,11 @@ EventAction::EventAction() : EventAction::~EventAction() { } -void EventAction::BeginOfEventAction(const G4Event*) { +void EventAction::BeginOfEventAction(const G4Event* anEvent) { // Reset current track state. CurrentTrackState::setCurrentTrackID(-1); + + m_pluginManager->beginEvent(anEvent); } void EventAction::EndOfEventAction(const G4Event *anEvent) { @@ -50,6 +52,8 @@ void EventAction::EndOfEventAction(const G4Event *anEvent) { LcioManager::instance()->endEvent(anEvent); } + m_pluginManager->endEvent(anEvent); + /* Stop the event timer. */ stopEventTimer(); diff --git a/src/PluginLoader.cc b/src/PluginLoader.cc new file mode 100644 index 0000000000000000000000000000000000000000..1a44c7aa739a88a59f8b839ccf3de12b948b280a --- /dev/null +++ b/src/PluginLoader.cc @@ -0,0 +1,86 @@ +#include "PluginLoader.hh" + +#include <dlfcn.h> + +namespace slic { + +UserActionPlugin* PluginLoader::create(std::string pluginName, std::string libName) { + + // Open a handle to the specific dynamic lib. + void* handle = dlopen(libName.c_str(), RTLD_LAZY); + + // Plugin to be created. + UserActionPlugin* plugin = nullptr; + + // Is there a proper handle to the lib? + if (handle) { + + // Get a function pointer from the library to create the plugin object. + UserActionPlugin* (*createIt)(); + createIt = (UserActionPlugin* (*)())dlsym(handle, std::string("create" + pluginName).c_str()); + + // Did we get back a good function pointer from the lib? + if(createIt) { + + // Create the plugin object from the function pointer. + plugin = (UserActionPlugin*)createIt(); + + // Was the plugin created successfully? + if (plugin) { + // Register the plugin handle for when it needs to be destroyed. + this->pluginHandles_[plugin] = handle; + } else { + // For some reason, the plugin could not be created by the lib function! + std::cerr << "[ PluginLoader ] : Failed to create plugin " << pluginName << " from lib " + << libName << "!!!" << std::endl; + throw std::runtime_error("Failed to create the plugin."); + } + } else { + // The create function was not found in the lib. + std::cerr << "[ PluginLoader ] : Failed to find create function for plugin " << pluginName << " in lib " + << libName << "!!!" << std::endl; + throw std::runtime_error("Failed to find library function for creating plugin."); + } + } else { + // The plugin lib could not be opened. Probably it doesn't exist! + std::cerr << "[ PluginLoader ] : Could not open " << libName << " plugin lib." << std::endl; + throw std::runtime_error("Plugin lib not found."); + } + + return plugin; +} + +void PluginLoader::destroy(UserActionPlugin* plugin) { + + // Is the plugin argument non-null? + if (plugin) { + + // Get the lib handle for the plugin. + void* handle = this->pluginHandles_[plugin]; + + // Do we have a lib handle for this plugin? + if (handle) { + + // Destroy the plugin by calling its destroy method from the lib. + void (*destroyIt)(UserActionPlugin*); + destroyIt = (void (*)(UserActionPlugin*))dlsym(handle, std::string("destroy" + plugin->getName()).c_str());destroyIt + (plugin); + + // Delete from plugin handles. + std::map<UserActionPlugin*, void*>::iterator it; + it = this->pluginHandles_.find(plugin); + if (it != pluginHandles_.end()) { + this->pluginHandles_.erase(it); + } + } else { + // No handle exists for this plugin. Maybe it wasn't registered with this PluginLoader? + std::cerr << "[ PluginLoader ] : Failed to find handle for " << plugin->getName() << " plugin!!!" << std::endl; + throw std::runtime_error("Failed to find handle for plugin."); + } + } else { + // Null argument is just ignored with a warning. + std::cerr << "[ PluginLoader ] : Ignoring null plugin argument. " << std::endl; + } +} + +} diff --git a/src/PluginManager.cc b/src/PluginManager.cc new file mode 100644 index 0000000000000000000000000000000000000000..64ef4288e21fb1ede77ecda9c77f64d32d93f94d --- /dev/null +++ b/src/PluginManager.cc @@ -0,0 +1,173 @@ +#include "PluginManager.hh" + +namespace slic { + +PluginManager::~PluginManager() { + destroyPlugins(); +} + +void PluginManager::beginRun(const G4Run* run) { + for (PluginVec::iterator it = plugins_.begin(); it != plugins_.end(); it++) { + if ((*it)->hasRunAction()) { + (*it)->beginRun(run); + } + } +} + +void PluginManager::endRun(const G4Run* run) { + for (PluginVec::iterator it = plugins_.begin(); it != plugins_.end(); it++) { + if ((*it)->hasRunAction()) { + (*it)->endRun(run); + } + } +} + +void PluginManager::stepping(const G4Step* step) { + for (PluginVec::iterator it = plugins_.begin(); it != plugins_.end(); it++) { + if ((*it)->hasSteppingAction()) { + (*it)->stepping(step); + } + } +} + +void PluginManager::preTracking(const G4Track* track) { + for (PluginVec::iterator it = plugins_.begin(); it != plugins_.end(); it++) { + if ((*it)->hasTrackingAction()) { + (*it)->preTracking(track); + } + } +} + +void PluginManager::postTracking(const G4Track* track) { + for (PluginVec::iterator it = plugins_.begin(); it != plugins_.end(); it++) { + if ((*it)->hasTrackingAction()) { + (*it)->postTracking(track); + } + } +} + +void PluginManager::beginEvent(const G4Event* event) { + for (PluginVec::iterator it = plugins_.begin(); it != plugins_.end(); it++) { + if ((*it)->hasEventAction()) { + (*it)->beginEvent(event); + } + } +} + +void PluginManager::endEvent(const G4Event* event) { + for (PluginVec::iterator it = plugins_.begin(); it != plugins_.end(); it++) { + if ((*it)->hasEventAction()) { + (*it)->endEvent(event); + } + } +} + +void PluginManager::generatePrimary(G4Event* event) { + for (PluginVec::iterator it = plugins_.begin(); it != plugins_.end(); it++) { + if ((*it)->hasPrimaryGeneratorAction()) { + (*it)->generatePrimary(event); + } + } +} + +G4ClassificationOfNewTrack PluginManager::stackingClassifyNewTrack(const G4Track* track) { + + // Default value of a track is fUrgent. + G4ClassificationOfNewTrack currentTrackClass = G4ClassificationOfNewTrack::fUrgent; + + for (PluginVec::iterator it = plugins_.begin(); it != plugins_.end(); it++) { + if ((*it)->hasStackingAction()) { + + // Get proposed new track classification from this plugin. + G4ClassificationOfNewTrack newTrackClass = (*it)->stackingClassifyNewTrack(track, currentTrackClass); + + // Only set the current classification if the plugin changed it. + if (newTrackClass != currentTrackClass) { + + // Set the track classification from this plugin. + currentTrackClass = newTrackClass; + } + } + } + + // Return the current track classification. + return currentTrackClass; +} + +void PluginManager::stackingNewStage() { + for (PluginVec::iterator it = plugins_.begin(); it != plugins_.end(); it++) { + if ((*it)->hasEventAction()) { + (*it)->stackingNewStage(); + } + } +} + +void PluginManager::stackingPrepareNewEvent() { + for (PluginVec::iterator it = plugins_.begin(); it != plugins_.end(); it++) { + if ((*it)->hasStackingAction()) { + (*it)->stackingPrepareNewEvent(); + } + } +} + +UserActionPlugin* PluginManager::findPlugin(const std::string& pluginName) { + UserActionPlugin* foundPlugin = nullptr; + for (PluginVec::iterator iPlugin = plugins_.begin(); iPlugin != plugins_.end(); iPlugin++) { + if ((*iPlugin)->getName() == pluginName) { + foundPlugin = *iPlugin; + break; + } + } + return foundPlugin; +} + +void PluginManager::create(const std::string& pluginName, const std::string& libName) { + if (findPlugin(pluginName) == nullptr) { + UserActionPlugin* plugin = pluginLoader_.create(pluginName, libName); + registerPlugin(plugin); + } else { + std::cerr << "[ PluginManager ] - Plugin " << pluginName << " already exists." << std::endl; + throw new std::runtime_error("Plugin already loaded."); + } +} + +void PluginManager::destroy(const std::string& pluginName) { + UserActionPlugin* plugin = findPlugin(pluginName); + if (plugin != nullptr) { + destroy(plugin); + } +} + +void PluginManager::destroy(UserActionPlugin* plugin) { + if (plugin != nullptr) { + deregisterPlugin(plugin); + pluginLoader_.destroy(plugin); + } +} + +std::ostream& PluginManager::print(std::ostream& os) { + for (PluginVec::iterator iPlugin = plugins_.begin(); iPlugin != plugins_.end(); iPlugin++) { + os << (*iPlugin)->getName() << std::endl; + } + return os; +} + +void PluginManager::registerPlugin(UserActionPlugin* plugin) { + plugins_.push_back(plugin); +} + +void PluginManager::deregisterPlugin(UserActionPlugin* plugin) { + std::vector<UserActionPlugin*>::iterator pos = std::find(plugins_.begin(), plugins_.end(), plugin); + if (pos != plugins_.end()) { + plugins_.erase(pos); + } +} + +void PluginManager::destroyPlugins() { + for (unsigned iPlugin = 0; iPlugin < plugins_.size(); iPlugin++) { + destroy(plugins_[iPlugin]); + } + plugins_.clear(); +} + +} // namespace sim diff --git a/src/PluginMessenger.cc b/src/PluginMessenger.cc new file mode 100644 index 0000000000000000000000000000000000000000..dda18ea10e4219058e33a10de36080ae78ba6efa --- /dev/null +++ b/src/PluginMessenger.cc @@ -0,0 +1,60 @@ +#include "PluginMessenger.hh" + +namespace slic { + +PluginMessenger::PluginMessenger(PluginManager* thePluginManager) : + pluginManager_(thePluginManager) { + + pluginDir_ = new G4UIdirectory("/slic/plugins/"); + pluginDir_->SetGuidance("Commands for controlling LDMX sim plugins"); + + loadCmd_ = new G4UIcommand("/slic/plugins/load", this); + loadCmd_->AvailableForStates(G4ApplicationState::G4State_PreInit, G4ApplicationState::G4State_Idle); + loadCmd_->SetGuidance("Load a sim plugin from a shared library. A plugin of a specific type may only be loaded once."); + G4UIparameter* pluginName = new G4UIparameter("pluginName", 's', false); + pluginName->SetGuidance("Name of plugin to load."); + loadCmd_->SetParameter(pluginName); + G4UIparameter* libName = new G4UIparameter("libName", 's', true); + libName->SetGuidance("Name of plugin library; if omitted will use the 'libSimPlugins.so' library."); + loadCmd_->SetParameter(libName); + + destroyCmd_ = new G4UIcommand("/slic/plugins/destroy", this); + destroyCmd_->SetGuidance("Destroy a loaded plugin by name."); + destroyCmd_->AvailableForStates(G4ApplicationState::G4State_Idle); + pluginName = new G4UIparameter("pluginName", 's', false); + pluginName->SetGuidance("Name of plugin to destroy."); + destroyCmd_->SetParameter(pluginName); + + listCmd_ = new G4UIcommand("/slic/plugins/list", this); + listCmd_->SetGuidance("List currently loaded plugins."); + listCmd_->AvailableForStates(G4ApplicationState::G4State_Idle, G4ApplicationState::G4State_PreInit); +} + +PluginMessenger::~PluginMessenger() { + delete pluginDir_; + delete loadCmd_; + delete destroyCmd_; + delete listCmd_; +} + +void PluginMessenger::SetNewValue(G4UIcommand* command, G4String newValues) { + + std::istringstream is((const char*) newValues); + std::string pluginName, libName; + + is >> pluginName >> libName; + + if (libName.size() == 0 || libName == "") { + libName = "libslicPlugins.so"; + } + + if (command == loadCmd_) { + pluginManager_->create(pluginName, libName); + } else if (command == destroyCmd_) { + pluginManager_->destroy(pluginName); + } else if (command == listCmd_) { + pluginManager_->print(std::cout); + } +} + +} diff --git a/src/PrimaryGeneratorAction.cc b/src/PrimaryGeneratorAction.cc index ce7eade8a514b1e265dd0ca0b39c0bdcb53994e9..58b9941d8df086d78757aee87df918df26cf8718 100644 --- a/src/PrimaryGeneratorAction.cc +++ b/src/PrimaryGeneratorAction.cc @@ -51,6 +51,8 @@ void PrimaryGeneratorAction::GeneratePrimaries(G4Event *anEvent) { if (_manager->isEOF()) { SlicApplication::instance()->setAborting(true); } + + m_pluginManager->generatePrimary(anEvent); } void PrimaryGeneratorAction::printBeginEventMessage(G4Event* anEvent) { diff --git a/src/RunAction.cc b/src/RunAction.cc index e1d4a8bfdcf4a810ae2a492d22cf746e1b09a6e7..6eb59b25a8dc35605ec32ad5efbebe340aa6a34e 100644 --- a/src/RunAction.cc +++ b/src/RunAction.cc @@ -37,6 +37,8 @@ void RunAction::BeginOfRunAction(const G4Run *aRun) { // Execute GeometryManager's beginRun action. GeometryManager::instance()->beginRun(aRun); + + m_pluginManager->beginRun(aRun); } void RunAction::EndOfRunAction(const G4Run *run) { @@ -47,6 +49,8 @@ void RunAction::EndOfRunAction(const G4Run *run) { // event source mgr EventSourceManager::instance()->endRun(run); + m_pluginManager->endRun(run); + // stop run clock stopRunTimer(); diff --git a/src/RunManager.cc b/src/RunManager.cc index 327d9b75e000f45d71f5ac0b77e9dd91ef3f68e8..35de48a9b0f9ba994061e0cd1de3dbf981b533c1 100644 --- a/src/RunManager.cc +++ b/src/RunManager.cc @@ -10,6 +10,7 @@ #include "StackingAction.hh" #include "SteppingAction.hh" #include "TrackingAction.hh" +#include "PluginMessenger.hh" // LCDD #include "lcdd/core/LCDDParser.hh" @@ -26,6 +27,7 @@ RunManager::RunManager() : } RunManager::~RunManager() { + delete m_pluginManager; } void RunManager::Initialize() { @@ -37,12 +39,29 @@ void RunManager::Initialize() { // This makes sure that physics initialization occurs before other user actions. G4RunManager::Initialize(); - SetUserAction(new PrimaryGeneratorAction()); - SetUserAction(new RunAction()); - SetUserAction(new EventAction()); - SetUserAction(new TrackingAction()); - SetUserAction(new SteppingAction()); - SetUserAction(new StackingAction()); + m_pluginManager = new PluginManager(); + new PluginMessenger(m_pluginManager); + + PrimaryGeneratorAction* genAction = new PrimaryGeneratorAction; + RunAction* runAction = new RunAction; + EventAction* eventAction = new EventAction; + TrackingAction* trackingAction = new TrackingAction; + SteppingAction* steppingAction = new SteppingAction; + StackingAction* stackingAction = new StackingAction; + + genAction->setPluginManager(m_pluginManager); + runAction->setPluginManager(m_pluginManager); + eventAction->setPluginManager(m_pluginManager); + trackingAction->setPluginManager(m_pluginManager); + steppingAction->setPluginManager(m_pluginManager); + stackingAction->setPluginManager(m_pluginManager); + + SetUserAction(genAction); + SetUserAction(runAction); + SetUserAction(eventAction); + SetUserAction(trackingAction); + SetUserAction(steppingAction); + SetUserAction(stackingAction); // Initialize the event generation manager. EventSourceManager::instance(); @@ -141,3 +160,4 @@ bool RunManager::isRunAborted() { return m_abortRun; } } // namespace slic + diff --git a/src/StackingAction.cc b/src/StackingAction.cc index c3e6057fd98d3f227144620a0f1535103a602e46..9b2381e373cbbb868c03bf7a54910aedeb9fbadf 100644 --- a/src/StackingAction.cc +++ b/src/StackingAction.cc @@ -5,6 +5,8 @@ #include "G4DecayProducts.hh" #include "G4ios.hh" +namespace slic { + StackingAction::StackingAction() { } @@ -12,8 +14,17 @@ StackingAction::~StackingAction() { } G4ClassificationOfNewTrack StackingAction::ClassifyNewTrack(const G4Track* aTrack) { - G4ClassificationOfNewTrack classification = fUrgent; - if(aTrack->GetTrackStatus()==fSuspend) classification = fWaiting; - return classification; + // FIXME: Need to determine how these are supposed to work together! + G4ClassificationOfNewTrack classification = m_pluginManager->stackingClassifyNewTrack(aTrack); + if(aTrack->GetTrackStatus() == fSuspend) classification = fWaiting; +} + +void StackingAction::NewStage() { + m_pluginManager->stackingNewStage(); } +void StackingAction::PrepareNewEvent() { + m_pluginManager->stackingPrepareNewEvent(); +} + +} diff --git a/src/SteppingAction.cc b/src/SteppingAction.cc index afaf279675395e73941f044ed4eeac92a0819c38..5fdda8ae8f21f64dc6cf7b3cfd709a8ed8805513 100644 --- a/src/SteppingAction.cc +++ b/src/SteppingAction.cc @@ -48,6 +48,8 @@ void SteppingAction::UserSteppingAction(const G4Step* step) { /* Check if the track should be killed. */ checkKillTrack(step); + + m_pluginManager->stepping(step); } void SteppingAction::checkKillTrack(const G4Step* aStep) { diff --git a/src/TrackingAction.cc b/src/TrackingAction.cc index 09cffd7803fcddec1269cebd1138632422c3f898..a18a70f218e5151481d84dbf7505e695c7f1eda2 100644 --- a/src/TrackingAction.cc +++ b/src/TrackingAction.cc @@ -64,6 +64,8 @@ void TrackingAction::PreUserTrackingAction(const G4Track* track) { fpTrackingManager->SetStoreTrajectory(false); } } + + m_pluginManager->preTracking(track); } void TrackingAction::PostUserTrackingAction(const G4Track* track) { @@ -85,6 +87,8 @@ void TrackingAction::PostUserTrackingAction(const G4Track* track) { // Update the track summary. trackSummary->update(track); } + + m_pluginManager->postTracking(track); } } // namespace slic diff --git a/src/UserActionPluginMessenger.cc b/src/UserActionPluginMessenger.cc new file mode 100644 index 0000000000000000000000000000000000000000..cc39851ac3a3e3524190145b4f1a0a5092f93b31 --- /dev/null +++ b/src/UserActionPluginMessenger.cc @@ -0,0 +1,24 @@ +#include "UserActionPluginMessenger.hh" + +namespace slic { + +UserActionPluginMessenger::UserActionPluginMessenger(UserActionPlugin* userPlugin) : + userPlugin_(userPlugin) { + + pluginDir_ = new G4UIdirectory(std::string("/slic/plugins/" + userPlugin->getName() + "/").c_str()); + pluginDir_->SetGuidance(std::string("Commands for the sim plugin " + userPlugin->getName()).c_str()); + + verboseCmd_ = new G4UIcommand(std::string(getPath() + "verbose").c_str(), this); + G4UIparameter* verbose = new G4UIparameter("verboseLevel", 'i', false); + verboseCmd_->SetParameter(verbose); + verboseCmd_->SetGuidance("Set the verbosity level of the sim plugin (1-4)."); + verboseCmd_->AvailableForStates(G4ApplicationState::G4State_PreInit, G4ApplicationState::G4State_Idle); +} + +void UserActionPluginMessenger::SetNewValue(G4UIcommand *command, G4String newValue) { + if (command == verboseCmd_) { + userPlugin_->setVerboseLevel(std::atoi(newValue)); + std::cout << userPlugin_->getName() << " verbose set to " << userPlugin_->getVerboseLevel() << std::endl; + } +} +}