diff --git a/Configuration/Generator/python/CepGen_LPAIR_GamGamToLL_singlediss_13TeV_cfi.py b/Configuration/Generator/python/CepGen_LPAIR_GamGamToLL_singlediss_13TeV_cfi.py
new file mode 100644
index 0000000000000..f089fb29c5c3e
--- /dev/null
+++ b/Configuration/Generator/python/CepGen_LPAIR_GamGamToLL_singlediss_13TeV_cfi.py
@@ -0,0 +1,25 @@
+import FWCore.ParameterSet.Config as cms
+
+from GeneratorInterface.CepGenInterface.cepgenDefaultParameters_cff import *
+
+generator = cms.EDFilter("CepGenGeneratorFilter",
+ process = cms.PSet(
+ name = cms.string('lpair'),
+ kinematics = cms.PSet(
+ mode = cms.uint32(2), # 1 = elastic, 2-3 = SD, 4 = DD
+ structureFunctions = cms.PSet(
+ name = cms.int32(301) # see https://cepgen.hepforge.org/raw-modules
+ ),
+ cmEnergy = cms.double(13000.0),
+ eta = cms.vdouble(-2.5, 2.5),
+ pt = cms.vdouble(25., 9999.)
+ ),
+ processParameters = cms.PSet(
+ pair = cms.uint32(13)
+ )
+ ),
+ modifierModules = cepgenPythia6BeamFragmenter,
+ outputModules = cepgenOutputModules,
+ maxEventsToPrint = cms.untracked.int32(0),
+ verbosity = cms.untracked.int32(0)
+)
diff --git a/Configuration/Generator/python/CepGen_pptoff_GamGamToLL_singlediss_13TeV_cfi.py b/Configuration/Generator/python/CepGen_pptoff_GamGamToLL_singlediss_13TeV_cfi.py
new file mode 100644
index 0000000000000..d9d7c5ed1f51e
--- /dev/null
+++ b/Configuration/Generator/python/CepGen_pptoff_GamGamToLL_singlediss_13TeV_cfi.py
@@ -0,0 +1,28 @@
+import FWCore.ParameterSet.Config as cms
+
+from GeneratorInterface.CepGenInterface.cepgenDefaultParameters_cff import *
+
+generator = cms.EDFilter("CepGenGeneratorFilter",
+ process = cms.PSet(
+ name = cms.string('pptoff'),
+ kinematics = cms.PSet(
+ mode = cms.uint32(2), # 1 = elastic, 2-3 = SD, 4 = DD
+ structureFunctions = cms.PSet(
+ name = cms.int32(301) # see https://cepgen.hepforge.org/raw-modules
+ ),
+ cmEnergy = cms.double(13000.0),
+ qt = cms.vdouble(0., 50.),
+ rapidity = cms.vdouble(-6., 6.),
+ eta = cms.vdouble(-2.5, 2.5),
+ pt = cms.vdouble(25., 9999.),
+ ptdiff = cms.vdouble(0., 500.)
+ ),
+ processParameters = cms.PSet(
+ ktFactorised = cms.bool(True),
+ pair = cms.uint32(13)
+ )
+ ),
+ outputModules = cepgenOutputModules,
+ maxEventsToPrint = cms.untracked.int32(0),
+ verbosity = cms.untracked.int32(0)
+)
diff --git a/GeneratorInterface/CepGenInterface/BuildFile.xml b/GeneratorInterface/CepGenInterface/BuildFile.xml
new file mode 100644
index 0000000000000..940486bc97ba8
--- /dev/null
+++ b/GeneratorInterface/CepGenInterface/BuildFile.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/GeneratorInterface/CepGenInterface/interface/CepGenEventGenerator.h b/GeneratorInterface/CepGenInterface/interface/CepGenEventGenerator.h
new file mode 100644
index 0000000000000..6ef187abc9602
--- /dev/null
+++ b/GeneratorInterface/CepGenInterface/interface/CepGenEventGenerator.h
@@ -0,0 +1,43 @@
+// CepGen-CMSSW interfacing module
+// 2022-2024, Laurent Forthomme
+
+#ifndef GeneratorInterface_CepGenInterface_CepGenEventGenerator_h
+#define GeneratorInterface_CepGenInterface_CepGenEventGenerator_h
+
+#include "FWCore/Framework/interface/ConsumesCollector.h"
+#include "FWCore/ParameterSet/interface/ParameterSet.h"
+#include "GeneratorInterface/Core/interface/BaseHadronizer.h"
+
+#include
+
+namespace gen {
+ class CepGenEventGenerator : public BaseHadronizer {
+ public:
+ explicit CepGenEventGenerator(const edm::ParameterSet&, edm::ConsumesCollector&&);
+ virtual ~CepGenEventGenerator();
+
+ bool readSettings(int) { return true; }
+ bool declareStableParticles(const std::vector&) { return true; }
+ bool declareSpecialSettings(const std::vector&) { return true; }
+
+ bool initializeForInternalPartons();
+ bool generatePartonsAndHadronize();
+ bool decay() { return true; } // NOT used - let's call it "design imperfection"
+ bool residualDecay() { return true; }
+
+ void finalizeEvent() {}
+ void statistics() {}
+
+ const char* classname() const { return "CepGenEventGenerator"; }
+ const std::vector& doSharedResources() const override { return shared_resources_; }
+
+ private:
+ cepgen::Generator* gen_{nullptr};
+ const cepgen::ParametersList proc_params_;
+ std::vector > modif_modules_, output_modules_;
+ const std::vector shared_resources_;
+ HepMC::GenCrossSection xsec_;
+ };
+} // namespace gen
+
+#endif
diff --git a/GeneratorInterface/CepGenInterface/interface/CepGenGeneratorFilter.h b/GeneratorInterface/CepGenInterface/interface/CepGenGeneratorFilter.h
new file mode 100644
index 0000000000000..a922d9d73ff34
--- /dev/null
+++ b/GeneratorInterface/CepGenInterface/interface/CepGenGeneratorFilter.h
@@ -0,0 +1,24 @@
+// CepGen-CMSSW interfacing module
+// 2022-2024, Laurent Forthomme
+
+#ifndef GeneratorInterface_CepGenInterface_CepGenGeneratorFilter_h
+#define GeneratorInterface_CepGenInterface_CepGenGeneratorFilter_h
+
+#include "GeneratorInterface/Core/interface/GeneratorFilter.h"
+#include "GeneratorInterface/CepGenInterface/interface/CepGenEventGenerator.h"
+#include "GeneratorInterface/ExternalDecays/interface/ExternalDecayDriver.h"
+
+namespace edm {
+ template <>
+ inline GeneratorFilter::GeneratorFilter(
+ const ParameterSet& iConfig)
+ : hadronizer_(iConfig, consumesCollector()) {
+ init(iConfig);
+ }
+} // namespace edm
+
+namespace gen {
+ using CepGenGeneratorFilter = edm::GeneratorFilter;
+}
+
+#endif
diff --git a/GeneratorInterface/CepGenInterface/interface/CepGenParametersConverter.h b/GeneratorInterface/CepGenInterface/interface/CepGenParametersConverter.h
new file mode 100644
index 0000000000000..240f442b59c4e
--- /dev/null
+++ b/GeneratorInterface/CepGenInterface/interface/CepGenParametersConverter.h
@@ -0,0 +1,41 @@
+// CepGen-CMSSW interfacing module
+// 2022-2024, Laurent Forthomme
+
+#ifndef GeneratorInterface_CepGenInterface_CepGenParametersConverter_h
+#define GeneratorInterface_CepGenInterface_CepGenParametersConverter_h
+
+#include "FWCore/ParameterSet/interface/ParameterSet.h"
+
+#include
+
+namespace cepgen {
+ ParametersList fromParameterSet(const edm::ParameterSet& iConfig) {
+ ParametersList params;
+ for (const auto& param : iConfig.getParameterNames()) {
+ const auto cepgen_param = param == "name" ? MODULE_NAME : param;
+ if (iConfig.existsAs(param))
+ params.set(cepgen_param, iConfig.getParameter(param));
+ if (iConfig.existsAs(param))
+ params.set(cepgen_param, iConfig.getParameter(param));
+ if (iConfig.existsAs(param))
+ params.set(cepgen_param, iConfig.getParameter(param));
+ if (iConfig.existsAs(param))
+ params.set(cepgen_param, iConfig.getParameter(param));
+ if (iConfig.existsAs(param))
+ params.set(cepgen_param, iConfig.getParameter(param));
+ if (iConfig.existsAs >(param)) {
+ const auto& vec = iConfig.getParameter >(param);
+ if (vec.size() == 2)
+ params.set(cepgen_param, Limits{vec.at(0), vec.at(1)});
+ params.set(cepgen_param, iConfig.getParameter >(param));
+ }
+ if (iConfig.existsAs >(param))
+ params.set(cepgen_param, iConfig.getParameter >(param));
+ if (iConfig.existsAs(param))
+ params.set(cepgen_param, fromParameterSet(iConfig.getParameter(param)));
+ }
+ return params;
+ }
+} // namespace cepgen
+
+#endif
diff --git a/GeneratorInterface/CepGenInterface/plugins/BuildFile.xml b/GeneratorInterface/CepGenInterface/plugins/BuildFile.xml
new file mode 100644
index 0000000000000..2d00a611c2704
--- /dev/null
+++ b/GeneratorInterface/CepGenInterface/plugins/BuildFile.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/GeneratorInterface/CepGenInterface/plugins/CepGenGeneratorFilter.cc b/GeneratorInterface/CepGenInterface/plugins/CepGenGeneratorFilter.cc
new file mode 100644
index 0000000000000..ae3fdc0d8789a
--- /dev/null
+++ b/GeneratorInterface/CepGenInterface/plugins/CepGenGeneratorFilter.cc
@@ -0,0 +1,8 @@
+// CepGen-CMSSW interfacing module
+// 2022-2024, Laurent Forthomme
+
+#include "FWCore/Framework/interface/MakerMacros.h"
+#include "GeneratorInterface/CepGenInterface/interface/CepGenGeneratorFilter.h"
+
+using gen::CepGenGeneratorFilter;
+DEFINE_FWK_MODULE(CepGenGeneratorFilter);
diff --git a/GeneratorInterface/CepGenInterface/python/cepgenDefaultParameters_cff.py b/GeneratorInterface/CepGenInterface/python/cepgenDefaultParameters_cff.py
new file mode 100644
index 0000000000000..22401fac2f296
--- /dev/null
+++ b/GeneratorInterface/CepGenInterface/python/cepgenDefaultParameters_cff.py
@@ -0,0 +1,23 @@
+import FWCore.ParameterSet.Config as cms
+
+cepgenOutputModules = cms.untracked.PSet(
+ # place here all CepGen modules steering for output
+ # e.g. for a printout of every 1000th event:
+ #dump = cms.PSet(printEvery = cms.uint32(1000))
+)
+
+cepgenPythia6BeamFragmenter = cms.untracked.PSet(
+ pythia6 = cms.PSet(
+ maxTrials = cms.int32(10),
+ seed = cms.int32(42),
+ preConfiguration = cms.vstring(
+ 'MSTU(21)=1 ! Check on possible errors during program execution',
+ 'MSTU(25)=0 ! No warnings are written',
+ 'MSTJ(22)=2 ! Decay those unstable particles',
+ 'PARJ(71)=10 . ! for which ctau 10 mm',
+ 'MSTP(33)=0 ! no K factors in hard cross sections',
+ 'MSTP(2)=1 ! which order running alphaS',
+ 'MSTP(81)=0 ! multiple parton interactions 1 is Pythia default'
+ )
+ )
+)
diff --git a/GeneratorInterface/CepGenInterface/src/CepGenEventGenerator.cc b/GeneratorInterface/CepGenInterface/src/CepGenEventGenerator.cc
new file mode 100644
index 0000000000000..4507f5d7ec415
--- /dev/null
+++ b/GeneratorInterface/CepGenInterface/src/CepGenEventGenerator.cc
@@ -0,0 +1,92 @@
+// CepGen-CMSSW interfacing module
+// 2022-2024, Laurent Forthomme
+
+#include "FWCore/MessageLogger/interface/MessageLogger.h"
+#include "FWCore/ParameterSet/interface/ParameterSet.h"
+#include "FWCore/Utilities/interface/StreamID.h"
+
+#include "GeneratorInterface/CepGenInterface/interface/CepGenEventGenerator.h"
+#include "GeneratorInterface/CepGenInterface/interface/CepGenParametersConverter.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace gen;
+
+CepGenEventGenerator::CepGenEventGenerator(const edm::ParameterSet& iConfig, edm::ConsumesCollector&& iC)
+ : BaseHadronizer(iConfig),
+ proc_params_(cepgen::fromParameterSet(iConfig.getParameter("process"))) {
+ // specify the overall module verbosity
+ cepgen::utils::Logger::get().setLevel(
+ static_cast(iConfig.getUntrackedParameter("verbosity", 0)));
+
+ // build the process
+ edm::LogInfo("CepGenEventGenerator") << "Process to be generated: " << proc_params_ << ".";
+
+ const auto modif_mods = cepgen::fromParameterSet(
+ iConfig.getUntrackedParameter("modifierModules", edm::ParameterSet{}));
+ edm::LogInfo("CepGenEventGenerator") << "Event modifier modules: " << modif_mods << ".";
+ for (const auto& mod : modif_mods.keys())
+ modif_modules_.emplace_back(std::make_pair(mod, modif_mods.get(mod)));
+
+ const auto output_mods =
+ cepgen::fromParameterSet(iConfig.getUntrackedParameter("outputModules", edm::ParameterSet{}));
+ edm::LogInfo("CepGenEventGenerator") << "Output modules: " << output_mods << ".";
+ for (const auto& mod : output_mods.keys())
+ output_modules_.emplace_back(std::make_pair(mod, output_mods.get(mod)));
+}
+
+CepGenEventGenerator::~CepGenEventGenerator() { edm::LogInfo("CepGenEventGenerator") << "Destructor called."; }
+
+bool CepGenEventGenerator::initializeForInternalPartons() {
+ gen_ = new cepgen::Generator(true /* "safe" mode: start without plugins */);
+
+ auto pproc = proc_params_;
+ { // little treatment to allow for standard CepGen configurations to be copy-pasted in place
+ pproc += proc_params_.get("processParameters");
+ pproc.erase("processParameters");
+ auto& pkin = pproc.operator[]("kinematics");
+ pkin += pproc.get("inKinematics");
+ pproc.erase("inKinematics");
+ pkin += pproc.get("outKinematics");
+ pproc.erase("outKinematics");
+ if (pproc.has("mode"))
+ pkin.set("mode", pproc.get("mode"));
+ }
+
+ gen_->runParameters().setProcess(cepgen::ProcessFactory::get().build(pproc));
+ if (!gen_->runParameters().hasProcess())
+ throw cms::Exception("CepGenEventGenerator") << "Failed to retrieve a process from the configuration";
+ for (const auto& mod : modif_modules_) {
+ auto modifier = cepgen::EventModifierFactory::get().build(mod.first, mod.second);
+ for (const auto& cfg : mod.second.get >("preConfiguration"))
+ modifier->readString(cfg);
+ for (const auto& cfg : mod.second.get >("processConfiguration"))
+ modifier->readString(cfg);
+ gen_->runParameters().addModifier(std::move(modifier));
+ }
+ for (const auto& mod : output_modules_)
+ gen_->runParameters().addEventExporter(cepgen::EventExporterFactory::get().build(mod.first, mod.second));
+
+ edm::LogInfo("CepGenEventGenerator") << "Run parameters:\n" << gen_->runParameters();
+ const auto xsec = gen_->computeXsection();
+ xsec_.set_cross_section(xsec, xsec.uncertainty());
+ runInfo().setInternalXSec(GenRunInfoProduct::XSec(xsec, xsec.uncertainty()));
+ return true;
+}
+
+bool CepGenEventGenerator::generatePartonsAndHadronize() {
+ event().reset(new HepMC::CepGenEvent(gen_->next()));
+ event()->set_cross_section(xsec_);
+ event()->weights().push_back(1.);
+ return true;
+}
diff --git a/GeneratorInterface/CepGenInterface/src/CepGenGeneratorFilter.cc b/GeneratorInterface/CepGenInterface/src/CepGenGeneratorFilter.cc
new file mode 100644
index 0000000000000..d0ca0a8ebc136
--- /dev/null
+++ b/GeneratorInterface/CepGenInterface/src/CepGenGeneratorFilter.cc
@@ -0,0 +1,4 @@
+// CepGen-CMSSW interfacing module
+// 2022-2024, Laurent Forthomme
+
+#include "GeneratorInterface/CepGenInterface/interface/CepGenGeneratorFilter.h"