diff --git a/GeneratorInterface/EvtGenInterface/BuildFile.xml b/GeneratorInterface/EvtGenInterface/BuildFile.xml index 1c760778eb73e..96c60fae69557 100644 --- a/GeneratorInterface/EvtGenInterface/BuildFile.xml +++ b/GeneratorInterface/EvtGenInterface/BuildFile.xml @@ -4,6 +4,7 @@ + diff --git a/GeneratorInterface/EvtGenInterface/interface/myEvtRandomEngine.h b/GeneratorInterface/EvtGenInterface/interface/myEvtRandomEngine.h index be9ab5345067f..abdf86ff981a1 100644 --- a/GeneratorInterface/EvtGenInterface/interface/myEvtRandomEngine.h +++ b/GeneratorInterface/EvtGenInterface/interface/myEvtRandomEngine.h @@ -32,6 +32,10 @@ class myEvtRandomEngine : public EvtRandomEngine { double random() override; + void setSeed(unsigned long int seed) override; + + unsigned long int lastSeed() const override; + void setRandomEngine(CLHEP::HepRandomEngine* v) { the_engine = v; } CLHEP::HepRandomEngine* engine() const { return the_engine; } @@ -40,5 +44,6 @@ class myEvtRandomEngine : public EvtRandomEngine { void throwNullPtr() const; CLHEP::HepRandomEngine* the_engine; + unsigned long int m_lastSeed = 0; }; #endif diff --git a/GeneratorInterface/EvtGenInterface/plugins/EvtGen/EvtGenInterface.cc b/GeneratorInterface/EvtGenInterface/plugins/EvtGen/EvtGenInterface.cc index c71fe59e637a5..ed8ff91ee0430 100644 --- a/GeneratorInterface/EvtGenInterface/plugins/EvtGen/EvtGenInterface.cc +++ b/GeneratorInterface/EvtGenInterface/plugins/EvtGen/EvtGenInterface.cc @@ -36,25 +36,38 @@ #include "EvtGenBase/EvtDecayBase.hh" #include "EvtGenBase/EvtId.hh" #include "EvtGenBase/EvtDecayTable.hh" +#include "EvtGenBase/EvtPDL.hh" +#include "EvtGenBase/EvtRandom.hh" #include "EvtGenBase/EvtParticle.hh" #include "EvtGenBase/EvtParticleFactory.hh" #include "EvtGenBase/EvtHepMCEvent.hh" #include "HepPID/ParticleIDTranslations.hh" +#include "ATOOLS/Org/My_MPI.H" + #include "TString.h" #include #include #include +thread_local std::unique_ptr gen::EvtGenInterface::m_EvtGen{}; + using namespace gen; using namespace edm; -CLHEP::HepRandomEngine* EvtGenInterface::fRandomEngine; +// Sherpa is built with MPI and aborts unless MPI is initialized. +// We only need a dummy init, and it must happen exactly once per process not per thread. +void initDummyMPIOnce() { + [[maybe_unused]] static const bool init = [] { + MPI_Init(0, nullptr); + return true; + }(); +} EvtGenInterface::EvtGenInterface(const ParameterSet& pset) { - fPSet = new ParameterSet(pset); - the_engine = new myEvtRandomEngine(nullptr); + fPSet = std::make_unique(pset); + the_engine = std::make_unique(nullptr); } void EvtGenInterface::SetDefault_m_PDGs() { @@ -284,19 +297,28 @@ void EvtGenInterface::SetDefault_m_PDGs() { } } +// Destructor is a no-op: m_EvtGen is a thread_local std::unique_ptr that cleans up at thread exit. EvtGenInterface::~EvtGenInterface() {} -void EvtGenInterface::init() { - // flags for pythia8 - fSpecialSettings.push_back("Pythia8:ParticleDecays:mixB = off"); - // +void EvtGenInterface::ensureEvtGenOnThread() { + // This thread already has its EvtGen + if (m_EvtGen) + return; edm::FileInPath decay_table(fPSet->getParameter("decay_table")); edm::FileInPath pdt(fPSet->getParameter("particle_property_file")); bool usePythia = fPSet->getUntrackedParameter("use_internal_pythia", true); bool useTauola = fPSet->getUntrackedParameter("use_internal_tauola", true); - bool usePhotos = fPSet->getUntrackedParameter("use_internal_photos", true); + + if (fPSet->existsAs("use_internal_fsr", false)) { + edm::LogWarning("EvtGenInterface::ensureEvtGenOnThread") + << "The 'use_internal_fsr' parameter is deprecated and has no effect. " + "Please use 'fsr_model' instead (set to 'none' to disable FSR, or " + "'photos', 'sherpa', or 'vincia' to select the FSR model)."; + } + + std::string fsrModel = fPSet->getParameter("fsr_model"); //Setup evtGen following instructions on http://evtgen.warwick.ac.uk/docs/external/ bool convertPythiaCodes = fPSet->getUntrackedParameter( @@ -305,8 +327,8 @@ void EvtGenInterface::init() { std::getenv("PYTHIA8DATA"); // Specify the pythia xml data directory to use the default PYTHIA8DATA location if (tmp == nullptr) { - edm::LogError("EvtGenInterface::~EvtGenInterface") - << "EvtGenInterface::init() PYTHIA8DATA not defined. Terminating program "; + edm::LogError("EvtGenInterface::ensureEvtGenOnThread") + << "PYTHIA8DATA not defined. Terminating program "; exit(0); } @@ -317,8 +339,20 @@ void EvtGenInterface::init() { // Set up the default external generator list: Photos, Pythia and/or Tauola EvtExternalGenList genList(convertPythiaCodes, pythiaDir, photonType, useEvtGenRandom); EvtAbsRadCorr* radCorrEngine = nullptr; - if (usePhotos) - radCorrEngine = genList.getPhotosModel(); // Get interface to radiative correction engine + if (fsrModel == "none") { + // FSR disabled + } else if (fsrModel == "photos") { + radCorrEngine = genList.getPhotosModel(); + } else if (fsrModel == "sherpa") { + initDummyMPIOnce(); // Sherpa is built with MPI and complains if not initialized; do this once per process. + radCorrEngine = genList.getSherpaPhotonsModel(1e-7, 1, 0); + } else if (fsrModel == "vincia") { + radCorrEngine = genList.getVinciaQEDModel(1.0e-7); + } else { + throw cms::Exception("Configuration") + << "EvtGenInterface: unknown fsr_model '" << fsrModel + << "'. Allowed values are 'none', 'photos', 'sherpa', or 'vincia'."; + } std::list extraModels = genList.getListOfModels(); // get interface to Pythia and Tauola std::list myExtraModels; for (unsigned int i = 0; i < extraModels.size(); i++) { @@ -339,21 +373,12 @@ void EvtGenInterface::init() { std::list::iterator it = userModels.begin(); std::advance(it, i); TString name = (*it)->getName(); - edm::LogInfo("EvtGenInterface::~EvtGenInterface") << "Adding user model: " << name; + edm::LogInfo("EvtGenInterface::ensureEvtGenOnThread") << "Adding user model: " << name; myExtraModels.push_back(*it); } - // Set up the incoherent (1) or coherent (0) B mixing option - BmixingOption = fPSet->getUntrackedParameter("B_Mixing", 1); - if (BmixingOption != 0 && BmixingOption != 1) { - throw cms::Exception("Configuration") << "EvtGenProducer requires B_Mixing to be 0 (coherent) or 1 (incoherent) \n" - "Please fix this in your configuration."; - } - - ////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Create the EvtGen generator object, passing the external generators - m_EvtGen = new EvtGen( - decay_table.fullPath().c_str(), pdt.fullPath().c_str(), the_engine, radCorrEngine, &myExtraModels, BmixingOption); + m_EvtGen = std::make_unique( + decay_table.fullPath().c_str(), pdt.fullPath().c_str(), the_engine.get(), radCorrEngine, &myExtraModels, BmixingOption); // Add additional user information if (fPSet->exists("user_decay_file")) { @@ -370,9 +395,8 @@ void EvtGenInterface::init() { int tmp_creation = mkstemp(user_decay_tmp); FILE* tmpf = std::fopen(user_decay_tmp, "w"); if (!tmpf || (tmp_creation == -1)) { - edm::LogError("EvtGenInterface::~EvtGenInterface") - << "EvtGenInterface::init() fails when trying to open a temporary file for embedded user.dec. Terminating " - "program "; + edm::LogError("EvtGenInterface::ensureEvtGenOnThread") + << "fails when trying to open a temporary file for embedded user.dec. Terminating program "; exit(0); } for (unsigned int i = 0; i < user_decay_lines.size(); i++) { @@ -382,6 +406,23 @@ void EvtGenInterface::init() { std::fclose(tmpf); m_EvtGen->readUDecay(user_decay_tmp); } +} + +void EvtGenInterface::init() { + // flags for pythia8 + fSpecialSettings.push_back("Pythia8:ParticleDecays:mixB = off"); + + // Set up the incoherent (1) or coherent (0) B mixing option. Must be set before + // ensureEvtGenOnThread() because the EvtGen ctor consumes it. + BmixingOption = fPSet->getUntrackedParameter("B_Mixing", 1); + if (BmixingOption != 0 && BmixingOption != 1) { + throw cms::Exception("Configuration") << "EvtGenProducer requires B_Mixing to be 0 (coherent) or 1 (incoherent) \n" + "Please fix this in your configuration."; + } + + // Construct the EvtGen instance for this thread (no-op if already constructed). Streams + // running decay() later on a different thread will lazy-construct on that thread instead. + ensureEvtGenOnThread(); // setup pdgid which the generator/hadronizer should not decay if (fPSet->exists("operates_on_particles")) { @@ -452,6 +493,10 @@ void EvtGenInterface::init() { } HepMC::GenEvent* EvtGenInterface::decay(HepMC::GenEvent* evt) { + // If the framework scheduled this stream onto a thread that has not yet built an EvtGen, + // construct one now. No-op on threads that already initialised in init(). + ensureEvtGenOnThread(); + if (the_engine->engine() == nullptr) { throw edm::Exception(edm::errors::LogicError) << "The EvtGen code attempted to use a random number engine while\n" @@ -496,8 +541,8 @@ HepMC::GenEvent* EvtGenInterface::decay(HepMC::GenEvent* evt) { } EvtId idEvt = EvtPDL::evtIdFromStdHep(idHep); int ipart = idEvt.getId(); - EvtDecayTable* evtDecayTable = EvtDecayTable::getInstance(); - if (!isforced && isDefaultEvtGen && ipart != -1 && evtDecayTable->getNMode(ipart) != 0) { + EvtDecayTable& evtDecayTable = EvtDecayTable::getInstance(); + if (!isforced && isDefaultEvtGen && ipart != -1 && evtDecayTable.getNMode(ipart) != 0) { addToHepMC(*p, idEvt, evt, true); // generate decay and remove daugther if they are forced } } @@ -616,17 +661,11 @@ void EvtGenInterface::update_particles(HepMC::GenParticle* partHep, HepMC::GenEv void EvtGenInterface::setRandomEngine(CLHEP::HepRandomEngine* v) { the_engine->setRandomEngine(v); - fRandomEngine = v; + EvtRandom::setRandomEngine(the_engine.get()); } double EvtGenInterface::flat() { - if (!fRandomEngine) { - throw cms::Exception("LogicError") - << "EvtGenInterface::flat: Attempt to generate random number when engine pointer is null\n" - << "This might mean that the code was modified to generate a random number outside the\n" - << "event and beginLuminosityBlock methods, which is not allowed.\n"; - } - return fRandomEngine->flat(); + return the_engine->random(); } bool EvtGenInterface::findLastinChain(HepMC::GenParticle*& p) { diff --git a/GeneratorInterface/EvtGenInterface/plugins/EvtGen/EvtGenInterface.h b/GeneratorInterface/EvtGenInterface/plugins/EvtGen/EvtGenInterface.h index 0dad34911846c..bb5f810784254 100644 --- a/GeneratorInterface/EvtGenInterface/plugins/EvtGen/EvtGenInterface.h +++ b/GeneratorInterface/EvtGenInterface/plugins/EvtGen/EvtGenInterface.h @@ -43,7 +43,7 @@ namespace gen { const std::vector& operatesOnParticles() override { return m_PDGs; } HepMC::GenEvent* decay(HepMC::GenEvent*) override; void setRandomEngine(CLHEP::HepRandomEngine* v) override; - static double flat(); + double flat(); private: bool addToHepMC(HepMC::GenParticle* partHep, const EvtId& idEvt, HepMC::GenEvent* theEvent, bool del_daug); @@ -52,8 +52,10 @@ namespace gen { bool findLastinChain(HepMC::GenParticle*& p); bool hasnoDaughter(HepMC::GenParticle* p); void go_through_daughters(EvtParticle* part); + void ensureEvtGenOnThread(); - EvtGen* m_EvtGen; // EvtGen main object + // One EvtGen per thread + static thread_local std::unique_ptr m_EvtGen; std::vector forced_id; // EvtGen Id's of particles which are to be forced by EvtGen std::vector forced_pdgids; // PDG Id's of particles which are to be forced by EvtGen @@ -65,10 +67,9 @@ namespace gen { std::vector polarize_pol; std::map polarizations; int BmixingOption = 1; - edm::ParameterSet* fPSet; + std::unique_ptr fPSet; - static CLHEP::HepRandomEngine* fRandomEngine; - myEvtRandomEngine* the_engine; + std::unique_ptr the_engine; }; } // namespace gen #endif diff --git a/GeneratorInterface/EvtGenInterface/plugins/myEvtRandomEngine.cc b/GeneratorInterface/EvtGenInterface/plugins/myEvtRandomEngine.cc index 43506f9a9b132..5d39dd28369a3 100644 --- a/GeneratorInterface/EvtGenInterface/plugins/myEvtRandomEngine.cc +++ b/GeneratorInterface/EvtGenInterface/plugins/myEvtRandomEngine.cc @@ -30,6 +30,10 @@ double myEvtRandomEngine::random() { return the_engine->flat(); } +void myEvtRandomEngine::setSeed(unsigned long int seed) { m_lastSeed = seed; } + +unsigned long int myEvtRandomEngine::lastSeed() const { return m_lastSeed; } + void myEvtRandomEngine::throwNullPtr() const { throw edm::Exception(edm::errors::LogicError) << "The EvtGen code attempted to a generate random number while\n" << "the engine pointer was null. This might mean that the code\n" diff --git a/GeneratorInterface/EvtGenInterface/plugins/test/Py8_lambadb_evtgen1_Lb2plnuLCSR_cfg.py b/GeneratorInterface/EvtGenInterface/plugins/test/Py8_lambadb_evtgen1_Lb2plnuLCSR_cfg.py index d9678b66c8d3b..c845c0d3fd33f 100644 --- a/GeneratorInterface/EvtGenInterface/plugins/test/Py8_lambadb_evtgen1_Lb2plnuLCSR_cfg.py +++ b/GeneratorInterface/EvtGenInterface/plugins/test/Py8_lambadb_evtgen1_Lb2plnuLCSR_cfg.py @@ -56,6 +56,7 @@ decay_table = cms.string('GeneratorInterface/EvtGenInterface/data/DECAY_NOLONGLIFE.DEC'), list_forced_decays = cms.vstring('MyLambda_b0','Myanti-Lambda_b0'), particle_property_file = cms.FileInPath('GeneratorInterface/EvtGenInterface/data/evt.pdl'), + fsr_model = cms.string('sherpa'), operates_on_particles = cms.vint32(5122), #only care about signal particle user_decay_embedded = cms.vstring( """ diff --git a/GeneratorInterface/EvtGenInterface/test/Py8_bplus_evtgen1_cfg.py b/GeneratorInterface/EvtGenInterface/test/Py8_bplus_evtgen1_cfg.py index 08dc631309246..289c2d96b9e85 100644 --- a/GeneratorInterface/EvtGenInterface/test/Py8_bplus_evtgen1_cfg.py +++ b/GeneratorInterface/EvtGenInterface/test/Py8_bplus_evtgen1_cfg.py @@ -97,7 +97,8 @@ '0.0168 Mychi_c1 K+ SVS ;', 'Enddecay', 'CDecay MyB-', - 'End') + 'End'), + fsr_model = cms.string('sherpa'), ), parameterSets = cms.vstring('EvtGen1') ), diff --git a/GeneratorInterface/EvtGenInterface/test/Py8_tt_evtgen1_cfg.py b/GeneratorInterface/EvtGenInterface/test/Py8_tt_evtgen1_cfg.py index db0b7f6c948cf..9c2a3e81ae620 100644 --- a/GeneratorInterface/EvtGenInterface/test/Py8_tt_evtgen1_cfg.py +++ b/GeneratorInterface/EvtGenInterface/test/Py8_tt_evtgen1_cfg.py @@ -24,7 +24,8 @@ particle_property_file = cms.FileInPath('GeneratorInterface/EvtGenInterface/data/evt.pdl'), convertPythiaCodes = cms.untracked.bool(False), # this is needed since 1.6 list_forced_decays = cms.vstring(), - operates_on_particles = cms.vint32(0) #will decay all particles coded in interface, it test the whole system + operates_on_particles = cms.vint32(0), #will decay all particles coded in interface, it test the whole system, + fsr_model = cms.string('sherpa') ), parameterSets = cms.vstring('EvtGen1') ), diff --git a/GeneratorInterface/EvtGenInterface/test/external_Py8_bplus_evtgen1_cfg.py b/GeneratorInterface/EvtGenInterface/test/external_Py8_bplus_evtgen1_cfg.py index ceb2a1d1440f9..72d8c8457a2fd 100644 --- a/GeneratorInterface/EvtGenInterface/test/external_Py8_bplus_evtgen1_cfg.py +++ b/GeneratorInterface/EvtGenInterface/test/external_Py8_bplus_evtgen1_cfg.py @@ -97,7 +97,8 @@ '0.0168 Mychi_c1 K+ SVS ;', 'Enddecay', 'CDecay MyB-', - 'End') + 'End'), + fsr_model = cms.string('sherpa') ), parameterSets = cms.vstring('EvtGen1') ), diff --git a/GeneratorInterface/ExternalDecays/BuildFile.xml b/GeneratorInterface/ExternalDecays/BuildFile.xml index 64b095a3fc707..fbe5ec16d2f99 100644 --- a/GeneratorInterface/ExternalDecays/BuildFile.xml +++ b/GeneratorInterface/ExternalDecays/BuildFile.xml @@ -1,6 +1,7 @@ + diff --git a/GeneratorInterface/ExternalDecays/interface/ConcurrentExternalDecayDriver.h b/GeneratorInterface/ExternalDecays/interface/ConcurrentExternalDecayDriver.h index 80f45590dfa09..244d95cee8199 100644 --- a/GeneratorInterface/ExternalDecays/interface/ConcurrentExternalDecayDriver.h +++ b/GeneratorInterface/ExternalDecays/interface/ConcurrentExternalDecayDriver.h @@ -21,6 +21,7 @@ namespace lhef { namespace gen { + class EvtGenThreadOwner; class EvtGenInterfaceBase; class TauolaInterfaceBase; class PhotosInterfaceBase; @@ -45,8 +46,9 @@ namespace gen { private: bool fIsInitialized; + std::unique_ptr fThreadOwner; + std::unique_ptr fEvtGenInterface; //std::unique_ptr fTauolaInterface; - //std::unique_ptr fEvtGenInterface; //std::unique_ptr fPhotosInterface; std::vector fPDGs; std::vector fSpecialSettings; diff --git a/GeneratorInterface/ExternalDecays/interface/EvtGenThreadOwner.h b/GeneratorInterface/ExternalDecays/interface/EvtGenThreadOwner.h new file mode 100644 index 0000000000000..d3c2573efbedd --- /dev/null +++ b/GeneratorInterface/ExternalDecays/interface/EvtGenThreadOwner.h @@ -0,0 +1,33 @@ +#ifndef gen_EvtGenThreadOwner_h +#define gen_EvtGenThreadOwner_h + +// Pins one dedicated pthread per stream and marshals every EvtGen call onto it. + +#include "FWCore/Utilities/interface/ThreadHandoff.h" +#include "FWCore/ServiceRegistry/interface/ServiceRegistry.h" + +namespace gen { + + class EvtGenThreadOwner { + public: + explicit EvtGenThreadOwner(int stackSize) : m_handoff{stackSize} {} + + EvtGenThreadOwner(const EvtGenThreadOwner&) = delete; + EvtGenThreadOwner& operator=(const EvtGenThreadOwner&) = delete; + + template + void run(F&& f) { + auto token = edm::ServiceRegistry::instance().presentToken(); + m_handoff.runAndWait([token, &f]() { + edm::ServiceRegistry::Operate guard{token}; + f(); + }); + } + + private: + edm::ThreadHandoff m_handoff; + }; + +} + +#endif diff --git a/GeneratorInterface/ExternalDecays/src/ConcurrentExternalDecayDriver.cc b/GeneratorInterface/ExternalDecays/src/ConcurrentExternalDecayDriver.cc index 57ccbe49710af..c86db8ecc2279 100644 --- a/GeneratorInterface/ExternalDecays/src/ConcurrentExternalDecayDriver.cc +++ b/GeneratorInterface/ExternalDecays/src/ConcurrentExternalDecayDriver.cc @@ -1,4 +1,5 @@ #include "GeneratorInterface/ExternalDecays/interface/ConcurrentExternalDecayDriver.h" +#include "GeneratorInterface/ExternalDecays/interface/EvtGenThreadOwner.h" #include "GeneratorInterface/Core/interface/FortranInstance.h" #include "GeneratorInterface/EvtGenInterface/interface/EvtGenFactory.h" @@ -20,100 +21,55 @@ using namespace gen; using namespace edm; -ConcurrentExternalDecayDriver::ConcurrentExternalDecayDriver(const ParameterSet& pset) : fIsInitialized(false) { +// Matches SimG4Core's OscarMTProducer default (`workerThreadStackSize`). +constexpr int kEvtGenThreadStackSize = 10 * 1024 * 1024; + +ConcurrentExternalDecayDriver::ConcurrentExternalDecayDriver(const ParameterSet& pset) + : fIsInitialized(false), fThreadOwner(std::make_unique(kEvtGenThreadStackSize)) { std::vector extGenNames = pset.getParameter >("parameterSets"); for (unsigned int ip = 0; ip < extGenNames.size(); ++ip) { const std::string& curSet = extGenNames[ip]; - throw cms::Exception("ThreadUnsafeDecayer") << "The decayer " << curSet << " is not thread-friendly."; - /* - if (curSet == "EvtGen") { - fEvtGenInterface = std::unique_ptr( - EvtGenFactory::get()->create("EvtGen", pset.getUntrackedParameter(curSet))); - exSharedResources.emplace_back(edm::SharedResourceNames::kEvtGen); - exSharedResources.emplace_back(edm::SharedResourceNames::kPythia6); - exSharedResources.emplace_back(gen::FortranInstance::kFortranInstance); - } else if (curSet == "EvtGen1" || curSet == "EvtGen130") { - fEvtGenInterface = std::unique_ptr( - EvtGenFactory::get()->create("EvtGen130", pset.getUntrackedParameter(curSet))); - exSharedResources.emplace_back(edm::SharedResourceNames::kEvtGen); - exSharedResources.emplace_back(edm::SharedResourceNames::kPythia8); - exSharedResources.emplace_back(edm::SharedResourceNames::kTauola); - exSharedResources.emplace_back(edm::SharedResourceNames::kPhotos); - exSharedResources.emplace_back(gen::FortranInstance::kFortranInstance); - } else if (curSet == "Tauola" || curSet == "Tauolapp" || curSet == "Tauolapp114") { - fTauolaInterface = std::unique_ptr( - TauolaFactory::get()->create("Tauolapp114", pset.getUntrackedParameter(curSet))); - fPhotosInterface = std::unique_ptr( - PhotosFactory::get()->create("Photos2155", pset.getUntrackedParameter(curSet))); - fPhotosInterface->configureOnlyFor(15); - fPhotosInterface->avoidTauLeptonicDecays(); - exSharedResources.emplace_back(edm::SharedResourceNames::kTauola); - exSharedResources.emplace_back(edm::SharedResourceNames::kPhotos); - } else if (curSet == "Photos" || curSet == "Photos2155") { - if (!fPhotosInterface) { - fPhotosInterface = std::unique_ptr( - PhotosFactory::get()->create("Photos2155", pset.getUntrackedParameter(curSet))); - exSharedResources.emplace_back(edm::SharedResourceNames::kPhotos); - } - } else if (curSet == "Photospp" || curSet == "Photospp356") { - if (!fPhotosInterface) { - fPhotosInterface = std::unique_ptr( - PhotosFactory::get()->create("Photospp356", pset.getUntrackedParameter(curSet))); - exSharedResources.emplace_back(edm::SharedResourceNames::kPhotos); - } + if (curSet == "EvtGen1" || curSet == "EvtGen130") { + fThreadOwner->run([&]() { + fEvtGenInterface = std::unique_ptr( + EvtGenFactory::get()->create("EvtGen130", pset.getUntrackedParameter(curSet))); + }); + } else { + throw cms::Exception("ThreadUnsafeDecayer") << "The decayer " << curSet << " is not thread-friendly."; } - */ } } -ConcurrentExternalDecayDriver::~ConcurrentExternalDecayDriver() = default; +ConcurrentExternalDecayDriver::~ConcurrentExternalDecayDriver() { + if (fEvtGenInterface) { + fThreadOwner->run([&]() { fEvtGenInterface.reset(); }); + } +} HepMC::GenEvent* ConcurrentExternalDecayDriver::decay(HepMC::GenEvent* evt, lhef::LHEEvent* lheEvent) { - /* if (fTauolaInterface) - fTauolaInterface->SetLHE(lheEvent); */ return decay(evt); } HepMC::GenEvent* ConcurrentExternalDecayDriver::decay(HepMC::GenEvent* evt) { if (!fIsInitialized) return evt; - /* - if (fEvtGenInterface) { - evt = fEvtGenInterface->decay(evt); - if (!evt) - return nullptr; - } - if (fTauolaInterface) { - evt = fTauolaInterface->decay(evt); + if (fEvtGenInterface) { + fThreadOwner->run([&]() { evt = fEvtGenInterface->decay(evt); }); if (!evt) return nullptr; } - if (fPhotosInterface) { - evt = fPhotosInterface->apply(evt); - if (!evt) - return nullptr; - } - */ return evt; } void ConcurrentExternalDecayDriver::init(const edm::EventSetup& es) { if (fIsInitialized) return; - /* - if (fTauolaInterface) { - fTauolaInterface->init(es); - for (std::vector::const_iterator i = fTauolaInterface->operatesOnParticles().begin(); - i != fTauolaInterface->operatesOnParticles().end(); - i++) - fPDGs.push_back(*i); - } if (fEvtGenInterface) { - fEvtGenInterface->init(); + fThreadOwner->run([&]() { fEvtGenInterface->init(); }); for (std::vector::const_iterator i = fEvtGenInterface->operatesOnParticles().begin(); i != fEvtGenInterface->operatesOnParticles().end(); i++) @@ -123,39 +79,15 @@ void ConcurrentExternalDecayDriver::init(const edm::EventSetup& es) { } } - if (fPhotosInterface) { - fPhotosInterface->init(); - // for tauola++ - if (fPhotosInterface) { - for (unsigned int iss = 0; iss < fPhotosInterface->specialSettings().size(); iss++) { - fSpecialSettings.push_back(fPhotosInterface->specialSettings()[iss]); - } - } - } - */ - fIsInitialized = true; return; } -void ConcurrentExternalDecayDriver::statistics() const { - /* if (fTauolaInterface) - fTauolaInterface->statistics(); - if (fPhotosInterface) - fPhotosInterface->statistics(); - */ - // similar for EvtGen if needed - return; -} +void ConcurrentExternalDecayDriver::statistics() const { return; } void ConcurrentExternalDecayDriver::setRandomEngine(CLHEP::HepRandomEngine* v) { - /* - if (fTauolaInterface) - fTauolaInterface->setRandomEngine(v); - if (fEvtGenInterface) - fEvtGenInterface->setRandomEngine(v); - if (fPhotosInterface) - fPhotosInterface->setRandomEngine(v); - */ + if (fEvtGenInterface) { + fThreadOwner->run([&]() { fEvtGenInterface->setRandomEngine(v); }); + } }