Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:06:37

0001 // HepMC2.h is a part of the PYTHIA event generator.
0002 // Copyright (C) 2024 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   // Following methods are not implemented for this class.
0135   virtual bool fill_next_event( GenEvent*  ) { return 0; }
0136   virtual void write_event( const GenEvent* ) {;}
0137 
0138   // Use of copy constructor is not allowed.
0139   Pythia8ToHepMC( const Pythia8ToHepMC& ) : IO_BaseClass() {;}
0140 
0141   // Data members.
0142   int  m_internal_event_number;
0143   bool m_print_inconsistency, m_free_parton_exception, m_convert_gluon_to_0,
0144   m_store_pdf, m_store_proc, m_store_xsec, m_store_weights;
0145 
0146 };
0147 
0148 //==========================================================================
0149 
0150 // Main method for conversion from PYTHIA event to HepMC event.
0151 // Read one event from Pythia8 and fill a new GenEvent, alternatively
0152 // append to an existing GenEvent, and return T/F = success/failure.
0153 
0154 inline bool Pythia8ToHepMC::fill_next_event( Pythia8::Event& pyev,
0155   GenEvent* evt, int ievnum, const Pythia8::Info* pyinfo,
0156   Pythia8::Settings* pyset, bool append, GenParticle* rootParticle,
0157   int iBarcode) {
0158 
0159   // 1. Error if no event passed.
0160   if (!evt) {
0161     std::cout << " Pythia8ToHepMC::fill_next_event error: passed null event."
0162               << std::endl;
0163     return 0;
0164   }
0165 
0166   // Update event number counter.
0167   if (!append) {
0168     if (ievnum >= 0) {
0169       evt->set_event_number(ievnum);
0170       m_internal_event_number = ievnum;
0171     } else {
0172       evt->set_event_number(m_internal_event_number);
0173       ++m_internal_event_number;
0174     }
0175   }
0176 
0177   // Conversion factors from Pythia units GeV and mm to HepMC ones.
0178   double momFac = HepMC::Units::conversion_factor(HepMC::Units::GEV,
0179     evt->momentum_unit());
0180   double lenFac = HepMC::Units::conversion_factor(HepMC::Units::MM,
0181     evt->length_unit());
0182 
0183   // Set up for alternative to append to an existing event.
0184   int iStart     = 1;
0185   int newBarcode = 0;
0186   if (append) {
0187     if (!rootParticle) {
0188       std::cout << " Pythia8ToHepMC::fill_next_event error: passed null "
0189                 << "root particle in append mode." << std::endl;
0190       return 0;
0191     }
0192     iStart     = 2;
0193     newBarcode = (iBarcode > -1) ? iBarcode : evt->particles_size();
0194     // New vertex associated with appended particles.
0195     GenVertex* prod_vtx0 = new GenVertex();
0196     prod_vtx0->add_particle_in( rootParticle );
0197     evt->add_vertex( prod_vtx0 );
0198   }
0199 
0200   // 1a. If there is a HIInfo object fill info from that.
0201   if ( pyinfo && pyinfo->hiInfo ) {
0202     HepMC::HeavyIon ion;
0203     ion.set_Ncoll_hard(pyinfo->hiInfo->nCollNDTot());
0204     ion.set_Ncoll(pyinfo->hiInfo->nAbsProj() +
0205                   pyinfo->hiInfo->nDiffProj() +
0206                   pyinfo->hiInfo->nAbsTarg() +
0207                   pyinfo->hiInfo->nDiffTarg() -
0208                   pyinfo->hiInfo->nCollND() -
0209                   pyinfo->hiInfo->nCollDD());
0210     ion.set_Npart_proj(pyinfo->hiInfo->nAbsProj() +
0211                        pyinfo->hiInfo->nDiffProj());
0212     ion.set_Npart_targ(pyinfo->hiInfo->nAbsTarg() +
0213                        pyinfo->hiInfo->nDiffTarg());
0214     ion.set_impact_parameter(pyinfo->hiInfo->b());
0215     evt->set_heavy_ion(ion);
0216   }
0217 
0218   // 2. Create a particle instance for each entry and fill a map, and
0219   // a vector which maps from the particle index to the GenParticle address.
0220   std::vector<GenParticle*> hepevt_particles( pyev.size() );
0221   for (int i = iStart; i < pyev.size(); ++i) {
0222 
0223     // Fill the particle.
0224     hepevt_particles[i] = new GenParticle(
0225       FourVector( momFac * pyev[i].px(), momFac * pyev[i].py(),
0226                   momFac * pyev[i].pz(), momFac * pyev[i].e()  ),
0227       pyev[i].id(), pyev[i].statusHepMC() );
0228     if (iBarcode != 0) ++newBarcode;
0229     hepevt_particles[i]->suggest_barcode( (append) ? newBarcode : i );
0230     hepevt_particles[i]->set_generated_mass( momFac * pyev[i].m() );
0231 
0232     // Colour flow uses index 1 and 2.
0233     int colType = pyev[i].colType();
0234     if (colType ==  1 || colType == 2)
0235       hepevt_particles[i]->set_flow(1, pyev[i].col());
0236     if (colType == -1 || colType == 2)
0237       hepevt_particles[i]->set_flow(2, pyev[i].acol());
0238   }
0239 
0240   // Here we assume that the first two particles in the list
0241   // are the incoming beam particles.
0242   if (!append)
0243     evt->set_beam_particles( hepevt_particles[1], hepevt_particles[2] );
0244 
0245   // 3. Loop over particles AGAIN, this time creating vertices.
0246   // We build the production vertex for each entry in hepevt.
0247   // The HEPEVT pointers are bi-directional, so gives decay vertices as well.
0248   for (int i = iStart; i < pyev.size(); ++i) {
0249     GenParticle* p = hepevt_particles[i];
0250 
0251     // 3a. Search to see if a production vertex already exists.
0252     std::vector<int> mothers = pyev[i].motherList();
0253     unsigned int imother = 0;
0254     int mother = -1; // note that in Pythia8 there is a particle number 0!
0255     if ( !mothers.empty() ) mother = mothers[imother];
0256     GenVertex* prod_vtx = p->production_vertex();
0257     while ( !prod_vtx && mother > 0 ) {
0258       prod_vtx = (append && mother == 1) ? rootParticle->end_vertex()
0259                : hepevt_particles[mother]->end_vertex();
0260       if (prod_vtx) prod_vtx->add_particle_out( p );
0261       mother = ( ++imother < mothers.size() ) ? mothers[imother] : -1;
0262     }
0263 
0264     // 3b. If no suitable production vertex exists - and the particle has
0265     // at least one mother or position information to store - make one.
0266     FourVector prod_pos( lenFac * pyev[i].xProd(), lenFac * pyev[i].yProd(),
0267                          lenFac * pyev[i].zProd(), lenFac * pyev[i].tProd() );
0268     if ( !prod_vtx && ( mothers.size() > 0 || prod_pos != FourVector() ) ) {
0269       prod_vtx = new GenVertex();
0270       prod_vtx->add_particle_out( p );
0271       evt->add_vertex( prod_vtx );
0272     }
0273 
0274     // 3c. If prod_vtx doesn't already have position specified, fill it.
0275     if ( prod_vtx && prod_vtx->position() == FourVector() )
0276       prod_vtx->set_position( prod_pos );
0277 
0278     // 3d. loop over mothers to make sure their end_vertices are consistent.
0279     imother = 0;
0280     mother = -1;
0281     if ( !mothers.empty() ) mother = mothers[imother];
0282     while ( prod_vtx && mother > 0 ) {
0283 
0284       // If end vertex of the mother isn't specified, do it now.
0285       GenParticle* ppp = (append && mother == 1) ? rootParticle
0286                        : hepevt_particles[mother];
0287       if ( !ppp->end_vertex() ) {
0288         prod_vtx->add_particle_in( ppp );
0289       } else if (ppp->end_vertex() != prod_vtx ) {
0290         // Problem scenario: the mother already has a decay vertex which
0291         // differs from the daughter's production vertex.
0292         // Can happen with Vincia showers since antenna emissions have two
0293         // parents. In that case, let vertex structure be defined by first
0294         // parent, ignoring second parent.
0295         if ( (pyev[i].statusAbs() == 43 || pyev[i].statusAbs() == 51
0296             || pyev[i].statusAbs() == 53) && mother >= 1) break;
0297         // Otherwise this means there is internal inconsistency in the
0298         // HEPEVT event record. Print an error.
0299         // Note: we could provide a fix by joining the two vertices with a
0300         // dummy particle if the problem arises often.
0301         if ( m_print_inconsistency ) std::cout
0302           << " Pythia8ToHepMC::fill_next_event: inconsistent mother/daugher "
0303           << "information in Pythia8 event " << std::endl
0304           << "i = " << i << " mother = " << mother
0305           << "\n This warning can be turned off with the "
0306           << "Pythia8ToHepMC::print_inconsistency switch." << std::endl;
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() &&
0323          !hepevt_particles[i]->production_vertex() ) {
0324       std::cout << " Pythia8ToHepMC::fill_next_event error: "
0325         << "hanging particle " << i << std::endl;
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_event_scale( pyinfo->QRen() );
0362     if (evt->alphaQED() <= 0) evt->set_alphaQED( pyinfo->alphaEM() );
0363     if (evt->alphaQCD() <= 0) evt->set_alphaQCD( pyinfo->alphaS() );
0364   }
0365 
0366   // Store cross-section information in pb and event weight. The latter is
0367   // usually dimensionless, but in units of pb for Les Houches strategies +-4.
0368   if (m_store_xsec && pyinfo != 0) {
0369     HepMC::GenCrossSection xsec;
0370     xsec.set_cross_section( pyinfo->sigmaGen() * 1e9,
0371       pyinfo->sigmaErr() * 1e9);
0372     evt->set_cross_section(xsec);
0373     // If multiweights with possibly different xsec, overwrite central value
0374     std::vector<double> xsecVec = pyinfo->weightContainerPtr->getTotalXsec();
0375     if (xsecVec.size() > 0) {
0376       xsec.set_cross_section(xsecVec[0]*1e9);
0377       evt->set_cross_section(xsec);
0378     }
0379   }
0380 
0381   if (m_store_weights && pyinfo != 0) {
0382     for (int iweight = 0; iweight < pyinfo->numberOfWeights();
0383       ++iweight) {
0384       std::string name  = pyinfo->weightNameByIndex(iweight);
0385       double value      = pyinfo->weightValueByIndex(iweight);
0386       evt->weights()[name] = value;
0387     }
0388   }
0389 
0390   // Done for new event.
0391   return true;
0392 
0393 }
0394 
0395 //==========================================================================
0396 
0397 } // end namespace HepMC
0398 
0399 namespace Pythia8 {
0400 
0401 //==========================================================================
0402 // This a wrapper around HepMC::Pythia8ToHepMC in the Pythia8
0403 // namespace that simplify the most common use cases. It stores the
0404 // current GenEvent and output stream internally to avoid cluttering
0405 // of user code. This class is also defined in HepMC3.h with the same
0406 // signatures, and the user can therefore switch between HepMC version
0407 // 2 and 3, by simply changing the include file.
0408 class Pythia8ToHepMC : public HepMC::Pythia8ToHepMC {
0409 
0410 public:
0411 
0412   // We can either have standard ascii output or none at all.
0413   enum OutputType { none, ascii2 };
0414 
0415   // Typedef for the version 2 specific classes used.
0416   typedef HepMC::GenEvent GenEvent;
0417   typedef shared_ptr<GenEvent> EventPtr;
0418   typedef HepMC::IO_GenEvent Writer;
0419   typedef shared_ptr<Writer> WriterPtr;
0420 
0421   // The empty constructor does not creat an aoutput stream.
0422   Pythia8ToHepMC() {}
0423 
0424   // Construct an object with an internal output stream.
0425   Pythia8ToHepMC(string filename, OutputType ft = ascii2) {
0426     setNewFile(filename, ft);
0427   }
0428 
0429   // Open a new external output stream.
0430   bool setNewFile(string filename, OutputType ft = ascii2) {
0431     switch ( ft ) {
0432     case ascii2:
0433       writerPtr = make_shared<HepMC::IO_GenEvent>(filename);
0434       break;
0435     case none:
0436       writerPtr = nullptr;
0437       break;
0438     }
0439     return writerPtr != nullptr;
0440   }
0441 
0442   // Create a new GenEvent object and fill it with information from
0443   // the given Pythia object.
0444   bool fillNextEvent(Pythia & pythia) {
0445     geneve = make_shared<GenEvent>();
0446     return fill_next_event(pythia, *geneve);
0447   }
0448 
0449   // Write out the current GenEvent to the internal stream.
0450   void writeEvent() {
0451     writerPtr->write_event(&*geneve);
0452   }
0453 
0454   // Create a new GenEvent object and fill it with information from
0455   // the given Pythia object and write it out directly to the
0456   // internal stream.
0457   bool writeNextEvent(Pythia & pythia) {
0458     if ( !fillNextEvent(pythia) ) return false;
0459     writeEvent();
0460     return true;
0461   }
0462 
0463   // Get a reference to the current GenEvent.
0464   GenEvent & event() {
0465     return *geneve;
0466   }
0467 
0468   // Get a pointer to the current GenEvent.
0469   EventPtr getEventPtr() {
0470     return geneve;
0471   }
0472 
0473   // Get a reference to the internal stream.
0474   Writer & output() {
0475     return *writerPtr;
0476   }
0477 
0478   // Get a pointer to the internal stream.
0479   WriterPtr outputPtr() {
0480     return writerPtr;
0481   }
0482 
0483   // Set cross section information in the current GenEvent.
0484   void setXSec(double xsec, double xsecerr) {
0485     HepMC::GenCrossSection xs;
0486     xs.set_cross_section(xsec, xsecerr);
0487     geneve->set_cross_section(xs);
0488   }
0489 
0490   // Update all weights in the current GenEvent.
0491   void setWeights(const vector<double> & wv) {
0492     if ( wv.size() != weightNames.size() )
0493       geneve->weights() = wv;
0494     else
0495       for ( int i= 0, N = wv.size(); i < N; ++i )
0496         geneve->weights()[weightNames[i]] = wv[i];
0497   }
0498 
0499   // Set all weight names in the current run.
0500   void setWeightNames(const vector<string> &wnv) {
0501     weightNames = wnv;
0502   }
0503 
0504   // Update the PDF information in the current GenEvent
0505   void setPdfInfo(int id1, int id2, double x1, double x2,
0506                   double scale, double xf1, double xf2,
0507                   int pdf1 = 0, int pdf2 = 0) {
0508     HepMC::PdfInfo pdf(id1, id2, x1, x2, scale, xf1, xf2, pdf1, pdf2);
0509     geneve->set_pdf_info(pdf);
0510   }
0511 
0512 private:
0513 
0514   // The current GenEvent.
0515   EventPtr geneve = nullptr;
0516 
0517   // The output stream.
0518   WriterPtr writerPtr = nullptr;
0519 
0520   // The weight names in the current run.
0521   vector<string> weightNames;
0522 
0523 };
0524 
0525 }
0526 
0527 #endif  // end Pythia8_HepMC2_H