Plugins

  1. Loading a Plugin
  2. Plugin Library Paths
  3. Writing a Plugin Library
Pythia is designed as a standalone package, with no external dependencies. However, there are many use cases for interfacing external packages with Pythia. To that end, the include/Pythia8Plugins directory provides a number of header interfaces, which are then demonstrated in examples. However, this method of including external dependencies in Pythia is not always sufficient, and so a plugin system is also available. The system works as follows (more details are given later):
  1. A user creates a standalone plugin library, which implements derived classes from Pythia. This plugin library can be linked against external libraries.
  2. At runtime, a Pythia object loads this plugin library.
  3. Any new object requested by the user from this plugin library is created and returned as a shared pointer. The shared pointer is the same type as the Pythia base class of the plugin object. For example, consider a plugin library that implements a new MyPDF class which derives from the Pythia PDF class. The plugin system will then return a shared pointer of type PDF which allows access to a MyPDF object.

This type of system has a number of advantages over the header interface style of plugins.

  1. The external dependencies only need to be handled once. For example, consider using HepMC to write out event files. With the plugin system, we only need to link the standalone plugin library with HepMC at compile time. Then, any main program we might build after this does not need to be linked against HepMC (headers or libraries), but can still write HepMC output to file.
  2. In some cases, we might want to replace core functionality in Pythia with code that requires external dependencies. A good example of this is LHAPDF, which can be used to replace the internal Pythia PDF sets. Here, we can allow LHAPDF sets to be used seamlessly within Pythia without introducing any external dependencies to the core Pythia code.
  3. We oftentimes want to use libraries that provide duplicate symbols. This is happens when linking against FORTRAN libraries with standard common blocks, or libraries that were generated using some automated tool. An example of this is the matrix element corrections provided via MG5 for the parton shower. Here, MG5 builds libraries with identical symbol names and so we cannot link against multiple versions of these libraries. The plugin system allows us to not only choose which MG5 matrix element correction library we load at runtime, but also load multiple libraries without causing symbol conflicts.
  4. It is now possible to create a Pythia executable, where all interactions by the user are through command files, and no code needs to be compiled.
Within Pythia, the plugin library is already used to provide access to external libraries such as LHAPDF and MG5 matrix element corrections in the parton shower.

Loading a Plugin

There are two ways to load plugins within Pythia code. The first is to provide a list of plugins to Pythia via the Init:plugins option (see Main Program Settings for the definition of this option). To give an example, consider writing a UserHooks class called MyUserHooks and compiling this in the plugin library libMyPlugins.so. To automatically load this user hook and pass it to your Pythia object, the following command should be given to Pythia.

 
Init:plugins = {libMyPlugins.so::MyUserHooks} 

Then, when pythia.init() is called, a MyUserHooks object will be automatically created and set as the UserHooks object for the Pythia object via the method pythia.setUserHooksPtr. For most plugin object classes of generic type BaseClass, the relevant pointer will be set via the corresponding pythia.setBaseClassPtr method. For some class types, there is an option to either set the pointer, overwriting any previous pointer, or add the pointer to a list of pointers that will all be used. To specify whether the plugin should be set or added, a third optional keyword can be specified,

 
Init:plugins = {libMyPlugins.so::MyUserHooks::set} 

where this third keyword can be either set (the default) or add. In this example, if there was a previous UserHooks pointer, it would be replaced by a new MyUserHooks pointer.

The treatment of this third keyword is different for PDF plugins, where it specifies the beam type (and the PDF pointer is always set, rather than added). For example,

 
Init:plugins = {libMyPlugins.so::MyPDF1::A, libMyPlugins.so::MyPDF2::B} 

sets MyPDF1 for beam A, while MyPDF2 is set for beam B. This beam type can be taken from the list of arguments to the Pythia::setPDFPtr method in Program Flow, with the pdf prefix and Ptr suffix stripped from the argument name, for example pdfPomAPtr becomes PomA. If there are new settings which are defined in the libMyPlugins.so library, these settings are registered before the MyUserHooks object is created. In this way, it is possible to pass settings to the MyUserHooks object from a command file. This would be done as,

 
Init:plugins = {libMyPlugins.so::MyUserHooks::set::plugin.cmnd} 

where plugin.cmnd is a standard command file for Pythia. It is also possible to use the subrun feature of the Pythia command files.

 
Init:plugins = {libMyPlugins.so::MyUserHooks::set::plugin.cmnd::2} 

