CMS 3D CMS Logo

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