00001
00002
00003
00004
00005
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
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
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
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
00118
00119
00120
00121
00122
00123
00124
00125
00126
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
00151
00152
00153
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
00199 void
00200 ExternalLHEProducer::beginJob()
00201 {
00202 }
00203
00204
00205 void
00206 ExternalLHEProducer::endJob() {
00207
00208 reader_.reset();
00209
00210 }
00211
00212
00213 void
00214 ExternalLHEProducer::beginRun(edm::Run& run, edm::EventSetup const& es)
00215 {
00216
00217
00218
00219 std::ostringstream eventStream;
00220 eventStream << nEvents_;
00221 args_.push_back(eventStream.str());
00222
00223
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
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
00268 runInfoProducts.push_back(new LHERunInfoProduct(*product));
00269 wasMerged = false;
00270
00271 run.put(product);
00272
00273 runInfo.reset();
00274 }
00275
00276 }
00277
00278
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
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
00308 return -1;
00309 }
00310 if (fd > maxfd) {
00311 maxfd = fd;
00312 }
00313 }
00314 if (errno) {
00315
00316 return errno;
00317 }
00318 closedir(dir);
00319 }
00320 #endif
00321
00322 for (fd=3; fd<maxfd+1; fd++) {
00323 if (fd != preserve)
00324 close(fd);
00325 }
00326 return 0;
00327 }
00328
00329
00330 void
00331 ExternalLHEProducer::executeScript()
00332 {
00333
00334
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
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
00364 if (!(rc = closeDescriptors(filedes[1]))) {
00365 execvp(argv[0], argv);
00366 rc = errno;
00367 }
00368 while ((write(filedes[1], &rc, sizeof(int)) == -1) && (errno == EINTR)) {}
00369 _exit(1);
00370 }
00371
00372
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
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
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
00443 void
00444 ExternalLHEProducer::beginLuminosityBlock(edm::LuminosityBlock& lumi, edm::EventSetup const&)
00445 {
00446 }
00447
00448
00449 void
00450 ExternalLHEProducer::endLuminosityBlock(edm::LuminosityBlock&, edm::EventSetup const&)
00451 {
00452 }
00453
00454
00455 void
00456 ExternalLHEProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
00457
00458
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
00490 DEFINE_FWK_MODULE(ExternalLHEProducer);