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