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::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 cms::Exception("ExternalLHEProducer") << "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 
230  // pass the random number generator seed as last argument
231 
233 
234  if ( ! rng.isAvailable()) {
235  throw cms::Exception("Configuration")
236  << "The ExternalLHEProducer module requires the RandomNumberGeneratorService\n"
237  "which is not present in the configuration file. You must add the service\n"
238  "in the configuration file if you want to run ExternalLHEProducer";
239  }
240  std::ostringstream randomStream;
241  randomStream << rng->mySeed();
242  args_.push_back(randomStream.str());
243 
244  args_.emplace_back(std::to_string(nThreads_));
245 
246  for ( unsigned int iArg = 0; iArg < args_.size() ; iArg++ ) {
247  LogDebug("LHEInputArgs") << "arg [" << iArg << "] = " << args_[iArg];
248  }
249 
250  executeScript();
251 
252  //fill LHEXMLProduct (streaming read directly into compressed buffer to save memory)
253  std::unique_ptr<LHEXMLStringProduct> p(new LHEXMLStringProduct);
254  std::ifstream instream(outputFile_);
255  if (!instream) {
256  throw cms::Exception("OutputOpenError") << "Unable to open script output file " << outputFile_ << ".";
257  }
258  instream.seekg (0, instream.end);
259  int insize = instream.tellg();
260  instream.seekg (0, instream.beg);
261  p->fillCompressedContent(instream, 0.25*insize);
262  instream.close();
263  run.put(std::move(p), "LHEScriptOutput");
264 
265  // LHE C++ classes translation
266  // (read back uncompressed file from disk in streaming mode again to save memory)
267 
268  std::vector<std::string> infiles(1, outputFile_);
269  unsigned int skip = 0;
270  std::auto_ptr<lhef::LHEReader> thisRead(new lhef::LHEReader(infiles, skip));
271  reader_ = thisRead;
272 
273  nextEvent();
274  if (runInfoLast) {
276 
277  std::unique_ptr<LHERunInfoProduct> product(new LHERunInfoProduct(*runInfo->getHEPRUP()));
278  std::for_each(runInfo->getHeaders().begin(),
279  runInfo->getHeaders().end(),
280  boost::bind(&LHERunInfoProduct::addHeader,
281  product.get(), _1));
282  std::for_each(runInfo->getComments().begin(),
283  runInfo->getComments().end(),
284  boost::bind(&LHERunInfoProduct::addComment,
285  product.get(), _1));
286 
287  // keep a copy around in case of merging
288  runInfoProducts.push_back(new LHERunInfoProduct(*product));
289  wasMerged = false;
290 
291  run.put(std::move(product));
292 
293  runInfo.reset();
294  }
295 
296 }
297 
298 // ------------ method called when ending the processing of a run ------------
299 void
301 {
302 
303  if (!runInfoProducts.empty()) {
304  std::unique_ptr<LHERunInfoProduct> product(runInfoProducts.pop_front().release());
305  run.put(std::move(product));
306  }
307 
308  nextEvent();
309  if (partonLevel) {
310  throw cms::Exception("ExternalLHEProducer") << "Error in ExternalLHEProducer::endRunProduce(). "
311  << "Event loop is over, but there are still lhe events to process."
312  << "This could happen if lhe file contains more events than requested. This is never expected to happen.";
313  }
314 
315  reader_.reset();
316 
317  if (unlink(outputFile_.c_str())) {
318  throw cms::Exception("OutputDeleteError") << "Unable to delete original script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
319  }
320 
321 }
322 
323 // ------------ Close all the open file descriptors ------------
324 int
326 {
327  int maxfd = 1024;
328  int fd;
329 #ifdef __linux__
330  DIR * dir;
331  struct dirent *dp;
332  maxfd = preserve;
333  if ((dir = opendir("/proc/self/fd"))) {
334  errno = 0;
335  while ((dp = readdir (dir)) != NULL) {
336  if ((strcmp(dp->d_name, ".") == 0) || (strcmp(dp->d_name, "..") == 0)) {
337  continue;
338  }
339  if (sscanf(dp->d_name, "%d", &fd) != 1) {
340  //throw cms::Exception("closeDescriptors") << "Found unexpected filename in /proc/self/fd: " << dp->d_name;
341  return -1;
342  }
343  if (fd > maxfd) {
344  maxfd = fd;
345  }
346  }
347  if (errno) {
348  //throw cms::Exception("closeDescriptors") << "Unable to determine the number of fd (errno=" << errno << ", " << strerror(errno) << ").";
349  return errno;
350  }
351  closedir(dir);
352  }
353 #endif
354  // TODO: assert for an unreasonable number of fds?
355  for (fd=3; fd<maxfd+1; fd++) {
356  if (fd != preserve)
357  close(fd);
358  }
359  return 0;
360 }
361 
362 // ------------ Execute the script associated with this producer ------------
363 void
365 {
366 
367  // Fork a script, wait until it finishes.
368 
369  int rc = 0, rc2 = 0;
370  int filedes[2], fd_flags;
371  unsigned int argc;
372 
373  if (pipe(filedes)) {
374  throw cms::Exception("Unable to create a new pipe");
375  }
376  FileCloseSentry sentry1(filedes[0]), sentry2(filedes[1]);
377 
378  if ((fd_flags = fcntl(filedes[1], F_GETFD, NULL)) == -1) {
379  throw cms::Exception("ExternalLHEProducer") << "Failed to get pipe file descriptor flags (errno=" << rc << ", " << strerror(rc) << ")";
380  }
381  if (fcntl(filedes[1], F_SETFD, fd_flags | FD_CLOEXEC) == -1) {
382  throw cms::Exception("ExternalLHEProducer") << "Failed to set pipe file descriptor flags (errno=" << rc << ", " << strerror(rc) << ")";
383  }
384 
385  argc = 1 + args_.size();
386  // TODO: assert that we have a reasonable number of arguments
387  char **argv = new char *[argc+1];
388  argv[0] = strdup(scriptName_.c_str());
389  for (unsigned int i=1; i<argc; i++) {
390  argv[i] = strdup(args_[i-1].c_str());
391  }
392  argv[argc] = NULL;
393 
394  pid_t pid = fork();
395  if (pid == 0) {
396  // The child process
397  if (!(rc = closeDescriptors(filedes[1]))) {
398  execvp(argv[0], argv); // If execv returns, we have an error.
399  rc = errno;
400  }
401  while ((write(filedes[1], &rc, sizeof(int)) == -1) && (errno == EINTR)) {}
402  _exit(1);
403  }
404 
405  // Free the arg vector ASAP
406  for (unsigned int i=0; i<args_.size()+1; i++) {
407  free(argv[i]);
408  }
409  delete [] argv;
410 
411  if (pid == -1) {
412  throw cms::Exception("ForkException") << "Unable to fork a child (errno=" << errno << ", " << strerror(errno) << ")";
413  }
414 
415  close(filedes[1]);
416  // If the exec succeeds, the read will fail.
417  while (((rc2 = read(filedes[0], &rc, sizeof(int))) == -1) && (errno == EINTR)) { rc2 = 0; }
418  if ((rc2 == sizeof(int)) && rc) {
419  throw cms::Exception("ExternalLHEProducer") << "Failed to execute script (errno=" << rc << ", " << strerror(rc) << ")";
420  }
421  close(filedes[0]);
422 
423  int status = 0;
424  errno = 0;
425  do {
426  if (waitpid(pid, &status, 0) < 0) {
427  if (errno == EINTR) {
428  continue;
429  } else {
430  throw cms::Exception("ExternalLHEProducer") << "Failed to read child status (errno=" << errno << ", " << strerror(errno) << ")";
431  }
432  }
433  if (WIFSIGNALED(status)) {
434  throw cms::Exception("ExternalLHEProducer") << "Child exited due to signal " << WTERMSIG(status) << ".";
435  }
436  if (WIFEXITED(status)) {
437  rc = WEXITSTATUS(status);
438  break;
439  }
440  } while (true);
441  if (rc) {
442  throw cms::Exception("ExternalLHEProducer") << "Child failed with exit code " << rc << ".";
443  }
444 
445 }
446 
447 // ------------ Read the output script ------------
448 #define BUFSIZE 4096
449 std::unique_ptr<std::string> ExternalLHEProducer::readOutput()
450 {
451  int fd;
452  ssize_t n;
453  char buf[BUFSIZE];
454 
455  if ((fd = open(outputFile_.c_str(), O_RDONLY)) == -1) {
456  throw cms::Exception("OutputOpenError") << "Unable to open script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
457  }
458 
459  std::stringstream ss;
460  while ((n = read(fd, buf, BUFSIZE)) > 0 || (n == -1 && errno == EINTR)) {
461  if (n > 0)
462  ss.write(buf, n);
463  }
464  if (n == -1) {
465  throw cms::Exception("OutputOpenError") << "Unable to read from script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
466  }
467 
468  if (unlink(outputFile_.c_str())) {
469  throw cms::Exception("OutputDeleteError") << "Unable to delete original script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
470  }
471 
472  return std::unique_ptr<std::string>(new std::string(ss.str()));
473 }
474 
475 // ------------ method fills 'descriptions' with the allowed parameters for the module ------------
476 void
478  //The following says we do not know what parameters are allowed so do no validation
479  // Please change this to state exactly what you do use, even if it is no parameters
481  desc.setComment("Executes an external script and places its output file into an EDM collection");
482 
483  edm::FileInPath thePath;
484  desc.add<edm::FileInPath>("scriptName", thePath);
485  desc.add<std::string>("outputFile", "myoutput");
486  desc.add<std::vector<std::string> >("args");
487  desc.add<uint32_t>("numberOfParameters");
488  desc.addUntracked<uint32_t>("nEvents");
489 
490  descriptions.addDefault(desc);
491 }
492 
494 {
495 
496  if (partonLevel)
497  return;
498 
499  partonLevel = reader_->next();
500  if (!partonLevel)
501  return;
502 
503  boost::shared_ptr<lhef::LHERunInfo> runInfoThis = partonLevel->getRunInfo();
504  if (runInfoThis != runInfoLast) {
505  runInfo = runInfoThis;
506  runInfoLast = runInfoThis;
507  }
508 }
509 
510 //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
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