CMS 3D CMS Logo

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