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