Semi-Internal Resonances

  1. The ResonanceWidths Class
  2. Access to resonance widths
The introduction of a new semi-internal process may also involve a new particle, not currently implemented in PYTHIA. Often it is then enough to use the standard machinery to introduce a new particle (id:all = ...) and new decay channels (id:addChannel = ...). By default this only allows you to define a fixed total width and fixed branching ratios. Using meMode values 100 or bigger provides the possibility of a very simple threshold behaviour.

If you want to have complete freedom, however, there are two ways to go. One is that you make the resonance decay part of the hard process itself, either using the Les Houches interface or a semi-internal process. The other is for you to create a new ResonanceWidths object, where you write the code needed for a calculation of the partial width of a particular channel.

Here we will explain what is involved in setting up a resonance. Should you actually go ahead with this, it is strongly recommended to use an existing resonance as a template, to get the correct structure. There also exists a sample main program, main22.cc, that illustrates how you could combine a new process and a new resonance.

There are three steps involved in implementing a new resonance:
1) providing the standard particle information, as already outlined above (id:all = ..., id:addChannel = ...), except that now branching ratios need not be specified, since they anyway will be overwritten by the dynamically calculated values.
2) writing the class that calculates the partial widths.
3) handing in a pointer to an instance of this class to PYTHIA.
We consider the latter two aspects in turn.

The ResonanceWidths Class

The resonance-width calculation has to be encoded in a new class. The relevant code could either be put before the main program in the same file, or be stored separately, e.g. in a matched pair of .h and .cc files. The latter may be more convenient, in particular if the calculations are lengthy, or likely to be used in many different runs, but of course requires that these additional files are correctly compiled and linked.

The class has to be derived from the ResonanceWidths base class. It can implement a number of methods. The constructor and the calcWidth ones are always needed, while others are for convenience. Much of the administrative machinery is handled by methods in the base class.

Thus, in particular, you must implement expressions for all possible final states, whether switched on in the current run or not, since all contribute to the total width needed in the denominator of the Breit-Wigner expression. Then the methods in the base class take care of selecting only allowed channels where that is required, and also of including effects of closed channels in secondary decays. These methods can be accessed indirectly via the res... methods of the normal particle database.

A constructor for the derived class obviously must be available. Here you are quite free to allow a list of arguments, to set the parameters of your model. The constructor must call the base-class initBasic(idResIn) method, where the argument idResIn is the PDG-style identity code you have chosen for the new resonance. When you create several related resonances as instances of the same class you would naturally make idResIn an argument of the constructor; for the PYTHIA classes this convention is used also in cases when it is not needed.
The initBasic(...) method will hook up the ResonanceWidths object with the corresponding entry in the generic particle database, i.e. with the normal particle information you set up in point 1) above. It will store, in base-class member variables, a number of quantities that you later may find useful:
idRes : the identity code you provide;
hasAntiRes : whether there is an antiparticle;
mRes : resonance mass;
GammaRes resonance width;
m2Res : the squared mass;
GamMRat : the ratio of width to mass.

A destructor is only needed if you require some special behaviour.

void ResonanceWidths::initConstants()  
is called once during initialization, and can then be used to set up further parameters specific to this particle species, such as couplings, and perform calculations that need not be repeated for each new event, thereby saving time. This method needs not be implemented.

void ResonanceWidths::calcPreFac(bool calledFromInit = false)  
is called once a mass has been chosen for the resonance, but before a specific final state is considered. This routine can therefore be used to perform calculations that otherwise might have to be repeated over and over again in calcWidth below. It is optional whether you want to use this method, however, or put everything in calcWidth().
The optional argument will have the value true when the resonance is initialized, and then be false throughout the event generation, should you wish to make a distinction. In PYTHIA such a distinction is made for gamma^*/Z^0 and gamma^*/Z^0/Z'^0, owing to the necessity of a special description of interference effects, but not for other resonances.
In addition to the base-class member variables already described above, mHat contains the current mass of the resonance. At initialization this agrees with the nominal mass mRes, but during the run it will not (in general).

void ResonanceWidths::calcWidth(bool calledFromInit = false)  
is the key method for width calculations and returns a partial width value, as further described below. It is called for a specific final state, typically in a loop over all allowed final states, subsequent to the calcPreFac(...) call above. Information on the final state is stored in a number of base-class variables, for you to use in your calculations:
iChannel : the channel number in the list of possible decay channels;
mult : the number of decay products;
id1, id2, id3 : the identity code of up to the first three decay products, arranged in descending order of the absolute value of the identity code;
id1Abs, id2Abs, id3Abs : the absolute value of the above three identity codes;
mHat : the current resonance mass, which is the same as in the latest calcPreFac(...) call;
mf1, mf2, mf3 : masses of the above decay products;
mr1, mr2, mr3 : squared ratio of the product masses to the resonance mass;
ps : is only meaningful for two-body decays, where it gives the phase-space factor ps = sqrt( (1. - mr1 - mr2)^2 - 4. * mr1 * mr2 );
In two-body decays the third slot is zero for the above properties. Should there be more than three particles in the decay, you would have to take care of the subsequent products yourself, e.g. using
particlePtr->decay[iChannel].product(j);
to extract the j'th decay products (with j = 0 for the first, etc.). Currently we are not aware of any such examples.
The base class also contains methods for alpha_em and alpha_strong evaluation, and can access many standard-model couplings; see the existing code for examples.
The result of your calculation should be stored in
widNow : the partial width of the current channel, expressed in GeV.

double ResonanceWidths::widthChan( double mHat, int idAbs1, int idAbs2)  
is not normally used. In PYTHIA the only exception is Higgs decays, where it is used to define the width (except for colour factors) associated with a specific incoming/outgoing state. It allows the results of some loop expressions to be pretabulated.

bool ResonanceWidths::allowCalc()  
can normally be left dummy (and then always returns true) but can optionally be used to determine whether to force dynamical width calculation to be switched off (return false). An example is provided by the SUSYResonanceWidths class, in which the implementation of this method checks for the existence of SLHA decay tables for the particular resonance in question, and checks if those tables should be given precedence over the internal width calculation.

bool ResonanceWidths::initBSM()  
can normally be left dummy, but for advanced implementations it provides a possibility to initialize data members of the derived class at a very early stage during initialization, before any of the other members are called. An example is provided by the SUSYResonanceWidths class, in which an internal pointer to a derived Couplings class must be (re)set before any of the other methods are used. A return value of false can be used to signal that this initialization step failed.

Access to resonance widths

Once you have implemented a class, it is straightforward to make use of it in a run. Assume you have written a new class MyResonance, which inherits from ResonanceWidths. You then create an instance of this class and hand it in to a pythia object with
 
      ResonanceWidthsPtr myResonance = make_shared<MyResonance()>; 
      pythia.setResonancePtr( myResonance); 
If you have several resonances you can repeat the procedure any number of times. When pythia.init() is called these resonances are initialized along with all the internal resonances, and treated in exactly the same manner. See also the Program Flow description.

If the code should be of good quality and general usefulness, it would be simple to include it as a permanently available process in the standard program distribution. The final step of that integration ought to be left for the PYTHIA authors, but basically all that is needed is to add one line in ParticleData::initResonances, where one creates an instance of the resonance in the same way as for the resonances already there. In addition, the particle data and decay table for the new resonance has to be added to the permanent particle database, and the code itself to include/ResonanceWidths.h and src/ResonanceWidths.cc.