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  virtual ~ExternalLHEProducer();
70 
71  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
72 
73 private:
74 
75  virtual void produce(edm::Event&, const edm::EventSetup&) override;
76  virtual void beginRunProduce(edm::Run& run, edm::EventSetup const& es) override;
77  virtual void endRunProduce(edm::Run&, edm::EventSetup const&) override;
78  virtual void preallocThreads(unsigned int) override;
79 
80  int closeDescriptors(int preserve);
81  void executeScript();
82  std::unique_ptr<std::string> readOutput();
83 
84  virtual 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::auto_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().c_str()),
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::InRun>("LHEScriptOutput");
137 
138  produces<LHEEventProduct>();
139  produces<LHERunInfoProduct, edm::InRun>();
140 }
141 
142 
144 {
145 }
146 
147 
148 //
149 // member functions
150 //
151 
152 // ------------ method called with number of threads in job --
153 void
155 {
156  nThreads_ = iThreads;
157 }
158 
159 // ------------ method called to produce the data ------------
160 void
162 {
163  nextEvent();
164  if (!partonLevel) {
165  throw cms::Exception("ExternalLHEProducer") << "No lhe event found in ExternalLHEProducer::produce(). "
166  << "The likely cause is that the lhe file contains fewer events than were requested, which is possible "
167  << "in case of phase space integration or uneweighting efficiency problems.";
168  }
169 
170  std::unique_ptr<LHEEventProduct> product(
171  new LHEEventProduct(*partonLevel->getHEPEUP(),
172  partonLevel->originalXWGTUP())
173  );
174  if (partonLevel->getPDF()) {
175  product->setPDF(*partonLevel->getPDF());
176  }
177  std::for_each(partonLevel->weights().begin(),
178  partonLevel->weights().end(),
179  boost::bind(&LHEEventProduct::addWeight,
180  product.get(), _1));
181  product->setScales(partonLevel->scales());
182  product->setNpLO(partonLevel->npLO());
183  product->setNpNLO(partonLevel->npNLO());
184  std::for_each(partonLevel->getComments().begin(),
185  partonLevel->getComments().end(),
186  boost::bind(&LHEEventProduct::addComment,
187  product.get(), _1));
188 
189  iEvent.put(std::move(product));
190 
191  if (runInfo) {
192  std::auto_ptr<LHERunInfoProduct> product(new LHERunInfoProduct(*runInfo->getHEPRUP()));
193  std::for_each(runInfo->getHeaders().begin(),
194  runInfo->getHeaders().end(),
195  boost::bind(&LHERunInfoProduct::addHeader,
196  product.get(), _1));
197  std::for_each(runInfo->getComments().begin(),
198  runInfo->getComments().end(),
199  boost::bind(&LHERunInfoProduct::addComment,
200  product.get(), _1));
201 
202  if (!runInfoProducts.empty()) {
203  runInfoProducts.front().mergeProduct(*product);
204  if (!wasMerged) {
205  runInfoProducts.pop_front();
206  runInfoProducts.push_front(product);
207  wasMerged = true;
208  }
209  }
210 
211  runInfo.reset();
212  }
213 
214  partonLevel.reset();
215  return;
216 }
217 
218 // ------------ method called when starting to processes a run ------------
219 void
221 {
222 
223  // pass the number of events as previous to last argument
224 
225  std::ostringstream eventStream;
226  eventStream << nEvents_;
227  args_.push_back(eventStream.str());
228 
229  // pass the random number generator seed as last argument
230 
232 
233  if ( ! rng.isAvailable()) {
234  throw cms::Exception("Configuration")
235  << "The ExternalLHEProducer module requires the RandomNumberGeneratorService\n"
236  "which is not present in the configuration file. You must add the service\n"
237  "in the configuration file if you want to run ExternalLHEProducer";
238  }
239  std::ostringstream randomStream;
240  randomStream << rng->mySeed();
241  args_.push_back(randomStream.str());
242 
243  args_.emplace_back(std::to_string(nThreads_));
244 
245  for ( unsigned int iArg = 0; iArg < args_.size() ; iArg++ ) {
246  LogDebug("LHEInputArgs") << "arg [" << iArg << "] = " << args_[iArg];
247  }
248 
249  executeScript();
250 
251  //fill LHEXMLProduct (streaming read directly into compressed buffer to save memory)
252  std::unique_ptr<LHEXMLStringProduct> p(new LHEXMLStringProduct);
253  std::ifstream instream(outputFile_);
254  if (!instream) {
255  throw cms::Exception("OutputOpenError") << "Unable to open script output file " << outputFile_ << ".";
256  }
257  instream.seekg (0, instream.end);
258  int insize = instream.tellg();
259  instream.seekg (0, instream.beg);
260  p->fillCompressedContent(instream, 0.25*insize);
261  instream.close();
262  run.put(std::move(p), "LHEScriptOutput");
263 
264  // LHE C++ classes translation
265  // (read back uncompressed file from disk in streaming mode again to save memory)
266 
267  std::vector<std::string> infiles(1, outputFile_);
268  unsigned int skip = 0;
269  std::auto_ptr<lhef::LHEReader> thisRead(new lhef::LHEReader(infiles, skip));
270  reader_ = thisRead;
271 
272  nextEvent();
273  if (runInfoLast) {
275 
276  std::unique_ptr<LHERunInfoProduct> product(new LHERunInfoProduct(*runInfo->getHEPRUP()));
277  std::for_each(runInfo->getHeaders().begin(),
278  runInfo->getHeaders().end(),
279  boost::bind(&LHERunInfoProduct::addHeader,
280  product.get(), _1));
281  std::for_each(runInfo->getComments().begin(),
282  runInfo->getComments().end(),
283  boost::bind(&LHERunInfoProduct::addComment,
284  product.get(), _1));
285 
286  // keep a copy around in case of merging
287  runInfoProducts.push_back(new LHERunInfoProduct(*product));
288  wasMerged = false;
289 
290  run.put(std::move(product));
291 
292  runInfo.reset();
293  }
294 
295 }
296 
297 // ------------ method called when ending the processing of a run ------------
298 void
300 {
301 
302  if (!runInfoProducts.empty()) {
303  std::unique_ptr<LHERunInfoProduct> product(runInfoProducts.pop_front().release());
304  run.put(std::move(product));
305  }
306 
307  nextEvent();
308  if (partonLevel) {
309  throw cms::Exception("ExternalLHEProducer") << "Error in ExternalLHEProducer::endRunProduce(). "
310  << "Event loop is over, but there are still lhe events to process."
311  << "This could happen if lhe file contains more events than requested. This is never expected to happen.";
312  }
313 
314  reader_.reset();
315 
316  if (unlink(outputFile_.c_str())) {
317  throw cms::Exception("OutputDeleteError") << "Unable to delete original script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
318  }
319 
320 }
321 
322 // ------------ Close all the open file descriptors ------------
323 int
325 {
326  int maxfd = 1024;
327  int fd;
328 #ifdef __linux__
329  DIR * dir;
330  struct dirent *dp;
331  maxfd = preserve;
332  if ((dir = opendir("/proc/self/fd"))) {
333  errno = 0;
334  while ((dp = readdir (dir)) != NULL) {
335  if ((strcmp(dp->d_name, ".") == 0) || (strcmp(dp->d_name, "..") == 0)) {
336  continue;
337  }
338  if (sscanf(dp->d_name, "%d", &fd) != 1) {
339  //throw cms::Exception("closeDescriptors") << "Found unexpected filename in /proc/self/fd: " << dp->d_name;
340  return -1;
341  }
342  if (fd > maxfd) {
343  maxfd = fd;
344  }
345  }
346  if (errno) {
347  //throw cms::Exception("closeDescriptors") << "Unable to determine the number of fd (errno=" << errno << ", " << strerror(errno) << ").";
348  return errno;
349  }
350  closedir(dir);
351  }
352 #endif
353  // TODO: assert for an unreasonable number of fds?
354  for (fd=3; fd<maxfd+1; fd++) {
355  if (fd != preserve)
356  close(fd);
357  }
358  return 0;
359 }
360 
361 // ------------ Execute the script associated with this producer ------------
362 void
364 {
365 
366  // Fork a script, wait until it finishes.
367 
368  int rc = 0, rc2 = 0;
369  int filedes[2], fd_flags;
370  unsigned int argc;
371 
372  if (pipe(filedes)) {
373  throw cms::Exception("Unable to create a new pipe");
374  }
375  FileCloseSentry sentry1(filedes[0]), sentry2(filedes[1]);
376 
377  if ((fd_flags = fcntl(filedes[1], F_GETFD, NULL)) == -1) {
378  throw cms::Exception("ExternalLHEProducer") << "Failed to get pipe file descriptor flags (errno=" << rc << ", " << strerror(rc) << ")";
379  }
380  if (fcntl(filedes[1], F_SETFD, fd_flags | FD_CLOEXEC) == -1) {
381  throw cms::Exception("ExternalLHEProducer") << "Failed to set pipe file descriptor flags (errno=" << rc << ", " << strerror(rc) << ")";
382  }
383 
384  argc = 1 + args_.size();
385  // TODO: assert that we have a reasonable number of arguments
386  char **argv = new char *[argc+1];
387  argv[0] = strdup(scriptName_.c_str());
388  for (unsigned int i=1; i<argc; i++) {
389  argv[i] = strdup(args_[i-1].c_str());
390  }
391  argv[argc] = NULL;
392 
393  pid_t pid = fork();
394  if (pid == 0) {
395  // The child process
396  if (!(rc = closeDescriptors(filedes[1]))) {
397  execvp(argv[0], argv); // If execv returns, we have an error.
398  rc = errno;
399  }
400  while ((write(filedes[1], &rc, sizeof(int)) == -1) && (errno == EINTR)) {}
401  _exit(1);
402  }
403 
404  // Free the arg vector ASAP
405  for (unsigned int i=0; i<args_.size()+1; i++) {
406  free(argv[i]);
407  }
408  delete [] argv;
409 
410  if (pid == -1) {
411  throw cms::Exception("ForkException") << "Unable to fork a child (errno=" << errno << ", " << strerror(errno) << ")";
412  }
413 
414  close(filedes[1]);
415  // If the exec succeeds, the read will fail.
416  while (((rc2 = read(filedes[0], &rc, sizeof(int))) == -1) && (errno == EINTR)) { rc2 = 0; }
417  if ((rc2 == sizeof(int)) && rc) {
418  throw cms::Exception("ExternalLHEProducer") << "Failed to execute script (errno=" << rc << ", " << strerror(rc) << ")";
419  }
420  close(filedes[0]);
421 
422  int status = 0;
423  errno = 0;
424  do {
425  if (waitpid(pid, &status, 0) < 0) {
426  if (errno == EINTR) {
427  continue;
428  } else {
429  throw cms::Exception("ExternalLHEProducer") << "Failed to read child status (errno=" << errno << ", " << strerror(errno) << ")";
430  }
431  }
432  if (WIFSIGNALED(status)) {
433  throw cms::Exception("ExternalLHEProducer") << "Child exited due to signal " << WTERMSIG(status) << ".";
434  }
435  if (WIFEXITED(status)) {
436  rc = WEXITSTATUS(status);
437  break;
438  }
439  } while (true);
440  if (rc) {
441  throw cms::Exception("ExternalLHEProducer") << "Child failed with exit code " << rc << ".";
442  }
443 
444 }
445 
446 // ------------ Read the output script ------------
447 #define BUFSIZE 4096
448 std::unique_ptr<std::string> ExternalLHEProducer::readOutput()
449 {
450  int fd;
451  ssize_t n;
452  char buf[BUFSIZE];
453 
454  if ((fd = open(outputFile_.c_str(), O_RDONLY)) == -1) {
455  throw cms::Exception("OutputOpenError") << "Unable to open script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
456  }
457 
458  std::stringstream ss;
459  while ((n = read(fd, buf, BUFSIZE)) > 0 || (n == -1 && errno == EINTR)) {
460  if (n > 0)
461  ss.write(buf, n);
462  }
463  if (n == -1) {
464  throw cms::Exception("OutputOpenError") << "Unable to read from script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
465  }
466 
467  if (unlink(outputFile_.c_str())) {
468  throw cms::Exception("OutputDeleteError") << "Unable to delete original script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
469  }
470 
471  return std::unique_ptr<std::string>(new std::string(ss.str()));
472 }
473 
474 // ------------ method fills 'descriptions' with the allowed parameters for the module ------------
475 void
477  //The following says we do not know what parameters are allowed so do no validation
478  // Please change this to state exactly what you do use, even if it is no parameters
480  desc.setComment("Executes an external script and places its output file into an EDM collection");
481 
482  edm::FileInPath thePath;
483  desc.add<edm::FileInPath>("scriptName", thePath);
484  desc.add<std::string>("outputFile", "myoutput");
485  desc.add<std::vector<std::string> >("args");
486  desc.add<uint32_t>("numberOfParameters");
487  desc.addUntracked<uint32_t>("nEvents");
488 
489  descriptions.addDefault(desc);
490 }
491 
493 {
494 
495  if (partonLevel)
496  return;
497 
498  partonLevel = reader_->next();
499  if (!partonLevel)
500  return;
501 
502  boost::shared_ptr<lhef::LHERunInfo> runInfoThis = partonLevel->getRunInfo();
503  if (runInfoThis != runInfoLast) {
504  runInfo = runInfoThis;
505  runInfoLast = runInfoThis;
506  }
507 }
508 
509 //define this as a plug-in
#define LogDebug(id)
boost::shared_ptr< lhef::LHEEvent > partonLevel
virtual void beginRunProduce(edm::Run &run, edm::EventSetup const &es) override
int i
Definition: DBlmapReader.cc:9
virtual void endRunProduce(edm::Run &, edm::EventSetup const &) override
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:122
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
virtual 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)
std::auto_ptr< lhef::LHEReader > reader_
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)
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
virtual void preallocThreads(unsigned int) override
void put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Run.h:111
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:42