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