This command tells Pythia to load the specific commands for subrun two from the plugin.cmnd file.

The plugin functionality is available for a number of Pythia base classes which can be passed as external pointers to a Pythia object. These include:

  1. PDF set via Pythia::setPDFPtr
  2. LHAup set via Pythia::setLHAupPtr
  3. DecayHandler set via Pythia::setDecayPtr
  4. RndmEngine set via Pythia::setRndmEnginePtr
  5. UserHooks set via Pythia::set/addUserHooksPtr
  6. Merging set via Pythia::setMergingPtr
  7. MergingHooks set via Pythia::setMergingHooksPtr
  8. BeamShape set via Pythia::setBeamShapePtr
  9. SigmaProcess set via Pythia::set/addSigmaPtr with a null argument for the PhaseSpace pointer
  10. PhaseSpace set via the second argument of Pythia::set/addSigmaPtr; the previous plugin must be the SigmaProcess which uses this phase-space generator
  11. ResonanceWidths set via Pythia::set/addResonancePtr
  12. ShowerModel set via Pythia::setShowerModelPtr
  13. HeavyIons set via Pythia::setHeavyIonsPtr
  14. HIUserHooks set via Pythia::setHIHooks

The second method for loading a plugin can be used directly in user code, with or without a Pythia instance, using a number of helper functions. The simplest is as follows.

shared_ptr<BaseClass> make_plugin<BaseClass>( string libName, string className)  
creates a shared pointer of type BaseClass from the plugin library libName and the plugin class className.
argument libName, className : the plugin library name, typically of the form lib*.so, and the plugin class name to load.

shared_ptr<BaseClass> make_plugin<BaseClass>( string libName, string className, Pythia* pythiaPtr)  
same as above, but with an optional Pythia pointer that is passed to the constructor of the plugin class.
argument pythiaPtr : pointer to a Pythia instance. This pointer is passed to the constructor of the plugin object, and can be used by that object.

shared_ptr<BaseClass> make_plugin<BaseClass>( string libName, string className, Pythia* pythiaPtr, Settings* settingsPtr, Logger* loggerPtr)  
same as above, but with an optional Settings and Logger pointer.
argument settingsPtr : optional pointer to a Settings instance. This pointer is passed to the plugin object constructor. If a valid pythiaPtr is provided, but no settingsPtr, then the settingsPtr is taken from the pythiaPtr object.
argument loggerPtr : optional pointer to a Logger instance, similar to settingsPtr.

Plugin classes are always required to take a Pythia, Settings, and Logger pointer in their constructors. However, none of these pointers is required to be valid. If a plugin class requires one of these pointers to be valid, it is possible to specify this when creating the plugin library (see below). A plugin library may optionally register new settings in a Settings object passed to the plugin library. This allows the settings to pass a wide range of arguments to a plugin object. The idea is as follows. First, the plugin library settings are registered with a Settings object. Then, the new settings from the plugin in this Settings object can be modified by the user. Finally, the plugin object is created, with the Settings object passed to the constructor so that it can access these specialised settings. The following method registers the settings from a plugin library.

bool Settings::registerPluginLibrary(string libName, string startFile)  
register any settings provided in a plugin library. Typically, this method is not needed by the user.
argument libName : the plugin library name, typically of the form lib*.so.
argument startFile (default = "") : read in the settings from all the files listed in this file, and assumed to be located in the same subdirectory.

The following methods then combine these three steps together into a single method.

shared_ptr<BaseClass> make_plugin<BaseClass>( string libName, string className, Pythia* pythiaPtr, vector<string>& cmnds)  
register the plugin settings with the Pythia instance and read the commands of cmnds into the pythiaPtr.
argument cmnds : vector of commands to read into Pythia before loading the plugin, but after registering the plugin settings.

shared_ptr<BaseClass> make_plugin<BaseClass>( string libName, string className, Pythia* pythiaPtr, string fileName, int subrun = SUBRUNDEFAULT)  
register the plugin settings with the Pythia instance and read the commands of the file fileName with optional subrun.
argument fileName : name of the file to read into the Pythia object.
argument subrun : optionally specify the commands from the subrun to use.

The following demonstrates the simplest construction.

 
PDFPtr pdf = make_plugin<PDF>("libMyPlugins.so", "MyPDF"); 

To register settings and pass these to the plugin, the following could be done.

 
Settings settings; 
settings.registerPluginLibrary("libMyPlugins.so"); 
// Modify the settings here. 
PDFPtr pdf = make_plugin<PDF>("libMyPlugins.so", "MyPDF", nullptr, 
  &settings, nullptr); 

