20 #include "tbb/task_arena.h"
21 #include "tbb/task_group.h"
30 #include <sys/resource.h>
33 #include <system_error>
37 #include "boost/ptr_container/ptr_deque.hpp"
82 std::vector<std::string>
makeArgs(uint32_t
nEvents,
unsigned int nThreads, std::uint32_t
seed)
const;
84 void executeScript(std::vector<std::string>
const&
args,
int id,
bool isPost)
const;
92 const std::vector<std::string>
args_;
130 : scriptName_((iConfig.getParameter<edm::FileInPath>(
"scriptName")).
fullPath()),
131 outputFile_(iConfig.getParameter<std::
string>(
"outputFile")),
132 args_(iConfig.getParameter<std::
vector<std::
string>>(
"args")),
133 npars_(iConfig.getParameter<uint32_t>(
"numberOfParameters")),
134 nEvents_(iConfig.getUntrackedParameter<uint32_t>(
"nEvents")),
135 storeXML_(iConfig.getUntrackedParameter<bool>(
"storeXML")),
136 generateConcurrently_(iConfig.getUntrackedParameter<bool>(
"generateConcurrently")),
137 postGenerationCommand_(iConfig.getUntrackedParameter<std::
vector<std::
string>>(
"postGenerationCommand")) {
140 <<
"Problem with configuration: " <<
args_.size() <<
" script arguments given, expected " <<
npars_;
142 if (iConfig.
exists(
"nPartonMapping")) {
144 for (
auto&
cfg : processMap) {
145 unsigned processId(
cfg.getParameter<
unsigned>(
"idprup"));
149 if (orderStr ==
"LO")
151 else if (orderStr ==
"NLO")
155 <<
"Invalid order specification for process " << processId <<
": " << orderStr;
157 unsigned np(
cfg.getParameter<
unsigned>(
"np"));
163 xmlPutToken_ = produces<LHEXMLStringProduct, edm::Transition::BeginRun>(
"LHEScriptOutput");
181 <<
"No lhe event found in ExternalLHEProducer::produce(). "
182 <<
"The likely cause is that the lhe file contains fewer events than were requested, which is possible "
183 <<
"in case of phase space integration or uneweighting efficiency problems.";
186 std::unique_ptr<LHEEventProduct> product(
205 order = procDef.first;
207 }
catch (std::out_of_range&) {
209 <<
"Unexpected IDPRUP encountered: " <<
partonLevel_->getHEPEUP()->IDPRUP;
214 product->setNpLO(np);
215 product->setNpNLO(-1);
218 product->setNpLO(-1);
219 product->setNpNLO(np);
246 <<
"The ExternalLHEProducer module requires the RandomNumberGeneratorService\n"
247 "which is not present in the configuration file. You must add the service\n"
248 "in the configuration file if you want to run ExternalLHEProducer";
251 std::vector<std::string> infiles;
257 std::exception_ptr except;
258 std::atomic<char> exceptSet{0};
260 tbb::this_task_arena::isolate([
this, &except, &infiles, &exceptSet, nEventsAve, overflow,
seed]() {
261 tbb::task_group
group;
264 if (
nEvents_ % nThreads_ != 0 and
t >= overflow) {
267 group.run([
t,
this, &infiles,
seed, nEvents, &except, &exceptSet]() {
269 using namespace std::filesystem;
270 using namespace std::string_literals;
272 infiles[
t] =
out.native();
276 if (exceptSet.compare_exchange_strong(expected, 1)) {
277 except = std::current_exception();
285 if (exceptSet != 0) {
286 std::rethrow_exception(except);
289 infiles = std::vector<std::string>(1,
outputFile_);
299 edm::LogWarning(
"ExternalLHEProducer") << postcmd[0] <<
" is not a relative path. Run it as a shell command.";
311 using namespace std::filesystem;
316 std::ifstream instream(file);
320 instream.seekg(0, instream.end);
321 int insize = instream.tellg();
322 instream.seekg(0, instream.beg);
323 p->fillCompressedContent(instream, 0.25 * insize);
336 unsigned int skip = 0;
337 reader_ = std::make_unique<lhef::LHEReader>(infiles,
skip);
348 if (std::getenv(
"VALIDATION_RUN") !=
nullptr) {
350 <<
"Event loop is over, but there are still lhe events to process, ignoring...";
353 <<
"Error in ExternalLHEProducer::endRunProduce(). "
354 <<
"Event loop is over, but there are still lhe events to process."
355 <<
"This could happen if lhe file contains more events than requested. This is never expected to happen.";
362 using namespace std::filesystem;
363 using namespace std::string_literals;
365 if (unlink(
out.c_str())) {
366 throw cms::Exception(
"OutputDeleteError") <<
"Unable to delete original script output file " <<
out
367 <<
" (errno=" << errno <<
", " << strerror(errno) <<
").";
373 <<
" (errno=" << errno <<
", " << strerror(errno) <<
").";
379 unsigned int nThreads,
380 std::uint32_t
seed)
const {
381 std::vector<std::string>
args;
382 args.reserve(3 +
args_.size());
384 args.push_back(
args_.front());
385 args.push_back(std::to_string(nEvents));
387 args.push_back(std::to_string(seed));
389 args.push_back(std::to_string(nThreads));
392 for (
unsigned int iArg = 0; iArg < args.size(); iArg++) {
393 LogDebug(
"LHEInputArgs") <<
"arg [" << iArg <<
"] = " << args[iArg];
407 if ((dir = opendir(
"/proc/self/fd"))) {
409 while ((dp = readdir(dir)) !=
nullptr) {
410 if ((strcmp(dp->d_name,
".") == 0) || (strcmp(dp->d_name,
"..") == 0)) {
413 if (sscanf(dp->d_name,
"%d", &fd) != 1) {
429 for (fd = 3; fd < maxfd + 1; fd++) {
441 int filedes[2], fd_flags;
448 if ((fd_flags = fcntl(filedes[1], F_GETFD,
NULL)) == -1) {
450 <<
"Failed to get pipe file descriptor flags (errno=" << rc <<
", " << strerror(rc) <<
")";
452 if (fcntl(filedes[1], F_SETFD, fd_flags | FD_CLOEXEC) == -1) {
454 <<
"Failed to set pipe file descriptor flags (errno=" << rc <<
", " << strerror(rc) <<
")";
457 unsigned int argc_pre = 0;
462 unsigned int argc = argc_pre + args.size();
464 char**
argv =
new char*[argc + 1];
468 for (
unsigned int i = 0;
i < args.size();
i++) {
469 argv[argc_pre +
i] = strdup(args[
i].c_str());
471 argv[
argc] =
nullptr;
478 using namespace std::filesystem;
479 using namespace std::string_literals;
481 auto newDir =
path(
"thread"s + std::to_string(
id));
482 create_directory(newDir, ec);
483 current_path(newDir, ec);
485 execvp(argv[0], argv);
488 while ((
write(filedes[1], &rc,
sizeof(
int)) == -1) && (errno == EINTR)) {
494 for (
unsigned int i = 0;
i < args.size() + 1;
i++) {
501 <<
"Unable to fork a child (errno=" << errno <<
", " << strerror(errno) <<
")";
506 while (((rc2 =
read(filedes[0], &rc,
sizeof(
int))) == -1) && (errno == EINTR)) {
509 if ((rc2 ==
sizeof(
int)) && rc) {
511 <<
"Failed to execute script (errno=" << rc <<
", " << strerror(rc) <<
")";
518 if (waitpid(pid, &status, 0) < 0) {
519 if (errno == EINTR) {
523 <<
"Failed to read child status (errno=" << errno <<
", " << strerror(errno) <<
")";
526 if (WIFSIGNALED(status)) {
527 throw cms::Exception(
"ExternalLHEProducer") <<
"Child exited due to signal " << WTERMSIG(status) <<
".";
529 if (WIFEXITED(status)) {
530 rc = WEXITSTATUS(status);
535 throw cms::Exception(
"ExternalLHEProducer") <<
"Child failed with exit code " << rc <<
".";
544 desc.
setComment(
"Executes an external script and places its output file into an EDM collection");
549 desc.
add<std::vector<std::string>>(
"args");
550 desc.
add<uint32_t>(
"numberOfParameters");
554 ->setComment(
"If true, run the script concurrently in separate processes.");
555 desc.
addUntracked<std::vector<std::string>>(
"postGenerationCommand", std::vector<std::string>())
557 "Command to run after the generation script has completed. The first argument can be a relative path.");
560 nPartonMappingDesc.
add<
unsigned>(
"idprup");
562 nPartonMappingDesc.
add<
unsigned>(
"np");
569 std::unique_ptr<LHERunInfoProduct> retValue;
571 for (
auto const&
file : iFiles) {
572 unsigned int skip = 0;
573 std::vector<std::string> infiles(1,
file);
574 auto reader = std::make_unique<lhef::LHEReader>(infiles,
skip);
575 auto parton =
reader->next();
579 auto runInfo = parton->getRunInfo();
582 std::for_each(
runInfo->getHeaders().begin(),
585 std::for_each(
runInfo->getComments().begin(),
589 retValue = std::make_unique<LHERunInfoProduct>(
std::move(product));
611 newFileOpened =
false;
void beginRunProduce(edm::Run &run, edm::EventSetup const &es) override
void setComment(std::string const &value)
VParameterSet const & getParameterSetVector(std::string const &name) const
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
ParameterDescriptionBase * addUntracked(U const &iLabel, T const &value)
std::unique_ptr< LHERunInfoProduct > generateRunInfo(std::vector< std::string > const &files) const
void addHeader(const Header &header)
void addComment(const std::string &line)
#define DEFINE_FWK_MODULE(type)
ParameterDescriptionBase * addVPSetOptional(U const &iLabel, ParameterSetDescription const &validator, std::vector< ParameterSet > const &defaults)
void produce(edm::Event &, const edm::EventSetup &) override
void executeScript(std::vector< std::string > const &args, int id, bool isPost) const
void addWeight(const WGT &wgt)
bool exists(std::string const ¶meterName) const
checks if a parameter exists
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
edm::EDPutTokenT< LHERunInfoProduct > beginRunPutToken_
edm::EDPutTokenT< LHEEventProduct > eventPutToken_
void setComment(std::string const &value)
void addDefault(ParameterSetDescription const &psetDescription)
virtual std::uint32_t mySeed() const =0
edm::EDPutTokenT< LHEXMLStringProduct > xmlPutToken_
bool generateConcurrently_
int closeDescriptors(int preserve) const
std::unique_ptr< lhef::LHEReader > reader_
std::map< unsigned, std::pair< unsigned, unsigned > > nPartonMapping_
std::vector< std::string > makeArgs(uint32_t nEvents, unsigned int nThreads, std::uint32_t seed) const
ParameterDescriptionBase * add(U const &iLabel, T const &value)
const std::vector< std::string > args_
std::string outputContents_
const std::vector< std::string > postGenerationCommand_
void addComment(const std::string &line)
void beginRun(edm::Run const &, edm::EventSetup const &) override
void preallocThreads(unsigned int) override
void put(std::unique_ptr< PROD > product)
Put a new product.
bool mergeProduct(const LHERunInfoProduct &other)
std::string fullPath() const
FileCloseSentry & operator=(const FileCloseSentry &)=delete
Log< level::Warning, false > LogWarning
ExternalLHEProducer(const edm::ParameterSet &iConfig)
std::shared_ptr< lhef::LHEEvent > partonLevel_
void endRun(edm::Run const &, edm::EventSetup const &) override