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 <unistd.h>
26 #include <dirent.h>
27 #include <fcntl.h>
28 #include <sys/wait.h>
29 
30 #include <boost/shared_ptr.hpp>
31 #include <boost/ptr_container/ptr_deque.hpp>
32 
33 // user include files
37 
41 
44 
49 
53 
56 
58 
59 //
60 // class declaration
61 //
62 
63 class ExternalLHEProducer : public edm::one::EDProducer<edm::BeginRunProducer,
64  edm::EndRunProducer> {
65 public:
66  explicit ExternalLHEProducer(const edm::ParameterSet& iConfig);
67  virtual ~ExternalLHEProducer();
68 
69  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
70 
71 private:
72 
73  virtual void produce(edm::Event&, const edm::EventSetup&) override;
74  virtual void endJob() 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.getParameter<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 once each job just after ending the event loop ------------
206 void
208 
209  reader_.reset();
210 }
211 
212 // ------------ method called when starting to processes a run ------------
213 void
215 {
216 
217  // pass the number of events as previous to last argument
218 
219  std::ostringstream eventStream;
220  eventStream << nEvents_;
221  args_.push_back(eventStream.str());
222 
223  // pass the random number generator seed as last argument
224 
226 
227  if ( ! rng.isAvailable()) {
228  throw cms::Exception("Configuration")
229  << "The ExternalLHEProducer module requires the RandomNumberGeneratorService\n"
230  "which is not present in the configuration file. You must add the service\n"
231  "in the configuration file if you want to run ExternalLHEProducer";
232  }
233  std::ostringstream randomStream;
234  randomStream << rng->mySeed();
235  args_.push_back(randomStream.str());
236 
237  for ( unsigned int iArg = 0; iArg < args_.size() ; iArg++ ) {
238  LogDebug("LHEInputArgs") << "arg [" << iArg << "] = " << args_[iArg];
239  }
240 
241  executeScript();
242  std::auto_ptr<std::string> localContents = readOutput();
243  outputContents_ = *localContents;
244  std::auto_ptr<LHEXMLStringProduct> p(new LHEXMLStringProduct(*localContents));
245  run.put(p, "LHEScriptOutput");
246 
247  // LHE C++ classes translation
248 
249  unsigned int skip = 0;
250  std::auto_ptr<lhef::LHEReader> thisRead( new lhef::LHEReader(outputContents_, skip ) );
251  reader_ = thisRead;
252 
253  nextEvent();
254  if (runInfoLast) {
256 
257  std::auto_ptr<LHERunInfoProduct> product(new LHERunInfoProduct(*runInfo->getHEPRUP()));
258  std::for_each(runInfo->getHeaders().begin(),
259  runInfo->getHeaders().end(),
260  boost::bind(&LHERunInfoProduct::addHeader,
261  product.get(), _1));
262  std::for_each(runInfo->getComments().begin(),
263  runInfo->getComments().end(),
264  boost::bind(&LHERunInfoProduct::addComment,
265  product.get(), _1));
266 
267  // keep a copy around in case of merging
268  runInfoProducts.push_back(new LHERunInfoProduct(*product));
269  wasMerged = false;
270 
271  run.put(product);
272 
273  runInfo.reset();
274  }
275 
276 }
277 
278 // ------------ method called when ending the processing of a run ------------
279 void
281 {
282 
283  if (!runInfoProducts.empty()) {
284  std::auto_ptr<LHERunInfoProduct> product(runInfoProducts.pop_front().release());
285  run.put(product);
286  }
287 
288 }
289 
290 // ------------ Close all the open file descriptors ------------
291 int
293 {
294  int maxfd = 1024;
295  int fd;
296 #ifdef __linux__
297  DIR * dir;
298  struct dirent *dp;
299  maxfd = preserve;
300  if ((dir = opendir("/proc/self/fd"))) {
301  errno = 0;
302  while ((dp = readdir (dir)) != NULL) {
303  if ((strcmp(dp->d_name, ".") == 0) || (strcmp(dp->d_name, "..") == 0)) {
304  continue;
305  }
306  if (sscanf(dp->d_name, "%d", &fd) != 1) {
307  //throw cms::Exception("closeDescriptors") << "Found unexpected filename in /proc/self/fd: " << dp->d_name;
308  return -1;
309  }
310  if (fd > maxfd) {
311  maxfd = fd;
312  }
313  }
314  if (errno) {
315  //throw cms::Exception("closeDescriptors") << "Unable to determine the number of fd (errno=" << errno << ", " << strerror(errno) << ").";
316  return errno;
317  }
318  closedir(dir);
319  }
320 #endif
321  // TODO: assert for an unreasonable number of fds?
322  for (fd=3; fd<maxfd+1; fd++) {
323  if (fd != preserve)
324  close(fd);
325  }
326  return 0;
327 }
328 
329 // ------------ Execute the script associated with this producer ------------
330 void
332 {
333 
334  // Fork a script, wait until it finishes.
335 
336  int rc = 0, rc2 = 0;
337  int filedes[2], fd_flags;
338  unsigned int argc;
339 
340  if (pipe(filedes)) {
341  throw cms::Exception("Unable to create a new pipe");
342  }
343  FileCloseSentry sentry1(filedes[0]), sentry2(filedes[1]);
344 
345  if ((fd_flags = fcntl(filedes[1], F_GETFD, NULL)) == -1) {
346  throw cms::Exception("ExternalLHEProducer") << "Failed to get pipe file descriptor flags (errno=" << rc << ", " << strerror(rc) << ")";
347  }
348  if (fcntl(filedes[1], F_SETFD, fd_flags | FD_CLOEXEC) == -1) {
349  throw cms::Exception("ExternalLHEProducer") << "Failed to set pipe file descriptor flags (errno=" << rc << ", " << strerror(rc) << ")";
350  }
351 
352  argc = 1 + args_.size();
353  // TODO: assert that we have a reasonable number of arguments
354  char **argv = new char *[argc+1];
355  argv[0] = strdup(scriptName_.c_str());
356  for (unsigned int i=1; i<argc; i++) {
357  argv[i] = strdup(args_[i-1].c_str());
358  }
359  argv[argc] = NULL;
360 
361  pid_t pid = fork();
362  if (pid == 0) {
363  // The child process
364  if (!(rc = closeDescriptors(filedes[1]))) {
365  execvp(argv[0], argv); // If execv returns, we have an error.
366  rc = errno;
367  }
368  while ((write(filedes[1], &rc, sizeof(int)) == -1) && (errno == EINTR)) {}
369  _exit(1);
370  }
371 
372  // Free the arg vector ASAP
373  for (unsigned int i=0; i<args_.size()+1; i++) {
374  free(argv[i]);
375  }
376  delete [] argv;
377 
378  if (pid == -1) {
379  throw cms::Exception("ForkException") << "Unable to fork a child (errno=" << errno << ", " << strerror(errno) << ")";
380  }
381 
382  close(filedes[1]);
383  // If the exec succeeds, the read will fail.
384  while (((rc2 = read(filedes[0], &rc, sizeof(int))) == -1) && (errno == EINTR)) { rc2 = 0; }
385  if ((rc2 == sizeof(int)) && rc) {
386  throw cms::Exception("ExternalLHEProducer") << "Failed to execute script (errno=" << rc << ", " << strerror(rc) << ")";
387  }
388  close(filedes[0]);
389 
390  int status = 0;
391  errno = 0;
392  do {
393  if (waitpid(pid, &status, 0) < 0) {
394  if (errno == EINTR) {
395  continue;
396  } else {
397  throw cms::Exception("ExternalLHEProducer") << "Failed to read child status (errno=" << errno << ", " << strerror(errno) << ")";
398  }
399  }
400  if (WIFSIGNALED(status)) {
401  throw cms::Exception("ExternalLHEProducer") << "Child exited due to signal " << WTERMSIG(status) << ".";
402  }
403  if (WIFEXITED(status)) {
404  rc = WEXITSTATUS(status);
405  break;
406  }
407  } while (true);
408  if (rc) {
409  throw cms::Exception("ExternalLHEProducer") << "Child failed with exit code " << rc << ".";
410  }
411 
412 }
413 
414 // ------------ Read the output script ------------
415 #define BUFSIZE 4096
416 std::auto_ptr<std::string> ExternalLHEProducer::readOutput()
417 {
418  int fd;
419  ssize_t n;
420  char buf[BUFSIZE];
421 
422  if ((fd = open(outputFile_.c_str(), O_RDONLY)) == -1) {
423  throw cms::Exception("OutputOpenError") << "Unable to open script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
424  }
425 
426  std::stringstream ss;
427  while ((n = read(fd, buf, BUFSIZE)) > 0 || (n == -1 && errno == EINTR)) {
428  if (n > 0)
429  ss.write(buf, n);
430  }
431  if (n == -1) {
432  throw cms::Exception("OutputOpenError") << "Unable to read from script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
433  }
434 
435  if (unlink(outputFile_.c_str())) {
436  throw cms::Exception("OutputDeleteError") << "Unable to delete original script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
437  }
438 
439  return std::auto_ptr<std::string>(new std::string(ss.str()));
440 }
441 
442 // ------------ method fills 'descriptions' with the allowed parameters for the module ------------
443 void
445  //The following says we do not know what parameters are allowed so do no validation
446  // Please change this to state exactly what you do use, even if it is no parameters
448  desc.setComment("Executes an external script and places its output file into an EDM collection");
449 
450  edm::FileInPath thePath;
451  desc.add<edm::FileInPath>("scriptName", thePath);
452  desc.add<std::string>("outputFile", "myoutput");
453  desc.add<std::vector<std::string> >("args");
454  desc.add<uint32_t>("numberOfParameters");
455  desc.add<uint32_t>("nEvents");
456 
457  descriptions.addDefault(desc);
458 }
459 
461 {
462 
463  if (partonLevel)
464  return;
465 
466  partonLevel = reader_->next();
467  if (!partonLevel)
468  return;
469 
470  boost::shared_ptr<lhef::LHERunInfo> runInfoThis = partonLevel->getRunInfo();
471  if (runInfoThis != runInfoLast) {
472  runInfo = runInfoThis;
473  runInfoLast = runInfoThis;
474  }
475 }
476 
477 //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
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)
virtual void endJob() override
boost::shared_ptr< lhef::LHERunInfo > runInfo
void addComment(const std::string &line)
auto dp
Definition: deltaR.h:24
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