The PartonSystems
class is primarily used to keep track
of the current positions of all partons belonging to each system,
represented by the index iPos
for a parton stored in the
event-record slot event[iPos]
. With "all" we mean the
current set of outgoing partons, as well as the currently defined two
incoming partons that system (for 2→n processes) or
one incoming parton in the case of a decay (1→n) process. No
intermediate-state (off-shell) ISR or FSR
partons are present. That is, the parton system stores all partons
that could be subject to some action in the next step of the
combined MPI/ISR/FSR/BR description. As a special case, an outgoing
parton is stored even if it undergoes a rescattering, and thus no
longer belongs to the final state proper.
Note also that an unstable (decaying) resonance will normally appear in two different systems; once, as an outgoing parton in the system that produced it (a hard process or the decay system of a previous resonance decay), and once as an incoming parton in its own decay system.
The partonSystems
instance of PartonSystems
class is a public member of the Pythia
top-level class,
but is also available as a pointer partonSystemsPtr
in
various PartonLevel
classes, e.g. inside the current
instances of the TimeShower
and SpaceShower
classes.
A number of PartonSystems
methods can be used to set or
get information on the subsystems:
clear()
resets all the contents in preparation for the
next event.addSys()
add a new (initially empty) subsystem to the
current list and return its index iSys
in the list,
where index 0 is the hardest subcollision and so on.sizeSys()
the number of separate subsystems.setInA(iSys, iPos), setInB(iSys, iPos)
store position
iPos
of the incoming parton from beam A or beam B to the
iSys
'th subcollision. These values are 0 initially, and
should so remain if there are no beams, such as in resonance decays.
setInRes(iSys, iPos)
stores position
iPos
of the incoming (decaying) resonance whose
decay produced the outgoing partons for the iSys
'th
system. This value is 0 initially and should so remain for systems
that are not produced by the decay of a resonance, such as
2→n subcollision systems. addOut(iSys, iPos)
store position iPos
of a new outgoing parton in the iSys
'th subcollision,
by appending it at the end of the current vector, with beginning in
slot 0.setOut(iSys, iMem, iPos)
store position iPos
in the iMem
'th slot in the vector of outgoing partons in the
iSys
'th subcollision. Here iMem
must be in
the range already constructed by addOut
calls. replace(iSys, iPosOld, iPosNew)
replace the existing
incoming or outgoing parton position iPosOld
by
iPosNew
in the iSys
'th subcollision.setSHat(iSys, sHat)
set the invariant squared mass
sHat
of the iSys
'th subcollision.hasInAB(iSys)
true if an incoming parton has been set
for beam A or beam B (and hence should have been set for both) in the
iSys
'th subcollision, else false.getInA(iSys), getInB(iSys)
the position iPos
of the incoming parton from beam A or beam B to the iSys
'th
subcollision.hasInRes(iSys)
true if an incoming (decaying)
resonance has been set for the iSys
'th parton system,
else false.sizeOut(iSys)
the number of outgoing partons
in the iSys
'th subcollision.getOut(iSys, iMem)
the position iPos
of an outgoing parton in the iSys
'th subcollision,
with the iMem
range limited by sizeOut(iSys)
.
These partons are not guaranteed to appear in any particular order. sizeAll(iSys)
the total number of incoming and outgoing
partons in the iSys
'th subcollision.getAll(iSys, iMem)
the position iPos
of an incoming or outgoing parton in the iSys
'th subcollision.
In case there are beams it gives same as getInA(iSys)
and
getInB(iSys)
for indices 0 and 1, and thereafter agrees with
getOut(iSys, iMem)
offset two positions. In case there is
an incoming (decaying) resonance set for the system, it gives the same
as getInRes(iSys)
for index 0, and thereafter agrees with
getOut(iSys, iMem)
offset one position. If there are
neither beams nor an incoming resonance set for the system,
it is identical with getOut(iSys, iMem)
.getSystemOf(iPos, alsoIn)
returns the system
(iSys
) of the parton specified by iPos
.
If the parton is outgoing in one system and incoming in another (eg a
decaying resonance), the system in which it is incoming will be returned if
alsoIn == true
, else the system in which it is outgoing
will be returned. The default is alsoIn = false
.
getSHat(iSys)
the invariant squared mass
sHat
of the iSys
'th subcollision.list()
print a listing of all the system information,
except for the sHat
values.New systems are created from the hard process, from resonance decays, and by the MPI, not from any of the other components. Both FSR and ISR modify the position of partons, however. Since an FSR or ISR branching typically implies a new state with one more parton than before, an outgoing parton must be added to the system. Furthermore, in a branching, several existing partons may also be moved to new slots, including the incoming beam ones. In a FSR 1 → 2 branching it is irrelevant which parton position you let overwrite the existing slot and which is added to the end of the system.
The system information must be kept up-to-date. Both the MPI, ISR, FSR and BR descriptions make extensive use of the existing information. As an example, the introduction of primordial kT in the beam remnants will fail if the information on which final-state partons belong to which system is out-of-date. The introduction of rescattering as part of the MPI framework adds further complications, where an outgoing parton of one subsystem may be the incoming one of another system. This part of the code is still under development.
Currently the system information is kept throughout the continued history of the event. Specifically, resonance decays create new systems, appended to the existing ones. This could be useful during the hadronization stage, to collect the partons that belong to a resonance with preserved mass when a small string collapses to one particle, but is not yet used for that.
beamA
and beamB
,
is therefore as crucial to keep correct as the above subsystem list.
Both beam objects are of the BeamParticle
class.
Each such object contains a vector with the partons extracted from it.
The number of such partons, beamX.size()
(X = A or B),
of course is the same as the above number of subsystems in the event
record. (The two diverge at the BR step, where further beam remnants
are added to the beams without corresponding to new subsystems.)
The individual partons are accessed by an overloaded indexing
operator to a vector of ResolvedParton
objects. The
iPos()
property corresponds to the iPos
one above, i.e. providing the position in the main event record of
a parton. In particular,
beamA[iSys].iPos() = partonSystemsPtr->getInA(iSys)
and
beamB[iSys].iPos() = partonSystemsPtr->getInB(iSys)
.
Whereas thus the indices of the two incoming partons to a subsystem
are stored in two places, the ones of the outgoing partons only
appear in the system part of the PartonSystems
class.
Just as the subsystems in PartonSystems
must be updated,
so must the information in the two BeamParticle
's, e.g.
with methodsbeamX[iSys].iPos( iPosIn)
when an incoming
parton is replaced by a new one in line iPosIn
. Furthermore
the new parton identity should be set by beamX[iSys].id( idIn)
and the new x energy-momentum fraction by
beamX[iSys].x( xIn)
. The three can be combined in one go
by beamX[iSys].update( iPosIn, idIn, xIn)
.
To be specific, it is assumed that, at each step, the two incoming partons are moving along the +-z axis and are massless. Since the event is constructed in the c.m. frame of the incoming beams this implies that x = 2 E / E_cm. If the x values are not defined accordingly or not kept up-to-date the BR treatment will not conserve energy-momentum.
In return, the BeamParticle
objects give access to some
useful methods. The beamX.xf( id, x, Q2)
returns the
standard PDF weight x f_id(x, Q^2). More interestingly,
beamX.xfISR( iSys, id, x, Q2)
returns the modified weight
required when several subsystems have to share the energy and flavours.
Thus iSys
is added as an extra argument, and the momentum
already assigned to the other subsystems is not available for evolution,
i.e. the maximal x is correspondingly smaller than unity.
Also flavour issues are handled in a similar spirit.
An additional complication is that a parton can be either valence or
sea, and in the latter case the BR treatment also distinguishes
companion quarks, i.e. quark-antiquark pairs that are assumed to
come from the same original g → q qbar branching, whether
perturbative or not. This can be queried either with the
beamX[iSys].companion()
method, for detailed information,
or with the beamX[iSys].isValence()
,
beamX[iSys].isUnmatched()
and
beamX[iSys].isCompanion()
methods for yes/no answers
whether a parton is valence, unmatched sea or matched sea.
This choice should affect the ISR evolution; e.g., a valence quark
cannot be constructed back to come from a gluon.
To keep this info up-to-date, the beamX.pickValSeaComp()
method should be called whenever a parton of a new flavour has been
picked in the ISR backwards evolution, but not if the flavour has not
been changed, since then one should not be allowed to switch back and
forth between the same quark being considered as valence or as sea.
Since the pickValSeaComp()
method makes use of the
current parton-density values, it should be preceded by a call
to beamX.xfISR( iSys, id, x, Q2)
, where the values in
the call are the now finally accepted ones for the newly-found mother.
(Such a call is likely to have been made before, during the evolution,
but is not likely to be the most recent one, i.e. still in memory, and
therefore had better be redone.)