Back to home page

EIC code displayed by LXR

 
 

    


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

0001 // HepMC3.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: HepMC 3 Collaboration, hepmc-dev@.cern.ch
0007 // Based on the HepMC2 interface by Mikhail Kirsanov, Mikhail.Kirsanov@cern.ch.
0008 // Header file and function definitions for the Pythia8ToHepMC class,
0009 // which converts a PYTHIA event record to the standard HepMC format.
0010 
0011 #ifndef Pythia8_HepMC3_H
0012 #define Pythia8_HepMC3_H
0013 
0014 #ifdef Pythia8_HepMC2_H
0015 #error Cannot include HepMC3.h if HepMC2.h has already been included.
0016 #endif
0017 
0018 #include <vector>
0019 #include "Pythia8/Pythia.h"
0020 #include "Pythia8/HIInfo.h"
0021 #include "HepMC3/GenVertex.h"
0022 #include "HepMC3/GenParticle.h"
0023 #include "HepMC3/GenEvent.h"
0024 #include "HepMC3/WriterAscii.h"
0025 #include "HepMC3/WriterAsciiHepMC2.h"
0026 #include "HepMC3/GenHeavyIon.h"
0027 #include "HepMC3/GenPdfInfo.h"
0028 
0029 namespace HepMC3 {
0030 
0031 //==========================================================================
0032 
0033 class Pythia8ToHepMC3 {
0034 
0035 public:
0036 
0037   // Constructor and destructor
0038   Pythia8ToHepMC3(): m_internal_event_number(0), m_print_inconsistency(true),
0039     m_free_parton_warnings(true), m_crash_on_problem(false),
0040     m_convert_gluon_to_0(false), m_store_pdf(true), m_store_proc(true),
0041     m_store_xsec(true), m_store_weights(true) {}
0042   virtual ~Pythia8ToHepMC3() {}
0043 
0044   // The recommended method to convert Pythia events into HepMC3 ones.
0045   bool fill_next_event( Pythia8::Pythia& pythia, GenEvent* evt,
0046     int ievnum = -1 ) { return fill_next_event( pythia.event, evt,
0047     ievnum, &pythia.info, &pythia.settings); }
0048   bool fill_next_event( Pythia8::Pythia& pythia, GenEvent& evt) {
0049     return fill_next_event( pythia, &evt); }
0050 
0051   // Alternative method to convert Pythia events into HepMC3 ones.
0052   bool fill_next_event( Pythia8::Event& pyev, GenEvent&evt, int ievnum = -1,
0053     const Pythia8::Info* pyinfo = 0, Pythia8::Settings* pyset = 0) {
0054     return fill_next_event(pyev, &evt, ievnum, pyinfo, pyset); }
0055   bool fill_next_event( Pythia8::Event& pyev, GenEvent* evt, int ievnum = -1,
0056     const Pythia8::Info* pyinfo = 0, Pythia8::Settings* pyset = 0) {
0057 
0058     // 1. Error if no event passed.
0059     if (!evt) {
0060       std::cerr << "Pythia8ToHepMC3::fill_next_event error - "
0061                 << "passed null event." << std::endl;
0062       return false;
0063     }
0064 
0065     // Event number counter.
0066     if ( ievnum >= 0 ) {
0067       evt->set_event_number(ievnum);
0068       m_internal_event_number = ievnum;
0069     }
0070     else {
0071       evt->set_event_number(m_internal_event_number);
0072       ++m_internal_event_number;
0073     }
0074 
0075     // Set units to be GeV and mm, to agree with Pythia ones.
0076     evt->set_units(Units::GEV,Units::MM);
0077 
0078     // 1a. If there is a HIInfo object fill info from that.
0079     if ( pyinfo && pyinfo->hiInfo ) {
0080       auto ion = make_shared<HepMC3::GenHeavyIon>();
0081       ion->Ncoll_hard = pyinfo->hiInfo->nCollNDTot();
0082       ion->Ncoll = pyinfo->hiInfo->nAbsProj() +
0083                    pyinfo->hiInfo->nDiffProj() +
0084                    pyinfo->hiInfo->nAbsTarg() +
0085                    pyinfo->hiInfo->nDiffTarg() -
0086                    pyinfo->hiInfo->nCollND() -
0087                    pyinfo->hiInfo->nCollDD();
0088       ion->Npart_proj = pyinfo->hiInfo->nAbsProj() +
0089                         pyinfo->hiInfo->nDiffProj();
0090       ion->Npart_targ = pyinfo->hiInfo->nAbsTarg() +
0091                         pyinfo->hiInfo->nDiffTarg();
0092       ion->impact_parameter = pyinfo->hiInfo->b();
0093       evt->set_heavy_ion(ion);
0094     }
0095 
0096     // 2. Fill particle information.
0097     std::vector<GenParticlePtr> hepevt_particles;
0098     hepevt_particles.reserve( pyev.size() );
0099     for(int i = 0; i < pyev.size(); ++i) {
0100       hepevt_particles.push_back( std::make_shared<GenParticle>(
0101         FourVector( pyev[i].px(), pyev[i].py(), pyev[i].pz(), pyev[i].e() ),
0102         pyev[i].id(), pyev[i].statusHepMC() ) );
0103       hepevt_particles[i]->set_generated_mass( pyev[i].m() );
0104     }
0105 
0106     // 3. Fill vertex information.
0107     std::vector<GenVertexPtr> vertex_cache;
0108     for (int i = 3; i < pyev.size(); ++i) {
0109       std::vector<int> mothers = pyev[i].motherList();
0110       if (mothers.size()) {
0111         GenVertexPtr prod_vtx = hepevt_particles[mothers[0]]->end_vertex();
0112         if (!prod_vtx) {
0113           prod_vtx = make_shared<GenVertex>();
0114           vertex_cache.push_back(prod_vtx);
0115           for (unsigned int j = 0; j < mothers.size(); ++j)
0116             prod_vtx->add_particle_in( hepevt_particles[mothers[j]] );
0117         }
0118         FourVector prod_pos( pyev[i].xProd(), pyev[i].yProd(),pyev[i].zProd(),
0119           pyev[i].tProd() );
0120 
0121         // Update vertex position if necessary.
0122         if (!prod_pos.is_zero() && prod_vtx->position().is_zero())
0123           prod_vtx->set_position( prod_pos );
0124         prod_vtx->add_particle_out( hepevt_particles[i] );
0125       }
0126     }
0127 
0128     // Reserve memory for the event.
0129     evt->reserve( hepevt_particles.size(), vertex_cache.size() );
0130 
0131     // Here we assume that the first two particles are the beam particles.
0132     vector<GenParticlePtr> beam_particles;
0133     beam_particles.push_back(hepevt_particles[1]);
0134     beam_particles.push_back(hepevt_particles[2]);
0135 
0136     // Add particles and vertices in topological order.
0137     evt->add_tree( beam_particles );
0138     // Attributes should be set after adding the particles to event.
0139     for (int i = 0; i < pyev.size(); ++i) {
0140       /* TODO: Set polarization */
0141       // Colour flow uses index 1 and 2.
0142       int colType = pyev[i].colType();
0143       if (colType ==  -1 ||colType ==  1 || colType == 2) {
0144         int flow1 = 0, flow2 = 0;
0145         if (colType ==  1 || colType == 2) flow1 = pyev[i].col();
0146         if (colType == -1 || colType == 2) flow2 = pyev[i].acol();
0147         hepevt_particles[i]->add_attribute("flow1",
0148           make_shared<IntAttribute>(flow1));
0149         hepevt_particles[i]->add_attribute("flow2",
0150           make_shared<IntAttribute>(flow2));
0151       }
0152     }
0153 
0154     // If hadronization switched on then no final coloured particles.
0155     bool doHadr = (pyset == 0) ? m_free_parton_warnings
0156       : pyset->flag("HadronLevel:all") && pyset->flag("HadronLevel:Hadronize");
0157 
0158     // 4. Check for particles which come from nowhere, i.e. are without
0159     // mothers or daughters. These need to be attached to a vertex, or else
0160     // they will never become part of the event.
0161     for (int i = 1; i < pyev.size(); ++i) {
0162 
0163       // Check for particles not added to the event.
0164       // NOTE: We have to check if this step makes any sense in
0165       // the HepMC event standard.
0166       if ( !hepevt_particles[i] ) {
0167         std::cerr << "hanging particle " << i << std::endl;
0168         GenVertexPtr prod_vtx = make_shared<GenVertex>();
0169         prod_vtx->add_particle_out( hepevt_particles[i] );
0170         evt->add_vertex(prod_vtx);
0171       }
0172 
0173       // Also check for free partons (= gluons and quarks; not diquarks?).
0174       if ( doHadr && m_free_parton_warnings ) {
0175         if ( hepevt_particles[i]->pid() == 21
0176            && !hepevt_particles[i]->end_vertex() ) {
0177            std::cerr << "gluon without end vertex " << i << std::endl;
0178            if ( m_crash_on_problem ) exit(1);
0179         }
0180         if ( std::abs(hepevt_particles[i]->pid()) <= 6
0181           && !hepevt_particles[i]->end_vertex() ) {
0182           std::cerr << "quark without end vertex " << i << std::endl;
0183           if ( m_crash_on_problem ) exit(1);
0184         }
0185       }
0186     }
0187 
0188     // 5. Store PDF, weight, cross section and other event information.
0189     // Flavours of incoming partons.
0190     if (m_store_pdf && pyinfo != 0) {
0191       int id1pdf = pyinfo->id1pdf();
0192       int id2pdf = pyinfo->id2pdf();
0193       if ( m_convert_gluon_to_0 ) {
0194         if (id1pdf == 21) id1pdf = 0;
0195         if (id2pdf == 21) id2pdf = 0;
0196       }
0197 
0198       // Store PDF information.
0199       GenPdfInfoPtr pdfinfo = make_shared<GenPdfInfo>();
0200       pdfinfo->set(id1pdf, id2pdf, pyinfo->x1pdf(), pyinfo->x2pdf(),
0201         pyinfo->QFac(), pyinfo->pdf1(), pyinfo->pdf2() );
0202       evt->set_pdf_info( pdfinfo );
0203     }
0204 
0205     // Store process code, scale, alpha_em, alpha_s.
0206     if (m_store_proc && pyinfo != 0) {
0207       evt->add_attribute("signal_process_id",
0208         std::make_shared<IntAttribute>( pyinfo->code()));
0209       evt->add_attribute("event_scale",
0210         std::make_shared<DoubleAttribute>(pyinfo->QRen()));
0211       evt->add_attribute("alphaQCD",
0212         std::make_shared<DoubleAttribute>(pyinfo->alphaS()));
0213       evt->add_attribute("alphaQED",
0214         std::make_shared<DoubleAttribute>(pyinfo->alphaEM()));
0215     }
0216 
0217     // Store event weights.
0218     if (m_store_weights && pyinfo != 0) {
0219       evt->weights().clear();
0220       for (int iWeight = 0; iWeight < pyinfo->numberOfWeights(); ++iWeight)
0221         evt->weights().push_back(pyinfo->weightValueByIndex(iWeight));
0222     }
0223 
0224     // Store cross-section information in pb.
0225     if (m_store_xsec && pyinfo != 0) {
0226       // First set atribute to event, such that
0227       // GenCrossSection::set_cross_section knows how many weights the
0228       // event has and sets the number of cross sections accordingly.
0229       GenCrossSectionPtr xsec = make_shared<GenCrossSection>();
0230       evt->set_cross_section(xsec);
0231       xsec->set_cross_section( pyinfo->sigmaGen() * 1e9,
0232         pyinfo->sigmaErr() * 1e9);
0233       // If multiweights with possibly different xsec, overwrite central value
0234       vector<double> xsecVec = pyinfo->weightContainerPtr->getTotalXsec();
0235       if (xsecVec.size() > 0) {
0236         for (unsigned int iXsec = 0; iXsec < xsecVec.size(); ++iXsec) {
0237           xsec->set_xsec(iXsec, xsecVec[iXsec]*1e9);
0238         }
0239       }
0240     }
0241 
0242     // Done.
0243     return true;
0244   }
0245 
0246   // Read out values for some switches.
0247   bool print_inconsistency()  const { return m_print_inconsistency; }
0248   bool free_parton_warnings() const { return m_free_parton_warnings; }
0249   bool crash_on_problem()     const { return m_crash_on_problem; }
0250   bool convert_gluon_to_0()   const { return m_convert_gluon_to_0; }
0251   bool store_pdf()            const { return m_store_pdf; }
0252   bool store_proc()           const { return m_store_proc; }
0253   bool store_xsec()           const { return m_store_xsec; }
0254   bool store_weights()        const { return m_store_weights; }
0255 
0256   // Set values for some switches.
0257   void set_print_inconsistency(bool b = true)  { m_print_inconsistency  = b; }
0258   void set_free_parton_warnings(bool b = true) { m_free_parton_warnings = b; }
0259   void set_crash_on_problem(bool b = false)    { m_crash_on_problem     = b; }
0260   void set_convert_gluon_to_0(bool b = false)  { m_convert_gluon_to_0   = b; }
0261   void set_store_pdf(bool b = true)            { m_store_pdf            = b; }
0262   void set_store_proc(bool b = true)           { m_store_proc           = b; }
0263   void set_store_xsec(bool b = true)           { m_store_xsec           = b; }
0264   void set_store_weights(bool b = true)        { m_store_weights        = b; }
0265 
0266 private:
0267 
0268   // Following methods are not implemented for this class.
0269   virtual bool fill_next_event( GenEvent*  )  { return 0; }
0270   virtual void write_event( const GenEvent* ) {}
0271 
0272   // Use of copy constructor is not allowed.
0273   Pythia8ToHepMC3( const Pythia8ToHepMC3& ) {}
0274 
0275   // Data members.
0276   int  m_internal_event_number;
0277   bool m_print_inconsistency, m_free_parton_warnings, m_crash_on_problem,
0278        m_convert_gluon_to_0, m_store_pdf, m_store_proc, m_store_xsec,
0279        m_store_weights;
0280 
0281 };
0282 
0283 //==========================================================================
0284 
0285 } // end namespace HepMC3
0286 
0287 namespace Pythia8 {
0288 
0289 //==========================================================================
0290 // This a wrapper around HepMC::Pythia8ToHepMC in the Pythia8
0291 // namespace that simplify the most common use cases. It stores the
0292 // current GenEvent and output stream internally to avoid cluttering
0293 // of user code. This class is also defined in HepMC2.h with the same
0294 // signatures, and the user can therefore switch between HepMC version
0295 // 2 and 3, by simply changing the include file.
0296 class Pythia8ToHepMC : public HepMC3::Pythia8ToHepMC3 {
0297 
0298 public:
0299 
0300   // We can either have standard ascii output version 2 or three or
0301   // none at all.
0302   enum OutputType { none, ascii2, ascii3 };
0303 
0304   // Typedef for the version 3 specific classes used.
0305   typedef HepMC3::GenEvent GenEvent;
0306   typedef shared_ptr<GenEvent> EventPtr;
0307   typedef HepMC3::Writer Writer;
0308   typedef shared_ptr<Writer> WriterPtr;
0309 
0310   // The empty constructor does not creat an aoutput stream.
0311   Pythia8ToHepMC() : runinfo(make_shared<HepMC3::GenRunInfo>()) {}
0312 
0313   // Construct an object with an internal output stream.
0314   Pythia8ToHepMC(string filename, OutputType ft = ascii3)
0315     : runinfo(make_shared<HepMC3::GenRunInfo>()) {
0316     setNewFile(filename, ft);
0317   }
0318 
0319   // Open a new external output stream.
0320   bool setNewFile(string filename, OutputType ft = ascii3) {
0321     switch ( ft ) {
0322     case ascii3:
0323       writerPtr = make_shared<HepMC3::WriterAscii>(filename);
0324       break;
0325     case ascii2:
0326       writerPtr = make_shared<HepMC3::WriterAsciiHepMC2>(filename);
0327       break;
0328     case none:
0329       break;
0330     }
0331     return writerPtr != nullptr;
0332   }
0333 
0334   // Create a new GenEvent object and fill it with information from
0335   // the given Pythia object.
0336   bool fillNextEvent(Pythia & pythia) {
0337     geneve = make_shared<HepMC3::GenEvent>(runinfo);
0338     if (runinfo->weight_names().size() == 0)
0339       setWeightNames(pythia.info.weightNameVector());
0340     return fill_next_event(pythia, *geneve);
0341   }
0342 
0343   // Write out the current GenEvent to the internal stream.
0344   void writeEvent() {
0345     writerPtr->write_event(*geneve);
0346   }
0347 
0348   // Create a new GenEvent object and fill it with information from
0349   // the given Pythia object and write it out directly to the
0350   // internal stream.
0351   bool writeNextEvent(Pythia & pythia) {
0352     if ( !fillNextEvent(pythia) ) return false;
0353     writeEvent();
0354     return !writerPtr->failed();
0355   }
0356 
0357   // Get a reference to the current GenEvent.
0358   GenEvent & event() {
0359     return *geneve;
0360   }
0361 
0362   // Get a pointer to the current GenEvent.
0363    EventPtr getEventPtr() {
0364     return geneve;
0365   }
0366 
0367   // Get a reference to the internal stream.
0368   Writer & output() {
0369     return *writerPtr;
0370   }
0371 
0372   // Get a pointer to the internal stream.
0373   WriterPtr outputPtr() {
0374     return writerPtr;
0375   }
0376 
0377   // Set cross section information in the current GenEvent.
0378   void setXSec(double xsec, double xsecerr) {
0379     auto xsecptr = geneve->cross_section();
0380     if ( !xsecptr ) {
0381       xsecptr = make_shared<HepMC3::GenCrossSection>();
0382       geneve->set_cross_section(xsecptr);
0383     }
0384     xsecptr->set_cross_section(xsec, xsecerr);
0385   }
0386 
0387   // Update all weights in the current GenEvent.
0388   void setWeights(const vector<double> & wv) {
0389     geneve->weights() = wv;
0390   }
0391 
0392   // Set all weight names in the current run.
0393   void setWeightNames(const vector<string> &wnv) {
0394     runinfo->set_weight_names(wnv);
0395   }
0396 
0397   // Update the PDF information in the current GenEvent
0398   void setPdfInfo(int id1, int id2, double x1, double x2,
0399                   double scale, double xf1, double xf2,
0400                   int pdf1 = 0, int pdf2 = 0) {
0401     auto pdf = make_shared<HepMC3::GenPdfInfo>();
0402     pdf->set(id1, id2, x1, x2, scale, xf1, xf2, pdf1, pdf2);
0403     geneve->set_pdf_info(pdf);
0404   }
0405 
0406   // Add an additional attribute derived from HepMC3::Attribute
0407   // to the current event.
0408   template<class T>
0409   void addAtribute(const string& name, T& attribute) {
0410     shared_ptr<HepMC3::Attribute> att = make_shared<T>(attribute);
0411     geneve->add_attribute(name, att);
0412   }
0413 
0414   // Add an attribute of double type.
0415   template<class T=double>
0416   void addAttribute(const string& name, double& attribute) {
0417     auto dAtt = HepMC3::DoubleAttribute(attribute);
0418     shared_ptr<HepMC3::Attribute> att =
0419       make_shared<HepMC3::DoubleAttribute>(dAtt);
0420     geneve->add_attribute(name, att);
0421   }
0422 
0423   // Remove an attribute from the current event.
0424   void removeAttribute(const string& name) {
0425     geneve->remove_attribute(name);
0426   }
0427 
0428 private:
0429 
0430   // The current GenEvent
0431   EventPtr geneve = nullptr;
0432 
0433   // The output stream.
0434   WriterPtr writerPtr = nullptr;
0435 
0436   // The current run info.
0437   shared_ptr<HepMC3::GenRunInfo> runinfo;
0438 
0439 };
0440 
0441 }
0442 
0443 #endif // end Pythia8_HepMC3_H