Implement a Process
Normally users should not try to implement new processes internally
inside Pythia
, but rather use the
Les Houches Accord
to input your own events for processing by Pythia
.
However, in case you do want to implement a new process at the same
level as the internal Pythia
ones, here is a brief summary.
For the details, of course, it always makes sense to take a similar
already-implemented process as a starting point.
There are two steps involved in implementing a process:
1) implementing the matrix elements, including information on
incoming and outgoing flavours and colours, and
2) making the process available to the rest of the program,
so that it can be switched on by a user.
We consider these two aspects in turn.
Matrix Elements
The matrix-element information have to be stored in a matched pair
of .cc
and .h
files, in the
src
and include
directories, respectively.
These could be one set of existing files (SigmaQCD
,
SigmaEW
and SigmaSUSY
), if it belongs there,
or entirely new files, say SigmaCompositeness
, where
the name attaches to the scenario studied.
Header
The .h
file is used to define the class for the new
process. This class has to be derived either from
Sigma1Process
, for 2 -> 1 processes, or from
Sigma2Process
, for 2 -> 2 ones. (The
Sigma0Process
class is used for elastic, diffractive
and minimum-bias events, and should not be used.) Both
Sigma1Process
and Sigma2Process
are in their turn derived from the SigmaProcess
base class.
The header information of a new class must contain a constructor
and a destructor. The constructor can take arguments to allow a set
of related processes to share common code. For instance,
g g -> Q Qbar, Q = c or b, is only coded once, and then the
constructor takes the quark code (4 or 5) as argument,
to allow the proper amount of differentiation.
A few simple methods are used to encapsulate information on the
particular process:
* name()
returns the name of the process, as it will
be shown in listings.
* code()
returns an integer identifier of the process.
This has no internal function, but is only intended as a service for
the user to rapidly identify which process occured in a given event.
* id3Mass(), id4Mass()
are the one or two final-state
flavours, where masses are to be selected before the matrix elements
are evaluated. Only the absolute value need to be given. For massless
particles, like gluons and photons, one need not give anything, i.e.
one defaults to 0. The same goes for normal light quarks, where masses
presumably are not implemented in the matrix elements. Later on, these
quarks can still (automatically) obtain constituent masses, once a
u, d or s flavour has been selected.
* resonanceA(), resonanceB()
are the codes of up to two
s-channel resonances contributing to the matrix elements. These are
used by the program to improve the phase-space selection efficiency,
by partly sampling according to the relevant Breit-Wigner. Massless
resonances need not be specified.
In addition, the initProc()
, sigmaHat()
and
setIdColAcol()
methods have to be implemented. This
normally requires more code, and so the implementation belongs in the
.cc
file.
Initialization
initProc()
at the very least has to specify the
combinations of incoming partons that are allowed for the process
under consideration. This is obtained by creating a pointer to an
InFlux
object. Currently allowed options are
* InFluxgg
: g g ,
* InFluxqg
: q g or qbar g,
* InFluxqqbarqqDiff
: q q', q qbar' or qbar qbar',
q and q' different flavours,
* InFluxqqDiff
: q q' or qbar qbar',
q and q' different flavours,
* InFluxqqSame
: q q or qbar qbar, same flavour,
* InFluxqqbarDiff
: q qbar', q and q' different
flavours,
* InFluxqqbarSame
: q qbar, same flavour,
* InFluxff
: f f', f fbar' or fbar fbar', where
f and f' may be same or different,
* InFluxffbarSame
: f fbar, same flavour,
* InFluxffbarChg
: f fbar', where the combination
has charge +-1 (e.g. u dbar, e+ nu_e).
For a hadron beam, the two generic fermion alternatives default
back to quarks only.
After the allowed channels have been set up, it is possible to
specify that the channels come with a different weight, apart from
the automatic convolution with the respective parton densities
* weightCharge2()
: weights by the squared quark
charge (also works e.g. for q g states, but not for a quark pair
of different charge).
* weightCKM2()
: weights by the squared of the
CKM mixing-matrix element, vanishing when no such element exists.
* weightCKM2sum(int mode, int idQ)
: provides
the CKM-related weight for a number of different situations.
1) Sum of CKM weights for transformation of an incoming flavour
to an outgoing one, excluding top (used e.g. for f g -> f' W).
2) Ditto, but product of both incoming sides (not used currently).
3) Coupled CKM weights of the two sides, as consistent with
t-channel W exchange (used e.g. for q_1 q_2 -> q_3 q_4).
4) Coupled CKM weights of the two sides, but on one side to
specified flavour idQ (used e.g. for q_1 q_2 -> t q_3).
* weightInvCol()
: factor 1/3 for an incoming
qqbar pair and 1/8 for an incoming g g one.
* weightNeutrinoSpin()
: multiply by factor 2
for an incoming neutrino, since they always are lefthanded and so
are not averaged over incoming spin.
* weightFixed(double nowWeight)
:
weights all channels by nowWeight
.
* weightFixed(int id1, int id2, double nowWeight,
bool flipSide = true, bool conjugate = true, bool allGen = true)
:
weights by nowWeight
for the specific incoming state
consisting of id1
and id2
. If
flipside
then also apply this weight when the two
incoming sides are interchanged (but only once for
id1 = id2
, of course). If conjugate
then also apply it when quarks and leptons are replaced by their
antiparticles. If allGen
then apply weights provided
for first-generation fermions also to equivalents in the second
and third generation (i.e. u dbar is also applied to u sbar, u bbar,
c dbar, c sbar and c bbar).
You can see the list of allowed channels and their respective fixed
weights by switching on the InFlux:showChannels
flag.
Note that channels which are assigned a vanishing weight during the
initialization step are pruned from the channel list.
In addition, initProc()
is the place where all other
types of process-specific initialization calculations could be put.
Event weight
sigmaHat()
encodes the relevant matrix element. For a
2 -> 1 process, what is to be provided is
sigmaHat(sHat), where sH
and sH2
are available to be used. For a 2 -> 2 process, instead
d(sigmaHat)/d(tHat) should be calculated, based on
provided sH, sH2, tH, tH2, uH, uH2, m3, s3, m4, s4
and
pT2
values (s3 = m3*m3
). In either case,
alpha_s and alpha_em have also been calculated,
and are stored in alpS
and alpEM
. Also
other standard variables may be used, like
CoupEW::sin2thetaW()
, and related flavour-dependent
vector and axial couplings in CoupEW
and CKM combinations
in VCKM
. Note that, normally the cross sections would come
in dimensions of inverse GeV to second or fourth power, respectively.
To translate it to the compulsory mb or mb/GeV^2 dimensions, you need
to multiply by the CONVERT2MB
constant.
A further machinery exists when event-by-event channel-dependent
weights are required. A typical example would be that,
for q qbar -> gamma*/Z0, the relative weight of incoming u-type and
d-type quarks depends on the relative admixture of gamma* and of Z0,
which depends on the subprocess energy, and so varies from one event
to the next. Therefore, in addition to the fixed weight above, to be
set at initialization, each channel contains a variable weight factor,
and the total weight of a channel is a product of the two. The variable
weight is set to 1 at the creation of a new channel, so if not touched
it makes no difference. It is not changed between events, however,
i.e. not automatically reset to 1. It can be manipulated by two methods:
* weightInState(double nowWeight = 1.)
: set all variable
weights to the value specified (usually not necessary).
* weightInState(int id1, int id2, double nowWeight,
bool flipSide = true, bool conjugate = true, bool allGen = true)
:
set the variable weight factor for the incoming state defined by
id1
and id2
to be varWeight
Se above for an explanation of the flipside
,
conjugate
and allGen
options.
Normally, only one cross section is returned from sigmaHat()
,
and the standard machinery takes care of weighting it with parton
densities and the other factors specified above. However, if you use
variable weights, you should use the weightInState(...)
method above to specify the weight for each incoming flavour combination.
Note that, when weights are used, there is a complete freedom how you
shuffle contributions between the individual channels and the overall
weight returned by sigmaHat()
, since only the product is
relevant. For sanity, as much as possible should be put in the
sigmaHat()
, with weightFixed(...)
and
weightInState(...)
only providing dimensionless
extrafactors of order unity.
Finalize event
setIdColAcol()
is called when a kinematical configuration
has been accepted and flavours and colours need be provided. The first
part is handled by the setId
method. The two incoming
flavours have already been set in id1
and id2
,
whereas the one or two outgoing ones either are fixed for a given
process or can be determined from the instate (e.g. whether a W+ or W-
was produced). The colours are handled by the setColAcol
method. Les Houches style colour tags are used, but starting with
number 1. The input is grouped particle by particle, with the colour
index before the anticolour one. You may need to select colour flow
dynamically, depending on the kinematics, when several distinct
possibilities exist. Trivial operations, like swapping colours and
anticolours, can be done with existing methods. There is also a standard
method to pick a final flavour from an iniial one with CKM mixing.
When the id3Mass()
and id4Mass()
methods have been used, the order of the outgoing particles may be
inconsistent with the way the tHat and uHat
variables have been defined. A typical example would be a process like
q g -> q' W with tHat defined between incoming and
outgoing quark, but where id3Mass() = 24
and so the
process is to be stored as q g -> W q'. One should then put
the variable swapTU = true
for each event where the
tHat and uHat variables should be swapped before
the event kinematics is reconstructed. This variable is automatically
restored to false
for each new event.
Access
A flag has to be defined, that allows the process to be switched on;
by default it should always be off. The name of the flag should be
chosen of the type model:process
. Here the
model
would be related to the general scenario considered,
e.g. Compositeness
, while process
would
specify instate and outstate, separated by a 2 (= to), e.g.
ug2u*g
.
When several processes are implemented and "belong together" it is
also useful to define a model:all
switch that affects
all the separate processes.
The flags should normally be stored in the Processes.xml
file. This is to make them easily found by users. You could create
and use your own .xml
file, so long as you then add that
name to the list of files in the Index.xml
file. (If not,
the flags would never be created and the program would not work.)
In the ProcessContainer.c
file, the final
SetupContainers::init
routine needs to be expanded to
create instances of the processes switched on. This code is fairly
repetitive, and should be easy to copy and modify from the code
already there. The basic structure is
(i) check whether a process is requested by the user and, if so,
(ii) create an instance of the matrix-element class,
(iii)create a container for the matrix element and its associated
phase-space handling, and
(iv) add the container to the existing process list.
Two minor variations are possible. One is that a set of related
processes are lumped inside the the same initial check, i.e. are
switched on all together. The second is that the matrix-element
constructor may take arguments, as specified by you (see above).
If so, the same basic matrix element may be recycled for a set of
related processes, e.g. one for a composite u and one for a composite d.
Obviously these variations may be combined.