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