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 // $Id: ExternalLHEProducer.cc,v 1.7 2012/10/26 12:19:48 lenzip Exp $
17 //
18 //
19 
20 
21 // system include files
22 #include <cstdio>
23 #include <memory>
24 #include <vector>
25 #include <string>
26 #include <fstream>
27 #include <unistd.h>
28 #include <dirent.h>
29 #include <fcntl.h>
30 #include <sys/wait.h>
31 
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 
66 public:
67  explicit ExternalLHEProducer(const edm::ParameterSet& iConfig);
69 
70  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
71 
72 private:
73  virtual void beginJob();
74  virtual void produce(edm::Event&, const edm::EventSetup&) ;
75 
76  virtual void beginRun(edm::Run& run, edm::EventSetup const& es);
77  virtual void endRun(edm::Run&, edm::EventSetup const&);
79 
81 
82  int closeDescriptors(int preserve);
83  void executeScript();
84  std::auto_ptr<std::string> readOutput();
85 
86  virtual void nextEvent();
87 
88  // ----------member data ---------------------------
89  std::string scriptName_;
90  std::string outputFile_;
91  std::vector<std::string> args_;
92  uint32_t npars_;
93  uint32_t nEvents_;
94  std::string outputContents_;
95 
96  std::auto_ptr<lhef::LHEReader> reader_;
97  boost::shared_ptr<lhef::LHERunInfo> runInfoLast;
98  boost::shared_ptr<lhef::LHERunInfo> runInfo;
99  boost::shared_ptr<lhef::LHEEvent> partonLevel;
100  boost::ptr_deque<LHERunInfoProduct> runInfoProducts;
101  bool wasMerged;
102 
103  class FileCloseSentry : private boost::noncopyable {
104  public:
105  explicit FileCloseSentry(int fd) : fd_(fd) {};
106 
108  close(fd_);
109  }
110  private:
111  int fd_;
112  };
113 
114 };
115 
116 //
117 // constants, enums and typedefs
118 //
119 
120 
121 //
122 // static data member definitions
123 //
124 
125 //
126 // constructors and destructor
127 //
129  scriptName_((iConfig.getParameter<edm::FileInPath>("scriptName")).fullPath().c_str()),
130  outputFile_(iConfig.getParameter<std::string>("outputFile")),
131  args_(iConfig.getParameter<std::vector<std::string> >("args")),
132  npars_(iConfig.getParameter<uint32_t>("numberOfParameters")),
133  nEvents_(iConfig.getUntrackedParameter<uint32_t>("nEvents"))
134 {
135  if (npars_ != args_.size())
136  throw cms::Exception("ExternalLHEProducer") << "Problem with configuration: " << args_.size() << " script arguments given, expected " << npars_;
137  produces<LHEXMLStringProduct, edm::InRun>("LHEScriptOutput");
138 
139  produces<LHEEventProduct>();
140  produces<LHERunInfoProduct, edm::InRun>();
141 }
142 
143 
145 {
146 }
147 
148 
149 //
150 // member functions
151 //
152 
153 // ------------ method called to produce the data ------------
154 void
156 {
157  nextEvent();
158  if (!partonLevel)
159  return;
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 once each job just before starting event loop ------------
210 void
212 {
213 }
214 
215 // ------------ method called when starting to processes a run ------------
216 void
218 {
219 
220  // pass the number of events as previous to last argument
221 
222  std::ostringstream eventStream;
223  eventStream << nEvents_;
224  args_.push_back(eventStream.str());
225 
226  // pass the random number generator seed as last argument
227 
229 
230  if ( ! rng.isAvailable()) {
231  throw cms::Exception("Configuration")
232  << "The ExternalLHEProducer module requires the RandomNumberGeneratorService\n"
233  "which is not present in the configuration file. You must add the service\n"
234  "in the configuration file if you want to run ExternalLHEProducer";
235  }
236  std::ostringstream randomStream;
237  randomStream << rng->mySeed();
238  args_.push_back(randomStream.str());
239 
240  for ( unsigned int iArg = 0; iArg < args_.size() ; iArg++ ) {
241  LogDebug("LHEInputArgs") << "arg [" << iArg << "] = " << args_[iArg];
242  }
243 
244  executeScript();
245 
246  //fill LHEXMLProduct (streaming read directly into compressed buffer to save memory)
247  std::auto_ptr<LHEXMLStringProduct> p(new LHEXMLStringProduct);
248  std::ifstream instream(outputFile_);
249  if (!instream) {
250  throw cms::Exception("OutputOpenError") << "Unable to open script output file " << outputFile_ << ".";
251  }
252  instream.seekg (0, instream.end);
253  int insize = instream.tellg();
254  instream.seekg (0, instream.beg);
255  p->fillCompressedContent(instream, 0.25*insize);
256  instream.close();
257  run.put(p, "LHEScriptOutput");
258 
259  // LHE C++ classes translation
260  // (read back uncompressed file from disk in streaming mode again to save memory)
261 
262  std::vector<std::string> infiles(1, outputFile_);
263  unsigned int skip = 0;
264  std::auto_ptr<lhef::LHEReader> thisRead( new lhef::LHEReader(infiles, skip ) );
265  reader_ = thisRead;
266 
267  nextEvent();
268  if (runInfoLast) {
270 
271  std::auto_ptr<LHERunInfoProduct> product(new LHERunInfoProduct(*runInfo->getHEPRUP()));
272  std::for_each(runInfo->getHeaders().begin(),
273  runInfo->getHeaders().end(),
274  boost::bind(&LHERunInfoProduct::addHeader,
275  product.get(), _1));
276  std::for_each(runInfo->getComments().begin(),
277  runInfo->getComments().end(),
278  boost::bind(&LHERunInfoProduct::addComment,
279  product.get(), _1));
280 
281  // keep a copy around in case of merging
282  runInfoProducts.push_back(new LHERunInfoProduct(*product));
283  wasMerged = false;
284 
285  run.put(product);
286 
287  runInfo.reset();
288  }
289 
290 }
291 
292 // ------------ method called when ending the processing of a run ------------
293 void
295 {
296 
297  if (!runInfoProducts.empty()) {
298  std::auto_ptr<LHERunInfoProduct> product(runInfoProducts.pop_front().release());
299  run.put(product);
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 called when starting to processes a luminosity block ------------
463 void
465 {
466 }
467 
468 // ------------ method called when ending the processing of a luminosity block ------------
469 void
471 {
472 }
473 
474 // ------------ method fills 'descriptions' with the allowed parameters for the module ------------
475 void
477  //The following says we do not know what parameters are allowed so do no validation
478  // Please change this to state exactly what you do use, even if it is no parameters
480  desc.setComment("Executes an external script and places its output file into an EDM collection");
481 
482  edm::FileInPath thePath;
483  desc.add<edm::FileInPath>("scriptName", thePath);
484  desc.add<std::string>("outputFile", "myoutput");
485  desc.add<std::vector<std::string> >("args");
486  desc.add<uint32_t>("numberOfParameters");
487  desc.addUntracked<uint32_t>("nEvents");
488 
489  descriptions.addDefault(desc);
490 }
491 
493 {
494 
495  if (partonLevel)
496  return;
497 
498  partonLevel = reader_->next();
499  if (!partonLevel)
500  return;
501 
502  boost::shared_ptr<lhef::LHERunInfo> runInfoThis = partonLevel->getRunInfo();
503  if (runInfoThis != runInfoLast) {
504  runInfo = runInfoThis;
505  runInfoLast = runInfoThis;
506  }
507 }
508 
509 //define this as a plug-in
#define LogDebug(id)
boost::shared_ptr< lhef::LHEEvent > partonLevel
std::auto_ptr< std::string > readOutput()
int i
Definition: DBlmapReader.cc:9
virtual void produce(edm::Event &, const edm::EventSetup &)
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
tuple lumi
Definition: fjr2json.py:35
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:243
void addDefault(ParameterSetDescription const &psetDescription)
OrphanHandle< PROD > put(std::auto_ptr< PROD > product)
Put a new product.
Definition: Event.h:85
bool isAvailable() const
Definition: Service.h:47
virtual void beginRun(edm::Run &run, edm::EventSetup const &es)
#define BUFSIZE
ParameterDescriptionBase * add(U const &iLabel, T const &value)
boost::shared_ptr< lhef::LHERunInfo > runInfo
void addComment(const std::string &line)
tuple argc
Definition: dir2webdir.py:41
virtual void beginLuminosityBlock(edm::LuminosityBlock &, edm::EventSetup const &)
void put(std::auto_ptr< PROD > product)
Put a new product.
Definition: Run.h:81
boost::ptr_deque< LHERunInfoProduct > runInfoProducts
dbl *** dir
Definition: mlp_gen.cc:35
tuple status
Definition: ntuplemaker.py:245
virtual uint32_t mySeed() const =0
Exists for backward compatibility.
ExternalLHEProducer(const edm::ParameterSet &iConfig)
virtual void endLuminosityBlock(edm::LuminosityBlock &, edm::EventSetup const &)
Definition: Run.h:33
virtual void endRun(edm::Run &, edm::EventSetup const &)