CMS 3D CMS Logo

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