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