Skip to content

Commit

Permalink
Core+Pythia8: added a safer caller method for OS interaction
Browse files Browse the repository at this point in the history
  • Loading branch information
forthommel committed Oct 7, 2023
1 parent d7fe592 commit fb48316
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 130 deletions.
51 changes: 51 additions & 0 deletions CepGen/Utils/Caller.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* CepGen: a central exclusive processes event generator
* Copyright (C) 2023 Laurent Forthomme
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <memory>
#include <string>
#include <vector>

#include "CepGen/Core/Exception.h"
#include "CepGen/Utils/Caller.h"
#include "CepGen/Utils/String.h"

namespace cepgen {
namespace utils {
std::string Caller::call(const std::vector<std::string>& commands) { return call(utils::merge(commands, " ")); }

std::string Caller::call(const std::string& command) {
auto pipe = popen(command.c_str(), "r");
if (!pipe)
throw CG_FATAL("Caller") << "Failed to call the command '" << command << "'.";
std::array<char, 128> buffer;
std::string result;
while (!feof(pipe))
if (fgets(buffer.data(), buffer.size(), pipe) != nullptr)
result += buffer.data();
auto rc = pclose(pipe);
CG_DEBUG("Caller").log([&](auto& log) {
log << "Command '" << command << "' returned code '" << rc << "'.";
if (!result.empty())
log << " Message: '" << result << "'.";
});
if (rc != EXIT_SUCCESS)
throw CG_FATAL("Caller") << "Command '" << command << "' failed with return code '" << rc << "'.";
return result;
}
} // namespace utils
} // namespace cepgen
41 changes: 41 additions & 0 deletions CepGen/Utils/Caller.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* CepGen: a central exclusive processes event generator
* Copyright (C) 2023 Laurent Forthomme
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef CepGen_Utils_Caller_h
#define CepGen_Utils_Caller_h

#include <string>
#include <vector>

namespace cepgen {
namespace utils {
/// External command piping utility
class Caller {
public:
Caller() {}
/// Start a logged call command
/// \param[in] commands Command path for the session
static std::string call(const std::vector<std::string>& commands);
/// Start a logged call command
/// \param[in] command Command path for the session
static std::string call(const std::string& command);
};
} // namespace utils
} // namespace cepgen

