CMS 3D CMS Logo

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