CMS 3D CMS Logo

ExternalLHEProducer.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: ExternalLHEProducer
4 // Class: ExternalLHEProducer
5 //
13 //
14 // Original Author: Brian Paul Bockelman,8 R-018,+41227670861,
15 // Created: Fri Oct 21 11:37:26 CEST 2011
16 //
17 //
18 
19 
20 // system include files
21 #include <cstdio>
22 #include <memory>
23 #include <vector>
24 #include <string>
25 #include <fstream>
26 #include <unistd.h>
27 #include <dirent.h>
28 #include <fcntl.h>
29 #include <sys/wait.h>
30 
31 #include "boost/bind.hpp"
32 #include "boost/shared_ptr.hpp"
33 #include "boost/ptr_container/ptr_deque.hpp"
34 
35 // user include files
39 
43 
46 
51 
55 
58 
60 
61 //
62 // class declaration
63 //
64 
65 class ExternalLHEProducer : public edm::one::EDProducer<edm::BeginRunProducer,
66  edm::EndRunProducer> {
67 public:
68  explicit ExternalLHEProducer(const edm::ParameterSet& iConfig);
69  ~ExternalLHEProducer() override;
70 
71  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
72 
73 private:
74 
75  void produce(edm::Event&, const edm::EventSetup&) override;
76  void beginRunProduce(edm::Run& run, edm::EventSetup const& es) override;
77  void endRunProduce(edm::Run&, edm::EventSetup const&) override;
78  void preallocThreads(unsigned int) override;
79 
80  int closeDescriptors(int preserve);
81  void executeScript();
82  std::unique_ptr<std::string> readOutput();
83 
84  void nextEvent();
85 
86  // ----------member data ---------------------------
89  std::vector<std::string> args_;
90  uint32_t npars_;
91  uint32_t nEvents_;
92  unsigned int nThreads_{1};
94 
95  std::unique_ptr<lhef::LHEReader> reader_;
96  boost::shared_ptr<lhef::LHERunInfo> runInfoLast;
97  boost::shared_ptr<lhef::LHERunInfo> runInfo;
98  boost::shared_ptr<lhef::LHEEvent> partonLevel;
99  boost::ptr_deque<LHERunInfoProduct> runInfoProducts;
100  bool wasMerged;
101 
102  class FileCloseSentry : private boost::noncopyable {
103  public:
104  explicit FileCloseSentry(int fd) : fd_(fd) {};
105 
107  close(fd_);
108  }
109  private:
110  int fd_;
111  };
112 
113 };
114 
115 //
116 // constants, enums and typedefs
117 //
118 
119 
120 //
121 // static data member definitions
122 //
123 
124 //
125 // constructors and destructor
126 //
128  scriptName_((iConfig.getParameter<edm::FileInPath>("scriptName")).fullPath()),
129  outputFile_(iConfig.getParameter<std::string>("outputFile")),
130  args_(iConfig.getParameter<std::vector<std::string> >("args")),
131  npars_(iConfig.getParameter<uint32_t>("numberOfParameters")),
132  nEvents_(iConfig.getUntrackedParameter<uint32_t>("nEvents"))
133 {
134  if (npars_ != args_.size())
135  throw cms::Exception("ExternalLHEProducer") << "Problem with configuration: " << args_.size() << " script arguments given, expected " << npars_;
136  produces<LHEXMLStringProduct, edm::Transition::BeginRun>("LHEScriptOutput");
137 
138  produces<LHEEventProduct>();
139  produces<LHERunInfoProduct, edm::Transition::BeginRun>();
140  produces<LHERunInfoProduct, edm::Transition::EndRun>();
141 }
142 
143 
145 {
146 }
147 
148 
149 //
150 // member functions
151 //
152 
153 // ------------ method called with number of threads in job --
154 void
156 {
157  nThreads_ = iThreads;
158 }
159 
160 // ------------ method called to produce the data ------------
161 void
163 {
164  nextEvent();
165  if (!partonLevel) {
166  throw edm::Exception(edm::errors::EventGenerationFailure) << "No lhe event found in ExternalLHEProducer::produce(). "
167  << "The likely cause is that the lhe file contains fewer events than were requested, which is possible "
168  << "in case of phase space integration or uneweighting efficiency problems.";
169  }
170 
171  std::unique_ptr<LHEEventProduct> product(
172  new LHEEventProduct(*partonLevel->getHEPEUP(),
173  partonLevel->originalXWGTUP())
174  );
175  if (partonLevel->getPDF()) {
176  product->setPDF(*partonLevel->getPDF());
177  }
178  std::for_each(partonLevel->weights().begin(),
179  partonLevel->weights().end(),
180  boost::bind(&LHEEventProduct::addWeight,
181  product.get(), _1));
182  product->setScales(partonLevel->scales());
183  product->setNpLO(partonLevel->npLO());
184  product->setNpNLO(partonLevel->npNLO());
185  std::for_each(partonLevel->getComments().begin(),
186  partonLevel->getComments().end(),
187  boost::bind(&LHEEventProduct::addComment,
188  product.get(), _1));
189 
190  iEvent.put(std::move(product));
191 
192  if (runInfo) {
193  std::auto_ptr<LHERunInfoProduct> product(new LHERunInfoProduct(*runInfo->getHEPRUP()));
194  std::for_each(runInfo->getHeaders().begin(),
195  runInfo->getHeaders().end(),
196  boost::bind(&LHERunInfoProduct::addHeader,
197  product.get(), _1));
198  std::for_each(runInfo->getComments().begin(),
199  runInfo->getComments().end(),
200  boost::bind(&LHERunInfoProduct::addComment,
201  product.get(), _1));
202 
203  if (!runInfoProducts.empty()) {
204  runInfoProducts.front().mergeProduct(*product);
205  if (!wasMerged) {
206  runInfoProducts.pop_front();
207  runInfoProducts.push_front(product);
208  wasMerged = true;
209  }
210  }
211 
212  runInfo.reset();
213  }
214 
215  partonLevel.reset();
216  return;
217 }
218 
219 // ------------ method called when starting to processes a run ------------
220 void
222 {
223 
224  // pass the number of events as previous to last argument
225 
226  std::ostringstream eventStream;
227  eventStream << nEvents_;
228  // args_.push_back(eventStream.str());
229  args_.insert(args_.begin() + 1, eventStream.str());
230 
231  // pass the random number generator seed as last argument
232 
234 
235  if ( ! rng.isAvailable()) {
236  throw cms::Exception("Configuration")
237  << "The ExternalLHEProducer module requires the RandomNumberGeneratorService\n"
238  "which is not present in the configuration file. You must add the service\n"
239  "in the configuration file if you want to run ExternalLHEProducer";
240  }
241  std::ostringstream randomStream;
242  randomStream << rng->mySeed();
243  // args_.push_back(randomStream.str());
244  args_.insert(args_.begin() + 2, randomStream.str());
245 
246  // args_.emplace_back(std::to_string(nThreads_));
247  args_.insert(args_.begin() + 3, std::to_string(nThreads_));
248 
249  for ( unsigned int iArg = 0; iArg < args_.size() ; iArg++ ) {
250  LogDebug("LHEInputArgs") << "arg [" << iArg << "] = " << args_[iArg];
251  }
252 
253  executeScript();
254 
255  //fill LHEXMLProduct (streaming read directly into compressed buffer to save memory)
256  std::unique_ptr<LHEXMLStringProduct> p(new LHEXMLStringProduct);
257  std::ifstream instream(outputFile_);
258  if (!instream) {
259  throw cms::Exception("OutputOpenError") << "Unable to open script output file " << outputFile_ << ".";
260  }
261  instream.seekg (0, instream.end);
262  int insize = instream.tellg();
263  instream.seekg (0, instream.beg);
264  p->fillCompressedContent(instream, 0.25*insize);
265  instream.close();
266  run.put(std::move(p), "LHEScriptOutput");
267 
268  // LHE C++ classes translation
269  // (read back uncompressed file from disk in streaming mode again to save memory)
270 
271  std::vector<std::string> infiles(1, outputFile_);
272  unsigned int skip = 0;
273  reader_ = std::make_unique<lhef::LHEReader>(infiles, skip);
274 
275  nextEvent();
276  if (runInfoLast) {
278 
279  std::unique_ptr<LHERunInfoProduct> product(new LHERunInfoProduct(*runInfo->getHEPRUP()));
280  std::for_each(runInfo->getHeaders().begin(),
281  runInfo->getHeaders().end(),
282  boost::bind(&LHERunInfoProduct::addHeader,
283  product.get(), _1));
284  std::for_each(runInfo->getComments().begin(),
285  runInfo->getComments().end(),
286  boost::bind(&LHERunInfoProduct::addComment,
287  product.get(), _1));
288 
289  // keep a copy around in case of merging
290  runInfoProducts.push_back(new LHERunInfoProduct(*product));
291  wasMerged = false;
292 
293  run.put(std::move(product));
294 
295  runInfo.reset();
296  }
297 
298 }
299 
300 // ------------ method called when ending the processing of a run ------------
301 void
303 {
304 
305  if (!runInfoProducts.empty()) {
306  std::unique_ptr<LHERunInfoProduct> product(runInfoProducts.pop_front().release());
307  run.put(std::move(product));
308  }
309 
310  nextEvent();
311  if (partonLevel) {
312  throw edm::Exception(edm::errors::EventGenerationFailure) << "Error in ExternalLHEProducer::endRunProduce(). "
313  << "Event loop is over, but there are still lhe events to process."
314  << "This could happen if lhe file contains more events than requested. This is never expected to happen.";
315  }
316 
317  reader_.reset();
318 
319  if (unlink(outputFile_.c_str())) {
320  throw cms::Exception("OutputDeleteError") << "Unable to delete original script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
321  }
322 
323 }
324 
325 // ------------ Close all the open file descriptors ------------
326 int
328 {
329  int maxfd = 1024;
330  int fd;
331 #ifdef __linux__
332  DIR * dir;
333  struct dirent *dp;
334  maxfd = preserve;
335  if ((dir = opendir("/proc/self/fd"))) {
336  errno = 0;
337  while ((dp = readdir (dir)) != nullptr) {
338  if ((strcmp(dp->d_name, ".") == 0) || (strcmp(dp->d_name, "..") == 0)) {
339  continue;
340  }
341  if (sscanf(dp->d_name, "%d", &fd) != 1) {
342  //throw cms::Exception("closeDescriptors") << "Found unexpected filename in /proc/self/fd: " << dp->d_name;
343  return -1;
344  }
345  if (fd > maxfd) {
346  maxfd = fd;
347  }
348  }
349  if (errno) {
350  //throw cms::Exception("closeDescriptors") << "Unable to determine the number of fd (errno=" << errno << ", " << strerror(errno) << ").";
351  return errno;
352  }
353  closedir(dir);
354  }
355 #endif
356  // TODO: assert for an unreasonable number of fds?
357  for (fd=3; fd<maxfd+1; fd++) {
358  if (fd != preserve)
359  close(fd);
360  }
361  return 0;
362 }
363 
364 // ------------ Execute the script associated with this producer ------------
365 void
367 {
368 
369  // Fork a script, wait until it finishes.
370 
371  int rc = 0, rc2 = 0;
372  int filedes[2], fd_flags;
373  unsigned int argc;
374 
375  if (pipe(filedes)) {
376  throw cms::Exception("Unable to create a new pipe");
377  }
378  FileCloseSentry sentry1(filedes[0]), sentry2(filedes[1]);
379 
380  if ((fd_flags = fcntl(filedes[1], F_GETFD, NULL)) == -1) {
381  throw cms::Exception("ExternalLHEProducer") << "Failed to get pipe file descriptor flags (errno=" << rc << ", " << strerror(rc) << ")";
382  }
383  if (fcntl(filedes[1], F_SETFD, fd_flags | FD_CLOEXEC) == -1) {
384  throw cms::Exception("ExternalLHEProducer") << "Failed to set pipe file descriptor flags (errno=" << rc << ", " << strerror(rc) << ")";
385  }
386 
387  argc = 1 + args_.size();
388  // TODO: assert that we have a reasonable number of arguments
389  char **argv = new char *[argc+1];
390  argv[0] = strdup(scriptName_.c_str());
391  for (unsigned int i=1; i<argc; i++) {
392  argv[i] = strdup(args_[i-1].c_str());
393  }
394  argv[argc] = nullptr;
395 
396  pid_t pid = fork();
397  if (pid == 0) {
398  // The child process
399  if (!(rc = closeDescriptors(filedes[1]))) {
400  execvp(argv[0], argv); // If execv returns, we have an error.
401  rc = errno;
402  }
403  while ((write(filedes[1], &rc, sizeof(int)) == -1) && (errno == EINTR)) {}
404  _exit(1);
405  }
406 
407  // Free the arg vector ASAP
408  for (unsigned int i=0; i<args_.size()+1; i++) {
409  free(argv[i]);
410  }
411  delete [] argv;
412 
413  if (pid == -1) {
414  throw cms::Exception("ForkException") << "Unable to fork a child (errno=" << errno << ", " << strerror(errno) << ")";
415  }
416 
417  close(filedes[1]);
418  // If the exec succeeds, the read will fail.
419  while (((rc2 = read(filedes[0], &rc, sizeof(int))) == -1) && (errno == EINTR)) { rc2 = 0; }
420  if ((rc2 == sizeof(int)) && rc) {
421  throw cms::Exception("ExternalLHEProducer") << "Failed to execute script (errno=" << rc << ", " << strerror(rc) << ")";
422  }
423  close(filedes[0]);
424 
425  int status = 0;
426  errno = 0;
427  do {
428  if (waitpid(pid, &status, 0) < 0) {
429  if (errno == EINTR) {
430  continue;
431  } else {
432  throw cms::Exception("ExternalLHEProducer") << "Failed to read child status (errno=" << errno << ", " << strerror(errno) << ")";
433  }
434  }
435  if (WIFSIGNALED(status)) {
436  throw cms::Exception("ExternalLHEProducer") << "Child exited due to signal " << WTERMSIG(status) << ".";
437  }
438  if (WIFEXITED(status)) {
439  rc = WEXITSTATUS(status);
440  break;
441  }
442  } while (true);
443  if (rc) {
444  throw cms::Exception("ExternalLHEProducer") << "Child failed with exit code " << rc << ".";
445  }
446 
447 }
448 
449 // ------------ Read the output script ------------
450 #define BUFSIZE 4096
451 std::unique_ptr<std::string> ExternalLHEProducer::readOutput()
452 {
453  int fd;
454  ssize_t n;
455  char buf[BUFSIZE];
456 
457  if ((fd = open(outputFile_.c_str(), O_RDONLY)) == -1) {
458  throw cms::Exception("OutputOpenError") << "Unable to open script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
459  }
460 
461  std::stringstream ss;
462  while ((n = read(fd, buf, BUFSIZE)) > 0 || (n == -1 && errno == EINTR)) {
463  if (n > 0)
464  ss.write(buf, n);
465  }
466  if (n == -1) {
467  throw cms::Exception("OutputOpenError") << "Unable to read from script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
468  }
469 
470  if (unlink(outputFile_.c_str())) {
471  throw cms::Exception("OutputDeleteError") << "Unable to delete original script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
472  }
473 
474  return std::unique_ptr<std::string>(new std::string(ss.str()));
475 }
476 
477 // ------------ method fills 'descriptions' with the allowed parameters for the module ------------
478 void
480  //The following says we do not know what parameters are allowed so do no validation
481  // Please change this to state exactly what you do use, even if it is no parameters
483  desc.setComment("Executes an external script and places its output file into an EDM collection");
484 
485  edm::FileInPath thePath;
486  desc.add<edm::FileInPath>("scriptName", thePath);
487  desc.add<std::string>("outputFile", "myoutput");
488  desc.add<std::vector<std::string> >("args");
489  desc.add<uint32_t>("numberOfParameters");
490  desc.addUntracked<uint32_t>("nEvents");
491 
492  descriptions.addDefault(desc);
493 }
494 
496 {
497 
498  if (partonLevel)
499  return;
500 
501  if(not reader_) { return;}
502  partonLevel = reader_->next();
503  if (!partonLevel)
504  return;
505 
506  boost::shared_ptr<lhef::LHERunInfo> runInfoThis = partonLevel->getRunInfo();
507  if (runInfoThis != runInfoLast) {
508  runInfo = runInfoThis;
509  runInfoLast = runInfoThis;
510  }
511 }
512 
513 //define this as a plug-in
#define LogDebug(id)
boost::shared_ptr< lhef::LHEEvent > partonLevel
void beginRunProduce(edm::Run &run, edm::EventSetup const &es) override
void endRunProduce(edm::Run &, edm::EventSetup const &) override
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:136
std::unique_ptr< std::string > readOutput()
ParameterDescriptionBase * addUntracked(U const &iLabel, T const &value)
void addHeader(const Header &header)
void addComment(const std::string &line)
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:17
void produce(edm::Event &, const edm::EventSetup &) override
void addWeight(const WGT &wgt)
#define NULL
Definition: scimark2.h:8
std::vector< std::string > args_
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
boost::shared_ptr< lhef::LHERunInfo > runInfoLast
void setComment(std::string const &value)
int closeDescriptors(int preserve)
int iEvent
Definition: GenABIO.cc:230
void addDefault(ParameterSetDescription const &psetDescription)
std::unique_ptr< lhef::LHEReader > reader_
bool isAvailable() const
Definition: Service.h:46
#define BUFSIZE
def pipe(cmdline, input=None)
Definition: pipe.py:5
ParameterDescriptionBase * add(U const &iLabel, T const &value)
virtual std::uint32_t mySeed() const =0
boost::shared_ptr< lhef::LHERunInfo > runInfo
void addComment(const std::string &line)
auto dp
Definition: deltaR.h:22
void preallocThreads(unsigned int) override
void put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Run.h:114
HLT enums.
boost::ptr_deque< LHERunInfoProduct > runInfoProducts
dbl *** dir
Definition: mlp_gen.cc:35
def write(self, setup)
ExternalLHEProducer(const edm::ParameterSet &iConfig)
def move(src, dest)
Definition: eostools.py:510
Definition: Run.h:43