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/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
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
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
00115
00116
00117
00118
00119
00120
00121
00122
00123
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
00148
00149
00150
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
00196 void
00197 ExternalLHEProducer::endJob() {
00198
00199 reader_.reset();
00200 }
00201
00202
00203 void
00204 ExternalLHEProducer::beginRunProduce(edm::Run& run, edm::EventSetup const& es)
00205 {
00206
00207
00208
00209 std::ostringstream eventStream;
00210 eventStream << nEvents_;
00211 args_.push_back(eventStream.str());
00212
00213
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
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
00258 runInfoProducts.push_back(new LHERunInfoProduct(*product));
00259 wasMerged = false;
00260
00261 run.put(product);
00262
00263 runInfo.reset();
00264 }
00265
00266 }
00267
00268
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
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
00298 return -1;
00299 }
00300 if (fd > maxfd) {
00301 maxfd = fd;
00302 }
00303 }
00304 if (errno) {
00305
00306 return errno;
00307 }
00308 closedir(dir);
00309 }
00310 #endif
00311
00312 for (fd=3; fd<maxfd+1; fd++) {
00313 if (fd != preserve)
00314 close(fd);
00315 }
00316 return 0;
00317 }
00318
00319
00320 void
00321 ExternalLHEProducer::executeScript()
00322 {
00323
00324
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
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
00354 if (!(rc = closeDescriptors(filedes[1]))) {
00355 execvp(argv[0], argv);
00356 rc = errno;
00357 }
00358 while ((write(filedes[1], &rc, sizeof(int)) == -1) && (errno == EINTR)) {}
00359 _exit(1);
00360 }
00361
00362
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
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
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
00433 void
00434 ExternalLHEProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
00435
00436
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
00468 DEFINE_FWK_MODULE(ExternalLHEProducer);