CMS 3D CMS Logo

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