CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_5_3_14/src/GeneratorInterface/LHEInterface/plugins/ExternalLHEProducer.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:    ExternalLHEProducer
00004 // Class:      ExternalLHEProducer
00005 // 
00013 //
00014 // Original Author:  Brian Paul Bockelman,8 R-018,+41227670861,
00015 //         Created:  Fri Oct 21 11:37:26 CEST 2011
00016 // $Id: ExternalLHEProducer.cc,v 1.7 2012/10/26 12:19:48 lenzip Exp $
00017 //
00018 //
00019 
00020 
00021 // system include files
00022 #include <cstdio>
00023 #include <memory>
00024 #include <vector>
00025 #include <string>
00026 #include <unistd.h>
00027 #include <dirent.h>
00028 #include <fcntl.h>
00029 #include <sys/wait.h>
00030 
00031 #include <boost/shared_ptr.hpp>
00032 #include <boost/ptr_container/ptr_deque.hpp>
00033 
00034 // user include files
00035 #include "FWCore/Framework/interface/Frameworkfwd.h"
00036 #include "FWCore/Framework/interface/EDProducer.h"
00037 #include "FWCore/Framework/interface/LuminosityBlock.h"
00038 
00039 #include "FWCore/Framework/interface/Run.h"
00040 #include "FWCore/Framework/interface/Event.h"
00041 #include "FWCore/Framework/interface/MakerMacros.h"
00042 
00043 #include "FWCore/ParameterSet/interface/FileInPath.h"
00044 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00045 
00046 #include "SimDataFormats/GeneratorProducts/interface/LesHouches.h"
00047 #include "SimDataFormats/GeneratorProducts/interface/LHERunInfoProduct.h"
00048 #include "SimDataFormats/GeneratorProducts/interface/LHEEventProduct.h"
00049 #include "SimDataFormats/GeneratorProducts/interface/LHEXMLStringProduct.h"
00050 
00051 #include "GeneratorInterface/LHEInterface/interface/LHERunInfo.h"
00052 #include "GeneratorInterface/LHEInterface/interface/LHEEvent.h"
00053 #include "GeneratorInterface/LHEInterface/interface/LHEReader.h"
00054 
00055 #include "FWCore/ServiceRegistry/interface/Service.h"
00056 #include "FWCore/Utilities/interface/RandomNumberGenerator.h"
00057 
00058 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00059 
00060 //
00061 // class declaration
00062 //
00063 
00064 class ExternalLHEProducer : public edm::EDProducer {
00065 public:
00066   explicit ExternalLHEProducer(const edm::ParameterSet& iConfig);
00067   ~ExternalLHEProducer();
00068   
00069   static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
00070   
00071 private:
00072   virtual void beginJob();
00073   virtual void produce(edm::Event&, const edm::EventSetup&) ;
00074   virtual void endJob();
00075   
00076   virtual void beginRun(edm::Run& run, edm::EventSetup const& es);
00077   virtual void endRun(edm::Run&, edm::EventSetup const&);
00078   virtual void beginLuminosityBlock(edm::LuminosityBlock&, edm::EventSetup const&);
00079   
00080   virtual void endLuminosityBlock(edm::LuminosityBlock&, edm::EventSetup const&);
00081   
00082   int closeDescriptors(int preserve);
00083   void executeScript();
00084   std::auto_ptr<std::string> readOutput();
00085 
00086   virtual void nextEvent();
00087   
00088   // ----------member data ---------------------------
00089   std::string scriptName_;
00090   std::string outputFile_;
00091   std::vector<std::string> args_;
00092   uint32_t npars_;
00093   uint32_t nEvents_;
00094   std::string outputContents_;
00095 
00096   std::auto_ptr<lhef::LHEReader>                reader_;
00097   boost::shared_ptr<lhef::LHERunInfo>   runInfoLast;
00098   boost::shared_ptr<lhef::LHERunInfo>   runInfo;
00099   boost::shared_ptr<lhef::LHEEvent>     partonLevel;
00100   boost::ptr_deque<LHERunInfoProduct>   runInfoProducts;
00101   bool                                  wasMerged;
00102   
00103   class FileCloseSentry : private boost::noncopyable {
00104   public:
00105     explicit FileCloseSentry(int fd) : fd_(fd) {};
00106     
00107     ~FileCloseSentry() {
00108       close(fd_);
00109     }
00110   private:
00111     int fd_;
00112   };
00113  
00114 };
00115 
00116 //
00117 // constants, enums and typedefs
00118 //
00119 
00120 
00121 //
00122 // static data member definitions
00123 //
00124 
00125 //
00126 // constructors and destructor
00127 //
00128 ExternalLHEProducer::ExternalLHEProducer(const edm::ParameterSet& iConfig) :
00129   scriptName_((iConfig.getParameter<edm::FileInPath>("scriptName")).fullPath().c_str()),
00130   outputFile_(iConfig.getParameter<std::string>("outputFile")),
00131   args_(iConfig.getParameter<std::vector<std::string> >("args")),
00132   npars_(iConfig.getParameter<uint32_t>("numberOfParameters")),
00133   nEvents_(iConfig.getParameter<uint32_t>("nEvents"))
00134 {
00135   if (npars_ != args_.size())
00136     throw cms::Exception("ExternalLHEProducer") << "Problem with configuration: " << args_.size() << " script arguments given, expected " << npars_;
00137   produces<LHEXMLStringProduct, edm::InRun>("LHEScriptOutput"); 
00138 
00139   produces<LHEEventProduct>();
00140   produces<LHERunInfoProduct, edm::InRun>();
00141 }
00142 
00143 
00144 ExternalLHEProducer::~ExternalLHEProducer()
00145 {
00146 }
00147 
00148 
00149 //
00150 // member functions
00151 //
00152 
00153 // ------------ method called to produce the data  ------------
00154 void
00155 ExternalLHEProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup)
00156 {
00157   nextEvent();
00158   if (!partonLevel)
00159     return;
00160 
00161   std::auto_ptr<LHEEventProduct> product(new LHEEventProduct(*partonLevel->getHEPEUP()));
00162   if (partonLevel->getPDF())
00163     product->setPDF(*partonLevel->getPDF());
00164   std::for_each(partonLevel->getComments().begin(),
00165                 partonLevel->getComments().end(),
00166                 boost::bind(&LHEEventProduct::addComment,
00167                             product.get(), _1));
00168 
00169   iEvent.put(product);
00170 
00171   if (runInfo) {
00172     std::auto_ptr<LHERunInfoProduct> product(new LHERunInfoProduct(*runInfo->getHEPRUP()));
00173     std::for_each(runInfo->getHeaders().begin(),
00174                   runInfo->getHeaders().end(),
00175                   boost::bind(&LHERunInfoProduct::addHeader,
00176                               product.get(), _1));
00177     std::for_each(runInfo->getComments().begin(),
00178                   runInfo->getComments().end(),
00179                   boost::bind(&LHERunInfoProduct::addComment,
00180                               product.get(), _1));
00181   
00182     if (!runInfoProducts.empty()) {
00183       runInfoProducts.front().mergeProduct(*product);
00184       if (!wasMerged) {
00185         runInfoProducts.pop_front();
00186         runInfoProducts.push_front(product);
00187         wasMerged = true;
00188       }
00189     }
00190   
00191     runInfo.reset();
00192   }
00193   
00194   partonLevel.reset();
00195   return; 
00196 }
00197 
00198 // ------------ method called once each job just before starting event loop  ------------
00199 void 
00200 ExternalLHEProducer::beginJob()
00201 {
00202 }
00203 
00204 // ------------ method called once each job just after ending the event loop  ------------
00205 void 
00206 ExternalLHEProducer::endJob() {
00207 
00208   reader_.reset();
00209 
00210 }
00211 
00212 // ------------ method called when starting to processes a run  ------------
00213 void 
00214 ExternalLHEProducer::beginRun(edm::Run& run, edm::EventSetup const& es)
00215 {
00216 
00217   // pass the number of events as previous to last argument
00218   
00219   std::ostringstream eventStream;
00220   eventStream << nEvents_;
00221   args_.push_back(eventStream.str());
00222 
00223   // pass the random number generator seed as last argument
00224 
00225   edm::Service<edm::RandomNumberGenerator> rng;
00226 
00227   if ( ! rng.isAvailable()) {
00228     throw cms::Exception("Configuration")
00229       << "The ExternalLHEProducer module requires the RandomNumberGeneratorService\n"
00230       "which is not present in the configuration file.  You must add the service\n"
00231       "in the configuration file if you want to run ExternalLHEProducer";
00232   }
00233   std::ostringstream randomStream;
00234   randomStream << rng->mySeed(); 
00235   args_.push_back(randomStream.str());
00236 
00237   for ( unsigned int iArg = 0; iArg < args_.size() ; iArg++ ) {
00238     LogDebug("LHEInputArgs") << "arg [" << iArg << "] = " << args_[iArg];
00239   }
00240 
00241   executeScript();
00242   std::auto_ptr<std::string> localContents = readOutput();
00243   outputContents_ = *localContents;
00244   std::auto_ptr<LHEXMLStringProduct> p(new LHEXMLStringProduct(*localContents));  
00245   run.put(p, "LHEScriptOutput");
00246 
00247   // LHE C++ classes translation
00248 
00249   unsigned int skip = 0;
00250   std::auto_ptr<lhef::LHEReader> thisRead( new lhef::LHEReader(outputContents_, skip ) );
00251   reader_ = thisRead;
00252 
00253   nextEvent();
00254   if (runInfoLast) {
00255     runInfo = runInfoLast;
00256   
00257     std::auto_ptr<LHERunInfoProduct> product(new LHERunInfoProduct(*runInfo->getHEPRUP()));
00258     std::for_each(runInfo->getHeaders().begin(),
00259                   runInfo->getHeaders().end(),
00260                   boost::bind(&LHERunInfoProduct::addHeader,
00261                               product.get(), _1));
00262     std::for_each(runInfo->getComments().begin(),
00263                   runInfo->getComments().end(),
00264                   boost::bind(&LHERunInfoProduct::addComment,
00265                               product.get(), _1));
00266   
00267     // keep a copy around in case of merging
00268     runInfoProducts.push_back(new LHERunInfoProduct(*product));
00269     wasMerged = false;
00270   
00271     run.put(product);
00272   
00273     runInfo.reset();
00274   }
00275 
00276 }
00277 
00278 // ------------ method called when ending the processing of a run  ------------
00279 void 
00280 ExternalLHEProducer::endRun(edm::Run& run, edm::EventSetup const& es)
00281 {
00282 
00283   if (!runInfoProducts.empty()) {
00284     std::auto_ptr<LHERunInfoProduct> product(runInfoProducts.pop_front().release());
00285     run.put(product);
00286   }
00287 
00288 }
00289 
00290 // ------------ Close all the open file descriptors ------------
00291 int
00292 ExternalLHEProducer::closeDescriptors(int preserve)
00293 {
00294   int maxfd = 1024;
00295   int fd;
00296 #ifdef __linux__
00297   DIR * dir;
00298   struct dirent *dp;
00299   maxfd = preserve;
00300   if ((dir = opendir("/proc/self/fd"))) {
00301     errno = 0;
00302     while ((dp = readdir (dir)) != NULL) {
00303       if ((strcmp(dp->d_name, ".") == 0)  || (strcmp(dp->d_name, "..") == 0)) {
00304         continue;
00305       }
00306       if (sscanf(dp->d_name, "%d", &fd) != 1) {
00307         //throw cms::Exception("closeDescriptors") << "Found unexpected filename in /proc/self/fd: " << dp->d_name;
00308         return -1;
00309       }
00310       if (fd > maxfd) {
00311         maxfd = fd;
00312       }
00313     }
00314     if (errno) {
00315       //throw cms::Exception("closeDescriptors") << "Unable to determine the number of fd (errno=" << errno << ", " << strerror(errno) << ").";
00316       return errno;
00317     }
00318     closedir(dir);
00319   }
00320 #endif
00321   // TODO: assert for an unreasonable number of fds?
00322   for (fd=3; fd<maxfd+1; fd++) {
00323     if (fd != preserve)
00324       close(fd);
00325   }
00326   return 0;
00327 }
00328 
00329 // ------------ Execute the script associated with this producer ------------
00330 void 
00331 ExternalLHEProducer::executeScript()
00332 {
00333 
00334   // Fork a script, wait until it finishes.
00335 
00336   int rc = 0, rc2 = 0;
00337   int filedes[2], fd_flags;
00338   unsigned int argc;
00339 
00340   if (pipe(filedes)) {
00341     throw cms::Exception("Unable to create a new pipe");
00342   }
00343   FileCloseSentry sentry1(filedes[0]), sentry2(filedes[1]);
00344 
00345   if ((fd_flags = fcntl(filedes[1], F_GETFD, NULL)) == -1) {
00346     throw cms::Exception("ExternalLHEProducer") << "Failed to get pipe file descriptor flags (errno=" << rc << ", " << strerror(rc) << ")";
00347   }
00348   if (fcntl(filedes[1], F_SETFD, fd_flags | FD_CLOEXEC) == -1) {
00349     throw cms::Exception("ExternalLHEProducer") << "Failed to set pipe file descriptor flags (errno=" << rc << ", " << strerror(rc) << ")";
00350   }
00351 
00352   argc = 1 + args_.size();
00353   // TODO: assert that we have a reasonable number of arguments
00354   char **argv = new char *[argc+1];
00355   argv[0] = strdup(scriptName_.c_str());
00356   for (unsigned int i=1; i<argc; i++) {
00357     argv[i] = strdup(args_[i-1].c_str());
00358   }
00359   argv[argc] = NULL;
00360 
00361   pid_t pid = fork();
00362   if (pid == 0) {
00363     // The child process
00364     if (!(rc = closeDescriptors(filedes[1]))) {
00365       execvp(argv[0], argv); // If execv returns, we have an error.
00366       rc = errno;
00367     }
00368     while ((write(filedes[1], &rc, sizeof(int)) == -1) && (errno == EINTR)) {}
00369     _exit(1);
00370   }
00371 
00372   // Free the arg vector ASAP
00373   for (unsigned int i=0; i<args_.size()+1; i++) {
00374     free(argv[i]);
00375   }
00376   delete [] argv;
00377 
00378   if (pid == -1) {
00379     throw cms::Exception("ForkException") << "Unable to fork a child (errno=" << errno << ", " << strerror(errno) << ")";
00380   }
00381 
00382   close(filedes[1]);
00383   // If the exec succeeds, the read will fail.
00384   while (((rc2 = read(filedes[0], &rc, sizeof(int))) == -1) && (errno == EINTR)) { rc2 = 0; }
00385   if ((rc2 == sizeof(int)) && rc) {
00386     throw cms::Exception("ExternalLHEProducer") << "Failed to execute script (errno=" << rc << ", " << strerror(rc) << ")";
00387   }
00388   close(filedes[0]);
00389 
00390   int status = 0;
00391   errno = 0;
00392   do {
00393     if (waitpid(pid, &status, 0) < 0) {
00394       if (errno == EINTR) {
00395         continue;
00396       } else {
00397         throw cms::Exception("ExternalLHEProducer") << "Failed to read child status (errno=" << errno << ", " << strerror(errno) << ")";
00398       }
00399     }
00400     if (WIFSIGNALED(status)) {
00401       throw cms::Exception("ExternalLHEProducer") << "Child exited due to signal " << WTERMSIG(status) << ".";
00402     }
00403     if (WIFEXITED(status)) {
00404       rc = WEXITSTATUS(status);
00405       break;
00406     }
00407   } while (true);
00408   if (rc) {
00409     throw cms::Exception("ExternalLHEProducer") << "Child failed with exit code " << rc << ".";
00410   }
00411 
00412 }
00413 
00414 // ------------ Read the output script ------------
00415 #define BUFSIZE 4096
00416 std::auto_ptr<std::string> ExternalLHEProducer::readOutput()
00417 {
00418   int fd;
00419   ssize_t n;
00420   char buf[BUFSIZE];
00421 
00422   if ((fd = open(outputFile_.c_str(), O_RDONLY)) == -1) {
00423     throw cms::Exception("OutputOpenError") << "Unable to open script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
00424   }
00425 
00426   std::stringstream ss;
00427   while ((n = read(fd, buf, BUFSIZE)) > 0 || (n == -1 && errno == EINTR)) {
00428     if (n > 0)
00429       ss.write(buf, n);
00430   }
00431   if (n == -1) {
00432     throw cms::Exception("OutputOpenError") << "Unable to read from script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
00433   }
00434 
00435   if (unlink(outputFile_.c_str())) {
00436     throw cms::Exception("OutputDeleteError") << "Unable to delete original script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
00437   }
00438 
00439   return std::auto_ptr<std::string>(new std::string(ss.str()));
00440 }
00441 
00442 // ------------ method called when starting to processes a luminosity block  ------------
00443 void 
00444 ExternalLHEProducer::beginLuminosityBlock(edm::LuminosityBlock& lumi, edm::EventSetup const&)
00445 {
00446 }
00447 
00448 // ------------ method called when ending the processing of a luminosity block  ------------
00449 void 
00450 ExternalLHEProducer::endLuminosityBlock(edm::LuminosityBlock&, edm::EventSetup const&)
00451 {
00452 }
00453 
00454 // ------------ method fills 'descriptions' with the allowed parameters for the module  ------------
00455 void
00456 ExternalLHEProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
00457   //The following says we do not know what parameters are allowed so do no validation
00458   // Please change this to state exactly what you do use, even if it is no parameters
00459   edm::ParameterSetDescription desc;
00460   desc.setComment("Executes an external script and places its output file into an EDM collection");
00461 
00462   edm::FileInPath thePath;
00463   desc.add<edm::FileInPath>("scriptName", thePath);
00464   desc.add<std::string>("outputFile", "myoutput");
00465   desc.add<std::vector<std::string> >("args");
00466   desc.add<uint32_t>("numberOfParameters");
00467   desc.add<uint32_t>("nEvents");
00468 
00469   descriptions.addDefault(desc);
00470 }
00471 
00472 void ExternalLHEProducer::nextEvent()
00473 {
00474 
00475   if (partonLevel)
00476     return;
00477 
00478   partonLevel = reader_->next();
00479   if (!partonLevel)
00480     return;
00481 
00482   boost::shared_ptr<lhef::LHERunInfo> runInfoThis = partonLevel->getRunInfo();
00483   if (runInfoThis != runInfoLast) {
00484     runInfo = runInfoThis;
00485     runInfoLast = runInfoThis;
00486   }
00487 }
00488 
00489 //define this as a plug-in
00490 DEFINE_FWK_MODULE(ExternalLHEProducer);