Skip to content
Snippets Groups Projects
pythia_dis.cc 9.44 KiB
Newer Older
#include "Pythia8/Pythia.h"
#include "Pythia8Plugins/HepMC3.h"
#include <unistd.h>
#include <cassert>

using namespace Pythia8;

#include "clipp.h"
using namespace clipp;
using std::string;
//______________________________________________________________________________

enum class mode { none, help, list, part };

struct settings {
  double      E_electron   = 10.0;  // GeV
  double      E_ion        = 275.0; // GeV
  std::string outfile      = "dis.hepmc";
  int         ion_PID      = 2212;
  int         electron_PID = 11;
  bool        help         = false;
  bool        success      = false;
  double      Q2_min       = 4.0;
  int         N_events     = 1000;
  mode    selected       = mode::none;
};

template <typename T>
void print_usage(T cli, const char* argv0)
{
  // used default formatting
  std::cout << "Usage:\n" << usage_lines(cli, argv0) << "\nOptions:\n" << documentation(cli) << '\n';
}
//______________________________________________________________________________

template <typename T>
void print_man_page(T cli, const char* argv0)
{
  // all formatting options (with their default values)
  auto fmt = clipp::doc_formatting{}
                 .start_column(8)                    // column where usage lines and documentation starts
                 .doc_column(20)                     // parameter docstring start col
                 .indent_size(4)                     // indent of documentation lines for children of a
                                                     // documented group
                 .line_spacing(0)                    // number of empty lines after single documentation lines
                 .paragraph_spacing(1)               // number of empty lines before and after paragraphs
                 .flag_separator(", ")               // between flags of the same parameter
                 .param_separator(" ")               // between parameters
                 .group_separator(" ")               // between groups (in usage)
                 .alternative_param_separator("|")   // between alternative flags
                 .alternative_group_separator(" | ") // between alternative groups
                 .surround_group("(", ")")           // surround groups with these
                 .surround_alternatives("(", ")")    // surround group of alternatives with these
                 .surround_alternative_flags("", "") // surround alternative flags with these
                 .surround_joinable("(", ")")        // surround group of joinable flags with these
                 .surround_optional("[", "]")        // surround optional parameters with these
                 .surround_repeat("", "...");        // surround repeatable parameters with these

  auto mp = make_man_page(cli, argv0, fmt);
  mp.prepend_section("DESCRIPTION", "Simple pythia dis generator.");
  mp.append_section("EXAMPLES", " $ pythia_dis [output_file]");
  std::cout << mp << "\n";
}
//______________________________________________________________________________

settings cmdline_settings(int argc, char* argv[]) {
  settings s;
  auto     lastOpt =
      " options:" % (option("-h", "--help").set(s.selected, mode::help) % "show help",
                     value("file", s.outfile).if_missing([] {
                       std::cout << "You need to provide an output filename argument!\n";
                     }) % "output file");

  auto cli =
      (command("help").set(s.selected, mode::help) | lastOpt);

  assert(cli.flags_are_prefix_free());

  auto res = parse(argc, argv, cli);

  // if( res.any_error() ) {
  //  s.success = false;
  //  std::cout << make_man_page(cli, argv[0]).prepend_section("error: ",
  //                                                           "    The best
  //                                                           thing since
  //                                                           sliced bread.");
  //  return s;
  //}
  s.success = true;

  if (s.selected == mode::help) {
    print_man_page<decltype(cli)>(cli, argv[0]);
  };
  return s;
}
//______________________________________________________________________________

