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  // Used only if nPartonMapping is in the configuration
100  std::map<unsigned, std::pair<unsigned, unsigned>> nPartonMapping_{};
101 
102  std::unique_ptr<lhef::LHEReader> reader_;
103  std::shared_ptr<lhef::LHERunInfo> runInfoLast;
104  std::shared_ptr<lhef::LHERunInfo> runInfo;
105  std::shared_ptr<lhef::LHEEvent> partonLevel;
106  boost::ptr_deque<LHERunInfoProduct> runInfoProducts;
107  bool wasMerged;
108 
109  class FileCloseSentry : private boost::noncopyable {
110  public:
111  explicit FileCloseSentry(int fd) : fd_(fd) {};
112 
114  close(fd_);
115  }
116  private:
117  int fd_;
118  };
119 
120 };
121 
122 //
123 // constructors and destructor
124 //
126  scriptName_((iConfig.getParameter<edm::FileInPath>("scriptName")).fullPath()),
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  storeXML_(iConfig.getUntrackedParameter<bool>("storeXML"))
132 {
133  if (npars_ != args_.size())
134  throw cms::Exception("ExternalLHEProducer") << "Problem with configuration: " << args_.size() << " script arguments given, expected " << npars_;
135 
136  if (iConfig.exists("nPartonMapping")) {
137  auto& processMap(iConfig.getParameterSetVector("nPartonMapping"));
138  for (auto& cfg : processMap) {
139  unsigned processId(cfg.getParameter<unsigned>("idprup"));
140 
141  auto orderStr(cfg.getParameter<std::string>("order"));
142  unsigned order(0);
143  if (orderStr == "LO")
144  order = 0;
145  else if (orderStr == "NLO")
146  order = 1;
147  else
148  throw cms::Exception("ExternalLHEProducer") << "Invalid order specification for process " << processId << ": " << orderStr;
149 
150  unsigned np(cfg.getParameter<unsigned>("np"));
151 
152  nPartonMapping_.emplace(processId, std::make_pair(order, np));
153  }
154  }
155 
156  produces<LHEXMLStringProduct, edm::Transition::BeginRun>("LHEScriptOutput");
157 
158  produces<LHEEventProduct>();
159  produces<LHERunInfoProduct, edm::Transition::BeginRun>();
160  produces<LHERunInfoProduct, edm::Transition::EndRun>();
161 }
162 
163 
165 {
166 }
167 
168 
169 //
170 // member functions
171 //
172 
173 // ------------ method called with number of threads in job --
174 void
176 {
177  nThreads_ = iThreads;
178 }
179 
180 // ------------ method called to produce the data ------------
181 void
183 {
184  nextEvent();
185  if (!partonLevel) {
186  throw edm::Exception(edm::errors::EventGenerationFailure) << "No lhe event found in ExternalLHEProducer::produce(). "
187  << "The likely cause is that the lhe file contains fewer events than were requested, which is possible "
188  << "in case of phase space integration or uneweighting efficiency problems.";
189  }
190 
191  std::unique_ptr<LHEEventProduct> product(
192  new LHEEventProduct(*partonLevel->getHEPEUP(),
193  partonLevel->originalXWGTUP())
194  );
195  if (partonLevel->getPDF()) {
196  product->setPDF(*partonLevel->getPDF());
197  }
198  std::for_each(partonLevel->weights().begin(),
199  partonLevel->weights().end(),
200  boost::bind(&LHEEventProduct::addWeight,
201  product.get(), _1));
202  product->setScales(partonLevel->scales());
203  if (nPartonMapping_.empty()) {
204  product->setNpLO(partonLevel->npLO());
205  product->setNpNLO(partonLevel->npNLO());
206  }
207  else {
208  // overwrite npLO and npNLO values by user-specified mapping
209  unsigned processId(partonLevel->getHEPEUP()->IDPRUP);
210  unsigned order(0);
211  unsigned np(0);
212  try {
213  auto procDef(nPartonMapping_.at(processId));
214  order = procDef.first;
215  np = procDef.second;
216  }
217  catch (std::out_of_range&) {
218  throw cms::Exception("ExternalLHEProducer") << "Unexpected IDPRUP encountered: " << partonLevel->getHEPEUP()->IDPRUP;
219  }
220 
221  switch (order) {
222  case 0:
223  product->setNpLO(np);
224  product->setNpNLO(-1);
225  break;
226  case 1:
227  product->setNpLO(-1);
228  product->setNpNLO(np);
229  break;
230  default:
231  break;
232  }
233  }
234 
235  std::for_each(partonLevel->getComments().begin(),
236  partonLevel->getComments().end(),
237  boost::bind(&LHEEventProduct::addComment,
238  product.get(), _1));
239 
240  iEvent.put(std::move(product));
241 
242  if (runInfo) {
243  std::unique_ptr<LHERunInfoProduct> product(new LHERunInfoProduct(*runInfo->getHEPRUP()));
244  std::for_each(runInfo->getHeaders().begin(),
245  runInfo->getHeaders().end(),
246  boost::bind(&LHERunInfoProduct::addHeader,
247  product.get(), _1));
248  std::for_each(runInfo->getComments().begin(),
249  runInfo->getComments().end(),
250  boost::bind(&LHERunInfoProduct::addComment,
251  product.get(), _1));
252 
253  if (!runInfoProducts.empty()) {
254  runInfoProducts.front().mergeProduct(*product);
255  if (!wasMerged) {
256  runInfoProducts.pop_front();
257  runInfoProducts.push_front(product.release());
258  wasMerged = true;
259  }
260  }
261 
262  runInfo.reset();
263  }
264 
265  partonLevel.reset();
266  return;
267 }
268 
269 // ------------ method called when starting to processes a run ------------
270 void
272 {
273 
274  // pass the number of events as previous to last argument
275 
276  std::ostringstream eventStream;
277  eventStream << nEvents_;
278  // args_.push_back(eventStream.str());
279  args_.insert(args_.begin() + 1, eventStream.str());
280 
281  // pass the random number generator seed as last argument
282 
284 
285  if ( ! rng.isAvailable()) {
286  throw cms::Exception("Configuration")
287  << "The ExternalLHEProducer module requires the RandomNumberGeneratorService\n"
288  "which is not present in the configuration file. You must add the service\n"
289  "in the configuration file if you want to run ExternalLHEProducer";
290  }
291  std::ostringstream randomStream;
292  randomStream << rng->mySeed();
293  // args_.push_back(randomStream.str());
294  args_.insert(args_.begin() + 2, randomStream.str());
295 
296  // args_.emplace_back(std::to_string(nThreads_));
297  args_.insert(args_.begin() + 3, std::to_string(nThreads_));
298 
299  for ( unsigned int iArg = 0; iArg < args_.size() ; iArg++ ) {
300  LogDebug("LHEInputArgs") << "arg [" << iArg << "] = " << args_[iArg];
301  }
302 
303  executeScript();
304 
305  //fill LHEXMLProduct (streaming read directly into compressed buffer to save memory)
306  std::unique_ptr<LHEXMLStringProduct> p(new LHEXMLStringProduct);
307 
308  //store the XML file only if explictly requested
309  if (storeXML_) {
310  std::ifstream instream(outputFile_);
311  if (!instream) {
312  throw cms::Exception("OutputOpenError") << "Unable to open script output file " << outputFile_ << ".";
313  }
314  instream.seekg (0, instream.end);
315  int insize = instream.tellg();
316  instream.seekg (0, instream.beg);
317  p->fillCompressedContent(instream, 0.25*insize);
318  instream.close();
319  }
320  run.put(std::move(p), "LHEScriptOutput");
321 
322  // LHE C++ classes translation
323  // (read back uncompressed file from disk in streaming mode again to save memory)
324 
325  std::vector<std::string> infiles(1, outputFile_);
326  unsigned int skip = 0;
327  reader_ = std::make_unique<lhef::LHEReader>(infiles, skip);
328 
329  nextEvent();
330  if (runInfoLast) {
332 
333  std::unique_ptr<LHERunInfoProduct> product(new LHERunInfoProduct(*runInfo->getHEPRUP()));
334  std::for_each(runInfo->getHeaders().begin(),
335  runInfo->getHeaders().end(),
336  boost::bind(&LHERunInfoProduct::addHeader,
337  product.get(), _1));
338  std::for_each(runInfo->getComments().begin(),
339  runInfo->getComments().end(),
340  boost::bind(&LHERunInfoProduct::addComment,
341  product.get(), _1));
342 
343  // keep a copy around in case of merging
344  runInfoProducts.push_back(new LHERunInfoProduct(*product));
345  wasMerged = false;
346 
347  run.put(std::move(product));
348 
349  runInfo.reset();
350  }
351 
352 }
353 
354 // ------------ method called when ending the processing of a run ------------
355 void
357 {
358 
359  if (!runInfoProducts.empty()) {
360  std::unique_ptr<LHERunInfoProduct> product(runInfoProducts.pop_front().release());
361  run.put(std::move(product));
362  }
363 
364  nextEvent();
365  if (partonLevel) {
366  throw edm::Exception(edm::errors::EventGenerationFailure) << "Error in ExternalLHEProducer::endRunProduce(). "
367  << "Event loop is over, but there are still lhe events to process."
368  << "This could happen if lhe file contains more events than requested. This is never expected to happen.";
369  }
370 
371  reader_.reset();
372 
373  if (unlink(outputFile_.c_str())) {
374  throw cms::Exception("OutputDeleteError") << "Unable to delete original script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
375  }
376 
377 }
378 
379 // ------------ Close all the open file descriptors ------------
380 int
382 {
383  int maxfd = 1024;
384  int fd;
385 #ifdef __linux__
386  DIR * dir;
387  struct dirent *dp;
388  maxfd = preserve;
389  if ((dir = opendir("/proc/self/fd"))) {
390  errno = 0;
391  while ((dp = readdir (dir)) != nullptr) {
392  if ((strcmp(dp->d_name, ".") == 0) || (strcmp(dp->d_name, "..") == 0)) {
393  continue;
394  }
395  if (sscanf(dp->d_name, "%d", &fd) != 1) {
396  //throw cms::Exception("closeDescriptors") << "Found unexpected filename in /proc/self/fd: " << dp->d_name;
397  return -1;
398  }
399  if (fd > maxfd) {
400  maxfd = fd;
401  }
402  }
403  if (errno) {
404  //throw cms::Exception("closeDescriptors") << "Unable to determine the number of fd (errno=" << errno << ", " << strerror(errno) << ").";
405  return errno;
406  }
407  closedir(dir);
408  }
409 #endif
410  // TODO: assert for an unreasonable number of fds?
411  for (fd=3; fd<maxfd+1; fd++) {
412  if (fd != preserve)
413  close(fd);
414  }
415  return 0;
416 }
417 
418 // ------------ Execute the script associated with this producer ------------
419 void
421 {
422 
423  // Fork a script, wait until it finishes.
424 
425  int rc = 0, rc2 = 0;
426  int filedes[2], fd_flags;
427  unsigned int argc;
428 
429  if (pipe(filedes)) {
430  throw cms::Exception("Unable to create a new pipe");
431  }
432  FileCloseSentry sentry1(filedes[0]), sentry2(filedes[1]);
433 
434  if ((fd_flags = fcntl(filedes[1], F_GETFD, NULL)) == -1) {
435  throw cms::Exception("ExternalLHEProducer") << "Failed to get pipe file descriptor flags (errno=" << rc << ", " << strerror(rc) << ")";
436  }
437  if (fcntl(filedes[1], F_SETFD, fd_flags | FD_CLOEXEC) == -1) {
438  throw cms::Exception("ExternalLHEProducer") << "Failed to set pipe file descriptor flags (errno=" << rc << ", " << strerror(rc) << ")";
439  }
440 
441  argc = 1 + args_.size();
442  // TODO: assert that we have a reasonable number of arguments
443  char **argv = new char *[argc+1];
444  argv[0] = strdup(scriptName_.c_str());
445  for (unsigned int i=1; i<argc; i++) {
446  argv[i] = strdup(args_[i-1].c_str());
447  }
448  argv[argc] = nullptr;
449 
450  pid_t pid = fork();
451  if (pid == 0) {
452  // The child process
453  if (!(rc = closeDescriptors(filedes[1]))) {
454  execvp(argv[0], argv); // If execv returns, we have an error.
455  rc = errno;
456  }
457  while ((write(filedes[1], &rc, sizeof(int)) == -1) && (errno == EINTR)) {}
458  _exit(1);
459  }
460 
461  // Free the arg vector ASAP
462  for (unsigned int i=0; i<args_.size()+1; i++) {
463  free(argv[i]);
464  }
465  delete [] argv;
466 
467  if (pid == -1) {
468  throw cms::Exception("ForkException") << "Unable to fork a child (errno=" << errno << ", " << strerror(errno) << ")";
469  }
470 
471  close(filedes[1]);
472  // If the exec succeeds, the read will fail.
473  while (((rc2 = read(filedes[0], &rc, sizeof(int))) == -1) && (errno == EINTR)) { rc2 = 0; }
474  if ((rc2 == sizeof(int)) && rc) {
475  throw cms::Exception("ExternalLHEProducer") << "Failed to execute script (errno=" << rc << ", " << strerror(rc) << ")";
476  }
477  close(filedes[0]);
478 
479  int status = 0;
480  errno = 0;
481  do {
482  if (waitpid(pid, &status, 0) < 0) {
483  if (errno == EINTR) {
484  continue;
485  } else {
486  throw cms::Exception("ExternalLHEProducer") << "Failed to read child status (errno=" << errno << ", " << strerror(errno) << ")";
487  }
488  }
489  if (WIFSIGNALED(status)) {
490  throw cms::Exception("ExternalLHEProducer") << "Child exited due to signal " << WTERMSIG(status) << ".";
491  }
492  if (WIFEXITED(status)) {
493  rc = WEXITSTATUS(status);
494  break;
495  }
496  } while (true);
497  if (rc) {
498  throw cms::Exception("ExternalLHEProducer") << "Child failed with exit code " << rc << ".";
499  }
500 
501 }
502 
503 // ------------ Read the output script ------------
504 #define BUFSIZE 4096
505 std::unique_ptr<std::string> ExternalLHEProducer::readOutput()
506 {
507  int fd;
508  ssize_t n;
509  char buf[BUFSIZE];
510 
511  if ((fd = open(outputFile_.c_str(), O_RDONLY)) == -1) {
512  throw cms::Exception("OutputOpenError") << "Unable to open script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
513  }
514 
515  std::stringstream ss;
516  while ((n = read(fd, buf, BUFSIZE)) > 0 || (n == -1 && errno == EINTR)) {
517  if (n > 0)
518  ss.write(buf, n);
519  }
520  if (n == -1) {
521  throw cms::Exception("OutputOpenError") << "Unable to read from script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
522  }
523 
524  if (unlink(outputFile_.c_str())) {
525  throw cms::Exception("OutputDeleteError") << "Unable to delete original script output file " << outputFile_ << " (errno=" << errno << ", " << strerror(errno) << ").";
526  }
527 
528  return std::unique_ptr<std::string>(new std::string(ss.str()));
529 }
530 
531 // ------------ method fills 'descriptions' with the allowed parameters for the module ------------
532 void
534  //The following says we do not know what parameters are allowed so do no validation
535  // Please change this to state exactly what you do use, even if it is no parameters
537  desc.setComment("Executes an external script and places its output file into an EDM collection");
538 
539  edm::FileInPath thePath;
540  desc.add<edm::FileInPath>("scriptName", thePath);
541  desc.add<std::string>("outputFile", "myoutput");
542  desc.add<std::vector<std::string> >("args");
543  desc.add<uint32_t>("numberOfParameters");
544  desc.addUntracked<uint32_t>("nEvents");
545  desc.addUntracked<bool>("storeXML", false);
546 
547  edm::ParameterSetDescription nPartonMappingDesc;
548  nPartonMappingDesc.add<unsigned>("idprup");
549  nPartonMappingDesc.add<std::string>("order");
550  nPartonMappingDesc.add<unsigned>("np");
551  desc.addVPSetOptional("nPartonMapping", nPartonMappingDesc);
552 
553  descriptions.addDefault(desc);
554 }
555 
557 {
558 
559  if (partonLevel)
560  return;
561 
562  if(not reader_) { return;}
563  partonLevel = reader_->next();
564  if (!partonLevel)
565  return;
566 
567  std::shared_ptr<lhef::LHERunInfo> runInfoThis = partonLevel->getRunInfo();
568  if (runInfoThis != runInfoLast) {
569  runInfo = runInfoThis;
570  runInfoLast = runInfoThis;
571  }
572 }
573 
574 //define this as a plug-in
#define LogDebug(id)
void beginRunProduce(edm::Run &run, edm::EventSetup const &es) override
VParameterSet const & getParameterSetVector(std::string const &name) const
void endRunProduce(edm::Run &, edm::EventSetup const &) override
std::shared_ptr< lhef::LHEEvent > partonLevel
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:125
std::unique_ptr< std::string > readOutput()
std::shared_ptr< lhef::LHERunInfo > runInfoLast
ParameterDescriptionBase * addUntracked(U const &iLabel, T const &value)
void addHeader(const Header &header)
void addComment(const std::string &line)
ParameterDescriptionBase * addVPSetOptional(U const &iLabel, ParameterSetDescription const &validator, std::vector< ParameterSet > const &defaults)
void produce(edm::Event &, const edm::EventSetup &) override
void addWeight(const WGT &wgt)
bool exists(std::string const &parameterName) const
checks if a parameter exists
#define NULL
Definition: scimark2.h:8
std::vector< std::string > args_
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
void setComment(std::string const &value)
int closeDescriptors(int preserve)
int iEvent
Definition: GenABIO.cc:224
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
void addDefault(ParameterSetDescription const &psetDescription)
int np
Definition: AMPTWrapper.h:33
std::unique_ptr< lhef::LHEReader > reader_
bool isAvailable() const
Definition: Service.h:40
#define BUFSIZE
std::map< unsigned, std::pair< unsigned, unsigned > > nPartonMapping_
def pipe(cmdline, input=None)
Definition: pipe.py:5
ParameterDescriptionBase * add(U const &iLabel, T const &value)
virtual std::uint32_t mySeed() const =0
std::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:108
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:511
Definition: Run.h:45