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 <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 
65 public:
66  explicit ExternalLHEProducer(const edm::ParameterSet& iConfig);
68 
69  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
70 
71 private:
72  virtual void beginJob();
73  virtual void produce(edm::Event&, const edm::EventSetup&) ;
74  virtual void endJob();
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.getParameter<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  std::for_each(partonLevel->getComments().begin(),
168  partonLevel->getComments().end(),
169  boost::bind(&LHEEventProduct::addComment,
170  product.get(), _1));
171 
172  iEvent.put(product);
173 
174  if (runInfo) {
175  std::auto_ptr<LHERunInfoProduct> product(new LHERunInfoProduct(*runInfo->getHEPRUP()));
176  std::for_each(runInfo->getHeaders().begin(),
177  runInfo->getHeaders().end(),
178  boost::bind(&LHERunInfoProduct::addHeader,
179  product.get(), _1));
180  std::for_each(runInfo->getComments().begin(),
181  runInfo->getComments().end(),
182  boost::bind(&LHERunInfoProduct::addComment,
183  product.get(), _1));
184 
185  if (!runInfoProducts.empty()) {
186  runInfoProducts.front().mergeProduct(*product);
187  if (!wasMerged) {
188  runInfoProducts.pop_front();
189  runInfoProducts.push_front(product);
190  wasMerged = true;
191  }
192  }
193 
194  runInfo.reset();
195  }
196 
197  partonLevel.reset();
198  return;
199 }
200 
201 // ------------ method called once each job just before starting event loop ------------
202 void
204 {
205 }
206 
207 // ------------ method called once each job just after ending the event loop ------------
208 void
210 
211  reader_.reset();
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  std::auto_ptr<std::string> localContents = readOutput();
246  outputContents_ = *localContents;
247  std::auto_ptr<LHEXMLStringProduct> p(new LHEXMLStringProduct(*localContents));
248  run.put(p, "LHEScriptOutput");
249 
250  // LHE C++ classes translation
251 
252  unsigned int skip = 0;
253  std::auto_ptr<lhef::LHEReader> thisRead( new lhef::LHEReader(outputContents_, skip ) );
254  reader_ = thisRead;
255 
256  nextEvent();
257  if (runInfoLast) {
259 
260  std::auto_ptr<LHERunInfoProduct> product(new LHERunInfoProduct(*runInfo->getHEPRUP()));
261  std::for_each(runInfo->getHeaders().begin(),
262  runInfo->getHeaders().end(),
263  boost::bind(&LHERunInfoProduct::addHeader,
264  product.get(), _1));
265  std::for_each(runInfo->getComments().begin(),
266  runInfo->getComments().end(),
267  boost::bind(&LHERunInfoProduct::addComment,
268  product.get(), _1));
269 
270  // keep a copy around in case of merging
271  runInfoProducts.push_back(new LHERunInfoProduct(*product));
272  wasMerged = false;
273 
274  run.put(product);
275 
276  runInfo.reset();
277  }
278 
279 }
280 
281 // ------------ method called when ending the processing of a run ------------
282 void
284 {
285 
286  if (!runInfoProducts.empty()) {
287  std::auto_ptr<LHERunInfoProduct> product(runInfoProducts.pop_front().release());
288  run.put(product);
289  }
290 
291 }
292 
293 // ------------ Close all the open file descriptors ------------
294 int
296 {
297  int maxfd = 1024;
298  int fd;
299 #ifdef __linux__
300  DIR * dir;
301  struct dirent *dp;
302  maxfd = preserve;
303  if ((dir = opendir("/proc/self/fd"))) {
304  errno = 0;
305  while ((dp = readdir (dir)) != NULL) {
306  if ((strcmp(dp->d_name, ".") == 0) || (strcmp(dp->d_name, "..") == 0)) {
307  continue;
308  }
309  if (sscanf(dp->d_name, "%d", &fd) != 1) {
310  //throw cms::Exception("closeDescriptors") << "Found unexpected filename in /proc/self/fd: " << dp->d_name;
311  return -1;
312  }
313  if (fd > maxfd) {
314  maxfd = fd;
315  }
316  }
317  if (errno) {
318  //throw cms::Exception("closeDescriptors") << "Unable to determine the number of fd (errno=" << errno << ", " << strerror(errno) << ").";
319  return errno;
320  }
321  closedir(dir);
322  }
323 #endif
324  // TODO: assert for an unreasonable number of fds?
325  for (fd=3; fd<maxfd+1; fd++) {
326  if (fd != preserve)
327  close(fd);
328  }
329  return 0;
330 }
331 
332 // ------------ Execute the script associated with this producer ------------
333 void
335 {
336 
337  // Fork a script, wait until it finishes.
338 
339  int rc = 0, rc2 = 0;
340  int filedes[2], fd_flags;
341  unsigned int argc;
342 
343  if (pipe(filedes)) {
344  throw cms::Exception("Unable to create a new pipe");
345  }
346  FileCloseSentry sentry1(filedes[0]), sentry2(filedes[1]);
347 
348  if ((fd_flags = fcntl(filedes[1], F_GETFD, NULL)) == -1) {
349  throw cms::Exception("ExternalLHEProducer") << "Failed to get pipe file descriptor flags (errno=" << rc << ", " << strerror(rc) << ")";
350  }
351  if (fcntl(filedes[1], F_SETFD, fd_flags | FD_CLOEXEC) == -1) {
352  throw cms::Exception("ExternalLHEProducer") << "Failed to set pipe file descriptor flags (errno=" << rc << ", " << strerror(rc) << ")";
353  }
354 
355  argc = 1 + args_.size();
356  // TODO: assert that we have a reasonable number of arguments
357  char **argv = new char *[argc+1];
358  argv[0] = strdup(scriptName_.c_str());
359  for (unsigned int i=1; i<argc; i++) {
360  argv[i] = strdup(args_[i-1].c_str());
361  }
362  argv[argc] = NULL;
363 
364  pid_t pid = fork();
365  if (pid == 0) {
366  // The child process
367  if (!(rc = closeDescriptors(filedes[1]))) {
368  execvp(argv[0], argv); // If execv returns, we have an error.
369  rc = errno;
370  }
371  while ((write(filedes[1], &rc, sizeof(int)) == -1) && (errno == EINTR)) {}
372  _exit(1);
373  }
374 
375  // Free the arg vector ASAP
376  for (unsigned int i=0; i<args_.size()+1; i++) {
377  free(argv[i]);
378  }
379  delete [] argv;
380 
381  if (pid == -1) {
382  throw cms::Exception("ForkException") << "Unable to fork a child (errno=" << errno << ", " << strerror(errno) << ")";
383  }
384 
385  close(filedes[1]);
386  // If the exec succeeds, the read will fail.
387  while (((rc2 = read(filedes[0], &rc, sizeof(int))) == -1) && (errno == EINTR)) { rc2 = 0; }
388  if ((rc2 == sizeof(int)) && rc) {
389  throw cms::Exception("ExternalLHEProducer") << "Failed to execute script (errno=" << rc << ", " << strerror(rc) << ")";
390  }
391  close(filedes[0]);
392 
393  int status = 0;
394  errno = 0;
395  do {
396  if (waitpid(pid, &status, 0) < 0) {
397  if (errno == EINTR) {
398  continue;
399  } else {
400  throw cms::Exception("ExternalLHEProducer") << "Failed to read child status (errno=" << errno << ", " << strerror(errno) << ")";
401  }
402  }
403  if (WIFSIGNALED(status)) {
404  throw cms::Exception("ExternalLHEProducer") << "Child exited due to signal " << WTERMSIG(status) << ".";
405  }
406  if (WIFEXITED(status)) {
407  rc = WEXITSTATUS(status);
408  break;
409  }
410  } while (true);
411  if (rc) {
412  throw cms::Exception("ExternalLHEProducer") << "Child failed with exit code " << rc << ".";
413  }
414 
415 }
416 
417 // ------------ Read the output script ------------
418 #define BUFSIZE 4096
419 std::auto_ptr<std::string> ExternalLHEProducer::readOutput()
420 {
421  int fd;
422  ssize_t n;
423  char buf[BUFSIZE];
424 
425  if ((fd = open(outputFile_.c_str(), O_RDONLY)) == -1) {
426  throw cms::Exception("OutputOpenError") << "Unable to open script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
427  }
428 
429  std::stringstream ss;
430  while ((n = read(fd, buf, BUFSIZE)) > 0 || (n == -1 && errno == EINTR)) {
431  if (n > 0)
432  ss.write(buf, n);
433  }
434  if (n == -1) {
435  throw cms::Exception("OutputOpenError") << "Unable to read from script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
436  }
437 
438  if (unlink(outputFile_.c_str())) {
439  throw cms::Exception("OutputDeleteError") << "Unable to delete original script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
440  }
441 
442  return std::auto_ptr<std::string>(new std::string(ss.str()));
443 }
444 
445 // ------------ method called when starting to processes a luminosity block ------------
446 void
448 {
449 }
450 
451 // ------------ method called when ending the processing of a luminosity block ------------
452 void
454 {
455 }
456 
457 // ------------ method fills 'descriptions' with the allowed parameters for the module ------------
458 void
460  //The following says we do not know what parameters are allowed so do no validation
461  // Please change this to state exactly what you do use, even if it is no parameters
463  desc.setComment("Executes an external script and places its output file into an EDM collection");
464 
465  edm::FileInPath thePath;
466  desc.add<edm::FileInPath>("scriptName", thePath);
467  desc.add<std::string>("outputFile", "myoutput");
468  desc.add<std::vector<std::string> >("args");
469  desc.add<uint32_t>("numberOfParameters");
470  desc.add<uint32_t>("nEvents");
471 
472  descriptions.addDefault(desc);
473 }
474 
476 {
477 
478  if (partonLevel)
479  return;
480 
481  partonLevel = reader_->next();
482  if (!partonLevel)
483  return;
484 
485  boost::shared_ptr<lhef::LHERunInfo> runInfoThis = partonLevel->getRunInfo();
486  if (runInfoThis != runInfoLast) {
487  runInfo = runInfoThis;
488  runInfoLast = runInfoThis;
489  }
490 }
491 
492 //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 &)
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
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)
list DIR
Definition: linker.py:124
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 &)