#endif
148 changes: 67 additions & 81 deletions CepGenAddOns/Pythia8Wrapper/LHEFPythiaHandler.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* CepGen: a central exclusive processes event generator
* Copyright (C) 2013-2023 Laurent Forthomme
* Copyright (C) 2016-2023 Laurent Forthomme
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand All @@ -22,6 +22,7 @@
#include "CepGen/Event/Event.h"
#include "CepGen/EventFilter/EventExporter.h"
#include "CepGen/Modules/EventExporterFactory.h"
#include "CepGen/Utils/Caller.h"
#include "CepGen/Utils/Filesystem.h"
#include "CepGen/Utils/String.h"
#include "CepGen/Utils/Value.h"
Expand All @@ -36,97 +37,82 @@ namespace cepgen {
class LHEFPythiaHandler : public EventExporter {
public:
/// Class constructor
explicit LHEFPythiaHandler(const ParametersList&);
~LHEFPythiaHandler();

static ParametersDescription description();

void initialise() override;
/// Writer operator
void operator<<(const Event&) override;
void setCrossSection(const Value&) override;

private:
std::unique_ptr<Pythia8::Pythia> pythia_;
std::shared_ptr<Pythia8::CepGenEvent> lhaevt_;
const bool compress_event_;
std::string filename_;
bool gzip_;
};

LHEFPythiaHandler::LHEFPythiaHandler(const ParametersList& params)
: EventExporter(params),
pythia_(new Pythia8::Pythia),
lhaevt_(new Pythia8::CepGenEvent),
compress_event_(steer<bool>("compress")),
filename_(steer<std::string>("filename")),
gzip_(false) {
explicit LHEFPythiaHandler(const ParametersList& params)
: EventExporter(params),
pythia_(new Pythia8::Pythia),
lhaevt_(new Pythia8::CepGenEvent),
compress_event_(steer<bool>("compress")),
filename_(steer<std::string>("filename")) {
if (utils::fileExtension(filename_) == ".gz") {
#ifdef GZIP_BIN
if (utils::fileExtension(filename_) == ".gz") {
utils::replace_all(filename_, ".gz", "");
gzip_ = true;
utils::replace_all(filename_, ".gz", "");
#else
CG_WARNING("LHEFPythiaHandler")
<< "gzip compression requested, but the executable was not linked at Pythia8 wrapper compile time.";
#endif
gzip_ = true;
}
{
auto file_tmp = std::ofstream(filename_);
if (!file_tmp.is_open())
throw CG_FATAL("LHEFPythiaHandler") << "Failed to open output filename \"" << filename_ << "\" for writing!";
}
lhaevt_->openLHEF(filename_);
}
inline ~LHEFPythiaHandler() {
if (lhaevt_)
lhaevt_->closeLHEF(false); // we do not want to rewrite the init block
if (gzip_)
#ifdef GZIP_BIN
utils::Caller::call({GZIP_BIN, "-f", filename_});
#endif
{
auto file_tmp = std::ofstream(filename_);
if (!file_tmp.is_open())
throw CG_FATAL("LHEFPythiaHandler") << "Failed to open output filename \"" << filename_ << "\" for writing!";
}
lhaevt_->openLHEF(filename_);
}

LHEFPythiaHandler::~LHEFPythiaHandler() {
if (lhaevt_)
lhaevt_->closeLHEF(false); // we do not want to rewrite the init block
#ifdef GZIP_BIN
if (gzip_) {
std::string cmnd(GZIP_BIN);
cmnd += " -f " + filename_;
if (system(cmnd.c_str()) != 0)
CG_WARNING("LHEFPythiaHandler") << "Failed to zip the output file with command \"" << cmnd << "\".";
CG_DEBUG("LHEFPythiaHandler") << cmnd;
inline static ParametersDescription description() {
auto desc = EventExporter::description();
desc.setDescription("Pythia 8-based LHEF output module");
desc.add<bool>("compress", true);
desc.add<std::string>("filename", "output.lhe").setDescription("Output filename");
return desc;
}
#endif
}

void LHEFPythiaHandler::initialise() {
std::ostringstream oss_init;
oss_init << "<!--\n" << banner() << "\n-->";
oss_init << std::endl; // LHEF is usually not as beautifully parsed as a standard XML...
// we're physicists, what do you expect?
lhaevt_->addComments(oss_init.str());
lhaevt_->initialise(runParameters());
inline void initialise() override {
std::ostringstream oss_init;
oss_init << "<!--\n" << banner() << "\n-->";
oss_init << std::endl; // LHEF is usually not as beautifully parsed as a standard XML...
// we're physicists, what do you expect?
lhaevt_->addComments(oss_init.str());
lhaevt_->initialise(runParameters());
#if PYTHIA_VERSION_INTEGER < 8300
pythia_->setLHAupPtr(lhaevt_.get());
pythia_->setLHAupPtr(lhaevt_.get());
#else
pythia_->setLHAupPtr(lhaevt_);
pythia_->setLHAupPtr(lhaevt_);
#endif
pythia_->settings.flag("ProcessLevel:all", false); // we do not want Pythia to interfere...
pythia_->settings.flag("PartonLevel:all", false); // we do not want Pythia to interfere...
pythia_->settings.flag("HadronLevel:all", false); // we do not want Pythia to interfere...
pythia_->settings.mode("Beams:frameType", 5); // LHEF event readout
pythia_->settings.mode("Next:numberCount", 0); // remove some of the Pythia output
pythia_->init();
lhaevt_->initLHEF();
}

void LHEFPythiaHandler::operator<<(const Event& ev) {
lhaevt_->feedEvent(compress_event_ ? ev : ev.compress(), Pythia8::CepGenEvent::Type::centralAndFullBeamRemnants);
pythia_->next();
lhaevt_->eventLHEF();
}

void LHEFPythiaHandler::setCrossSection(const Value& cross_section) {
lhaevt_->setCrossSection(0, cross_section, cross_section.uncertainty());
}
pythia_->settings.flag("ProcessLevel:all", false); // we do not want Pythia to interfere...
pythia_->settings.flag("PartonLevel:all", false); // we do not want Pythia to interfere...
pythia_->settings.flag("HadronLevel:all", false); // we do not want Pythia to interfere...
pythia_->settings.mode("Beams:frameType", 5); // LHEF event readout
pythia_->settings.mode("Next:numberCount", 0); // remove some of the Pythia output
pythia_->init();
lhaevt_->initLHEF();
}
/// Writer operator
inline void operator<<(const Event& ev) override {
lhaevt_->feedEvent(compress_event_ ? ev : ev.compress(), Pythia8::CepGenEvent::Type::centralAndFullBeamRemnants);
pythia_->next();
lhaevt_->eventLHEF();
}
inline void setCrossSection(const Value& cross_section) override {
lhaevt_->setCrossSection(0, cross_section, cross_section.uncertainty());
}

ParametersDescription LHEFPythiaHandler::description() {
auto desc = EventExporter::description();
desc.setDescription("Pythia 8-based LHEF output module");
desc.add<bool>("compress", true);
desc.add<std::string>("filename", "output.lhe").setDescription("Output filename");
return desc;
}
private:
const std::unique_ptr<Pythia8::Pythia> pythia_;
const std::shared_ptr<Pythia8::CepGenEvent> lhaevt_;
const bool compress_event_;
std::string filename_;
bool gzip_{false};
};
} // namespace cepgen

REGISTER_EXPORTER("lhef", LHEFPythiaHandler);
18 changes: 11 additions & 7 deletions CepGenAddOns/Pythia8Wrapper/Pythia8CollinearFlux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ namespace cepgen {
explicit Pythia8CollinearFlux(const ParametersList& params)
: CollinearFlux(params), type_(steer<std::string>("type")), pdgid_(steer<pdgid_t>("partonPdgId")) {
if (type_ == "Lepton") {
auto lepton_params = steer<ParametersList>("leptonParams");
info_.reset(new Pythia8::Info);
if (const auto dil_sqrt_s = steer<double>("leptonBeamsSqrtS"); dil_sqrt_s > 0.)
if (const auto dil_sqrt_s = lepton_params.get<double>("sqrtS"); dil_sqrt_s > 0.)
info_->setECM(dil_sqrt_s);
else
CG_WARNING("Pythia8CollinearFlux") << "Beam-beam centre-of-mass energy is required (through the "
"'leptonBeamsSqrtS' parameter) for the 'Lepton' collinear flux mode.";
pdf_.reset(new Pythia8::Lepton(steer<pdgid_t>("leptonBeamPdgId"), steer<double>("Q2max"), info_.get()));
CG_WARNING("Pythia8CollinearFlux") << "Beam-beam centre-of-mass energy is required (through the 'sqrtS' "
"parameter) for the 'Lepton' collinear flux mode.";
pdf_.reset(new Pythia8::Lepton(
lepton_params.get<pdgid_t>("beamPdgId"), lepton_params.get<double>("Q2max"), info_.get()));
} else if (type_ == "LHAGrid1")
pdf_.reset(new Pythia8::LHAGrid1);
else if (type_ == "MSTWpdf")
Expand All @@ -59,9 +61,11 @@ namespace cepgen {
desc.setDescription("Pythia 8 coll.flux");
desc.add<std::string>("type", "Proton2gammaDZ").setDescription("type of PDF evaluator to use");
desc.add<pdgid_t>("partonPdgId", PDG::photon).setDescription("parton PDG identifier");
desc.add<pdgid_t>("leptonBeamPdgId", PDG::electron).setDescription("beam particle PDG identifier (lepton case)");
desc.add<double>("leptonBeamsSqrtS", -1.);
desc.add<double>("Q2max", 50.);
auto lepton_desc = ParametersDescription();
lepton_desc.add<pdgid_t>("beamPdgId", PDG::electron).setDescription("beam particle PDG identifier");
lepton_desc.add<double>("sqrtS", -1.);
lepton_desc.add<double>("Q2max", 50.);
desc.add<ParametersDescription>("leptonParams", lepton_desc);
return desc;
}

Expand Down

0 comments on commit fb48316

Please sign in to comment.