## main324

Back to index.

    // main324.cc is a part of the PYTHIA event generator.
    // Copyright (C) 2025 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:
    //            Beam gas
    //            Fixed target
    //            Pileup
    //            Multi‑instance

    // This program runs four instances of Pythia simultaneously,
    // one for signal events, one for pileup background ones, and two
    // For beam-gas background ones. Note that beam-gas is represented by
    // "fixed-target" pp collisions, rather than a full Angantyr setup.
    // The = and += overloaded operators are used to join several
    // event records into one, but should be used with caution.

    // The possibility to instantiate Pythia with Settings and ParticleData
    // databases is illustrated, but not essential here. It means that the
    // share/Pythia8/xmldoc/*.xml files are only read once, saving some time.

    // Note that each instance of Pythia is running independently of any other,
    // but with two important points to remember.
    // 1) By default all generate the same random number sequence,
    //    which has to be corrected if they are to generate the same
    //    physics, like the two beam-gas ones below.
    // 2) Interfaces to external Fortran programs are "by definition" static.
    //    Thus it is not a good idea to use LHAPDF5 to set different PDF's
    //    in different instances.

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

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

    // Method to pick a number according to a Poissonian distribution.

    int poisson(double nAvg, Rndm& rndm) {

      // Set maximum to avoid overflow.
      const int NMAX = 100;

      // Random number.
      double rPoisson = rndm.flat() * exp(nAvg);

      // Initialize.
      double rSum  = 0.;
      double rTerm = 1.;

      // Add to sum and check whether done.
      for (int i = 0; i < NMAX; ) {
        rSum += rTerm;
        if (rSum > rPoisson) return i;

        // Evaluate next term.
        ++i;
        rTerm *= nAvg / i;
      }

      // Emergency return.
      return NMAX;
    }

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

    int main() {

      // Number of signal events to generate.
      int nEvent = 100;

      // Beam Energy.
      double eBeam = 7000.;

      // Average number of pileup events per signal event.
      double nPileupAvg = 2.5;

      // Average number of beam-gas events per signal ones, on two sides.
      double nBeamAGasAvg = 0.5;
      double nBeamBGasAvg = 0.5;

      // Signal generator instance.
      Pythia pythiaSignal;

      // Switch off automatic event listing (illustrates settings inheritance).
      pythiaSignal.readString("Next:numberShowInfo = 0");
      pythiaSignal.readString("Next:numberShowProcess = 0");
      pythiaSignal.readString("Next:numberShowEvent = 0");

      // Switch off K0S decay (illustrates particle data inheritance).
      pythiaSignal.readString("130:mayDecay = off");

      // Background generator instances copies settings and particle data.
      Pythia pythiaPileup(   pythiaSignal.settings, pythiaSignal.particleData);
      Pythia pythiaBeamAGas( pythiaSignal.settings, pythiaSignal.particleData);
      Pythia pythiaBeamBGas( pythiaSignal.settings, pythiaSignal.particleData);

      // Switch off Lambda decay (illustrates particle data non-inheritance).
      pythiaSignal.readString("3122:mayDecay = off");

      // One object where all individual events are to be collected.
      Event sumEvent;

      // Initialize generator for signal processes.
      pythiaSignal.readString("HardQCD:all = on");
      pythiaSignal.readString("PhaseSpace:pTHatMin = 50.");
      pythiaSignal.settings.parm("Beams:eCM", 2. * eBeam);

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

      // Initialize generator for pileup (background) processes.
      pythiaPileup.readString("Random:setSeed = on");
      pythiaPileup.readString("Random:seed = 10000002");
      pythiaPileup.readString("SoftQCD:all = on");
      pythiaPileup.settings.parm("Beams:eCM", 2. * eBeam);

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

      // Initialize generators for beam A - gas (background) processes.
      pythiaBeamAGas.readString("Random:setSeed = on");
      pythiaBeamAGas.readString("Random:seed = 10000003");
      pythiaBeamAGas.readString("SoftQCD:all = on");
      pythiaBeamAGas.readString("Beams:frameType = 2");
      pythiaBeamAGas.settings.parm("Beams:eA", eBeam);
      pythiaBeamAGas.settings.parm("Beams:eB", 0.);

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

      // Initialize generators for beam B - gas (background) processes.
      pythiaBeamBGas.readString("Random:setSeed = on");
      pythiaBeamBGas.readString("Random:seed = 10000004");
      pythiaBeamBGas.readString("SoftQCD:all = on");
      pythiaBeamBGas.readString("Beams:frameType = 2");
      pythiaBeamBGas.settings.parm("Beams:eA", 0.);
      pythiaBeamBGas.settings.parm("Beams:eB", eBeam);

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

      // Histograms: number of pileups, total charged multiplicity.
      Hist nPileH("number of pileup events per signal event", 100, -0.5, 99.5);
      Hist nAGH("number of beam A + gas events per signal event", 100, -0.5, 99.5);
      Hist nBGH("number of beam B + gas events per signal event", 100, -0.5, 99.5);
      Hist nChgH("number of charged multiplicity",100, -0.5, 1999.5);
      Hist sumPZH("total pZ of system",100, -100000., 100000.);

      // Loop over events.
      for (int iEvent = 0; iEvent < nEvent; ++iEvent) {

        // Generate a signal event. Copy this event into sumEvent.
        if (!pythiaSignal.next()) continue;
        sumEvent = pythiaSignal.event;

        // Select the number of pileup events to generate.
        int nPileup = poisson(nPileupAvg, pythiaPileup.rndm);
        nPileH.fill( nPileup );

        // Generate a number of pileup events. Add them to sumEvent.
        for (int iPileup = 0; iPileup < nPileup; ++iPileup) {
          pythiaPileup.next();
          sumEvent += pythiaPileup.event;
        }

        // Select the number of beam A + gas events to generate.
        int nBeamAGas = poisson(nBeamAGasAvg, pythiaBeamAGas.rndm);
        nAGH.fill( nBeamAGas );

        // Generate a number of beam A + gas events. Add them to sumEvent.
        for (int iAG = 0; iAG < nBeamAGas; ++iAG) {
          pythiaBeamAGas.next();
          sumEvent += pythiaBeamAGas.event;
        }

        // Select the number of beam B + gas events to generate.
        int nBeamBGas = poisson(nBeamBGasAvg, pythiaBeamBGas.rndm);
        nBGH.fill( nBeamBGas );

        // Generate a number of beam B + gas events. Add them to sumEvent.
        for (int iBG = 0; iBG < nBeamBGas; ++iBG) {
          pythiaBeamBGas.next();
          sumEvent += pythiaBeamBGas.event;
        }

        // List first few events.
        if (iEvent < 1) {
          pythiaSignal.info.list();
          pythiaSignal.process.list();
          sumEvent.list();
        }

        // Find charged multiplicity.
        int nChg = 0;
        for (int i = 0; i < sumEvent.size(); ++i)
          if (sumEvent[i].isFinal() && sumEvent[i].isCharged()) ++nChg;
        nChgH.fill( nChg );

        // Fill net pZ - nonvanishing owing to beam + gas.
        sumPZH.fill( sumEvent[0].pz() );

      // End of event loop
      }

      // Statistics. Histograms.
      pythiaSignal.stat();
      pythiaPileup.stat();
      pythiaBeamAGas.stat();
      pythiaBeamBGas.stat();
      cout << nPileH << nAGH << nBGH << nChgH << sumPZH;

      return 0;
    }