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