## main370

Back to index.

    // main370.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.

    // Authors:
    //            Torbjorn Sjostrand

    // Keywords:
    //            Top
    //            Toponium
    //            Openmp

    // Plot ttbar system properties contrasting five different scenarios:
    // 0 : pure Born baseline.
    // 1 : Coulomb enhancement.
    // 2 : Green's function, full top width in Breit-Wigner and matrix element.
    // 3 :  Green's function, reduced top width in Breit-Wigner.
    // 4 :  Green's function, reduced top width in matrix elements.
    // Plots all scenarios in one frame, which may be too much.

    // This main is the same as main369, but demonstrates how the run
    // can be done with PythiaParallel rather than OpenMP.

    // Based on threshold factors according to
    // V. Fadin,  V. Khoze and T. Sjostrand, Z. Phys. C48 (1990) 613.

    #include "Pythia8/PythiaParallel.h"
    using namespace Pythia8;

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

    int main() {

      // Restrict to threshold region only or not.
      bool thresholdOnly   = true;

      // Full event generation or only cross-section-oriented studies.
      bool fullEvents      = false;

      // Number of events.
      int nEvent           = 1000000;

      // LHC collision energy.
      double eCM           = 13000.;

      // Example of common possible setup values.
      double mt            = 172.5;
      double thrRegion     = 10.;
      int    alphasOrder   = 2;
      double alphasValue   = 0.118;
      double ggSingletFrac = 2. / 7.;
      double qqSingletFrac = 0.;

      // Histograms.
      Hist   mHatLow[5], mHatLowZoom[5], mThrOrig[5], mThrOrigZoom[5];
      for (int scenario = 0; scenario < 5; ++scenario) {
        mHatLow[scenario].book("ttbar invariant mass, low", 100, 300., 400.);
        mHatLowZoom[scenario].book("ttbar invariant mass, low", 100, 330., 355.);
        mThrOrig[scenario].book("original threshold", 100, -20., 80.);
        mThrOrigZoom[scenario].book("original threshold, zoom", 100, -10., 30.);
      }

      // Compare the five scenarios.
      for (int scenario = 0; scenario < 5; ++scenario) {

        // Scenario-specific settings choices.
        int    topModel    = min( scenario, 2);
        double gammat      = (scenario != 3) ? 1.34 : 0.2;
        // Warning:  a small gammatGreen may lead to event weights above unity.
        double gammatGreen = (scenario != 4) ? 1.34 : 0.2;

        // Generator.
        PythiaParallel pythia;

        // Feed in desired values.
        pythia.settings.mode("TopThreshold:model", topModel);
        pythia.particleData.m0(6, mt);
        pythia.readString("6:doForceWidth = true");
        pythia.particleData.mWidth( 6, gammat);
        pythia.settings.parm("TopThreshold:tWidthGreen",   gammatGreen);
        pythia.settings.parm("TopThreshold:thrRegion",     thrRegion);
        pythia.settings.mode("TopThreshold:alphasOrder",   alphasOrder);
        pythia.settings.parm("TopThreshold:alphasValue",   alphasValue);
        pythia.settings.parm("TopThreshold:ggSingletFrac", ggSingletFrac);
        pythia.settings.parm("TopThreshold:qqSingletFrac", qqSingletFrac);

        // Process selection and collision energy.
        pythia.readString("Top:gg2ttbar = on");
        pythia.readString("Top:qqbar2ttbar = on");
        pythia.settings.parm("Beams:eCM", eCM);

        // Restrict to threshold region.
        if (thresholdOnly) {
          pythia.readString("PhaseSpace:mHatMin = 300.");
          pythia.readString("PhaseSpace:mHatMax = 400.");
        }
        else pythia.readString("PhaseSpace:mHatMin = 200.");

        // Switch off (most) code parts not relevant here. Reduce printout.
        if (!fullEvents) {
          pythia.readString("PartonLevel:ISR = off");
          pythia.readString("PartonLevel:FSR = off");
          pythia.readString("PartonLevel:MPI = off");
          pythia.readString("HadronLevel:all = off");
        }
        pythia.readString("Next:numberCount = 100000");

        // If Pythia fails to initialize, abort this scenario.
        cout << " =============================================================="
          "=========\n Initializing PYTHIA for scenario " << scenario
             << " with topModel " << topModel << " and top mass " << mt
             << " GeV" << endl;
        bool ok = pythia.init();
        cout << " Completed initialization of PYTHIA for scenario " << scenario
             << "\n ============================================================"
          "===========\n";
        if (!ok) continue;

        // Counters. Real numbers since some events can come with weights > 1.
        double nEventEff = 0., nBelow2mt = 0., nBelow = 0., nBelowgg = 0.,
          nBelowqq = 0., nAbovegg = 0., nAboveqq = 0., eBelow = 0.;

        // Run events in parallel.
        pythia.run(nEvent, [&](Pythia* pythiaPtr) {

          // Original threshold value and other properties. Event weight.
          double eThr = pythiaPtr->info.toponiumE;
          double mHat = pythiaPtr->info.mHat();
          double wt   = pythiaPtr->info.weight();

          // Histogram threshold value and ttbar invariant mass.
          mHatLow[scenario].fill( mHat, wt);
          mHatLowZoom[scenario].fill( mHat, wt);
          mThrOrig[scenario].fill( eThr, wt);
          mThrOrigZoom[scenario].fill( eThr, wt);

          // Statistics for below- and above-threshold cross sections.
          nEventEff += wt;
          if (mHat < 2. * mt) nBelow2mt += wt;
          if (eThr < 0.) {
            nBelow += wt;
            if (pythiaPtr->info.code() == 601) nBelowgg += wt;
            else nBelowqq += wt;
            eBelow += eThr * wt;
          } else {
            if (pythiaPtr->info.code() == 601) nAbovegg += wt;
            else nAboveqq += wt;
          }

        // End of event loop.
        });

        // Normalization and statistics for this scenario.
        cout << "\n ===== End-of-run statistics for scenario " << scenario
             << " with topModel " << topModel << " and top mass " << mt
             << " GeV =====" << endl;

        // Normalize histogram to cross section, in pb/GeV.
        double sigmaGen         = 1e9 * pythia.sigmaGen();
        double sigmapb          = sigmaGen / nEventEff;
        mHatLow[scenario]      *= sigmapb;
        mHatLowZoom[scenario]  *= 4. * sigmapb;
        mThrOrig[scenario]     *= sigmapb;
        mThrOrigZoom[scenario] *= 2.5 * sigmapb;

        // Statistics and cross sections.
        pythia.stat();
        double sigma2mt = sigmapb * nBelow2mt;
        double sigAbv   = sigmapb * (nEventEff - nBelow);
        double sigAbvgg = sigmapb * nAbovegg;
        double sigAbvqq = sigmapb * nAboveqq;
        double sigBel   = sigmapb * nBelow;
        double sigBelgg = sigmapb * nBelowgg;
        double sigBelqq = sigmapb * nBelowqq;
        cout << "\n total sigma in studied region = " << fixed << setprecision(3)
             << sigmaGen << " pb whereof below 2 mt = " << sigma2mt << " pb"
             << endl << " sigma above threshold = "  << sigAbv << " pb" << endl
             << "   whereof gg = " << sigAbvgg << " pb and qq = " << sigAbvqq
             << " pb" << endl << " sigma below threshold = " << sigBel
             << " pb" << endl << "   whereof gg = " << sigBelgg << " pb and qq = "
             << sigBelqq << " pb" << endl;
        eBelow /= max(1., nBelow);
        cout << " average energy for below-threshold part = " << eBelow
             << " GeV" << endl;

      // End loop over threshold cases.
      }

      // Histograms with pyplot. Common notation.
      HistPlot hpl("plot370");
      string symbol[5] = {"h,black", "h,olive", "h,red", "h,orange", "h,blue"};
      string legend[5] = {"Born", "Coulomb", "Green's, wide BW and ME",
          "Green's, narrow BW", "Green's, narrow ME"};

      // Invariant mass of the ttbar pair.
      hpl.frame("fig370", "invariant mass of ttbar pair, near threshold",
        "$m(t+tbar) (GeV)$", "$\\mathrm{d}\\sigma/\\mathrm{d}m$ (pb/GeV)");
      for (int scenario = 0; scenario < 5; ++scenario)
        hpl.add( mHatLow[scenario], symbol[scenario], legend[scenario]);
      hpl.plot();
      hpl.frame("", "invariant mass of ttbar pair, near threshold, zoom-in",
        "$m(t+tbar) (GeV)$", "$\\mathrm{d}\\sigma/\\mathrm{d}m$ (pb/GeV)");
      for (int scenario = 0; scenario < 5; ++scenario)
        hpl.add( mHatLowZoom[scenario], symbol[scenario], legend[scenario]);
      hpl.plot();

      // The formal E_thr value above/below threshold, key for reweighting.
      hpl.frame("", "Energy above or below threshold",
        "$E$ (GeV)", "$\\mathrm{d}\\sigma/\\mathrm{d}m$ (pb/GeV)");
      for (int scenario = 0; scenario < 5; ++scenario)
        hpl.add( mThrOrig[scenario], symbol[scenario], legend[scenario]);
      hpl.plot();
      hpl.frame("", "Energy above or below threshold, zoom-in",
        "$E$ (GeV)", "$\\mathrm{d}\\sigma/\\mathrm{d}m$ (pb/GeV)");
      for (int scenario = 0; scenario < 5; ++scenario)
        hpl.add( mThrOrigZoom[scenario], symbol[scenario], legend[scenario]);
      hpl.plot();

      // Done.
      return 0;
    }