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