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
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
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
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
00116
00117
00118
00119
00120
00121
00122
00123
00124
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
00146
00147
00148
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
00194 void
00195 ExternalLHEProducer::beginJob()
00196 {
00197 }
00198
00199
00200 void
00201 ExternalLHEProducer::endJob() {
00202
00203 reader_.reset();
00204
00205 }
00206
00207
00208 void
00209 ExternalLHEProducer::beginRun(edm::Run& run, edm::EventSetup const& es)
00210 {
00211
00212
00213
00214 std::ostringstream eventStream;
00215 eventStream << nEvents_;
00216 args_.push_back(eventStream.str());
00217
00218
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
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
00263 runInfoProducts.push_back(new LHERunInfoProduct(*product));
00264 wasMerged = false;
00265
00266 run.put(product);
00267
00268 runInfo.reset();
00269 }
00270
00271 }
00272
00273
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
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
00303 return -1;
00304 }
00305 if (fd > maxfd) {
00306 maxfd = fd;
00307 }
00308 }
00309 if (errno) {
00310
00311 return errno;
00312 }
00313 closedir(dir);
00314 }
00315 #endif
00316
00317 for (fd=3; fd<maxfd+1; fd++) {
00318 if (fd != preserve)
00319 close(fd);
00320 }
00321 return 0;
00322 }
00323
00324
00325 void
00326 ExternalLHEProducer::executeScript()
00327 {
00328
00329
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
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
00359 if (!(rc = closeDescriptors(filedes[1]))) {
00360 execvp(argv[0], argv);
00361 rc = errno;
00362 }
00363 while ((write(filedes[1], &rc, sizeof(int)) == -1) && (errno == EINTR)) {}
00364 _exit(1);
00365 }
00366
00367
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
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
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
00438 void
00439 ExternalLHEProducer::beginLuminosityBlock(edm::LuminosityBlock& lumi, edm::EventSetup const&)
00440 {
00441 }
00442
00443
00444 void
00445 ExternalLHEProducer::endLuminosityBlock(edm::LuminosityBlock&, edm::EventSetup const&)
00446 {
00447 }
00448
00449
00450 void
00451 ExternalLHEProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
00452
00453
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
00484 DEFINE_FWK_MODULE(ExternalLHEProducer);