## main243

Back to index.

    // main243.cc is a part of the PYTHIA event generator.
    // Copyright (C) 2026 Torbjorn Sjostrand.
    // PYTHIA is licenced under the GNU GPL v2 or later, see COPYING for details.
    // Please respect the MCnet Guidelines, see GUIDELINES for details.

    // Keywords:
    //            Userhooks
    //            Onia
    //            External decays

    // This is a simple test program.
    // It illustrates
    // (a) how to use UserHooks to regularize onium cross section for pT -> 0,
    // (b) how decays could be handled externally.

    #include "Pythia8/Pythia.h"

    using namespace Pythia8;

    //==========================================================================

    // A derived class to do J/psi decays.

    class JpsiDecay : public DecayHandler {

    public:

      // Constructor.
      JpsiDecay(ParticleData* pdtPtrIn, Rndm* rndmPtrIn) {times = 0;
        pdtPtr = pdtPtrIn; rndmPtr = rndmPtrIn;}

      // Routine for doing the decay.
      bool decay(vector<int>& idProd, vector<double>& mProd,
        vector<Vec4>& pProd, int iDec, const Event& event);

    private:

      // Count number of times JpsiDecay is called.
      int times;

      // Pointer to the particle data table.
      ParticleData* pdtPtr;

      // Pointer to the random number generator.
      Rndm* rndmPtr;

    };

    //--------------------------------------------------------------------------

    // The actual J/psi decay routine.
    // Not intended for realism, just to illustrate the principles.

    bool JpsiDecay::decay(vector<int>& idProd, vector<double>& mProd,
      vector<Vec4>& pProd, int iDec, const Event& event) {

      // Always do decay J/psi -> mu+ mu-; store the muons.
      idProd.push_back(-13);
      idProd.push_back(13);

      // Muon mass(es), here from Pythia tables, also stored.
      double mMuon = pdtPtr->m0(13);
      mProd.push_back(mMuon);
      mProd.push_back(mMuon);

      // Calculate muon energy and momentum in J/psi rest frame.
      double eMuon = 0.5 * mProd[0];
      double pAbsMuon = sqrt(eMuon * eMuon - mMuon * mMuon);

      // Assume decay angles isotropic in rest frame.
      double cosTheta = 2. * rndmPtr->flat() - 1.;
      double sinTheta = sqrt(max(0., 1. - cosTheta * cosTheta));
      double phi = 2. * M_PI * rndmPtr->flat();
      double pxMuon = pAbsMuon * sinTheta * cos(phi);
      double pyMuon = pAbsMuon * sinTheta * sin(phi);
      double pzMuon = pAbsMuon * cosTheta;

      // Define mu+ and mu- four-vectors in the J/psi rest frame.
      Vec4 pMuPlus(   pxMuon,  pyMuon,  pzMuon, eMuon);
      Vec4 pMuMinus( -pxMuon, -pyMuon, -pzMuon, eMuon);

      // Boost them by velocity vector of the J/psi mother and store.
      pMuPlus.bst(pProd[0]);
      pMuMinus.bst(pProd[0]);
      pProd.push_back(pMuPlus);
      pProd.push_back(pMuMinus);

      // Print message the first few times, to show that it works.
      if (times++ < 10) {
        int iMother = event[iDec].mother1();
        int idMother = event[iMother].id();
        cout << "\n J/psi decay performed, J/psi in line " << iDec
             << ", mother id = " << idMother << "\n";
      }

      // Done
      return true;

    }

    //==========================================================================

    int main() {

      // Number of events to generate and to list. Max number of errors.
      int nEvent = 2000;
      int nList  = 2;
      int nAbort = 5;

      // Pythia generator.
      Pythia pythia;

      // Initialization for charmonium (singlet+octet) production at the LHC.
      pythia.readString("Charmonium:all = on");
      pythia.readString("Beams:eCM = 7000.");

      // Normally cutoff at pTHat = 1, but push it lower combined with dampening.
      pythia.readString("PhaseSpace:pTHatMin = 0.5");
      pythia.readString("PhaseSpace:pTHatMinDiverge = 0.5");

      // Set up to do a user veto and send it in.
      // First argument: multiplies the pT0 of multiparton interactions
      // to define the pT dampeing scale.
      // Second argument: how many powers of alpha_strong to
      // reweight with new (larger) argument.
      // Third argument: choice of process scale two different ways;
      // probably does not make much difference.
      // See "User Hooks" in manual for detail on SuppressSmallPT.
      auto oniumUserHook = make_shared<SuppressSmallPT>( 1., 3, false);
      pythia.setUserHooksPtr( oniumUserHook);

      // A class to do J/psi decays externally.
      DecayHandlerPtr handleDecays = make_shared<JpsiDecay>(&pythia.particleData,
        &pythia.rndm);

      // The list of particles the class can handle.
      vector<int> handledParticles;
      handledParticles.push_back(443);

      // Hand pointer and list to Pythia.
      pythia.setDecayPtr( handleDecays, handledParticles);

      // Switch off automatic event listing in favour of manual.
      pythia.readString("Next:numberShowInfo = 0");
      pythia.readString("Next:numberShowProcess = 0");
      pythia.readString("Next:numberShowEvent = 0");

      // If Pythia fails to initialize, exit with error.
      if (!pythia.init()) return 1;

      // Book histograms.
      Hist pThard("pTHat of hard subprocess", 100, 0., 50.);
      Hist pTJPsi("pT of J/Psi", 100, 0., 50.);

      // Begin event loop.
      int iList = 0;
      int iAbort = 0;
      for (int iEvent = 0; iEvent < nEvent; ++iEvent) {

        // Generate events. Quit if many failures.
        if (!pythia.next()) {
          if (++iAbort < nAbort) continue;
          cout << " Event generation aborted prematurely, owing to error!\n";
          break;
        }

        // Histogram pThard spectrum of process.
        double pTHat = pythia.info.pTHat();
        pThard.fill( pTHat );

        // Look for event with externally handled decays.
        bool externalDecay = false;
        for (int i = 0; i < pythia.event.size(); ++i) {
          int status = pythia.event[i].statusAbs();
          if (status == 93 || status == 94) {externalDecay = true; break;}
        }

        // List first few events with external decay.
        if (externalDecay && ++iList <= nList) {
          pythia.process.list();
          pythia.event.list();
        }

        // Histogram pT spectrum of J/Psi.
       for (int i = 0; i < pythia.event.size(); ++i)
       if (pythia.event[i].id() == 443) pTJPsi.fill( pythia.event[i].pT() );

      // End of event loop.
      }

      // Final statistics. Print histograms.
      pythia.stat();
      cout << pThard << pTJPsi;

      // Done.
      return 0;
    }