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