Alternatively, if working with a Pythia object, the multistep functions can be used.

 
Pythia pythia; 
vector<string> cmnds; 
 
// Fill the command string. 
PDFPtr pdf1 = make_plugin<PDF>( 
  "libMyPlugins.so", "MyPDF", &pythia, cmnds); 
 
// Alternatively, read the commands from a file. 
PDFPtr pdf2 = make_plugin<PDF>( 
  "libMyPlugins.so", "MyPDF", &pythia, "plugin.cmnd"); 

Note that in this example, two unique objects from the plugin library are created.

Plugin Library Paths

When libName is specified for any of the settings, methods, or functions above, it can be passed as either just the library name (e.g. libMyPlugins.so), the library name with a relative path (e.g. ./libMyPlugins.so), or the library name with an absolute path (e.g. /plugins/libMyPlugins.so). When the path is specified (i.e. the latter two options) then that file must exist, as the plugin library. When no path is specified then the same mechanism used for resolving library paths at runtime is used. This means that both the runtime search path specified to the linker at compile time will be searched (i.e. the RPATH mechanism using -Wl,rpath), as well as the path specified via the environment variable LD_LIBRARY_PATH.

Writing a Plugin Library

A plugin library consists of two parts: user defined classes inheriting from any Pythia class, and a function which registers settings. Arbitrary classes can be defined by the user, as long as they derive from a Pythia class. Additionally, the constructor for the class must always take the following form:

 
MyClass(Pythia* pythiaPtr, Settings* settingsPtr, Logger* loggerPtr) 

As discussed above, the validity of these three pointers is not guaranteed, and so the class must accordingly check their validity if needed. After a class is defined, it must then be made externally available so that it can be loaded from the plugin library. It is possible when making the class externally available to specify that certain pointers are required. This is done with the following macro.

 
PYTHIA8_PLUGIN_CLASS(BaseClass, MyClass, RequirePythia, RequireSettings, 
  RequireLogger) 

Here, BaseClass is whatever class the user wishes the MyClass> to be loaded as using the make_plugin functions. The argument ReqirePythia should be a boolean, and specifies whether the Pythia pointer is required by the plugin class. Similarly, the RequireSettings and RequireLogger arguments must also be booleans specifying whether the Settings and Logger pointers must be valid or not. Note, this macro can only be used once per class, and consequently can only be returned as a single base class. The settings can be registered by a function that follows the following form:

 
void registerMySettings(Settings* settingsPtr) 

which is then made externally available by the following macro.

 
PYTHIA8_PLUGIN_SETTINGS(registerMySettings) 

This macro can only be used once in a plugin library, and so all settings must be registered by a single function. Registering settings in a plugin library is optional. Users may also provide XML files, similar to the Pythia XML files, to define both setttings and documentation. This is done with the macro,

 
PYTHIA8_PLUGIN_XML("pluginLibraryName/xmldoc/startFile.xml") 

which takes a string as an argument. The string should provide the relative path to the XML index for the library, similar to Pythia8/xmldoc/Index.xml for Pythia. Here, pluginLibraryName should be the name of the plugin library, and startFile.xml is the index XML file which includes all other XML files needed for the plugin library. When a plugin library is loaded, an attempt will first be made to find the starting XML file on the path specified by the environment variable PYTHIA8CONTRIB, so here the full path would be PYTHIA8CONTRIB/pluginLibraryName/xmldoc/startFile.xml. If this path is not valid, then the path PYTHIA8DATA/../../ will be tried, followed by the provided path itself. Finally, it is required to define the versions of Pythia that the plugin library is compatible with. This is done with the macro:

 
PYTHIA8_PLUGIN_VERSIONS(8310, 8311) 

where a comma separated list of integer Pythia versions is passed as an argument. This list can be variable length, including length one. In this example, the plugin library is compatible with versions 8.309 and 8.310. When a user loads a plugin library the versions from this list are checked against the current Pythia version to test compatibility. If the current Pythia version is not found in the list then an error is given when loading the library. Additionally, the version of Pythia that the plugin library was compiled against is checked. If the versions between Pythia and the plugin library do not match a warning is given. This is because in principle the application binary interface between Pythia versions is expected to be stable. It is possible that a plugin library compiled against a different version of Pythia than the version loading the library might still function correctly. However, this behaviour may be changed to an error in the future.