Implementing an external ME+PS combination scheme and interfacing this
plugin with Pythia
For experts and developers of new matching/merging schemes, Pythia also offers
the possibility to completely replace its internal merging machinery with
a user-defined plugin code (much in the same way that parton shower plugins
(cf. Implement New Showers) are
possible). This allows for maximum flexibility while still benefiting from
the full Pythia event generation machinery. Note that the ME+PS merging with
the VINCIA and DIRE shower plugins make use of this flexibility, and might
thus provide helpful clarifications.
Of course, implementing your
own, new matching/merging scheme is a non-trivial task, and comprehensive
guidelines on how to proceed are impossible to set. However, it is important
that an external matching/merging plugin interfaces to Pythia in a simple and
well-defined manner. Here, we will document which C++ functions are necessary
to be able to use an external matching/merging (MM) plugin within Pythia.
To understand how to design a MM plugin for Pythia, it is useful to review
how Pythia's internal merging machinery is structured. The interaction between
the core Pythia and the merging code is governed by the
MergingHooks classes. Note that for
moderately complex requirements, it may be sufficient to only replace Pythia's
MergingHooks with a pointer to an external class (cf.
CKKW-L merging). The latter two classes
are supplemented with the helper classes
HardProcess. The latter gathers information on the (user-supplied
information about the) hard core scattering process to which hard jets are
by ME+PS merging. It is only used as a helper to the
History class contains the implementation of all
internal (LO or NLO) merging schemes. The
acts as a bridge between the implementation in the
and the rest of the Pythia code.
To implement an external MM plugin, you will have to write classes that derive
HardProcess classes of Pythia. For special cases, it might also
be permissible to only implement a replacement of the
class, while still using Pythia's implementation of the other two classes.
The external MM plugin can then be transferred to and
used by Pythia much in the same way as
UserHooks classes or
shower plugins. More concretely, an external MM code will
be used if a pointer to an instance of the external classes is transferred to
Pythia via the methods
Pythia::setMergingPtr( Merging* myMerging)
Pythia::setMergingHooksPtr( MergingHooks* myMergingHooks)
MergingHooks::setHardProcessPtr( HardProcess* myHardProcess)
The option to only use a user-defined
MergingHooks instance is
already documented in the item CKKW-L merging
and will not be discussed further. We will now focus on how to implement
HardProcess classes that can be used as a complete
replacement of the Pythia methods.
Let us assume that you want to create a class of type
and you call its instance
myMerging. For this external ME+PS
merging class to be interfaced to Pythia, the class needs to inherit from the
Pythia8::Merging base class. It is further necessary to define
the following functions that serve as interface to Pythia:
A destructor for your ME+PS class. If not defined, the base class's empty
destructor will be used.
virtual void MyMerging::init()
A method that is used to initialize your merging class. Pythia will call
this function during its initialization and after all pointers to
internal classes (e.g. to instances of the
ParticleData classes) have been set up.
virtual void MyMerging::statistics()
This function can be used to collect and print merging information at the
end of the event generation. Pythia will call this function in the execution
virtual int MyMerging::mergeProcess( Event& process)
This function should be the main interface of Pythia to the MM plugin.
Pythia will execute this function once the partonic (fixed-order) scattering
has been constructed (or read from LHEF). The partonic scattering is
transferred via the
process argument. The external MM plugin
should then, based on the
process, implement the matching/merging
strategy. It is permissible that this function changes
In this case, Pythia will continue the event generation with the changed
process as starting point. The return value of the function
steers how Pythia should proceed after the function execution. The following
return values are supported:
-1 : Reject the event and exit the generation/processing of the current
0: Reject the event but continue with the generation/processing of the
1: Keep the event but continue with the generation/processing of the
2: Reject the event but continue with the generation/processing of the
current event. However, re-evaluate resonance decays before any other
event generation step. This option can be necessary if the merging code
removes or changes resonant particles from
Note that because this function is the main interface between the MM plugin
and Pythia, it is necessary to use this function to set up all the information
that you might later need (merging weights, particle counters, etc) in this
For more details on how to design your
MyMerging class, and to
understand the interface to Pythia, studying Pythia's internal code is
unavoidable. Each potential developer of a MM plugin should do so.
The other main ingredient of the interface to MM plugins is a new
MergingHooks class. Let us assume that you want to
create a class of type
MyMergingHooks, and you call its
myMergingHooks. For this class to be interfaced to
Pythia, it will need to inherit from the
A destructor for your MergingHooks class. If not defined, the base class's
empty destructor will be used.
virtual void MyMergingHooks::init()
A method that is used to initialize your
Pythia will call this function during its initialization and after all
pointers to internal classes (e.g. to instances of the
ParticleData classes) have been set up.
virtual bool MyMergingHooks::canVetoStep()
This function will be used to tell Pythia if a CKKW-L-style event veto
after the first parton shower emission should be checked. If so, the function
should return true, and false otherwise.
virtual bool MyMergingHooks::doVetoStep( const Event& process, const Event& event, bool doResonance = false )
This function will be used to implement the check of a CKKW-L-style event veto
after the first parton shower emission, i.e. to check if the first parton
shower emission is above the merging scale.
If the input event
after emission should be kept, then false should be returned. If you want
instead to veto the event and continue with a completely now hard scattering
event, true should be returned.
virtual bool MyMergingHooks::canVetoEmission()
This function will be used to tell Pythia if a veto of emissions should
potentially be applied.
virtual bool MyMergingHooks::doVetoStep( const Event& event)
This function will be used to implement the check if shower emissions should
be discarded, as e.g. necessary in UMEPS or UNLOPS merging.
You can study the input event
event after emission, and return
true if the emission is valid, and false if you want to reject the emission.
Note that this veto does not lead to event rejections, only in potentially
removing certain emissions during shower evolution.
virtual bool MyMergingHooks::setShowerStartingScales( bool isTrial, bool doMergeFirstEmm, double& pTscaleIn, const Event& event, double& pTmaxFSRIn, bool& limitPTmaxFSRin, double& pTmaxISRIn, bool& limitPTmaxISRin, double& pTmaxMPIIn, bool& limitPTmaxMPIin )
This function allows to set the starting scales for timelike and spacelike
showering as well as multiparton interactions. It is thus necessary to
properly start trial showers (that generate necessary no-emission
probabilities), and for setting the correct starting conditions for parton
showering of accepted (non-zero weight) events.
event gives the hard process before showers and MPI
isTrial=true, this means that the function is currently called
from within a trial shower object (to produce no-emission probabilities). If
doMergeFirstEmm=true, then the function is called to set starting
conditions for the shower evolution of an (accepted) event. The double
pTmaxMPIIn are tentative values
for the starting scales of FSR, ISR and MPI. The function may overwrite
these with the desired values. Similarly,
limitPTmaxMPIin inform Pythia
if the phase space for FSR/ISR/MPI is restricted (true) or unrestricted
(false). Again, the tentative values can be overwritten.
MergingHooks base class allows for further virtual functions
that are not directly called by Pythia, and are hence
not necessary to define. Th usage of these functions within
History classes is documented
in CKKW-L merging. The additional (optional)
virtual functions are:
virtual double dampenIfFailCuts( const Event& inEvent )
virtual bool canCutOnRecState()
virtual bool doCutOnRecState( const Event& event )
virtual bool canVetoTrialEmission()
virtual bool doVetoTrialEmission( const Event&, const Event& )
virtual double hardProcessME( const Event& inEvent )
virtual double tmsDefinition( const Event& event)
virtual int getNumberOfClusteringSteps(const Event& event, bool resetNjetMax = false)
virtual bool useShowerPlugin()
The internal implementation of
MergingHooks in Pythia heavily
relies on the
HardProcess helper class. It is in principle
not necessary to follow the same strategy when implementing a derived
MyMergingHooks class. However, to benefit from the Pythia
implementation, and to allow for a structure similar to the internal code also
for an external MM plugin, it is also possible to effectively replace (in the
MergingHooks class) the pointer to an instance of
HardProcess with a pointer to an external implementation.
Let us assume that you want to create a class of type
MyHardProcess, and you call its instance
myHardProcess. For this class to be interfaced to
MergingHooks (or the derived
it will need to inherit from the
Pythia8::HardProcess base class.
A destructor for your HardProcess class. If not defined, the base class's
empty destructor will be used.
virtual void MyHardProcess::initOnProcess( string process, ParticleData* particleData)
This function can be used to initialize the instance of your HardProcess
class. In the internal Pythia implementation, this acts as a wrapper around
the next function.
virtual void MyHardProcess::translateProcessString( string process)
This function will use the string argument to set up the hard process
bookkeeping, e.g. how many incoming/outgoing particles of which flavour are
contained in the core (lowest multiplicity) scattering process.
virtual void MyHardProcess::storeCandidates( const Event& event, string process)
This function studies the input event and book-keeps the particles that
may be considered as part of the core scattering process. For this, it may
use the four next functions.
virtual bool MyHardProcess::allowCandidates(int iPos, vector<int> Pos1, vector<int> Pos2, const Event& event)
This function uses the input vectors of positions of particles in the input
event to decide if the particle with
iPos could be member
of the core scattering. If the particle with position
cannot be part of the core scattering (e.g. because it is a final state
parton, while the core scattering contains final state leptons only), then
the function should return false. Else, return true to allow this candidate.
Note that it might be possible to find multiple equally good core scattering
candidates. In this case, all candidates should be found (with the
findOtherCandidates function), and can be potentially be
virtual bool MyHardProcess::matchesAnyOutgoing(int iPos, const Event& event)
This function may be used to check if the particle with position
iPos in the input event should be considered an outgoing particle
of the core scattering.
virtual bool MyHardProcess::findOtherCandidates(int iPos, const Event& event, bool doReplace)
iPos specifies the position of a particle in the
input event which is tagged as part of the core scattering. This function may
be used to check the role of
iPos as core scattering member may
be filled by another particle in the event record. If so, and if
iPos will no longer be
book-kept as part of the core scattering. An example where this functionality
is helpful is if the input event is g g -> b b~ b b~, and the core scattering
is g g -> b b~. Not swapping the hard process candidates could in this case
mean that not all parton shower histories can be found.
The function should return false if no replacements can be found, and true
virtual bool MyHardProcess::exchangeCandidates( vector<int> candidates1, vector<int> candidates2, map<int, int> further1, map<int, int> further2)
This function implements the replacement of a list of core scattering
candidates by another list of candidates.