int main(int argc, char* argv[]) {

  settings s = cmdline_settings(argc, argv);
  if (!s.success) {
    return 1;
  }

  if (s.selected == mode::help) {
    return 0;
  }

  // Beam energies, minimal Q2, number of events to generate.
  double eProton   = s.E_ion;
  double eElectron = s.E_electron;
  double Q2min     = s.Q2_min;
  int    nEvent    = s.N_events;

  // Generator. Shorthand for event.
  Pythia pythia;
  Event& event = pythia.event;

  // Set up incoming beams, for frame with unequal beam energies.
  pythia.readString("Beams:frameType = 2");
  // BeamA = proton.
  pythia.readString("Beams:idA = " + std::to_string(s.ion_PID));
  pythia.settings.parm("Beams:eA", eProton);
  // BeamB = electron.
  pythia.readString("Beams:idB = 11");
  pythia.settings.parm("Beams:eB", eElectron);

  // Set up DIS process within some phase space.
  // Neutral current (with gamma/Z interference).
  pythia.readString("WeakBosonExchange:ff2ff(t:gmZ) = on");
  // Uncomment to allow charged current.
  // pythia.readString("WeakBosonExchange:ff2ff(t:W) = on");
  // Phase-space cut: minimal Q2 of process.
  pythia.settings.parm("PhaseSpace:Q2Min", Q2min);

  // Set dipole recoil on. Necessary for DIS + shower.
  pythia.readString("SpaceShower:dipoleRecoil = on");

  // Allow emissions up to the kinematical limit,
  // since rate known to match well to matrix elements everywhere.
  pythia.readString("SpaceShower:pTmaxMatch = 2");

  // QED radiation off lepton not handled yet by the new procedure.
  pythia.readString("PDF:lepton = off");
  pythia.readString("TimeShower:QEDshowerByL = off");

  // Initialize.
  pythia.init();

  // Interface for conversion from Pythia8::Event to HepMC one.
  HepMC3::Pythia8ToHepMC3 toHepMC;
  // Specify file where HepMC events will be stored.
  HepMC3::WriterAscii ascii_io(argv[1]);
  cout << endl << endl << endl;

  // Histograms.
  double Wmax = sqrt(4. * eProton * eElectron);
  Hist   Qhist("Q [GeV]", 100, 0., 50.);
  Hist   Whist("W [GeV]", 100, 0., Wmax);
  Hist   xhist("x", 100, 0., 1.);
  Hist   yhist("y", 100, 0., 1.);
  Hist   pTehist("pT of scattered electron [GeV]", 100, 0., 50.);
  Hist   pTrhist("pT of radiated parton [GeV]", 100, 0., 50.);
  Hist   pTdhist("ratio pT_parton/pT_electron", 100, 0., 5.);

  double sigmaTotal(0.), errorTotal(0.);
  bool   wroteRunInfo = false;
  // Get the inclusive x-section by summing over all process x-sections.
  double xs = 0.;
  for (int i = 0; i < pythia.info.nProcessesLHEF(); ++i) {
    xs += pythia.info.sigmaLHEF(i);
  }

  // Begin event loop.
  for (int iEvent = 0; iEvent < nEvent; ++iEvent) {
    if (!pythia.next())
      continue;

    double sigmaSample = 0., errorSample = 0.;

    // Four-momenta of proton, electron, virtual photon/Z^0/W^+-.
    Vec4 pProton = event[1].p();
    Vec4 peIn    = event[4].p();
    Vec4 peOut   = event[6].p();
    Vec4 pPhoton = peIn - peOut;

    // Q2, W2, Bjorken x, y.
    double Q2 = -pPhoton.m2Calc();
    double W2 = (pProton + pPhoton).m2Calc();
    double x  = Q2 / (2. * pProton * pPhoton);
    double y  = (pProton * pPhoton) / (pProton * peIn);

    // Fill kinematics histograms.
    Qhist.fill(sqrt(Q2));
    Whist.fill(sqrt(W2));
    xhist.fill(x);
    yhist.fill(y);
    pTehist.fill(event[6].pT());

    // pT spectrum of partons being radiated in shower.
    for (int i = 0; i < event.size(); ++i)
      if (event[i].statusAbs() == 43) {
        pTrhist.fill(event[i].pT());
        pTdhist.fill(event[i].pT() / event[6].pT());
      }

    // Get event weight(s).
    double evtweight = pythia.info.weight();

    // Do not print zero-weight events.
    if (evtweight == 0.)
      continue;

    // Create a GenRunInfo object with the necessary weight names and write
    // them to the HepMC3 file only once.
    if (!wroteRunInfo) {
      shared_ptr<HepMC3::GenRunInfo> genRunInfo;
      genRunInfo                  = make_shared<HepMC3::GenRunInfo>();
      vector<string> weight_names = pythia.info.weightNameVector();
      genRunInfo->set_weight_names(weight_names);
      ascii_io.set_run_info(genRunInfo);
      ascii_io.write_run_info();
      wroteRunInfo = true;
    }

    // Construct new empty HepMC event.
    HepMC3::GenEvent hepmcevt;

    // Work with weighted (LHA strategy=-4) events.
    double normhepmc = 1.;
    if (abs(pythia.info.lhaStrategy()) == 4)
      normhepmc = 1. / double(1e9 * nEvent);
    // Work with unweighted events.
    else
      normhepmc = xs / double(1e9 * nEvent);

    // Set event weight
    // hepmcevt.weights().push_back(evtweight*normhepmc);
    // Fill HepMC event
    toHepMC.fill_next_event(pythia, &hepmcevt);
    // Add the weight of the current event to the cross section.
    sigmaTotal += evtweight * normhepmc;
    sigmaSample += evtweight * normhepmc;
    errorTotal += pow2(evtweight * normhepmc);
    errorSample += pow2(evtweight * normhepmc);
    // Report cross section to hepmc
    shared_ptr<HepMC3::GenCrossSection> xsec;
    xsec = make_shared<HepMC3::GenCrossSection>();
    // First add object to event, then set cross section. This order ensures
    // that the lengths of the cross section and the weight vector agree.
    hepmcevt.set_cross_section(xsec);
    xsec->set_cross_section(sigmaTotal * 1e9, pythia.info.sigmaErr() * 1e9);
    // Write the HepMC event to file. Done with it.
    ascii_io.write_event(hepmcevt);

    // End of event loop. Statistics and histograms.
  }
  pythia.stat();
  cout << Qhist << Whist << xhist << yhist << pTehist << pTrhist << pTdhist;

  return 0;
}