Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 09:08:38

0001 // HepMC2.h is a part of the PYTHIA event generator.
0002 // Copyright (C) 2025 Torbjorn Sjostrand.
0003 // PYTHIA is licenced under the GNU GPL v2 or later, see COPYING for details.
0004 // Please respect the MCnet Guidelines, see GUIDELINES for details.
0005 
0006 // Author: Mikhail Kirsanov, Mikhail.Kirsanov@cern.ch
0007 // Exception classes provided by James Monk, with minor changes.
0008 // Header file and function definitions for the Pythia8ToHepMC class,
0009 // which converts a PYTHIA event record to the standard HepMC format.
0010 //
0011 // Common wrapper for HepMC2/3 added by Leif Lönnblad.
0012 
0013 #ifndef Pythia8_HepMC2_H
0014 #define Pythia8_HepMC2_H
0015 
0016 #ifdef Pythia8_HepMC3_H
0017 #error Cannot include HepMC2.h if HepMC3.h has already been included.
0018 #endif
0019 
0020 #include <exception>
0021 #include <sstream>
0022 #include <vector>
0023 #include "HepMC/IO_BaseClass.h"
0024 #include "HepMC/IO_GenEvent.h"
0025 #include "HepMC/GenEvent.h"
0026 #include "HepMC/Units.h"
0027 #include "Pythia8/Pythia.h"
0028 #include "Pythia8/HIInfo.h"
0029 
0030 namespace HepMC {
0031 
0032 //==========================================================================
0033 
0034 // Base exception for all exceptions that Pythia8ToHepMC might throw.
0035 
0036 class Pythia8ToHepMCException : public std::exception {
0037 
0038 public:
0039   virtual const char* what() const throw() { return "Pythia8ToHepMCException";}
0040 
0041 };
0042 
0043 //--------------------------------------------------------------------------
0044 
0045 // Exception thrown when an undecayed parton is written into the record.
0046 
0047 class PartonEndVertexException : public Pythia8ToHepMCException {
0048 
0049 public:
0050 
0051   // Constructor and destructor.
0052   PartonEndVertexException(int i, int pdg_idIn) : Pythia8ToHepMCException() {
0053     iSave  = i;
0054     idSave = pdg_idIn;
0055     std::stringstream ss;
0056     ss << "Bad end vertex at " << i << " for flavour " << pdg_idIn;
0057     msg = ss.str();
0058   }
0059   virtual ~PartonEndVertexException() throw() {}
0060 
0061   // Throw exception.
0062   virtual const char* what() const throw() {return msg.c_str();}
0063 
0064   // Return info on location and flavour of bad parton.
0065   int index() const {return iSave;}
0066   int pdg_id() const {return idSave;}
0067 
0068 protected:
0069 
0070   std::string msg;
0071   int iSave, idSave;
0072 };
0073 
0074 //==========================================================================
0075 
0076 // The Pythia8ToHepMC class.
0077 
0078 class Pythia8ToHepMC : public IO_BaseClass {
0079 
0080 public:
0081 
0082   // Constructor and destructor.
0083   Pythia8ToHepMC() : m_internal_event_number(0), m_print_inconsistency(true),
0084     m_free_parton_exception(true), m_convert_gluon_to_0(false),
0085     m_store_pdf(true), m_store_proc(true), m_store_xsec(true),
0086     m_store_weights(true) {;}
0087   virtual ~Pythia8ToHepMC() {;}
0088 
0089   // The recommended method to convert Pythia events into HepMC ones.
0090   bool fill_next_event( Pythia8::Pythia& pythia, GenEvent& evt,
0091     int ievnum = -1, bool append = false, GenParticle* rootParticle = 0,
0092     int iBarcode = -1 ) {return fill_next_event( pythia.event, &evt, ievnum,
0093     &pythia.info, &pythia.settings, append, rootParticle, iBarcode);}
0094   bool fill_next_event( Pythia8::Pythia& pythia, GenEvent* evt,
0095     int ievnum = -1, bool append = false, GenParticle* rootParticle = 0,
0096     int iBarcode = -1 ) {return fill_next_event( pythia.event, evt, ievnum,
0097     &pythia.info, &pythia.settings, append, rootParticle, iBarcode);}
0098 
0099   // Alternative method to convert Pythia events into HepMC ones.
0100   bool fill_next_event( Pythia8::Event& pyev, GenEvent& evt,
0101     int ievnum = -1, const Pythia8::Info* pyinfo = 0,
0102     Pythia8::Settings* pyset = 0, bool append = false,
0103     GenParticle* rootParticle = 0, int iBarcode = -1) {
0104     return fill_next_event(pyev, &evt, ievnum, pyinfo, pyset,
0105     append, rootParticle, iBarcode); }
0106 
0107   bool fill_next_event( Pythia8::Event& pyev, GenEvent* evt,
0108     int ievnum = -1, const Pythia8::Info* pyinfo = 0,
0109     Pythia8::Settings* pyset = 0, bool append = false,
0110     GenParticle* rootParticle = 0, int iBarcode = -1);
0111 
0112   // Read out values for some switches.
0113   bool print_inconsistency()   const {return m_print_inconsistency;}
0114   bool free_parton_exception() const {return m_free_parton_exception;}
0115   bool free_parton_warnings()  const {return m_free_parton_exception;}
0116   bool convert_gluon_to_0()    const {return m_convert_gluon_to_0;}
0117   bool store_pdf()             const {return m_store_pdf;}
0118   bool store_proc()            const {return m_store_proc;}
0119   bool store_xsec()            const {return m_store_xsec;}
0120   bool store_weights()         const {return m_store_weights;}
0121 
0122   // Set values for some switches.
0123   void set_print_inconsistency(bool b = true)   {m_print_inconsistency = b;}
0124   void set_free_parton_exception(bool b = true) {m_free_parton_exception = b;}
0125   void set_free_parton_warnings(bool b = true)  {m_free_parton_exception = b;}
0126   void set_convert_gluon_to_0(bool b = false)   {m_convert_gluon_to_0 = b;}
0127   void set_store_pdf(bool b = true)             {m_store_pdf = b;}
0128   void set_store_proc(bool b = true)            {m_store_proc = b;}
0129   void set_store_xsec(bool b = true)            {m_store_xsec = b;}
0130   void set_store_weights(bool b = true)         {m_store_weights = b;}
0131 
0132 private:
0133 
0134   // Try to send warning message to the logger if present, otherwise
0135   // send it to cout if print_inconsistency().
0136   bool warning(const Pythia8::Info* pyinfo, std::string loc,
0137     std::string message, std::string extraInfo = "") {
0138     if (pyinfo != nullptr)
0139       pyinfo->loggerPtr->warningMsg(loc, message, extraInfo);
0140     else if ( print_inconsistency() )
0141       std::cout << "Warning in " << loc << ": " << message << extraInfo
0142                 << std::endl;
0143     return false;
0144   }
0145 
0146   // Following methods are not implemented for this class.
0147   virtual bool fill_next_event( GenEvent*  ) { return 0; }
0148   virtual void write_event( const GenEvent* ) {;}
0149 
0150   // Use of copy constructor is not allowed.
0151   Pythia8ToHepMC( const Pythia8ToHepMC& ) : IO_BaseClass() {;}
0152 
0153   // Data members.
0154   int  m_internal_event_number;
0155   bool m_print_inconsistency, m_free_parton_exception, m_convert_gluon_to_0,
0156   m_store_pdf, m_store_proc, m_store_xsec, m_store_weights;
0157 
0158 };
0159 
0160 //==========================================================================
0161 
0162 // Main method for conversion from PYTHIA event to HepMC event.
0163 // Read one event from Pythia8 and fill a new GenEvent, alternatively
0164 // append to an existing GenEvent, and return T/F = success/failure.
0165 
0166 inline bool Pythia8ToHepMC::fill_next_event(Pythia8::Event& pyev,
0167   GenEvent* evt, int ievnum, const Pythia8::Info* pyinfo,
0168   Pythia8::Settings* pyset, bool append, GenParticle* rootParticle,
0169   int iBarcode) {
0170 
0171   // 1. Error if no event passed.
0172   if (evt == nullptr) return warning(pyinfo,
0173     "Pythia8ToHepMC::fill_next_event", "passed null event");
0174 
0175   // Update event number counter.
0176   if (!append) {
0177     if (ievnum >= 0) {
0178       evt->set_event_number(ievnum);
0179       m_internal_event_number = ievnum;
0180     } else {
0181       evt->set_event_number(m_internal_event_number);
0182       ++m_internal_event_number;
0183     }
0184   }
0185 
0186   // Conversion factors from Pythia units GeV and mm to HepMC ones.
0187   double momFac = HepMC::Units::conversion_factor(HepMC::Units::GEV,
0188     evt->momentum_unit());
0189   double lenFac = HepMC::Units::conversion_factor(HepMC::Units::MM,
0190     evt->length_unit());
0191 
0192   // Set up for alternative to append to an existing event.
0193   int iStart     = 1;
0194   int newBarcode = 0;
0195   if (append) {
0196     if (rootParticle == nullptr) return warning(pyinfo,
0197       "Pythia8ToHepMC::fill_next_event",
0198       "passed null root particle in append mode");
0199     iStart     = 2;
0200     newBarcode = (iBarcode > -1) ? iBarcode : evt->particles_size();
0201     // New vertex associated with appended particles.
0202     GenVertex* prod_vtx0 = new GenVertex();
0203     prod_vtx0->add_particle_in( rootParticle );
0204     evt->add_vertex( prod_vtx0 );
0205   }
0206 
0207   // 1a. If there is a HIInfo object fill info from that.
0208   if ( pyinfo && pyinfo->hiInfo ) {
0209     HepMC::HeavyIon ion;
0210     ion.set_Ncoll_hard(pyinfo->hiInfo->nCollND());
0211     ion.set_Ncoll(pyinfo->hiInfo->nCollTot());
0212     ion.set_Npart_proj(pyinfo->hiInfo->nAbsProj() +
0213                        pyinfo->hiInfo->nDiffProj());
0214     ion.set_Npart_targ(pyinfo->hiInfo->nAbsTarg() +
0215                        pyinfo->hiInfo->nDiffTarg());
0216     ion.set_impact_parameter(pyinfo->hiInfo->b());
0217     evt->set_heavy_ion(ion);
0218   }
0219 
0220   // 2. Create a particle instance for each entry and fill a map, and
0221   // a vector which maps from the particle index to the GenParticle address.
0222   std::vector<GenParticle*> hepevt_particles( pyev.size() );
0223   for (int i = iStart; i < pyev.size(); ++i) {
0224 
0225     // Fill the particle.
0226     hepevt_particles[i] = new GenParticle(
0227       FourVector( momFac * pyev[i].px(), momFac * pyev[i].py(),
0228                   momFac * pyev[i].pz(), momFac * pyev[i].e()  ),
0229       pyev[i].id(), pyev[i].statusHepMC() );
0230     if (iBarcode != 0) ++newBarcode;
0231     hepevt_particles[i]->suggest_barcode( (append) ? newBarcode : i );
0232     hepevt_particles[i]->set_generated_mass( momFac * pyev[i].m() );
0233 
0234     // Colour flow uses index 1 and 2.
0235     int colType = pyev[i].colType();
0236     if (colType ==  1 || colType == 2)
0237       hepevt_particles[i]->set_flow(1, pyev[i].col());
0238     if (colType == -1 || colType == 2)
0239       hepevt_particles[i]->set_flow(2, pyev[i].acol());
0240   }
0241 
0242   // Here we assume that the first two particles in the list
0243   // are the incoming beam particles.
0244   if (!append)
0245     evt->set_beam_particles( hepevt_particles[1], hepevt_particles[2] );
0246 
0247   // 3. Loop over particles AGAIN, this time creating vertices.
0248   // We build the production vertex for each entry in hepevt.
0249   // The HEPEVT pointers are bi-directional, so gives decay vertices as well.
0250   for (int i = iStart; i < pyev.size(); ++i) {
0251     GenParticle* p = hepevt_particles[i];
0252 
0253     // 3a. Search to see if a production vertex already exists.
0254     std::vector<int> mothers = pyev[i].motherList();
0255     unsigned int imother = 0;
0256     int mother = -1; // note that in Pythia8 there is a particle number 0!
0257     if ( !mothers.empty() ) mother = mothers[imother];
0258     GenVertex* prod_vtx = p->production_vertex();
0259     while ( !prod_vtx && mother > 0 ) {
0260       prod_vtx = (append && mother == 1) ? rootParticle->end_vertex()
0261                : hepevt_particles[mother]->end_vertex();
0262       if (prod_vtx) prod_vtx->add_particle_out( p );
0263       mother = ( ++imother < mothers.size() ) ? mothers[imother] : -1;
0264     }
0265 
0266     // 3b. If no suitable production vertex exists - and the particle has
0267     // at least one mother or position information to store - make one.
0268     FourVector prod_pos( lenFac * pyev[i].xProd(), lenFac * pyev[i].yProd(),
0269                          lenFac * pyev[i].zProd(), lenFac * pyev[i].tProd() );
0270     if ( !prod_vtx && ( mothers.size() > 0 || prod_pos != FourVector() ) ) {
0271       prod_vtx = new GenVertex();
0272       prod_vtx->add_particle_out( p );
0273       evt->add_vertex( prod_vtx );
0274     }
0275 
0276     // 3c. If prod_vtx doesn't already have position specified, fill it.
0277     if ( prod_vtx && prod_vtx->position() == FourVector() )
0278       prod_vtx->set_position( prod_pos );
0279 
0280     // 3d. loop over mothers to make sure their end_vertices are consistent.
0281     imother = 0;
0282     mother = -1;
0283     if ( !mothers.empty() ) mother = mothers[imother];
0284     while ( prod_vtx && mother > 0 ) {
0285 
0286       // If end vertex of the mother isn't specified, do it now.
0287       GenParticle* ppp = (append && mother == 1) ? rootParticle
0288                        : hepevt_particles[mother];
0289       if ( !ppp->end_vertex() ) {
0290         prod_vtx->add_particle_in( ppp );
0291       } else if (ppp->end_vertex() != prod_vtx ) {
0292         // Problem scenario: the mother already has a decay vertex which
0293         // differs from the daughter's production vertex.
0294         // Can happen with Vincia showers since antenna emissions have two
0295         // parents. In that case, let vertex structure be defined by first
0296         // parent, ignoring second parent.
0297         if ( (pyev[i].statusAbs() == 43 || pyev[i].statusAbs() == 51
0298             || pyev[i].statusAbs() == 53) && mother >= 1) break;
0299         // Otherwise this means there is internal inconsistency in the
0300         // HEPEVT event record. Print an error.
0301         // Note: we could provide a fix by joining the two vertices with a
0302         // dummy particle if the problem arises often.
0303         warning(pyinfo, "Pythia8ToHepMC::fill_next_event",
0304                 "inconsistent mother/daugher information in Pythia8 event",
0305                 "i = " + Pythia8::toString(i) + " mother = " +
0306                 Pythia8::toString(mother));
0307       }
0308 
0309       // End of vertex-setting loops.
0310       mother = ( ++imother < mothers.size() ) ? mothers[imother] : -1;
0311     }
0312   }
0313 
0314   // If hadronization switched on then no final coloured particles.
0315   bool doHadr = (pyset == 0) ? m_free_parton_exception
0316     : pyset->flag("HadronLevel:all") && pyset->flag("HadronLevel:Hadronize");
0317 
0318   // 4. Check for particles which come from nowhere, i.e. are without
0319   // mothers or daughters. These need to be attached to a vertex, or else
0320   // they will never become part of the event.
0321   for (int i = iStart; i < pyev.size(); ++i) {
0322     if ( hepevt_particles[i]->end_vertex() == nullptr &&
0323          hepevt_particles[i]->production_vertex() == nullptr ) {
0324       warning(pyinfo, "Pythia8ToHepMC::fill_next_event"
0325               "found orphan particle", "i = " + Pythia8::toString(i));
0326       GenVertex* prod_vtx = new GenVertex();
0327       prod_vtx->add_particle_out( hepevt_particles[i] );
0328       evt->add_vertex( prod_vtx );
0329     }
0330 
0331     // Also check for free partons (= gluons and quarks; not diquarks?).
0332     if ( doHadr && m_free_parton_exception ) {
0333       int pdg_tmp = hepevt_particles[i]->pdg_id();
0334       if ( (abs(pdg_tmp) <= 6 || pdg_tmp == 21)
0335         && !hepevt_particles[i]->end_vertex() )
0336         throw PartonEndVertexException(i, pdg_tmp);
0337     }
0338   }
0339 
0340   // Done if only appending to already existing event.
0341   if (append) return true;
0342 
0343   // 5. Store PDF, weight, cross section and other event information.
0344   // Flavours of incoming partons.
0345   if (m_store_pdf && pyinfo != 0) {
0346     int id1pdf = pyinfo->id1pdf();
0347     int id2pdf = pyinfo->id2pdf();
0348     if ( m_convert_gluon_to_0 ) {
0349       if (id1pdf == 21) id1pdf = 0;
0350       if (id2pdf == 21) id2pdf = 0;
0351     }
0352 
0353     // Store PDF information.
0354     evt->set_pdf_info( PdfInfo( id1pdf, id2pdf, pyinfo->x1pdf(),
0355       pyinfo->x2pdf(), pyinfo->QFac(), pyinfo->pdf1(), pyinfo->pdf2() ) );
0356   }
0357 
0358   // Store process code, scale, alpha_em, alpha_s.
0359   if (m_store_proc && pyinfo != 0) {
0360     evt->set_signal_process_id( pyinfo->code() );
0361     evt->set_mpi( pyinfo->nMPI() );
0362     evt->set_event_scale( pyinfo->QRen() );
0363     if (evt->alphaQED() <= 0) evt->set_alphaQED( pyinfo->alphaEM() );
0364     if (evt->alphaQCD() <= 0) evt->set_alphaQCD( pyinfo->alphaS() );
0365   }
0366 
0367   // Store cross-section information in pb and event weight. The latter is
0368   // usually dimensionless, but in units of pb for Les Houches strategies +-4.
0369   if (m_store_xsec && pyinfo != 0) {
0370     HepMC::GenCrossSection xsec;
0371     xsec.set_cross_section( pyinfo->sigmaGen() * 1e9,
0372       pyinfo->sigmaErr() * 1e9);
0373     evt->set_cross_section(xsec);
0374     // If multiweights with possibly different xsec, overwrite central value
0375     std::vector<double> xsecVec = pyinfo->weightContainerPtr->getTotalXsec();
0376     if (xsecVec.size() > 0) {
0377       xsec.set_cross_section(xsecVec[0]*1e9);
0378       evt->set_cross_section(xsec);
0379     }
0380   }
0381 
0382   if (m_store_weights && pyinfo != 0) {
0383     for (int iweight = 0; iweight < pyinfo->numberOfWeights();
0384       ++iweight) {
0385       std::string name  = pyinfo->weightNameByIndex(iweight);
0386       double value      = pyinfo->weightValueByIndex(iweight);
0387       evt->weights()[name] = value;
0388     }
0389   }
0390 
0391   // Done for new event.
0392   return true;
0393 
0394 }
0395 
0396 //==========================================================================
0397 
0398 } // end namespace HepMC
0399 
0400 namespace Pythia8 {
0401 
0402 //==========================================================================
0403 // This a wrapper around HepMC::Pythia8ToHepMC in the Pythia8
0404 // namespace that simplify the most common use cases. It stores the
0405 // current GenEvent and output stream internally to avoid cluttering
0406 // of user code. This class is also defined in HepMC3.h with the same
0407 // signatures, and the user can therefore switch between HepMC version
0408 // 2 and 3, by simply changing the include file.
0409 class Pythia8ToHepMC : public HepMC::Pythia8ToHepMC {
0410 
0411 public:
0412 
0413   // We can either have standard ascii output or none at all.
0414   enum OutputType { none, ascii2 };
0415 
0416   // Typedef for the version 2 specific classes used.
0417   typedef HepMC::GenEvent GenEvent;
0418   typedef shared_ptr<GenEvent> EventPtr;
0419   typedef HepMC::IO_GenEvent Writer;
0420   typedef shared_ptr<Writer> WriterPtr;
0421 
0422   // The empty constructor does not creat an aoutput stream.
0423   Pythia8ToHepMC() {}
0424 
0425   // Construct an object with an internal output stream.
0426   Pythia8ToHepMC(string filename, OutputType ft = ascii2) {
0427     setNewFile(filename, ft);
0428   }
0429 
0430   // Open a new external output stream.
0431   bool setNewFile(string filename, OutputType ft = ascii2) {
0432     switch ( ft ) {
0433     case ascii2:
0434       writerPtr = make_shared<HepMC::IO_GenEvent>(filename);
0435       break;
0436     case none:
0437       writerPtr = nullptr;
0438       break;
0439     }
0440     return writerPtr != nullptr;
0441   }
0442 
0443   // Create a new GenEvent object and fill it with information from
0444   // the given Pythia object.
0445   bool fillNextEvent(Pythia & pythia) {
0446     geneve = make_shared<GenEvent>();
0447     return fill_next_event(pythia, *geneve);
0448   }
0449 
0450   // Write out the current GenEvent to the internal stream.
0451   void writeEvent() {
0452     writerPtr->write_event(&*geneve);
0453   }
0454 
0455   // Create a new GenEvent object and fill it with information from
0456   // the given Pythia object and write it out directly to the
0457   // internal stream.
0458   bool writeNextEvent(Pythia & pythia) {
0459     if ( !fillNextEvent(pythia) ) return false;
0460     writeEvent();
0461     return true;
0462   }
0463 
0464   // Get a reference to the current GenEvent.
0465   GenEvent & event() {
0466     return *geneve;
0467   }
0468 
0469   // Get a pointer to the current GenEvent.
0470   EventPtr getEventPtr() {
0471     return geneve;
0472   }
0473 
0474   // Get a reference to the internal stream.
0475   Writer & output() {
0476     return *writerPtr;
0477   }
0478 
0479   // Get a pointer to the internal stream.
0480   WriterPtr outputPtr() {
0481     return writerPtr;
0482   }
0483 
0484   // Set cross section information in the current GenEvent.
0485   void setXSec(double xsec, double xsecerr) {
0486     HepMC::GenCrossSection xs;
0487     xs.set_cross_section(xsec, xsecerr);
0488     geneve->set_cross_section(xs);
0489   }
0490 
0491   // Update all weights in the current GenEvent.
0492   void setWeights(const vector<double> & wv) {
0493     if ( wv.size() != weightNames.size() )
0494       geneve->weights() = wv;
0495     else
0496       for ( int i= 0, N = wv.size(); i < N; ++i )
0497         geneve->weights()[weightNames[i]] = wv[i];
0498   }
0499 
0500   // Set all weight names in the current run.
0501   void setWeightNames(const vector<string> &wnv) {
0502     weightNames = wnv;
0503   }
0504 
0505   // Update the PDF information in the current GenEvent
0506   void setPdfInfo(int id1, int id2, double x1, double x2,
0507                   double scale, double xf1, double xf2,
0508                   int pdf1 = 0, int pdf2 = 0) {
0509     HepMC::PdfInfo pdf(id1, id2, x1, x2, scale, xf1, xf2, pdf1, pdf2);
0510     geneve->set_pdf_info(pdf);
0511   }
0512 
0513 private:
0514 
0515   // The current GenEvent.
0516   EventPtr geneve = nullptr;
0517 
0518   // The output stream.
0519   WriterPtr writerPtr = nullptr;
0520 
0521   // The weight names in the current run.
0522   vector<string> weightNames;
0523 
0524 };
0525 
0526 }
0527 
0528 #endif  // end Pythia8_HepMC2_H