CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/GeneratorInterface/Pythia6Interface/plugins/Pythia6Hadronizer.cc

Go to the documentation of this file.
00001    
00002 // -*- C++ -*-
00003 
00004 #include "Pythia6Hadronizer.h"
00005 
00006 #include "HepMC/GenEvent.h"
00007 #include "HepMC/PdfInfo.h"
00008 #include "HepMC/PythiaWrapper6_4.h"
00009 #include "HepMC/HEPEVT_Wrapper.h"
00010 #include "HepMC/IO_HEPEVT.h"
00011 
00012 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00013 
00014 #include "GeneratorInterface/Core/interface/FortranCallback.h"
00015 
00016 #include "GeneratorInterface/LHEInterface/interface/LHERunInfo.h"
00017 
00018 #include "SimDataFormats/GeneratorProducts/interface/LHEEventProduct.h"
00019 
00020 #include "GeneratorInterface/PartonShowerVeto/interface/JetMatching.h"
00021 
00022  
00023 HepMC::IO_HEPEVT conv;
00024 
00025 #include "HepPID/ParticleIDTranslations.hh"
00026 
00027 // NOTE: here a number of Pythia6 routines are declared,
00028 // plus some functionalities to pass around Pythia6 params
00029 //
00030 #include "GeneratorInterface/Pythia6Interface/interface/Pythia6Service.h"
00031 #include "GeneratorInterface/Pythia6Interface/interface/Pythia6Declarations.h"
00032 
00033 namespace gen
00034 {
00035 
00036 extern "C" {
00037    
00038    //
00039    // these two are NOT part of Pythi6 core code but are "custom" add-ons
00040    // we keep them interfaced here, rather than in GenExtensions, because
00041    // they tweak not at the ME level, but a step further, at the framgmentation
00042    //
00043    // stop-hadrons
00044    //
00045    void pystrhad_();   // init stop-hadrons (id's, names, charges...)
00046    void pystfr_(int&); // tweaks fragmentation, fragments the string near to a stop, 
00047                        // to form stop-hadron by producing a new q-qbar pair
00048    // gluino/r-hadrons
00049    void pyglrhad_();
00050    void pyglfr_();   // tweaks fragmentation, fragment the string near to a gluino,
00051                      // to form gluino-hadron, either by producing a new g-g pair,
00052                      // or two new q-qbar ones
00053 
00054 
00055 } // extern "C"
00056 
00057 class Pythia6ServiceWithCallback : public Pythia6Service {
00058   public:
00059      Pythia6ServiceWithCallback( const edm::ParameterSet& ps ) : Pythia6Service(ps) {}
00060 
00061   private:
00062     void upInit()
00063     { FortranCallback::getInstance()->fillHeader(); }
00064 
00065     void upEvnt()
00066     {
00067       FortranCallback::getInstance()->fillEvent(); 
00068       if ( Pythia6Hadronizer::getJetMatching() )
00069         Pythia6Hadronizer::getJetMatching()->beforeHadronisationExec();    
00070     }
00071 
00072     bool upVeto()
00073     { 
00074       if ( !Pythia6Hadronizer::getJetMatching() )
00075         return false;
00076 
00077       if ( !hepeup_.nup || Pythia6Hadronizer::getJetMatching()->isMatchingDone() )
00078          return true;
00079 
00080       bool retValue = Pythia6Hadronizer::getJetMatching()->match( 0, 0 );
00081       // below is old code and a note of it
00082       // NOTE: I'm passing NULL pointers, instead of HepMC::GenEvent, etc.
00083       //retValur = Pythia6Hadronizer::getJetMatching()->match(0, 0, true);
00084       return retValue;
00085 
00086 
00087     }
00088 };
00089 
00090 static struct {
00091         int n, npad, k[5][pyjets_maxn];
00092         double p[5][pyjets_maxn], v[5][pyjets_maxn];
00093 } pyjets_local;
00094 
00095 JetMatching* Pythia6Hadronizer::fJetMatching = 0;
00096 
00097 Pythia6Hadronizer::Pythia6Hadronizer(edm::ParameterSet const& ps) 
00098    : BaseHadronizer(ps),
00099      fPy6Service( new Pythia6ServiceWithCallback(ps) ), // this will store py6 params for further settings
00100      fInitialState(PP),
00101      fCOMEnergy(ps.getParameter<double>("comEnergy")),
00102      fHepMCVerbosity(ps.getUntrackedParameter<bool>("pythiaHepMCVerbosity",false)),
00103      fMaxEventsToPrint(ps.getUntrackedParameter<int>("maxEventsToPrint", 0)),
00104      fPythiaListVerbosity(ps.getUntrackedParameter<int>("pythiaPylistVerbosity", 0)),
00105      fDisplayPythiaBanner(ps.getUntrackedParameter<bool>("displayPythiaBanner",false)),
00106      fDisplayPythiaCards(ps.getUntrackedParameter<bool>("displayPythiaCards",false))
00107 { 
00108 
00109    
00110    // J.Y.: the following 3 parameters are hacked "for a reason"
00111    //
00112    if ( ps.exists( "PPbarInitialState" ) )
00113    {
00114       if ( fInitialState == PP )
00115       {
00116          fInitialState = PPbar;
00117          edm::LogInfo("GeneratorInterface|Pythia6Interface")
00118          << "Pythia6 will be initialized for PROTON-ANTIPROTON INITIAL STATE. "
00119          << "This is a user-request change from the DEFAULT PROTON-PROTON initial state." << std::endl;
00120          std::cout << "Pythia6 will be initialized for PROTON-ANTIPROTON INITIAL STATE." << std::endl;
00121          std::cout << "This is a user-request change from the DEFAULT PROTON-PROTON initial state." << std::endl;
00122       }
00123       else
00124       {
00125          // probably need to throw on attempt to override ?
00126       }
00127    }
00128    else if ( ps.exists( "ElectronPositronInitialState" ) )
00129    {
00130       if ( fInitialState == PP )
00131       {
00132          fInitialState = ElectronPositron;
00133          edm::LogInfo("GeneratorInterface|Pythia6Interface")
00134          << "Pythia6 will be initialized for ELECTRON-POSITRON INITIAL STATE. "
00135          << "This is a user-request change from the DEFAULT PROTON-PROTON initial state." << std::endl;
00136          std::cout << "Pythia6 will be initialized for ELECTRON-POSITRON INITIAL STATE." << std::endl;
00137          std::cout << "This is a user-request change from the DEFAULT PROTON-PROTON initial state." << std::endl;
00138       }
00139       else
00140       {
00141          // probably need to throw on attempt to override ?
00142       }
00143    }
00144    else if ( ps.exists( "ElectronProtonInitialState" ) )
00145    {
00146       if ( fInitialState == PP )
00147       {
00148          fInitialState = ElectronProton;         
00149          fBeam1PZ = (ps.getParameter<edm::ParameterSet>("ElectronProtonInitialState")).getParameter<double>("electronMomentum");
00150          fBeam2PZ = (ps.getParameter<edm::ParameterSet>("ElectronProtonInitialState")).getParameter<double>("protonMomentum");
00151          edm::LogInfo("GeneratorInterface|Pythia6Interface")
00152          << "Pythia6 will be initialized for ELECTRON-PROTON INITIAL STATE. "
00153          << "This is a user-request change from the DEFAULT PROTON-PROTON initial state." << std::endl;
00154          std::cout << "Pythia6 will be initialized for ELECTRON-PROTON INITIAL STATE." << std::endl;
00155          std::cout << "This is a user-request change from the DEFAULT PROTON-PROTON initial state." << std::endl;
00156       }
00157       else
00158       {
00159          // probably need to throw on attempt to override ?
00160       }
00161    }
00162    else if ( ps.exists( "PositronProtonInitialState" ) )
00163    {
00164       if ( fInitialState == PP )
00165       {
00166          fInitialState = PositronProton;         
00167          fBeam1PZ = (ps.getParameter<edm::ParameterSet>("ElectronProtonInitialState")).getParameter<double>("positronMomentum");
00168          fBeam2PZ = (ps.getParameter<edm::ParameterSet>("ElectronProtonInitialState")).getParameter<double>("protonMomentum");
00169          edm::LogInfo("GeneratorInterface|Pythia6Interface")
00170          << "Pythia6 will be initialized for POSITRON-PROTON INITIAL STATE. "
00171          << "This is a user-request change from the DEFAULT PROTON-PROTON initial state." << std::endl;
00172          std::cout << "Pythia6 will be initialized for POSITRON-PROTON INITIAL STATE." << std::endl;
00173          std::cout << "This is a user-request change from the DEFAULT PROTON-PROTON initial state." << std::endl;
00174       }
00175       else
00176       {
00177          // throw on unknown initial state !
00178          throw edm::Exception(edm::errors::Configuration,"Pythia6Interface") 
00179              <<" UNKNOWN INITIAL STATE. \n The allowed initial states are: PP, PPbar, ElectronPositron, ElectronProton, and PositronProton \n";
00180       }
00181    }
00182    
00183    
00184    // J.Y.: the following 4 params are "hacked", in the sense 
00185    // that they're tracked but get in optionally;
00186    // this will be fixed once we update all applications
00187    //
00188 
00189    fStopHadronsEnabled = false;
00190    if ( ps.exists( "stopHadrons" ) )
00191       fStopHadronsEnabled = ps.getParameter<bool>("stopHadrons") ;
00192 
00193    fGluinoHadronsEnabled = false;
00194    if ( ps.exists( "gluinoHadrons" ) )
00195       fGluinoHadronsEnabled = ps.getParameter<bool>("gluinoHadrons");
00196    
00197    fImposeProperTime = false;
00198    if ( ps.exists( "imposeProperTime" ) )
00199    {
00200       fImposeProperTime = ps.getParameter<bool>("imposeProperTime");
00201    }
00202    
00203    fConvertToPDG = false;
00204    if ( ps.exists( "doPDGConvert" ) )
00205       fConvertToPDG = ps.getParameter<bool>("doPDGConvert");
00206    
00207    if ( ps.exists("jetMatching") )
00208    {
00209       edm::ParameterSet jmParams =
00210                         ps.getUntrackedParameter<edm::ParameterSet>(
00211                                                                 "jetMatching");
00212 
00213       fJetMatching = JetMatching::create(jmParams).release();
00214    }
00215    
00216    // first of all, silence Pythia6 banner printout, unless display requested
00217    //
00218    if ( !fDisplayPythiaBanner )
00219    {
00220       if (!call_pygive("MSTU(12)=12345")) 
00221       {
00222          throw edm::Exception(edm::errors::Configuration,"PythiaError") 
00223              <<" Pythia did not accept MSTU(12)=12345";
00224       }
00225    }
00226    
00227 // silence printouts from PYGIVE, unless display requested
00228 //
00229    if ( ! fDisplayPythiaCards )
00230    {
00231       if (!call_pygive("MSTU(13)=0")) 
00232       {
00233          throw edm::Exception(edm::errors::Configuration,"PythiaError") 
00234              <<" Pythia did not accept MSTU(13)=0";
00235       }
00236    }
00237 
00238    // tmp stuff to deal with EvtGen corrupting pyjets
00239    // NPartsBeforeDecays = 0;
00240    flushTmpStorage();
00241    
00242 }
00243 
00244 Pythia6Hadronizer::~Pythia6Hadronizer()
00245 {
00246    if ( fPy6Service != 0 ) delete fPy6Service;
00247    if ( fJetMatching != 0 ) delete fJetMatching;
00248 }
00249 
00250 void Pythia6Hadronizer::flushTmpStorage()
00251 {
00252 
00253    pyjets_local.n = 0 ;
00254    pyjets_local.npad = 0 ;
00255    for ( int ip=0; ip<pyjets_maxn; ip++ )
00256    {
00257       for ( int i=0; i<5; i++ )
00258       {
00259          pyjets_local.k[i][ip] = 0;
00260          pyjets_local.p[i][ip] = 0.;
00261          pyjets_local.v[i][ip] = 0.;
00262       }
00263    }
00264    return;
00265 
00266 }
00267 
00268 void Pythia6Hadronizer::fillTmpStorage()
00269 {
00270 
00271    pyjets_local.n = pyjets.n;
00272    pyjets_local.npad = pyjets.npad;
00273    for ( int ip=0; ip<pyjets_maxn; ip++ )
00274    {
00275       for ( int i=0; i<5; i++ )
00276       {
00277          pyjets_local.k[i][ip] = pyjets.k[i][ip];
00278          pyjets_local.p[i][ip] = pyjets.p[i][ip];
00279          pyjets_local.v[i][ip] = pyjets.v[i][ip];
00280       }
00281    }
00282    
00283    return ;
00284 
00285 }
00286 
00287 void Pythia6Hadronizer::finalizeEvent()
00288 {
00289 
00290    bool lhe = lheEvent() != 0;
00291 
00292    HepMC::PdfInfo pdf;
00293 
00294    // if we are in hadronizer mode, we can pass on information from
00295    // the LHE input
00296    if (lhe)
00297    {
00298       lheEvent()->fillEventInfo( event().get() );
00299       lheEvent()->fillPdfInfo( &pdf );
00300    }
00301    else
00302    {
00303       // filling in factorization "Q scale" now! pthat moved to binningValues()
00304       //
00305             
00306       if ( event()->signal_process_id() <= 0) event()->set_signal_process_id( pypars.msti[0] );
00307       if ( event()->event_scale() <=0 )       event()->set_event_scale( pypars.pari[22] );
00308       if ( event()->alphaQED() <= 0)          event()->set_alphaQED( pyint1.vint[56] );
00309       if ( event()->alphaQCD() <= 0)          event()->set_alphaQCD( pyint1.vint[57] );
00310    
00311       // get pdf info directly from Pythia6 and set it up into HepMC::GenEvent
00312       // S. Mrenna: Prefer vint block
00313       //
00314       if ( pdf.id1() <= 0)      pdf.set_id1( pyint1.mint[14] == 21 ? 0 : pyint1.mint[14] );
00315       if ( pdf.id2() <= 0)      pdf.set_id2( pyint1.mint[15] == 21 ? 0 : pyint1.mint[15] );
00316       if ( pdf.x1() <= 0)       pdf.set_x1( pyint1.vint[40] );
00317       if ( pdf.x2() <= 0)       pdf.set_x2( pyint1.vint[41] );
00318       if ( pdf.pdf1() <= 0)     pdf.set_pdf1( pyint1.vint[38] / pyint1.vint[40] );
00319       if ( pdf.pdf2() <= 0)     pdf.set_pdf2( pyint1.vint[39] / pyint1.vint[41] );
00320       if ( pdf.scalePDF() <= 0) pdf.set_scalePDF( pyint1.vint[50] );   
00321    }
00322 
00323 /* 9/9/2010 - JVY: This is the old piece of code - I can't remember why we implemented it this way.
00324                    However, it's causing problems with pdf1 & pdf2 when processing LHE samples,
00325                    specifically, because both are set to -1, it tries to fill with Py6 numbers that
00326                    are NOT valid/right at this point !
00327                    In general, for LHE/ME event processing we should implement the correct calculation
00328                    of the pdf's, rather than using py6 ones.
00329 
00330    // filling in factorization "Q scale" now! pthat moved to binningValues()
00331 
00332    if (!lhe || event()->signal_process_id() < 0) event()->set_signal_process_id( pypars.msti[0] );
00333    if (!lhe || event()->event_scale() < 0)       event()->set_event_scale( pypars.pari[22] );
00334    if (!lhe || event()->alphaQED() < 0)          event()->set_alphaQED( pyint1.vint[56] );
00335    if (!lhe || event()->alphaQCD() < 0)          event()->set_alphaQCD( pyint1.vint[57] );
00336    
00337    // get pdf info directly from Pythia6 and set it up into HepMC::GenEvent
00338    // S. Mrenna: Prefer vint block
00339    //
00340    if (!lhe || pdf.id1() < 0)      pdf.set_id1( pyint1.mint[14] == 21 ? 0 : pyint1.mint[14] );
00341    if (!lhe || pdf.id2() < 0)      pdf.set_id2( pyint1.mint[15] == 21 ? 0 : pyint1.mint[15] );
00342    if (!lhe || pdf.x1() < 0)       pdf.set_x1( pyint1.vint[40] );
00343    if (!lhe || pdf.x2() < 0)       pdf.set_x2( pyint1.vint[41] );
00344    if (!lhe || pdf.pdf1() < 0)     pdf.set_pdf1( pyint1.vint[38] / pyint1.vint[40] );
00345    if (!lhe || pdf.pdf2() < 0)     pdf.set_pdf2( pyint1.vint[39] / pyint1.vint[41] );
00346    if (!lhe || pdf.scalePDF() < 0) pdf.set_scalePDF( pyint1.vint[50] );
00347 */
00348 
00349    event()->set_pdf_info( pdf ) ;
00350 
00351    // this is "standard" Py6 event weight (corresponds to PYINT1/VINT(97)
00352    //
00353    if (lhe && std::abs(lheRunInfo()->getHEPRUP()->IDWTUP) == 4)
00354      // translate mb to pb (CMS/Gen "convention" as of May 2009)
00355      event()->weights().push_back( pyint1.vint[96] * 1.0e9 );
00356    else
00357      event()->weights().push_back( pyint1.vint[96] );
00358    //
00359    // this is event weight as 1./VINT(99) (PYINT1/VINT(99) is returned by the PYEVWT) 
00360    //
00361    event()->weights().push_back( 1./(pyint1.vint[98]) );
00362 
00363    // now create the GenEventInfo product from the GenEvent and fill
00364    // the missing pieces
00365 
00366    eventInfo().reset( new GenEventInfoProduct( event().get() ) );
00367 
00368    // in Pythia6 pthat is used to subdivide samples into different bins
00369    // in LHE mode the binning is done by the external ME generator
00370    // which is likely not pthat, so only filling it for Py6 internal mode
00371    if (!lhe)
00372    {
00373      eventInfo()->setBinningValues( std::vector<double>(1, pypars.pari[16]) );
00374    }
00375 
00376    // here we treat long-lived particles
00377    //
00378    if ( fImposeProperTime || pydat1.mstj[21]==3 || pydat1.mstj[21]==4 ) imposeProperTime();
00379 
00380    // convert particle IDs Py6->PDG, if requested
00381    if ( fConvertToPDG ) {
00382       for ( HepMC::GenEvent::particle_iterator part = event()->particles_begin(); 
00383                                                part != event()->particles_end(); ++part) {
00384          (*part)->set_pdg_id(HepPID::translatePythiatoPDT((*part)->pdg_id()));
00385       }
00386    }
00387    
00388    // service printouts, if requested
00389    //
00390    if (fMaxEventsToPrint > 0) 
00391    {
00392       fMaxEventsToPrint--;
00393       if (fPythiaListVerbosity) call_pylist(fPythiaListVerbosity);
00394       if (fHepMCVerbosity) 
00395       {
00396          std::cout << "Event process = " << pypars.msti[0] << std::endl 
00397               << "----------------------" << std::endl;
00398          event()->print();
00399       }
00400    }
00401 
00402    // dump of all settings after all initializations
00403    if ( fDisplayPythiaCards ) {
00404      fDisplayPythiaCards = false;
00405      call_pylist(12);
00406      call_pylist(13);
00407      std::cout << "\n PYPARS \n" << std::endl;
00408      std::cout << std::setw(5) << std::fixed << "I"
00409                << std::setw(10) << std::fixed << "MSTP(I)"
00410                << std::setw(16) << std::fixed << "PARP(I)"
00411                << std::setw(10) << std::fixed << "MSTI(I)"
00412                << std::setw(16) << std::fixed << "PARI(I)" << std::endl;
00413      for ( unsigned int ind=0; ind < 200; ind++ ) {
00414        std::cout << std::setw(5) << std::fixed << ind+1
00415                  << std::setw(10) << std::fixed << pypars.mstp[ind]
00416                  << std::setw(16) << std::fixed << pypars.parp[ind]
00417                  << std::setw(10) << std::fixed << pypars.msti[ind]
00418                  << std::setw(16) << std::fixed << pypars.pari[ind] << std::endl;
00419      }
00420    }
00421    
00422    return;
00423 }
00424 
00425 bool Pythia6Hadronizer::generatePartonsAndHadronize()
00426 {
00427    Pythia6Service::InstanceWrapper guard(fPy6Service);  // grab Py6 instance
00428 
00429    FortranCallback::getInstance()->resetIterationsPerEvent();
00430       
00431    // generate event with Pythia6
00432    //
00433    
00434    if ( fStopHadronsEnabled || fGluinoHadronsEnabled )
00435    {
00436       // call_pygive("MSTJ(1)=-1");
00437       call_pygive("MSTJ(14)=-1");
00438    }
00439    
00440    call_pyevnt();
00441    
00442    if ( fStopHadronsEnabled || fGluinoHadronsEnabled )
00443    {
00444       // call_pygive("MSTJ(1)=1");
00445       call_pygive("MSTJ(14)=1");
00446       int ierr=0;
00447       if ( fStopHadronsEnabled ) 
00448       {
00449          pystfr_(ierr);
00450          if ( ierr != 0 ) // skip failed events
00451          {
00452             event().reset();
00453             return false;
00454          }
00455       }
00456       if ( fGluinoHadronsEnabled ) pyglfr_();
00457    }
00458    
00459    if ( pyint1.mint[50] != 0 ) // skip event if py6 considers it bad
00460    {
00461       event().reset();
00462       return false;
00463    }
00464    
00465    call_pyhepc(1);
00466    event().reset( conv.read_next_event() );
00467    
00468    // this is to deal with post-gen tools & residualDecay() that may reuse PYJETS
00469    //
00470    flushTmpStorage();
00471    fillTmpStorage();
00472       
00473    return true;
00474 }
00475 
00476 bool Pythia6Hadronizer::hadronize()
00477 {
00478    Pythia6Service::InstanceWrapper guard(fPy6Service);  // grab Py6 instance
00479 
00480    FortranCallback::getInstance()->setLHEEvent( lheEvent() );
00481    FortranCallback::getInstance()->resetIterationsPerEvent();
00482    if ( fJetMatching )
00483    {
00484       fJetMatching->resetMatchingStatus() ;
00485       fJetMatching->beforeHadronisation( lheEvent() );
00486    }
00487 
00488    // generate event with Pythia6
00489    //
00490    if ( fStopHadronsEnabled || fGluinoHadronsEnabled )
00491    {
00492       call_pygive("MSTJ(1)=-1");
00493       call_pygive("MSTJ(14)=-1");
00494    }
00495 
00496    call_pyevnt();
00497    
00498    if ( FortranCallback::getInstance()->getIterationsPerEvent() > 1 || 
00499         hepeup_.nup <= 0 || pypars.msti[0] == 1 )
00500    {
00501       // update LHE matching statistics
00502       lheEvent()->count( lhef::LHERunInfo::kSelected );
00503 
00504       event().reset();
00505       return false;
00506    }
00507 
00508    // update LHE matching statistics
00509    //
00510    lheEvent()->count( lhef::LHERunInfo::kAccepted );
00511 
00512    if ( fStopHadronsEnabled || fGluinoHadronsEnabled )
00513    {
00514       call_pygive("MSTJ(1)=1");
00515       call_pygive("MSTJ(14)=1");
00516       int ierr = 0;
00517       if ( fStopHadronsEnabled ) 
00518       {
00519          pystfr_(ierr);
00520          if ( ierr != 0 ) // skip failed events
00521          {
00522             event().reset();
00523             return false;
00524          }
00525       }
00526             
00527       if ( fGluinoHadronsEnabled ) pyglfr_();
00528    }
00529 
00530    if ( pyint1.mint[50] != 0 ) // skip event if py6 considers it bad
00531    {
00532       event().reset();
00533       return false;
00534    }
00535    
00536    call_pyhepc(1);
00537    event().reset( conv.read_next_event() );
00538    
00539    // this is to deal with post-gen tools and/or residualDecay(), that may reuse PYJETS
00540    //
00541    flushTmpStorage();
00542    fillTmpStorage();
00543       
00544    return true;
00545 }
00546 
00547 bool Pythia6Hadronizer::decay()
00548 {
00549    return true;
00550 }
00551 
00552 bool Pythia6Hadronizer::residualDecay()
00553 {
00554    
00555    // event().get()->print();
00556    
00557    Pythia6Service::InstanceWrapper guard(fPy6Service);  // grab Py6 instance
00558    
00559    // int nDocLines = pypars.msti[3];
00560       
00561    int NPartsBeforeDecays = pyjets_local.n ;
00562    int NPartsAfterDecays = event().get()->particles_size();
00563    int barcode = NPartsAfterDecays;
00564       
00565    // JVY: well, in principle, it's not a 100% fair to go up to NPartsBeforeDecays,
00566    // because Photos will attach gamma's to existing vertexes, i.e. in the middle
00567    // of the event rather than at the end; but this will only shift poiters down,
00568    // so we'll be going again over a few "original" particle...
00569    // in the alternative, we may go all the way up to the beginning of the event
00570    // and re-check if anything remains to decay, that's fine even if it'll take
00571    // some extra CPU...
00572    
00573    for ( int ipart=NPartsAfterDecays; ipart>NPartsBeforeDecays; ipart-- )
00574    {
00575       HepMC::GenParticle* part = event().get()->barcode_to_particle( ipart );
00576       int status = part->status();
00577       if ( status != 1 ) continue; // check only "stable" particles, 
00578                                    // as some undecayed may still be marked as such
00579       int pdgid  = part->pdg_id();
00580       int py6ptr = pycomp_( pdgid );
00581       if ( pydat3.mdcy[0][py6ptr-1] != 1 ) continue; // particle is not expected to decay
00582       int py6id = HepPID::translatePDTtoPythia( pdgid );
00583       //
00584       // first, will need to zero out, then fill up PYJETS
00585       // I better do it directly (by hands) rather than via py1ent 
00586       // - to avoid (additional) mass smearing
00587       //
00588       if ( part->momentum().t() <= part->generated_mass() )
00589       {
00590          continue ; // e==m --> 0-momentum, nothing to decay...
00591       }
00592       else
00593       {
00594          pyjets.n = 0;
00595          for ( int i=0; i<5; i++ )
00596          {
00597             pyjets.k[i][0] = 0;
00598             pyjets.p[i][0] = 0.;
00599             pyjets.v[i][0] = 0.;
00600          }
00601          pyjets.k[0][0] = 1;
00602          pyjets.k[1][0] = py6id;
00603          pyjets.p[4][0] = part->generated_mass();
00604          pyjets.p[3][0] = part->momentum().t();
00605          pyjets.p[0][0] = part->momentum().x();
00606          pyjets.p[1][0] = part->momentum().y();
00607          pyjets.p[2][0] = part->momentum().z();
00608          HepMC::GenVertex* prod_vtx = part->production_vertex();
00609          if ( !prod_vtx ) continue; // in principle, should never happen but...
00610          pyjets.v[0][0] = prod_vtx->position().x();
00611          pyjets.v[1][0] = prod_vtx->position().y();
00612          pyjets.v[2][0] = prod_vtx->position().z();
00613          pyjets.v[3][0] = prod_vtx->position().t();
00614          pyjets.v[4][0] = 0.;
00615          pyjets.n = 1;
00616          pyjets.npad = pyjets_local.npad;
00617       }
00618       
00619       // now call Py6 decay routine
00620       //
00621       int parent = 1; // since we always pass to Py6 a single particle
00622       pydecy_( parent );
00623       
00624       // now attach decay products to mother
00625       //
00626       for ( int iprt1=1; iprt1<pyjets.n; iprt1++ )
00627       {
00628          part->set_status( 2 );
00629          
00630          HepMC::GenVertex* DecVtx = new HepMC::GenVertex( HepMC::FourVector(pyjets.v[0][iprt1],
00631                                                                             pyjets.v[1][iprt1],
00632                                                                             pyjets.v[2][iprt1],
00633                                                                             pyjets.v[3][iprt1]) );
00634          DecVtx->add_particle_in( part ); // this will cleanup end_vertex if exists, replace with the new one
00635                                           // I presume (vtx) barcode will be given automatically
00636          
00637          HepMC::FourVector  pmom(pyjets.p[0][iprt1],pyjets.p[1][iprt1],
00638                                  pyjets.p[2][iprt1],pyjets.p[3][iprt1] );
00639          
00640          int dstatus = 0;
00641          if ( pyjets.k[0][iprt1] >= 1 && pyjets.k[0][iprt1] <= 10 )  
00642          {
00643                dstatus = 1;
00644          }
00645          else if ( pyjets.k[0][iprt1] >= 11 && pyjets.k[0][iprt1] <= 20 ) 
00646          {
00647                dstatus = 2;
00648          }
00649          else if ( pyjets.k[0][iprt1] >= 21 && pyjets.k[0][iprt1] <= 30 ) 
00650          {
00651                dstatus = 3;
00652          }
00653          else if ( pyjets.k[0][iprt1] >= 31 && pyjets.k[0][iprt1] <= 100 )
00654          {
00655                dstatus = pyjets.k[0][iprt1];
00656          }
00657          HepMC::GenParticle* daughter = new HepMC::GenParticle(pmom,
00658                                         HepPID::translatePythiatoPDT( pyjets.k[1][iprt1] ),
00659                                         dstatus);
00660          barcode++;
00661          daughter->suggest_barcode( barcode ); 
00662          DecVtx->add_particle_out( daughter );
00663 
00664          int iprt2;
00665          for ( iprt2=iprt1+1; iprt2<pyjets.n; iprt2++ ) // the pointer is shifted by -1, c++ style
00666          {
00667                if ( pyjets.k[2][iprt2] != parent ) 
00668                {
00669                   parent = pyjets.k[2][iprt2];
00670                   break; // another parent particle; reset & break the loop
00671                }
00672                
00673                HepMC::FourVector  pmomN(pyjets.p[0][iprt2],pyjets.p[1][iprt2],
00674                                         pyjets.p[2][iprt2],pyjets.p[3][iprt2] );
00675                
00676                dstatus = 0;
00677                if ( pyjets.k[0][iprt2] >= 1 && pyjets.k[0][iprt2] <= 10 )  
00678                {
00679                   dstatus = 1;
00680                }
00681                else if ( pyjets.k[0][iprt2] >= 11 && pyjets.k[0][iprt2] <= 20 ) 
00682                {
00683                   dstatus = 2;
00684                }
00685                else if ( pyjets.k[0][iprt2] >= 21 && pyjets.k[0][iprt2] <= 30 ) 
00686                {
00687                   dstatus = 3;
00688                }
00689                else if ( pyjets.k[0][iprt2] >= 31 && pyjets.k[0][iprt2] <= 100 )
00690                {
00691                   dstatus = pyjets.k[0][iprt2];
00692                }
00693                HepMC::GenParticle* daughterN = new HepMC::GenParticle(pmomN,
00694                                                HepPID::translatePythiatoPDT( pyjets.k[1][iprt2] ),
00695                                                dstatus);
00696                barcode++;
00697                daughterN->suggest_barcode( barcode ); 
00698                DecVtx->add_particle_out( daughterN );        
00699          }
00700          
00701          iprt1 = iprt2-1; // reset counter such that it doesn't go over the same child more than once
00702                           // don't forget to offset back into c++ counting, as it's already +1 forward
00703 
00704          event().get()->add_vertex( DecVtx );
00705       
00706       }
00707 
00708    }
00709    
00710    // now restore the very original Py6 event record 
00711    //
00712    if ( pyjets_local.n != pyjets.n )
00713    {
00714       // restore pyjets to its state as it was before external decays -
00715       // might have been jammed by action above or by py1ent calls in EvtGen
00716       pyjets.n = pyjets_local.n;
00717       pyjets.npad = pyjets_local.npad;
00718       for ( int ip=0; ip<pyjets_local.n; ip++ )
00719       {
00720          for ( int i=0; i<5; i++ )
00721          {
00722             pyjets.k[i][ip] = pyjets_local.k[i][ip];
00723             pyjets.p[i][ip] = pyjets_local.p[i][ip];
00724             pyjets.v[i][ip] = pyjets_local.v[i][ip];
00725          }
00726       }
00727    }  
00728          
00729    return true;
00730 }
00731 
00732 bool Pythia6Hadronizer::readSettings( int key )
00733 {
00734 
00735    Pythia6Service::InstanceWrapper guard(fPy6Service);  // grab Py6 instance
00736     
00737    fPy6Service->setGeneralParams();   
00738    if ( key == 0 ) fPy6Service->setCSAParams();
00739    fPy6Service->setSLHAParams();
00740 
00741    return true;
00742 
00743 }
00744 
00745 bool Pythia6Hadronizer::initializeForExternalPartons()
00746 {
00747    Pythia6Service::InstanceWrapper guard(fPy6Service);  // grab Py6 instance
00748 
00749    // note: CSA mode is NOT supposed to work with external partons !!!
00750    
00751    // fPy6Service->setGeneralParams();
00752    
00753    fPy6Service->setPYUPDAParams(false);
00754 
00755    FortranCallback::getInstance()->setLHERunInfo( lheRunInfo() );
00756 
00757    if ( fStopHadronsEnabled )
00758    {
00759       // overwrite mstp(111), no matter what
00760       call_pygive("MSTP(111)=0");
00761       pystrhad_();
00762       call_pygive("MWID(302)=0");   // I don't know if this is specific to processing ME/LHE only,
00763       call_pygive("MDCY(302,1)=0"); // or this should also be the case for full event...
00764                                     // anyway, this comes from experience of processing MG events
00765    }
00766    
00767    if ( fGluinoHadronsEnabled )
00768    {
00769       // overwrite mstp(111), no matter what
00770       call_pygive("MSTP(111)=0");
00771       pyglrhad_();
00772       //call_pygive("MWID(309)=0");   
00773       //call_pygive("MDCY(309,1)=0"); 
00774    }
00775    
00776    call_pyinit("USER", "", "", 0.0);
00777 
00778    fPy6Service->setPYUPDAParams(true);
00779 
00780    std::vector<std::string> slha = lheRunInfo()->findHeader("slha");
00781    if (!slha.empty()) {
00782                 edm::LogInfo("Generator|LHEInterface")
00783                         << "Pythia6 hadronisation found an SLHA header, "
00784                         << "will be passed on to Pythia." << std::endl;
00785       fPy6Service->setSLHAFromHeader(slha);   
00786       fPy6Service->closeSLHA();
00787    }
00788 
00789    if ( fJetMatching )
00790    {
00791       fJetMatching->init( lheRunInfo() );
00792 // FIXME: the jet matching routine might not be interested in PS callback
00793       call_pygive("MSTP(143)=1");
00794    }
00795 
00796    return true;
00797 }
00798 
00799 bool Pythia6Hadronizer::initializeForInternalPartons()
00800 {
00801 
00802    Pythia6Service::InstanceWrapper guard(fPy6Service);  // grab Py6 instance
00803    
00804    fPy6Service->setPYUPDAParams(false);
00805    
00806    if ( fStopHadronsEnabled )
00807    {
00808       // overwrite mstp(111), no matter what
00809       call_pygive("MSTP(111)=0");
00810       pystrhad_();
00811    }
00812    
00813    if ( fGluinoHadronsEnabled )
00814    {
00815       // overwrite mstp(111), no matter what
00816       call_pygive("MSTP(111)=0");
00817       pyglrhad_();
00818    }
00819 
00820    if ( fInitialState == PP ) // default
00821    {
00822       call_pyinit("CMS", "p", "p", fCOMEnergy);
00823    }
00824    else if ( fInitialState == PPbar )
00825    {
00826       call_pyinit( "CMS", "p", "pbar", fCOMEnergy);
00827    }
00828    else if ( fInitialState == ElectronPositron )
00829    {
00830       call_pyinit( "CMS", "e+", "e-", fCOMEnergy );
00831    }
00832    else if ( fInitialState == ElectronProton)
00833    {
00834       // set p(1,i) & p(2,i) for the beams in pyjets !
00835       pyjets.p[0][0] = 0.;
00836       pyjets.p[1][0] = 0.;
00837       pyjets.p[2][0] = fBeam1PZ;
00838       pyjets.p[0][1] = 0.;
00839       pyjets.p[1][1] = 0.;
00840       pyjets.p[2][1] = fBeam2PZ;
00841       // call "3mon" frame & 0.0 win
00842       call_pyinit( "3mom", "e-", "p", 0.0 );
00843    }
00844    else if ( fInitialState == PositronProton)
00845    {
00846       // set p(1,i) & p(2,i) for the beams in pyjets !
00847       pyjets.p[0][0] = 0.;
00848       pyjets.p[1][0] = 0.;
00849       pyjets.p[2][0] = fBeam1PZ;
00850       pyjets.p[0][1] = 0.;
00851       pyjets.p[1][1] = 0.;
00852       pyjets.p[2][1] = fBeam2PZ;
00853       // call "3mon" frame & 0.0 win
00854       call_pyinit( "3mom", "e+", "p", 0.0 );
00855    }
00856    else
00857    {
00858       // throw on unknown initial state !
00859       throw edm::Exception(edm::errors::Configuration,"Pythia6Interface") 
00860              <<" UNKNOWN INITIAL STATE. \n The allowed initial states are: PP, PPbar, ElectronPositron, ElectronProton, and PositronProton \n";
00861    }
00862    
00863 
00864    fPy6Service->setPYUPDAParams(true);
00865    
00866    fPy6Service->closeSLHA();
00867    
00868    return true;
00869 }
00870 
00871 bool Pythia6Hadronizer::declareStableParticles( const std::vector<int>& pdg )
00872 {
00873    
00874    for ( unsigned int i=0; i<pdg.size(); i++ )
00875    {
00876       int PyID = HepPID::translatePDTtoPythia( pdg[i] );
00877       // int PyID = pdg[i]; 
00878       int pyCode = pycomp_( PyID );
00879       if ( pyCode > 0 )
00880       {
00881          std::ostringstream pyCard ;
00882          pyCard << "MDCY(" << pyCode << ",1)=0";
00883 /* this is a test printout... 
00884          std::cout << "pdg= " << pdg[i] << " " << pyCard.str() << std::endl; 
00885 */
00886          call_pygive( pyCard.str() );
00887       }
00888    }
00889       
00890    return true;
00891 }
00892 
00893 bool Pythia6Hadronizer::declareSpecialSettings( const std::vector<std::string>& settings )
00894 {
00895    
00896    for ( unsigned int iss=0; iss<settings.size(); iss++ )
00897    {
00898       if ( settings[iss].find("QED-brem-off") == std::string::npos ) continue;
00899       size_t fnd1 = settings[iss].find(":");
00900       if ( fnd1 == std::string::npos ) continue;
00901       
00902       std::string value = settings[iss].substr (fnd1+1);
00903       
00904       if ( value == "all" ) 
00905       {
00906          call_pygive( "MSTJ(41)=3" );
00907       }
00908       else
00909       {
00910          int number = atoi(value.c_str());
00911          int PyID = HepPID::translatePDTtoPythia( number );
00912          int pyCode = pycomp_( PyID );
00913          if ( pyCode > 0 )
00914          {
00915             
00916             // first of all, check if mstj(39) is 0 or if we're trying to override user's setting
00917             // if so, throw an exception and stop, because otherwise the user will get behaviour
00918             // that's different from what she/he expects !
00919             if ( pydat1_.mstj[38] > 0 && pydat1_.mstj[38] != pyCode )
00920             {
00921                throw edm::Exception(edm::errors::Configuration,"Pythia6Interface") 
00922                    << " Fatal conflict: \n mandatory internal directive to set MSTJ(39)=" << pyCode 
00923                    << " overrides user setting MSTJ(39)=" << pydat1_.mstj[38] << " - user will not get expected behaviour \n";         
00924             }
00925             std::ostringstream pyCard ;
00926             pyCard << "MSTJ(39)=" << pyCode ;
00927             call_pygive( pyCard.str() );
00928          }
00929       }
00930    }
00931    
00932    return true;
00933 
00934 }
00935 
00936 void Pythia6Hadronizer::imposeProperTime()
00937 {
00938 
00939    // this is practically a copy/paste of the original code by J.Alcaraz, 
00940    // taken directly from PythiaSource
00941     
00942    int dumm=0;
00943    HepMC::GenEvent::vertex_const_iterator vbegin = event()->vertices_begin();
00944    HepMC::GenEvent::vertex_const_iterator vend = event()->vertices_end();
00945    HepMC::GenEvent::vertex_const_iterator vitr = vbegin;
00946    for (; vitr != vend; ++vitr ) 
00947    {
00948       HepMC::GenVertex::particle_iterator pbegin = (*vitr)->particles_begin(HepMC::children);
00949       HepMC::GenVertex::particle_iterator pend = (*vitr)->particles_end(HepMC::children);
00950       HepMC::GenVertex::particle_iterator pitr = pbegin;
00951       for (; pitr != pend; ++pitr) 
00952       {
00953          if ((*pitr)->end_vertex()) continue;
00954          if ((*pitr)->status()!=1) continue;
00955          
00956          int pdgcode= abs((*pitr)->pdg_id());
00957          // Do nothing if the particle is not expected to decay
00958          if ( pydat3.mdcy[0][pycomp_(pdgcode)-1] !=1 ) continue;
00959 
00960          double ctau = pydat2.pmas[3][pycomp_(pdgcode)-1];
00961          HepMC::FourVector mom = (*pitr)->momentum();
00962          HepMC::FourVector vin = (*vitr)->position();
00963          double x = 0.;
00964          double y = 0.;
00965          double z = 0.;
00966          double t = 0.;
00967          bool decayInRange = false;
00968          while (!decayInRange) 
00969          {
00970             double unif_rand = fPy6Service->call(pyr_, &dumm);
00971             // Value of 0 is excluded, so following line is OK
00972             double proper_length = - ctau * log(unif_rand);
00973             double factor = proper_length/mom.m();
00974             x = vin.x() + factor * mom.px();
00975             y = vin.y() + factor * mom.py();
00976             z = vin.z() + factor * mom.pz();
00977             t = vin.t() + factor * mom.e();
00978             // Decay must be happen outside a cylindrical region
00979             if (pydat1.mstj[21]==4) {
00980                if (std::sqrt(x*x+y*y)>pydat1.parj[72] || fabs(z)>pydat1.parj[73]) decayInRange = true;
00981                // Decay must be happen outside a given sphere
00982                } 
00983                else if (pydat1.mstj[21]==3) {
00984                   if (std::sqrt(x*x+y*y+z*z)>pydat1.parj[71]) decayInRange = true;
00985                } 
00986                // Decay is always OK otherwise
00987                else {
00988                   decayInRange = true;
00989                }
00990          }
00991                   
00992          HepMC::GenVertex* vdec = new HepMC::GenVertex(HepMC::FourVector(x,y,z,t));
00993          event()->add_vertex(vdec);
00994          vdec->add_particle_in((*pitr));
00995       }
00996    }   
00997 
00998    return;
00999    
01000 }
01001 
01002 void Pythia6Hadronizer::statistics()
01003 {
01004 
01005   if ( !runInfo().internalXSec() )
01006   {
01007      // set xsec if not already done (e.g. from LHE cross section collector)
01008      double cs = pypars.pari[0]; // cross section in mb
01009      cs *= 1.0e9; // translate to pb (CMS/Gen "convention" as of May 2009)
01010      runInfo().setInternalXSec( cs );
01011 // FIXME: can we get the xsec statistical error somewhere?
01012   }
01013 
01014   call_pystat(1);
01015   
01016   return;
01017 
01018 }
01019 
01020 const char* Pythia6Hadronizer::classname() const
01021 {
01022    return "gen::Pythia6Hadronizer";
01023 }
01024 
01025 } // namespace gen