CMS 3D CMS Logo

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 <fstream>
26 #include <unistd.h>
27 #include <dirent.h>
28 #include <fcntl.h>
29 #include <sys/wait.h>
30 #include <sys/time.h>
31 #include <sys/resource.h>
32 
33 
34 #include "boost/bind.hpp"
35 #include "boost/shared_ptr.hpp"
36 #include "boost/ptr_container/ptr_deque.hpp"
37 
38 // user include files
42 
46 
49 
54 
58 
62 
64 
65 //
66 // class declaration
67 //
68 
69 class ExternalLHEProducer : public edm::one::EDProducer<edm::BeginRunProducer,
70  edm::EndRunProducer> {
71 public:
72  explicit ExternalLHEProducer(const edm::ParameterSet& iConfig);
73  ~ExternalLHEProducer() override;
74 
75  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
76 
77 private:
78 
79  void produce(edm::Event&, const edm::EventSetup&) override;
80  void beginRunProduce(edm::Run& run, edm::EventSetup const& es) override;
81  void endRunProduce(edm::Run&, edm::EventSetup const&) override;
82  void preallocThreads(unsigned int) override;
83 
84  int closeDescriptors(int preserve);
85  void executeScript();
86  std::unique_ptr<std::string> readOutput();
87 
88  void nextEvent();
89 
90  // ----------member data ---------------------------
93  std::vector<std::string> args_;
94  uint32_t npars_;
95  uint32_t nEvents_;
96  unsigned int nThreads_{1};
98 
99  std::unique_ptr<lhef::LHEReader> reader_;
100  boost::shared_ptr<lhef::LHERunInfo> runInfoLast;
101  boost::shared_ptr<lhef::LHERunInfo> runInfo;
102  boost::shared_ptr<lhef::LHEEvent> partonLevel;
103  boost::ptr_deque<LHERunInfoProduct> runInfoProducts;
104  bool wasMerged;
105 
106  class FileCloseSentry : private boost::noncopyable {
107  public:
108  explicit FileCloseSentry(int fd) : fd_(fd) {};
109 
111  close(fd_);
112  }
113  private:
114  int fd_;
115  };
116 
117 };
118 
119 //
120 // constants, enums and typedefs
121 //
122 
123 
124 //
125 // static data member definitions
126 //
127 
128 //
129 // constructors and destructor
130 //
132  scriptName_((iConfig.getParameter<edm::FileInPath>("scriptName")).fullPath()),
133  outputFile_(iConfig.getParameter<std::string>("outputFile")),
134  args_(iConfig.getParameter<std::vector<std::string> >("args")),
135  npars_(iConfig.getParameter<uint32_t>("numberOfParameters")),
136  nEvents_(iConfig.getUntrackedParameter<uint32_t>("nEvents"))
137 {
138  if (npars_ != args_.size())
139  throw cms::Exception("ExternalLHEProducer") << "Problem with configuration: " << args_.size() << " script arguments given, expected " << npars_;
140  produces<LHEXMLStringProduct, edm::Transition::BeginRun>("LHEScriptOutput");
141 
142  produces<LHEEventProduct>();
143  produces<LHERunInfoProduct, edm::Transition::BeginRun>();
144  produces<LHERunInfoProduct, edm::Transition::EndRun>();
145 }
146 
147 
149 {
150 }
151 
152 
153 //
154 // member functions
155 //
156 
157 // ------------ method called with number of threads in job --
158 void
160 {
161  nThreads_ = iThreads;
162 }
163 
164 // ------------ method called to produce the data ------------
165 void
167 {
168  nextEvent();
169  if (!partonLevel) {
170  throw edm::Exception(edm::errors::EventGenerationFailure) << "No lhe event found in ExternalLHEProducer::produce(). "
171  << "The likely cause is that the lhe file contains fewer events than were requested, which is possible "
172  << "in case of phase space integration or uneweighting efficiency problems.";
173  }
174 
175  std::unique_ptr<LHEEventProduct> product(
176  new LHEEventProduct(*partonLevel->getHEPEUP(),
177  partonLevel->originalXWGTUP())
178  );
179  if (partonLevel->getPDF()) {
180  product->setPDF(*partonLevel->getPDF());
181  }
182  std::for_each(partonLevel->weights().begin(),
183  partonLevel->weights().end(),
184  boost::bind(&LHEEventProduct::addWeight,
185  product.get(), _1));
186  product->setScales(partonLevel->scales());
187  product->setNpLO(partonLevel->npLO());
188  product->setNpNLO(partonLevel->npNLO());
189  std::for_each(partonLevel->getComments().begin(),
190  partonLevel->getComments().end(),
191  boost::bind(&LHEEventProduct::addComment,
192  product.get(), _1));
193 
194  iEvent.put(std::move(product));
195 
196  if (runInfo) {
197  std::auto_ptr<LHERunInfoProduct> product(new LHERunInfoProduct(*runInfo->getHEPRUP()));
198  std::for_each(runInfo->getHeaders().begin(),
199  runInfo->getHeaders().end(),
200  boost::bind(&LHERunInfoProduct::addHeader,
201  product.get(), _1));
202  std::for_each(runInfo->getComments().begin(),
203  runInfo->getComments().end(),
204  boost::bind(&LHERunInfoProduct::addComment,
205  product.get(), _1));
206 
207  if (!runInfoProducts.empty()) {
208  runInfoProducts.front().mergeProduct(*product);
209  if (!wasMerged) {
210  runInfoProducts.pop_front();
211  runInfoProducts.push_front(product);
212  wasMerged = true;
213  }
214  }
215 
216  runInfo.reset();
217  }
218 
219  partonLevel.reset();
220  return;
221 }
222 
223 // ------------ method called when starting to processes a run ------------
224 void
226 {
227 
228  // pass the number of events as previous to last argument
229 
230  std::ostringstream eventStream;
231  eventStream << nEvents_;
232  // args_.push_back(eventStream.str());
233  args_.insert(args_.begin() + 1, eventStream.str());
234 
235  // pass the random number generator seed as last argument
236 
238 
239  if ( ! rng.isAvailable()) {
240  throw cms::Exception("Configuration")
241  << "The ExternalLHEProducer module requires the RandomNumberGeneratorService\n"
242  "which is not present in the configuration file. You must add the service\n"
243  "in the configuration file if you want to run ExternalLHEProducer";
244  }
245  std::ostringstream randomStream;
246  randomStream << rng->mySeed();
247  // args_.push_back(randomStream.str());
248  args_.insert(args_.begin() + 2, randomStream.str());
249 
250  // args_.emplace_back(std::to_string(nThreads_));
251  args_.insert(args_.begin() + 3, std::to_string(nThreads_));
252 
253  for ( unsigned int iArg = 0; iArg < args_.size() ; iArg++ ) {
254  LogDebug("LHEInputArgs") << "arg [" << iArg << "] = " << args_[iArg];
255  }
256 
257  executeScript();
258 
259  //fill LHEXMLProduct (streaming read directly into compressed buffer to save memory)
260  std::unique_ptr<LHEXMLStringProduct> p(new LHEXMLStringProduct);
261  std::ifstream instream(outputFile_);
262  if (!instream) {
263  throw cms::Exception("OutputOpenError") << "Unable to open script output file " << outputFile_ << ".";
264  }
265  instream.seekg (0, instream.end);
266  int insize = instream.tellg();
267  instream.seekg (0, instream.beg);
268  p->fillCompressedContent(instream, 0.25*insize);
269  instream.close();
270  run.put(std::move(p), "LHEScriptOutput");
271 
272  // LHE C++ classes translation
273  // (read back uncompressed file from disk in streaming mode again to save memory)
274 
275  std::vector<std::string> infiles(1, outputFile_);
276  unsigned int skip = 0;
277  reader_ = std::make_unique<lhef::LHEReader>(infiles, skip);
278 
279  nextEvent();
280  if (runInfoLast) {
282 
283  std::unique_ptr<LHERunInfoProduct> product(new LHERunInfoProduct(*runInfo->getHEPRUP()));
284  std::for_each(runInfo->getHeaders().begin(),
285  runInfo->getHeaders().end(),
286  boost::bind(&LHERunInfoProduct::addHeader,
287  product.get(), _1));
288  std::for_each(runInfo->getComments().begin(),
289  runInfo->getComments().end(),
290  boost::bind(&LHERunInfoProduct::addComment,
291  product.get(), _1));
292 
293  // keep a copy around in case of merging
294  runInfoProducts.push_back(new LHERunInfoProduct(*product));
295  wasMerged = false;
296 
297  run.put(std::move(product));
298 
299  runInfo.reset();
300  }
301 
302 }
303 
304 // ------------ method called when ending the processing of a run ------------
305 void
307 {
308 
309  if (!runInfoProducts.empty()) {
310  std::unique_ptr<LHERunInfoProduct> product(runInfoProducts.pop_front().release());
311  run.put(std::move(product));
312  }
313 
314  nextEvent();
315  if (partonLevel) {
316  throw edm::Exception(edm::errors::EventGenerationFailure) << "Error in ExternalLHEProducer::endRunProduce(). "
317  << "Event loop is over, but there are still lhe events to process."
318  << "This could happen if lhe file contains more events than requested. This is never expected to happen.";
319  }
320 
321  reader_.reset();
322 
323  if (unlink(outputFile_.c_str())) {
324  throw cms::Exception("OutputDeleteError") << "Unable to delete original script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
325  }
326 
327 }
328 
329 // ------------ Close all the open file descriptors ------------
330 int
332 {
333  int maxfd = 1024;
334  int fd;
335 #ifdef __linux__
336  DIR * dir;
337  struct dirent *dp;
338  maxfd = preserve;
339  if ((dir = opendir("/proc/self/fd"))) {
340  errno = 0;
341  while ((dp = readdir (dir)) != nullptr) {
342  if ((strcmp(dp->d_name, ".") == 0) || (strcmp(dp->d_name, "..") == 0)) {
343  continue;
344  }
345  if (sscanf(dp->d_name, "%d", &fd) != 1) {
346  //throw cms::Exception("closeDescriptors") << "Found unexpected filename in /proc/self/fd: " << dp->d_name;
347  return -1;
348  }
349  if (fd > maxfd) {
350  maxfd = fd;
351  }
352  }
353  if (errno) {
354  //throw cms::Exception("closeDescriptors") << "Unable to determine the number of fd (errno=" << errno << ", " << strerror(errno) << ").";
355  return errno;
356  }
357  closedir(dir);
358  }
359 #endif
360  // TODO: assert for an unreasonable number of fds?
361  for (fd=3; fd<maxfd+1; fd++) {
362  if (fd != preserve)
363  close(fd);
364  }
365  return 0;
366 }
367 
368 // ------------ Execute the script associated with this producer ------------
369 void
371 {
372 
373  // Fork a script, wait until it finishes.
374 
375  int rc = 0, rc2 = 0;
376  int filedes[2], fd_flags;
377  unsigned int argc;
378 
379  if (pipe(filedes)) {
380  throw cms::Exception("Unable to create a new pipe");
381  }
382  FileCloseSentry sentry1(filedes[0]), sentry2(filedes[1]);
383 
384  if ((fd_flags = fcntl(filedes[1], F_GETFD, NULL)) == -1) {
385  throw cms::Exception("ExternalLHEProducer") << "Failed to get pipe file descriptor flags (errno=" << rc << ", " << strerror(rc) << ")";
386  }
387  if (fcntl(filedes[1], F_SETFD, fd_flags | FD_CLOEXEC) == -1) {
388  throw cms::Exception("ExternalLHEProducer") << "Failed to set pipe file descriptor flags (errno=" << rc << ", " << strerror(rc) << ")";
389  }
390 
391  argc = 1 + args_.size();
392  // TODO: assert that we have a reasonable number of arguments
393  char **argv = new char *[argc+1];
394  argv[0] = strdup(scriptName_.c_str());
395  for (unsigned int i=1; i<argc; i++) {
396  argv[i] = strdup(args_[i-1].c_str());
397  }
398  argv[argc] = nullptr;
399 
400  pid_t pid = fork();
401  if (pid == 0) {
402  // The child process
403  if (!(rc = closeDescriptors(filedes[1]))) {
404  execvp(argv[0], argv); // If execv returns, we have an error.
405  rc = errno;
406  }
407  while ((write(filedes[1], &rc, sizeof(int)) == -1) && (errno == EINTR)) {}
408  _exit(1);
409  }
410 
411  // Free the arg vector ASAP
412  for (unsigned int i=0; i<args_.size()+1; i++) {
413  free(argv[i]);
414  }
415  delete [] argv;
416 
417  if (pid == -1) {
418  throw cms::Exception("ForkException") << "Unable to fork a child (errno=" << errno << ", " << strerror(errno) << ")";
419  }
420 
421  close(filedes[1]);
422  // If the exec succeeds, the read will fail.
423  while (((rc2 = read(filedes[0], &rc, sizeof(int))) == -1) && (errno == EINTR)) { rc2 = 0; }
424  if ((rc2 == sizeof(int)) && rc) {
425  throw cms::Exception("ExternalLHEProducer") << "Failed to execute script (errno=" << rc << ", " << strerror(rc) << ")";
426  }
427  close(filedes[0]);
428 
429  int status = 0;
430  errno = 0;
431  do {
432  if (waitpid(pid, &status, 0) < 0) {
433  if (errno == EINTR) {
434  continue;
435  } else {
436  throw cms::Exception("ExternalLHEProducer") << "Failed to read child status (errno=" << errno << ", " << strerror(errno) << ")";
437  }
438  }
439  if (WIFSIGNALED(status)) {
440  throw cms::Exception("ExternalLHEProducer") << "Child exited due to signal " << WTERMSIG(status) << ".";
441  }
442  if (WIFEXITED(status)) {
443  rc = WEXITSTATUS(status);
444  break;
445  }
446  } while (true);
448  if(ts.isAvailable()) {
449  struct rusage ru;
450  getrusage(RUSAGE_CHILDREN,&ru);
451  double time = static_cast<double>(ru.ru_stime.tv_sec) + (static_cast<double>(ru.ru_stime.tv_usec) * 1E-6);
452  ts->addToCPUTime(time);
453  }
454  if (rc) {
455  throw cms::Exception("ExternalLHEProducer") << "Child failed with exit code " << rc << ".";
456  }
457 
458 }
459 
460 // ------------ Read the output script ------------
461 #define BUFSIZE 4096
462 std::unique_ptr<std::string> ExternalLHEProducer::readOutput()
463 {
464  int fd;
465  ssize_t n;
466  char buf[BUFSIZE];
467 
468  if ((fd = open(outputFile_.c_str(), O_RDONLY)) == -1) {
469  throw cms::Exception("OutputOpenError") << "Unable to open script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
470  }
471 
472  std::stringstream ss;
473  while ((n = read(fd, buf, BUFSIZE)) > 0 || (n == -1 && errno == EINTR)) {
474  if (n > 0)
475  ss.write(buf, n);
476  }
477  if (n == -1) {
478  throw cms::Exception("OutputOpenError") << "Unable to read from script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
479  }
480 
481  if (unlink(outputFile_.c_str())) {
482  throw cms::Exception("OutputDeleteError") << "Unable to delete original script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
483  }
484 
485  return std::unique_ptr<std::string>(new std::string(ss.str()));
486 }
487 
488 // ------------ method fills 'descriptions' with the allowed parameters for the module ------------
489 void
491  //The following says we do not know what parameters are allowed so do no validation
492  // Please change this to state exactly what you do use, even if it is no parameters
494  desc.setComment("Executes an external script and places its output file into an EDM collection");
495 
496  edm::FileInPath thePath;
497  desc.add<edm::FileInPath>("scriptName", thePath);
498  desc.add<std::string>("outputFile", "myoutput");
499  desc.add<std::vector<std::string> >("args");
500  desc.add<uint32_t>("numberOfParameters");
501  desc.addUntracked<uint32_t>("nEvents");
502 
503  descriptions.addDefault(desc);
504 }
505 
507 {
508 
509  if (partonLevel)
510  return;
511 
512  if(not reader_) { return;}
513  partonLevel = reader_->next();
514  if (!partonLevel)
515  return;
516 
517  boost::shared_ptr<lhef::LHERunInfo> runInfoThis = partonLevel->getRunInfo();
518  if (runInfoThis != runInfoLast) {
519  runInfo = runInfoThis;
520  runInfoLast = runInfoThis;
521  }
522 }
523 
524 //define this as a plug-in
#define LogDebug(id)
boost::shared_ptr< lhef::LHEEvent > partonLevel
void beginRunProduce(edm::Run &run, edm::EventSetup const &es) override
void endRunProduce(edm::Run &, edm::EventSetup const &) override
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:136
std::unique_ptr< std::string > readOutput()
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
void produce(edm::Event &, const edm::EventSetup &) override
void addWeight(const WGT &wgt)
#define NULL
Definition: scimark2.h:8
std::vector< std::string > args_
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
virtual void addToCPUTime(double iTime)=0
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)
std::unique_ptr< lhef::LHEReader > reader_
bool isAvailable() const
Definition: Service.h:46
#define BUFSIZE
def pipe(cmdline, input=None)
Definition: pipe.py:5
ParameterDescriptionBase * add(U const &iLabel, T const &value)
virtual std::uint32_t mySeed() const =0
boost::shared_ptr< lhef::LHERunInfo > runInfo
void addComment(const std::string &line)
auto dp
Definition: deltaR.h:22
void preallocThreads(unsigned int) override
void put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Run.h:114
HLT enums.
boost::ptr_deque< LHERunInfoProduct > runInfoProducts
dbl *** dir
Definition: mlp_gen.cc:35
def write(self, setup)
ExternalLHEProducer(const edm::ParameterSet &iConfig)
def move(src, dest)
Definition: eostools.py:510
Definition: Run.h:43