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