CMS 3D CMS Logo

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