CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_4_5_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_2.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    return;
00398 }
00399 
00400 bool Pythia6Hadronizer::generatePartonsAndHadronize()
00401 {
00402    Pythia6Service::InstanceWrapper guard(fPy6Service);  // grab Py6 instance
00403 
00404    FortranCallback::getInstance()->resetIterationsPerEvent();
00405       
00406    // generate event with Pythia6
00407    //
00408    
00409    if ( fStopHadronsEnabled || fGluinoHadronsEnabled )
00410    {
00411       // call_pygive("MSTJ(1)=-1");
00412       call_pygive("MSTJ(14)=-1");
00413    }
00414    
00415    call_pyevnt();
00416    
00417    if ( fStopHadronsEnabled || fGluinoHadronsEnabled )
00418    {
00419       // call_pygive("MSTJ(1)=1");
00420       call_pygive("MSTJ(14)=1");
00421       int ierr=0;
00422       if ( fStopHadronsEnabled ) 
00423       {
00424          pystfr_(ierr);
00425          if ( ierr != 0 ) // skip failed events
00426          {
00427             event().reset();
00428             return false;
00429          }
00430       }
00431       if ( fGluinoHadronsEnabled ) pyglfr_();
00432    }
00433    
00434    if ( pyint1.mint[50] != 0 ) // skip event if py6 considers it bad
00435    {
00436       event().reset();
00437       return false;
00438    }
00439    
00440    call_pyhepc(1);
00441    event().reset( conv.read_next_event() );
00442    
00443    // this is to deal with post-gen tools & residualDecay() that may reuse PYJETS
00444    //
00445    flushTmpStorage();
00446    fillTmpStorage();
00447       
00448    return true;
00449 }
00450 
00451 bool Pythia6Hadronizer::hadronize()
00452 {
00453    Pythia6Service::InstanceWrapper guard(fPy6Service);  // grab Py6 instance
00454 
00455    FortranCallback::getInstance()->setLHEEvent( lheEvent() );
00456    FortranCallback::getInstance()->resetIterationsPerEvent();
00457    if ( fJetMatching )
00458    {
00459       fJetMatching->resetMatchingStatus() ;
00460       fJetMatching->beforeHadronisation( lheEvent() );
00461    }
00462 
00463    // generate event with Pythia6
00464    //
00465    if ( fStopHadronsEnabled || fGluinoHadronsEnabled )
00466    {
00467       call_pygive("MSTJ(1)=-1");
00468       call_pygive("MSTJ(14)=-1");
00469    }
00470 
00471    call_pyevnt();
00472    
00473    if ( FortranCallback::getInstance()->getIterationsPerEvent() > 1 || 
00474         hepeup_.nup <= 0 || pypars.msti[0] == 1 )
00475    {
00476       // update LHE matching statistics
00477       lheEvent()->count( lhef::LHERunInfo::kSelected );
00478 
00479       event().reset();
00480       return false;
00481    }
00482 
00483    // update LHE matching statistics
00484    //
00485    lheEvent()->count( lhef::LHERunInfo::kAccepted );
00486 
00487    if ( fStopHadronsEnabled || fGluinoHadronsEnabled )
00488    {
00489       call_pygive("MSTJ(1)=1");
00490       call_pygive("MSTJ(14)=1");
00491       int ierr = 0;
00492       if ( fStopHadronsEnabled ) 
00493       {
00494          pystfr_(ierr);
00495          if ( ierr != 0 ) // skip failed events
00496          {
00497             event().reset();
00498             return false;
00499          }
00500       }
00501             
00502       if ( fGluinoHadronsEnabled ) pyglfr_();
00503    }
00504 
00505    if ( pyint1.mint[50] != 0 ) // skip event if py6 considers it bad
00506    {
00507       event().reset();
00508       return false;
00509    }
00510    
00511    call_pyhepc(1);
00512    event().reset( conv.read_next_event() );
00513    
00514    // this is to deal with post-gen tools and/or residualDecay(), that may reuse PYJETS
00515    //
00516    flushTmpStorage();
00517    fillTmpStorage();
00518       
00519    return true;
00520 }
00521 
00522 bool Pythia6Hadronizer::decay()
00523 {
00524    return true;
00525 }
00526 
00527 bool Pythia6Hadronizer::residualDecay()
00528 {
00529    
00530    // event().get()->print();
00531    
00532    Pythia6Service::InstanceWrapper guard(fPy6Service);  // grab Py6 instance
00533    
00534    // int nDocLines = pypars.msti[3];
00535       
00536    int NPartsBeforeDecays = pyjets_local.n ;
00537    int NPartsAfterDecays = event().get()->particles_size();
00538    int barcode = NPartsAfterDecays;
00539       
00540    // JVY: well, in principle, it's not a 100% fair to go up to NPartsBeforeDecays,
00541    // because Photos will attach gamma's to existing vertexes, i.e. in the middle
00542    // of the event rather than at the end; but this will only shift poiters down,
00543    // so we'll be going again over a few "original" particle...
00544    // in the alternative, we may go all the way up to the beginning of the event
00545    // and re-check if anything remains to decay, that's fine even if it'll take
00546    // some extra CPU...
00547    
00548    for ( int ipart=NPartsAfterDecays; ipart>NPartsBeforeDecays; ipart-- )
00549    {
00550       HepMC::GenParticle* part = event().get()->barcode_to_particle( ipart );
00551       int status = part->status();
00552       if ( status != 1 ) continue; // check only "stable" particles, 
00553                                    // as some undecayed may still be marked as such
00554       int pdgid  = part->pdg_id();
00555       int py6ptr = pycomp_( pdgid );
00556       if ( pydat3.mdcy[0][py6ptr-1] != 1 ) continue; // particle is not expected to decay
00557       int py6id = HepPID::translatePDTtoPythia( pdgid );
00558       //
00559       // first, will need to zero out, then fill up PYJETS
00560       // I better do it directly (by hands) rather than via py1ent 
00561       // - to avoid (additional) mass smearing
00562       //
00563       if ( part->momentum().t() <= part->generated_mass() )
00564       {
00565          continue ; // e==m --> 0-momentum, nothing to decay...
00566       }
00567       else
00568       {
00569          pyjets.n = 0;
00570          for ( int i=0; i<5; i++ )
00571          {
00572             pyjets.k[i][0] = 0;
00573             pyjets.p[i][0] = 0.;
00574             pyjets.v[i][0] = 0.;
00575          }
00576          pyjets.k[0][0] = 1;
00577          pyjets.k[1][0] = py6id;
00578          pyjets.p[4][0] = part->generated_mass();
00579          pyjets.p[3][0] = part->momentum().t();
00580          pyjets.p[0][0] = part->momentum().x();
00581          pyjets.p[1][0] = part->momentum().y();
00582          pyjets.p[2][0] = part->momentum().z();
00583          HepMC::GenVertex* prod_vtx = part->production_vertex();
00584          if ( !prod_vtx ) continue; // in principle, should never happen but...
00585          pyjets.v[0][0] = prod_vtx->position().x();
00586          pyjets.v[1][0] = prod_vtx->position().y();
00587          pyjets.v[2][0] = prod_vtx->position().z();
00588          pyjets.v[3][0] = prod_vtx->position().t();
00589          pyjets.v[4][0] = 0.;
00590          pyjets.n = 1;
00591          pyjets.npad = pyjets_local.npad;
00592       }
00593       
00594       // now call Py6 decay routine
00595       //
00596       int parent = 1; // since we always pass to Py6 a single particle
00597       pydecy_( parent );
00598       
00599       // now attach decay products to mother
00600       //
00601       for ( int iprt1=1; iprt1<pyjets.n; iprt1++ )
00602       {
00603          part->set_status( 2 );
00604          
00605          HepMC::GenVertex* DecVtx = new HepMC::GenVertex( HepMC::FourVector(pyjets.v[0][iprt1],
00606                                                                             pyjets.v[1][iprt1],
00607                                                                             pyjets.v[2][iprt1],
00608                                                                             pyjets.v[3][iprt1]) );
00609          DecVtx->add_particle_in( part ); // this will cleanup end_vertex if exists, replace with the new one
00610                                           // I presume (vtx) barcode will be given automatically
00611          
00612          HepMC::FourVector  pmom(pyjets.p[0][iprt1],pyjets.p[1][iprt1],
00613                                  pyjets.p[2][iprt1],pyjets.p[3][iprt1] );
00614          
00615          int dstatus = 0;
00616          if ( pyjets.k[0][iprt1] >= 1 && pyjets.k[0][iprt1] <= 10 )  
00617          {
00618                dstatus = 1;
00619          }
00620          else if ( pyjets.k[0][iprt1] >= 11 && pyjets.k[0][iprt1] <= 20 ) 
00621          {
00622                dstatus = 2;
00623          }
00624          else if ( pyjets.k[0][iprt1] >= 21 && pyjets.k[0][iprt1] <= 30 ) 
00625          {
00626                dstatus = 3;
00627          }
00628          else if ( pyjets.k[0][iprt1] >= 31 && pyjets.k[0][iprt1] <= 100 )
00629          {
00630                dstatus = pyjets.k[0][iprt1];
00631          }
00632          HepMC::GenParticle* daughter = new HepMC::GenParticle(pmom,
00633                                         HepPID::translatePythiatoPDT( pyjets.k[1][iprt1] ),
00634                                         dstatus);
00635          barcode++;
00636          daughter->suggest_barcode( barcode ); 
00637          DecVtx->add_particle_out( daughter );
00638 
00639          int iprt2;
00640          for ( iprt2=iprt1+1; iprt2<pyjets.n; iprt2++ ) // the pointer is shifted by -1, c++ style
00641          {
00642                if ( pyjets.k[2][iprt2] != parent ) 
00643                {
00644                   parent = pyjets.k[2][iprt2];
00645                   break; // another parent particle; reset & break the loop
00646                }
00647                
00648                HepMC::FourVector  pmomN(pyjets.p[0][iprt2],pyjets.p[1][iprt2],
00649                                         pyjets.p[2][iprt2],pyjets.p[3][iprt2] );
00650                
00651                dstatus = 0;
00652                if ( pyjets.k[0][iprt2] >= 1 && pyjets.k[0][iprt2] <= 10 )  
00653                {
00654                   dstatus = 1;
00655                }
00656                else if ( pyjets.k[0][iprt2] >= 11 && pyjets.k[0][iprt2] <= 20 ) 
00657                {
00658                   dstatus = 2;
00659                }
00660                else if ( pyjets.k[0][iprt2] >= 21 && pyjets.k[0][iprt2] <= 30 ) 
00661                {
00662                   dstatus = 3;
00663                }
00664                else if ( pyjets.k[0][iprt2] >= 31 && pyjets.k[0][iprt2] <= 100 )
00665                {
00666                   dstatus = pyjets.k[0][iprt2];
00667                }
00668                HepMC::GenParticle* daughterN = new HepMC::GenParticle(pmomN,
00669                                                HepPID::translatePythiatoPDT( pyjets.k[1][iprt2] ),
00670                                                dstatus);
00671                barcode++;
00672                daughterN->suggest_barcode( barcode ); 
00673                DecVtx->add_particle_out( daughterN );        
00674          }
00675          
00676          iprt1 = iprt2-1; // reset counter such that it doesn't go over the same child more than once
00677                           // don't forget to offset back into c++ counting, as it's already +1 forward
00678 
00679          event().get()->add_vertex( DecVtx );
00680       
00681       }
00682 
00683    }
00684    
00685    // now restore the very original Py6 event record 
00686    //
00687    if ( pyjets_local.n != pyjets.n )
00688    {
00689       // restore pyjets to its state as it was before external decays -
00690       // might have been jammed by action above or by py1ent calls in EvtGen
00691       pyjets.n = pyjets_local.n;
00692       pyjets.npad = pyjets_local.npad;
00693       for ( int ip=0; ip<pyjets_local.n; ip++ )
00694       {
00695          for ( int i=0; i<5; i++ )
00696          {
00697             pyjets.k[i][ip] = pyjets_local.k[i][ip];
00698             pyjets.p[i][ip] = pyjets_local.p[i][ip];
00699             pyjets.v[i][ip] = pyjets_local.v[i][ip];
00700          }
00701       }
00702    }  
00703          
00704    return true;
00705 }
00706 
00707 bool Pythia6Hadronizer::readSettings( int key )
00708 {
00709 
00710    Pythia6Service::InstanceWrapper guard(fPy6Service);  // grab Py6 instance
00711     
00712    fPy6Service->setGeneralParams();   
00713    if ( key == 0 ) fPy6Service->setCSAParams();
00714    fPy6Service->setSLHAParams();
00715 
00716    return true;
00717 
00718 }
00719 
00720 bool Pythia6Hadronizer::initializeForExternalPartons()
00721 {
00722    Pythia6Service::InstanceWrapper guard(fPy6Service);  // grab Py6 instance
00723 
00724    // note: CSA mode is NOT supposed to work with external partons !!!
00725    
00726    // fPy6Service->setGeneralParams();
00727    
00728    fPy6Service->setPYUPDAParams(false);
00729 
00730    FortranCallback::getInstance()->setLHERunInfo( lheRunInfo() );
00731 
00732    if ( fStopHadronsEnabled )
00733    {
00734       // overwrite mstp(111), no matter what
00735       call_pygive("MSTP(111)=0");
00736       pystrhad_();
00737       call_pygive("MWID(302)=0");   // I don't know if this is specific to processing ME/LHE only,
00738       call_pygive("MDCY(302,1)=0"); // or this should also be the case for full event...
00739                                     // anyway, this comes from experience of processing MG events
00740    }
00741    
00742    if ( fGluinoHadronsEnabled )
00743    {
00744       // overwrite mstp(111), no matter what
00745       call_pygive("MSTP(111)=0");
00746       pyglrhad_();
00747       //call_pygive("MWID(309)=0");   
00748       //call_pygive("MDCY(309,1)=0"); 
00749    }
00750    
00751    call_pyinit("USER", "", "", 0.0);
00752 
00753    fPy6Service->setPYUPDAParams(true);
00754 
00755    std::vector<std::string> slha = lheRunInfo()->findHeader("slha");
00756    if (!slha.empty()) {
00757                 edm::LogInfo("Generator|LHEInterface")
00758                         << "Pythia6 hadronisation found an SLHA header, "
00759                         << "will be passed on to Pythia." << std::endl;
00760       fPy6Service->setSLHAFromHeader(slha);   
00761       fPy6Service->closeSLHA();
00762    }
00763 
00764    if ( fJetMatching )
00765    {
00766       fJetMatching->init( lheRunInfo() );
00767 // FIXME: the jet matching routine might not be interested in PS callback
00768       call_pygive("MSTP(143)=1");
00769    }
00770 
00771    return true;
00772 }
00773 
00774 bool Pythia6Hadronizer::initializeForInternalPartons()
00775 {
00776 
00777    Pythia6Service::InstanceWrapper guard(fPy6Service);  // grab Py6 instance
00778    
00779    fPy6Service->setPYUPDAParams(false);
00780    
00781    if ( fStopHadronsEnabled )
00782    {
00783       // overwrite mstp(111), no matter what
00784       call_pygive("MSTP(111)=0");
00785       pystrhad_();
00786    }
00787    
00788    if ( fGluinoHadronsEnabled )
00789    {
00790       // overwrite mstp(111), no matter what
00791       call_pygive("MSTP(111)=0");
00792       pyglrhad_();
00793    }
00794 
00795    if ( fInitialState == PP ) // default
00796    {
00797       call_pyinit("CMS", "p", "p", fCOMEnergy);
00798    }
00799    else if ( fInitialState == PPbar )
00800    {
00801       call_pyinit( "CMS", "p", "pbar", fCOMEnergy);
00802    }
00803    else if ( fInitialState == ElectronPositron )
00804    {
00805       call_pyinit( "CMS", "e+", "e-", fCOMEnergy );
00806    }
00807    else if ( fInitialState == ElectronProton)
00808    {
00809       // set p(1,i) & p(2,i) for the beams in pyjets !
00810       pyjets.p[0][0] = 0.;
00811       pyjets.p[1][0] = 0.;
00812       pyjets.p[2][0] = fBeam1PZ;
00813       pyjets.p[0][1] = 0.;
00814       pyjets.p[1][1] = 0.;
00815       pyjets.p[2][1] = fBeam2PZ;
00816       // call "3mon" frame & 0.0 win
00817       call_pyinit( "3mom", "e-", "p", 0.0 );
00818    }
00819    else if ( fInitialState == PositronProton)
00820    {
00821       // set p(1,i) & p(2,i) for the beams in pyjets !
00822       pyjets.p[0][0] = 0.;
00823       pyjets.p[1][0] = 0.;
00824       pyjets.p[2][0] = fBeam1PZ;
00825       pyjets.p[0][1] = 0.;
00826       pyjets.p[1][1] = 0.;
00827       pyjets.p[2][1] = fBeam2PZ;
00828       // call "3mon" frame & 0.0 win
00829       call_pyinit( "3mom", "e+", "p", 0.0 );
00830    }
00831    else
00832    {
00833       // throw on unknown initial state !
00834       throw edm::Exception(edm::errors::Configuration,"Pythia6Interface") 
00835              <<" UNKNOWN INITIAL STATE. \n The allowed initial states are: PP, PPbar, ElectronPositron, ElectronProton, and PositronProton \n";
00836    }
00837    
00838 
00839    fPy6Service->setPYUPDAParams(true);
00840    
00841    fPy6Service->closeSLHA();
00842    
00843    return true;
00844 }
00845 
00846 bool Pythia6Hadronizer::declareStableParticles( const std::vector<int> pdg )
00847 {
00848    
00849    for ( unsigned int i=0; i<pdg.size(); i++ )
00850    {
00851       int PyID = HepPID::translatePDTtoPythia( pdg[i] );
00852       // int PyID = pdg[i]; 
00853       int pyCode = pycomp_( PyID );
00854       if ( pyCode > 0 )
00855       {
00856          std::ostringstream pyCard ;
00857          pyCard << "MDCY(" << pyCode << ",1)=0";
00858 /* this is a test printout... 
00859          std::cout << "pdg= " << pdg[i] << " " << pyCard.str() << std::endl; 
00860 */
00861          call_pygive( pyCard.str() );
00862       }
00863    }
00864       
00865    return true;
00866 }
00867 
00868 bool Pythia6Hadronizer::declareSpecialSettings( const std::vector<std::string> settings )
00869 {
00870    
00871    for ( unsigned int iss=0; iss<settings.size(); iss++ )
00872    {
00873       if ( settings[iss].find("QED-brem-off") == std::string::npos ) continue;
00874       size_t fnd1 = settings[iss].find(":");
00875       if ( fnd1 == std::string::npos ) continue;
00876       
00877       std::string value = settings[iss].substr (fnd1+1);
00878       
00879       if ( value == "all" ) 
00880       {
00881          call_pygive( "MSTJ(41)=3" );
00882       }
00883       else
00884       {
00885          int number = atoi(value.c_str());
00886          int PyID = HepPID::translatePDTtoPythia( number );
00887          int pyCode = pycomp_( PyID );
00888          if ( pyCode > 0 )
00889          {
00890             
00891             // first of all, check if mstj(39) is 0 or if we're trying to override user's setting
00892             // if so, throw an exception and stop, because otherwise the user will get behaviour
00893             // that's different from what she/he expects !
00894             if ( pydat1_.mstj[38] > 0 && pydat1_.mstj[38] != pyCode )
00895             {
00896                throw edm::Exception(edm::errors::Configuration,"Pythia6Interface") 
00897                    << " Fatal conflict: \n mandatory internal directive to set MSTJ(39)=" << pyCode 
00898                    << " overrides user setting MSTJ(39)=" << pydat1_.mstj[38] << " - user will not get expected behaviour \n";         
00899             }
00900             std::ostringstream pyCard ;
00901             pyCard << "MSTJ(39)=" << pyCode ;
00902             call_pygive( pyCard.str() );
00903          }
00904       }
00905    }
00906    
00907    return true;
00908 
00909 }
00910 
00911 void Pythia6Hadronizer::imposeProperTime()
00912 {
00913 
00914    // this is practically a copy/paste of the original code by J.Alcaraz, 
00915    // taken directly from PythiaSource
00916     
00917    int dumm=0;
00918    HepMC::GenEvent::vertex_const_iterator vbegin = event()->vertices_begin();
00919    HepMC::GenEvent::vertex_const_iterator vend = event()->vertices_end();
00920    HepMC::GenEvent::vertex_const_iterator vitr = vbegin;
00921    for (; vitr != vend; ++vitr ) 
00922    {
00923       HepMC::GenVertex::particle_iterator pbegin = (*vitr)->particles_begin(HepMC::children);
00924       HepMC::GenVertex::particle_iterator pend = (*vitr)->particles_end(HepMC::children);
00925       HepMC::GenVertex::particle_iterator pitr = pbegin;
00926       for (; pitr != pend; ++pitr) 
00927       {
00928          if ((*pitr)->end_vertex()) continue;
00929          if ((*pitr)->status()!=1) continue;
00930          
00931          int pdgcode= abs((*pitr)->pdg_id());
00932          // Do nothing if the particle is not expected to decay
00933          if ( pydat3.mdcy[0][pycomp_(pdgcode)-1] !=1 ) continue;
00934 
00935          double ctau = pydat2.pmas[3][pycomp_(pdgcode)-1];
00936          HepMC::FourVector mom = (*pitr)->momentum();
00937          HepMC::FourVector vin = (*vitr)->position();
00938          double x = 0.;
00939          double y = 0.;
00940          double z = 0.;
00941          double t = 0.;
00942          bool decayInRange = false;
00943          while (!decayInRange) 
00944          {
00945             double unif_rand = fPy6Service->call(pyr_, &dumm);
00946             // Value of 0 is excluded, so following line is OK
00947             double proper_length = - ctau * log(unif_rand);
00948             double factor = proper_length/mom.m();
00949             x = vin.x() + factor * mom.px();
00950             y = vin.y() + factor * mom.py();
00951             z = vin.z() + factor * mom.pz();
00952             t = vin.t() + factor * mom.e();
00953             // Decay must be happen outside a cylindrical region
00954             if (pydat1.mstj[21]==4) {
00955                if (std::sqrt(x*x+y*y)>pydat1.parj[72] || fabs(z)>pydat1.parj[73]) decayInRange = true;
00956                // Decay must be happen outside a given sphere
00957                } 
00958                else if (pydat1.mstj[21]==3) {
00959                   if (std::sqrt(x*x+y*y+z*z)>pydat1.parj[71]) decayInRange = true;
00960                } 
00961                // Decay is always OK otherwise
00962                else {
00963                   decayInRange = true;
00964                }
00965          }
00966                   
00967          HepMC::GenVertex* vdec = new HepMC::GenVertex(HepMC::FourVector(x,y,z,t));
00968          event()->add_vertex(vdec);
00969          vdec->add_particle_in((*pitr));
00970       }
00971    }   
00972 
00973    return;
00974    
00975 }
00976 
00977 void Pythia6Hadronizer::statistics()
00978 {
00979 
00980   if ( !runInfo().internalXSec() )
00981   {
00982      // set xsec if not already done (e.g. from LHE cross section collector)
00983      double cs = pypars.pari[0]; // cross section in mb
00984      cs *= 1.0e9; // translate to pb (CMS/Gen "convention" as of May 2009)
00985      runInfo().setInternalXSec( cs );
00986 // FIXME: can we get the xsec statistical error somewhere?
00987   }
00988 
00989   call_pystat(1);
00990   
00991   return;
00992 
00993 }
00994 
00995 const char* Pythia6Hadronizer::classname() const
00996 {
00997    return "gen::Pythia6Hadronizer";
00998 }
00999 
01000 } // namespace gen