CMS 3D CMS Logo

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

Go to the documentation of this file.
00001 #include <algorithm>
00002 #include <functional>
00003 #include <iostream>
00004 #include <sstream>
00005 #include <fstream> 
00006 #include <cmath>
00007 #include <string>
00008 #include <set>
00009 
00010 #include <boost/bind.hpp>
00011 #include <boost/algorithm/string/classification.hpp>
00012 #include <boost/algorithm/string/split.hpp>
00013 
00014 #include <CLHEP/Random/RandomEngine.h>
00015 
00016 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00017 
00018 #include "FWCore/ParameterSet/interface/FileInPath.h"
00019 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00020 
00021 #include "GeneratorInterface/Core/interface/RNDMEngineAccess.h"
00022 
00023 #include "GeneratorInterface/Pythia6Interface/interface/Pythia6Service.h"
00024 #include "GeneratorInterface/Pythia6Interface/interface/Pythia6Declarations.h"
00025 // #include "GeneratorInterface/Core/interface/ParameterCollector.h"
00026 
00027 // This will force the symbols below to be kept, even in the case pythia6
00028 // is an archive library.
00029 //extern "C" void pyexec_(void);
00030 extern "C" void pyedit_(void);
00031 __attribute__((visibility("hidden"))) void dummy()
00032 {
00033   using namespace gen;
00034   int dummy = 0;
00035   double dummy2 = 0;
00036   char * dummy3 = 0;
00037   pyexec_();
00038   pystat_(0);
00039   pyjoin_(dummy, &dummy);
00040   py1ent_(dummy, dummy, dummy2, dummy2, dummy2);
00041   pygive_(dummy3, dummy);
00042   pycomp_(dummy);
00043   pylist_(0);
00044   pyevnt_();
00045   pyedit_();
00046 }
00047 
00048 extern "C"
00049 {
00050    void fioopn_( int* unit, const char* line, int length );
00051    void fioopnw_( int* unit, const char* line, int length );
00052    void fiocls_( int* unit );
00053    void pyslha_( int*, int*, int* );
00054    static int call_pyslha(int mupda, int kforig = 0)
00055    {
00056       int iretrn = 0;
00057       pyslha_(&mupda, &kforig, &iretrn);
00058       return iretrn;
00059    }
00060 
00061    void pyupda_(int*, int*);
00062    static void call_pyupda( int opt, int iunit ){ 
00063      pyupda_( &opt, &iunit ); 
00064    }
00065 
00066    double gen::pyr_(int *idummy)
00067    {
00068       // getInstance will throw if no one used enter/leave
00069       // or this is the wrong caller class, like e.g. Herwig6Instance
00070       Pythia6Service* service = FortranInstance::getInstance<Pythia6Service>();
00071       return service->fRandomEngine->flat(); 
00072    }
00073 }
00074 
00075 using namespace gen;
00076 using namespace edm;
00077 
00078 Pythia6Service* Pythia6Service::fPythia6Owner = 0;
00079 
00080 Pythia6Service::Pythia6Service()
00081   : fRandomEngine(&getEngineReference()), fUnitSLHA(24), fUnitPYUPDA(25)
00082 {
00083 }
00084 
00085 Pythia6Service::Pythia6Service( const ParameterSet& ps )
00086   : fRandomEngine(&getEngineReference()), fUnitSLHA(24), fUnitPYUPDA(25)
00087 {
00088    if (fPythia6Owner)
00089       throw cms::Exception("PythiaError") <<
00090             "Two Pythia6Service instances claiming Pythia6 ownership." <<
00091             std::endl;
00092 
00093    fPythia6Owner = this;
00094 
00095 /*
00096    ParameterCollector collector(ps.getParameter<edm::ParameterSet>("PythiaParameters"));
00097 
00098    fParamGeneral.clear();
00099    fParamCSA.clear();
00100    fParamSLHA.clear();
00101    
00102    fParamGeneral = std::vector<std::string>(collector.begin(), collector.end());
00103    fParamCSA     = std::vector<std::string>(collector.begin("CSAParameters"), collector.end());
00104    fParamSLHA    = std::vector<std::string>(collector.begin("SLHAParameters"), collector.end());
00105 */
00106      
00107 
00108    // Set PYTHIA parameters in a single ParameterSet
00109    //
00110    edm::ParameterSet pythia_params = 
00111       ps.getParameter<edm::ParameterSet>("PythiaParameters") ;
00112       
00113    // read and sort Pythia6 cards
00114    //
00115    std::vector<std::string> setNames =
00116       pythia_params.getParameter<std::vector<std::string> >("parameterSets");
00117       
00118    // std::vector<std::string>  paramLines;
00119    fParamGeneral.clear();
00120    fParamCSA.clear();
00121    fParamSLHA.clear();
00122    fParamPYUPDA.clear();
00123    
00124 
00125    for(std::vector<std::string>::const_iterator iter = setNames.begin();
00126                                                 iter != setNames.end(); ++iter) 
00127    {
00128       std::vector<std::string> lines =
00129          pythia_params.getParameter< std::vector<std::string> >(*iter);
00130 
00131       for(std::vector<std::string>::const_iterator line = lines.begin();
00132                                                    line != lines.end(); ++line ) 
00133       {
00134          if (line->substr(0, 7) == "MRPY(1)")
00135             throw cms::Exception("PythiaError") <<
00136             "Attempted to set random number"
00137             " using Pythia command 'MRPY(1)'."
00138             " Please use the"
00139             " RandomNumberGeneratorService." <<
00140             std::endl;
00141 
00142          if ( *iter == "CSAParameters" )
00143          {
00144             fParamCSA.push_back(*line);
00145          }
00146          else if ( *iter == "SLHAParameters" )
00147          {
00148             fParamSLHA.push_back(*line);
00149          }
00150          else if ( *iter == "PYUPDAParameters" )
00151          {
00152             fParamPYUPDA.push_back(*line);
00153          }
00154          else
00155          {
00156             fParamGeneral.push_back(*line);
00157          }
00158       }
00159    }
00160 }
00161 
00162 Pythia6Service::~Pythia6Service()
00163 {
00164    if (fPythia6Owner == this)
00165       fPythia6Owner = 0;
00166 
00167    fParamGeneral.clear();
00168    fParamCSA.clear();
00169    fParamSLHA.clear();
00170    fParamPYUPDA.clear();
00171 }
00172 
00173 void Pythia6Service::enter()
00174 {
00175    FortranInstance::enter();
00176 
00177    if (!fPythia6Owner) {
00178      edm::LogInfo("Generator|Pythia6Interface") <<
00179           "gen::Pythia6Service is going to initialise Pythia, as no other "
00180           "instace has done so yet, and Pythia service routines have been "
00181           "requested by a dummy instance." << std::endl;
00182 
00183      call_pygive("MSTU(12)=12345");
00184      call_pyinit("NONE", "", "", 0.0);
00185 
00186      fPythia6Owner = this;
00187    }
00188 }
00189 
00190 void Pythia6Service::setGeneralParams()
00191 {
00192    // now pass general config cards 
00193    //
00194    for(std::vector<std::string>::const_iterator iter = fParamGeneral.begin();
00195                                                 iter != fParamGeneral.end(); ++iter)
00196    {
00197       if (!call_pygive(*iter))
00198          throw cms::Exception("PythiaError")
00199          << "Pythia did not accept \""
00200          << *iter << "\"." << std::endl;
00201    }
00202    
00203    return ;
00204 }
00205 
00206 void Pythia6Service::setCSAParams()
00207 {
00208 #define SETCSAPARBUFSIZE 514
00209    char buf[SETCSAPARBUFSIZE];
00210    
00211    txgive_init_();
00212    for(std::vector<std::string>::const_iterator iter = fParamCSA.begin();
00213                                                 iter != fParamCSA.end(); ++iter)
00214    {
00215       // Null pad the string should not be needed because it uses
00216       // read, which will look for \n, but just in case...
00217       for (size_t i = 0; i < SETCSAPARBUFSIZE; ++i)
00218         buf[i] = ' ';
00219       // Skip empty parameters.
00220       if (iter->length() <= 0)
00221         continue;
00222       // Limit the size of the string to something which fits the buffer.
00223       size_t maxSize = iter->length() > (SETCSAPARBUFSIZE-2) ? (SETCSAPARBUFSIZE-2) : iter->length();
00224       strncpy(buf, iter->c_str(), maxSize);
00225       // Add extra \n if missing, otherwise "read" continues reading. 
00226       if (buf[maxSize-1] != '\n')
00227       {
00228          buf[maxSize] = '\n';
00229          // Null terminate in case the string is passed back to C.
00230          // Not sure that is actually needed.
00231          buf[maxSize + 1] = 0;
00232       }
00233       txgive_(buf, iter->length() );
00234    }   
00235    
00236    return ;
00237 #undef SETCSAPARBUFSIZE
00238 }
00239 
00240 void Pythia6Service::openSLHA( const char* file )
00241 {
00242 
00243         std::ostringstream pyCard1 ;
00244         pyCard1 << "IMSS(21)=" << fUnitSLHA;
00245         call_pygive( pyCard1.str() );
00246         std::ostringstream pyCard2 ;
00247         pyCard2 << "IMSS(22)=" << fUnitSLHA;
00248         call_pygive( pyCard2.str() );
00249 
00250         fioopn_( &fUnitSLHA, file, strlen(file) );
00251         
00252         return;
00253 
00254 }
00255 
00256 void Pythia6Service::openPYUPDA( const char* file, bool write_file )
00257 {
00258 
00259         if (write_file) {
00260           std::cout<<"=== WRITING PYUPDA FILE "<<file<<" ==="<<std::endl;
00261           fioopnw_( &fUnitPYUPDA, file, strlen(file) );
00262           // Write Pythia particle table to this card file.
00263           call_pyupda(1, fUnitPYUPDA);
00264         } else {
00265           std::cout<<"=== READING PYUPDA FILE "<<file<<" ==="<<std::endl;
00266           fioopn_( &fUnitPYUPDA, file, strlen(file) );
00267           // Update Pythia particle table with this card file.
00268           call_pyupda(3, fUnitPYUPDA);
00269         }
00270         
00271         return;
00272 
00273 }
00274 
00275 void Pythia6Service::closeSLHA() 
00276 {
00277 
00278    fiocls_(&fUnitSLHA);
00279    
00280    return;
00281 }
00282 
00283 void Pythia6Service::closePYUPDA() 
00284 {
00285 
00286    fiocls_(&fUnitPYUPDA);
00287    
00288    return;
00289 
00290 }
00291 
00292 void Pythia6Service::setSLHAParams()
00293 {
00294    for (std::vector<std::string>::const_iterator iter = fParamSLHA.begin();
00295                                                  iter != fParamSLHA.end(); iter++ )
00296    {
00297 
00298         if( iter->find( "SLHAFILE", 0 ) == std::string::npos ) continue;
00299         std::string::size_type start = iter->find_first_of( "=" ) + 1;
00300         std::string::size_type end = iter->length() - 1;
00301         std::string::size_type temp = iter->find_first_of( "'", start );
00302         if( temp != std::string::npos ) {
00303                         start = temp + 1;
00304                         end = iter->find_last_of( "'" ) - 1;
00305         } 
00306         start = iter->find_first_not_of( " ", start );
00307         end = iter->find_last_not_of( " ", end );
00308         //std::cout << " start, end = " << start << " " << end << std::endl;            
00309         std::string shortfile = iter->substr( start, end - start + 1 );
00310         FileInPath f1( shortfile );
00311         std::string file = f1.fullPath();
00312 
00313 /*
00314         //
00315         // override what might have be given via the external config
00316         //
00317         std::ostringstream pyCard ;
00318         pyCard << "IMSS(21)=" << fUnitSLHA;
00319         call_pygive( pyCard.str() );
00320         pyCard << "IMSS(22)=" << fUnitSLHA;
00321         call_pygive( pyCard.str() );
00322 
00323         fioopn_( &fUnitSLHA, file.c_str(), file.length() );
00324 */
00325 
00326         openSLHA( file.c_str() );
00327 
00328    }
00329    
00330    return;
00331 }
00332 
00333 void Pythia6Service::setPYUPDAParams(bool afterPyinit)
00334 {
00335    std::string shortfile;
00336    bool write_file = false;
00337    bool usePostPyinit = false;
00338 
00339    //   std::cout<<"=== CALLING setPYUPDAParams === "<<afterPyinit<<" "<<fParamPYUPDA.size()<<std::endl;
00340 
00341    // This assumes that PYUPDAFILE only appears once ...
00342 
00343    for (std::vector<std::string>::const_iterator iter = fParamPYUPDA.begin();
00344                                                  iter != fParamPYUPDA.end(); iter++ )
00345    {
00346      //     std::cout<<"PYUPDA check "<<*iter<<std::endl;
00347         if( iter->find( "PYUPDAFILE", 0 ) != std::string::npos ) {
00348           std::string::size_type start = iter->find_first_of( "=" ) + 1;
00349           std::string::size_type end = iter->length() - 1;
00350           std::string::size_type temp = iter->find_first_of( "'", start );
00351           if( temp != std::string::npos ) {
00352             start = temp + 1;
00353             end = iter->find_last_of( "'" ) - 1;
00354           } 
00355           start = iter->find_first_not_of( " ", start );
00356           end = iter->find_last_not_of( " ", end );
00357           //std::cout << " start, end = " << start << " " << end << std::endl;          
00358           shortfile = iter->substr( start, end - start + 1 );
00359         } else if ( iter->find( "PYUPDAWRITE", 0 ) != std::string::npos ) {
00360           write_file = true;
00361         } else if ( iter->find( "PYUPDApostPYINIT", 0 ) != std::string::npos ) {
00362           usePostPyinit = true;
00363         }
00364    }
00365    
00366    if (!shortfile.empty()) {
00367      std::string file;
00368      if (write_file) {
00369        file = shortfile;
00370      } else {
00371        // If reading, get full path to file and require it to exist.
00372        FileInPath f1( shortfile );
00373        file = f1.fullPath();
00374      }
00375 
00376      if (afterPyinit == usePostPyinit || (write_file && afterPyinit)) {
00377        openPYUPDA( file.c_str(), write_file );
00378      }
00379    }
00380 
00381    return;
00382 }
00383 
00384 void Pythia6Service::setSLHAFromHeader( const std::vector<std::string> &lines )
00385 {
00386 
00387         std::set<std::string> blocks;
00388         unsigned int model = 0, subModel = 0;
00389 
00390         const char *fname = std::tmpnam(NULL);
00391         std::ofstream file(fname, std::fstream::out | std::fstream::trunc);
00392         std::string block;
00393         for(std::vector<std::string>::const_iterator iter = lines.begin();
00394             iter != lines.end(); ++iter) {
00395                 file << *iter;
00396 
00397                 std::string line = *iter;
00398                 std::transform(line.begin(), line.end(),
00399                                line.begin(), (int(*)(int))std::toupper);
00400                 std::string::size_type pos = line.find('#');
00401                 if (pos != std::string::npos)
00402                         line.resize(pos);
00403 
00404                 if (line.empty())
00405                         continue;
00406 
00407                 if (!boost::algorithm::is_space()(line[0])) {
00408                         std::vector<std::string> tokens;
00409                         boost::split(tokens, line,
00410                                      boost::algorithm::is_space(),
00411                                      boost::token_compress_on);
00412                         if (!tokens.size())
00413                                 continue;
00414                         block.clear();
00415                         if (tokens.size() < 2)
00416                                 continue;
00417                         if (tokens[0] == "BLOCK") {
00418                                 block = tokens[1];
00419                                 blocks.insert(block);
00420                                 continue;
00421                         }
00422 
00423                         if (tokens[0] == "DECAY") {
00424                                 block = "DECAY";
00425                                 blocks.insert(block);
00426                         }
00427                 } else if (block == "MODSEL") {
00428                         std::istringstream ss(line);
00429                         ss >> model >> subModel;
00430                 } else if (block == "SMINPUTS") {
00431                         std::istringstream ss(line);
00432                         int index;
00433                         double value;
00434                         ss >> index >> value;
00435                         switch(index) {
00436                             case 1:
00437                                 pydat1_.paru[103 - 1] = 1.0 / value;
00438                                 break;
00439                             case 2:
00440                                 pydat1_.paru[105 - 1] = value;
00441                                 break;
00442                             case 4:
00443                                 pydat2_.pmas[0][23 - 1] = value;
00444                                 break;
00445                             case 6:
00446                                 pydat2_.pmas[0][6 - 1] = value;
00447                                 break;
00448                             case 7:
00449                                 pydat2_.pmas[0][15 - 1] = value;
00450                                 break;
00451                         }
00452                 }
00453         }
00454         file.close();
00455 
00456         if (blocks.count("SMINPUTS"))
00457                 pydat1_.paru[102 - 1] = 0.5 - std::sqrt(0.25 -
00458                         pydat1_.paru[0] * M_SQRT1_2 *
00459                         pydat1_.paru[103 - 1] / pydat1_.paru[105 - 1] /
00460                         (pydat2_.pmas[0][23 - 1] * pydat2_.pmas[0][23 - 1]));
00461 
00462 /*
00463         int unit = 24;
00464         fioopn_(&unit, fname, std::strlen(fname));
00465         std::remove(fname);
00466 
00467         call_pygive("IMSS(21)=24");
00468         call_pygive("IMSS(22)=24");
00469 */
00470         
00471         openSLHA( fname ) ;
00472         std::remove( fname );
00473         
00474         if (model ||
00475             blocks.count("HIGMIX") ||
00476             blocks.count("SBOTMIX") ||
00477             blocks.count("STOPMIX") ||
00478             blocks.count("STAUMIX") ||
00479             blocks.count("AMIX") ||
00480             blocks.count("NMIX") ||
00481             blocks.count("UMIX") ||
00482             blocks.count("VMIX"))
00483                 call_pyslha(1);
00484         if (model ||
00485             blocks.count("QNUMBERS") ||
00486             blocks.count("PARTICLE") ||
00487             blocks.count("MINPAR") ||
00488             blocks.count("EXTPAR") ||
00489             blocks.count("SMINPUTS") ||
00490             blocks.count("SMINPUTS"))
00491                 call_pyslha(0);
00492         if (blocks.count("MASS"))
00493                 call_pyslha(5, 0);
00494         if (blocks.count("DECAY"))
00495                 call_pyslha(2);
00496 
00497       return ;
00498 
00499 }