Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-01-27 00:42:08

0001 // -*- C++ -*-
0002 //
0003 //
0004 
0005 // class template ConcurrentHadronizerFilter<HAD> provides an EDFilter which uses
0006 // the hadronizer type HAD to read in external partons and hadronize them,
0007 // and decay the resulting particles, in the CMS framework.
0008 
0009 #ifndef GeneratorInterface_Core_ConcurrentHadronizerFilter_h
0010 #define GeneratorInterface_Core_ConcurrentHadronizerFilter_h
0011 
0012 #include <memory>
0013 #include <string>
0014 #include <vector>
0015 #include <atomic>
0016 
0017 #include "FWCore/Framework/interface/global/EDFilter.h"
0018 #include "FWCore/Framework/interface/Event.h"
0019 #include "FWCore/Framework/interface/EventSetup.h"
0020 #include "FWCore/Framework/interface/FileBlock.h"
0021 #include "FWCore/Framework/interface/LuminosityBlock.h"
0022 #include "FWCore/Framework/interface/MakerMacros.h"
0023 #include "FWCore/Framework/interface/Run.h"
0024 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0025 #include "FWCore/ServiceRegistry/interface/RandomEngineSentry.h"
0026 #include "FWCore/Utilities/interface/BranchType.h"
0027 #include "FWCore/Utilities/interface/EDMException.h"
0028 #include "FWCore/Utilities/interface/EDGetToken.h"
0029 #include "FWCore/Utilities/interface/TypeID.h"
0030 #include "DataFormats/Provenance/interface/BranchDescription.h"
0031 #include "CLHEP/Random/RandomEngine.h"
0032 
0033 #include "GeneratorInterface/Core/interface/HepMCFilterDriver.h"
0034 
0035 // LHE Run
0036 #include "SimDataFormats/GeneratorProducts/interface/LHERunInfoProduct.h"
0037 #include "GeneratorInterface/LHEInterface/interface/LHERunInfo.h"
0038 
0039 // LHE Event
0040 #include "SimDataFormats/GeneratorProducts/interface/LHEEventProduct.h"
0041 #include "GeneratorInterface/LHEInterface/interface/LHEEvent.h"
0042 
0043 #include "SimDataFormats/GeneratorProducts/interface/HepMCProduct.h"
0044 #include "SimDataFormats/GeneratorProducts/interface/GenRunInfoProduct.h"
0045 #include "SimDataFormats/GeneratorProducts/interface/GenLumiInfoHeader.h"
0046 #include "SimDataFormats/GeneratorProducts/interface/GenLumiInfoProduct.h"
0047 #include "SimDataFormats/GeneratorProducts/interface/GenEventInfoProduct.h"
0048 
0049 namespace edm {
0050   namespace gen {
0051     struct RunCache {
0052       mutable std::atomic<GenRunInfoProduct*> product_{nullptr};
0053       ~RunCache() { delete product_.load(); }
0054 
0055       //This is called from globalEndRunProduce which is known to
0056       // be safe as the framework would not be calling any other
0057       // methods of this module using this run at that time
0058       std::unique_ptr<GenRunInfoProduct> release() const noexcept {
0059         auto retValue = product_.load();
0060         product_.store(nullptr);
0061         return std::unique_ptr<GenRunInfoProduct>(retValue);
0062       }
0063     };
0064     struct LumiSummary {
0065       mutable std::unique_ptr<GenLumiInfoProduct> lumiInfo_;
0066       mutable std::unique_ptr<GenFilterInfo> filterInfo_;
0067     };
0068     template <typename HAD, typename DEC>
0069     struct StreamCache {
0070       StreamCache(ParameterSet const& iPSet) : hadronizer_{iPSet} {}
0071       HAD hadronizer_;
0072       std::unique_ptr<DEC> decayer_;
0073       std::unique_ptr<HepMCFilterDriver> filter_;
0074       bool initialized_ = false;
0075     };
0076   }  // namespace gen
0077 
0078   template <class HAD, class DEC>
0079   class ConcurrentHadronizerFilter : public global::EDFilter<EndRunProducer,
0080                                                              BeginLuminosityBlockProducer,
0081                                                              EndLuminosityBlockProducer,
0082                                                              RunCache<gen::RunCache>,
0083                                                              LuminosityBlockSummaryCache<gen::LumiSummary>,
0084                                                              StreamCache<gen::StreamCache<HAD, DEC>>> {
0085   public:
0086     typedef HAD Hadronizer;
0087     typedef DEC Decayer;
0088 
0089     // The given ParameterSet will be passed to the contained
0090     // Hadronizer object.
0091     explicit ConcurrentHadronizerFilter(ParameterSet const& ps);
0092 
0093     std::unique_ptr<gen::StreamCache<HAD, DEC>> beginStream(edm::StreamID) const override;
0094     bool filter(StreamID id, Event& e, EventSetup const& es) const override;
0095     void streamBeginRun(StreamID, Run const&, EventSetup const&) const override;
0096     void streamEndRun(StreamID, Run const&, EventSetup const&) const override;
0097     std::shared_ptr<gen::RunCache> globalBeginRun(edm::Run const&, edm::EventSetup const&) const override;
0098     void globalEndRun(edm::Run const&, edm::EventSetup const&) const override;
0099     void globalEndRunProduce(Run&, EventSetup const&) const override;
0100     void streamBeginLuminosityBlock(StreamID, LuminosityBlock const&, EventSetup const&) const override;
0101     void globalBeginLuminosityBlockProduce(LuminosityBlock&, EventSetup const&) const override;
0102     void streamEndLuminosityBlockSummary(StreamID,
0103                                          LuminosityBlock const&,
0104                                          EventSetup const&,
0105                                          gen::LumiSummary*) const override;
0106     std::shared_ptr<gen::LumiSummary> globalBeginLuminosityBlockSummary(edm::LuminosityBlock const&,
0107                                                                         edm::EventSetup const&) const override;
0108     void globalEndLuminosityBlockSummary(edm::LuminosityBlock const&,
0109                                          edm::EventSetup const&,
0110                                          gen::LumiSummary*) const override;
0111     void globalEndLuminosityBlockProduce(LuminosityBlock&, EventSetup const&, gen::LumiSummary const*) const override;
0112 
0113   private:
0114     void initLumi(gen::StreamCache<HAD, DEC>* cache, LuminosityBlock const& index, EventSetup const& es) const;
0115     ParameterSet config_;
0116     InputTag runInfoProductTag_;
0117     EDGetTokenT<LHERunInfoProduct> runInfoProductToken_;
0118     EDGetTokenT<LHEEventProduct> eventProductToken_;
0119     unsigned int counterRunInfoProducts_;
0120     unsigned int nAttempts_;
0121     mutable std::atomic<gen::StreamCache<HAD, DEC>*> useInLumi_{nullptr};
0122     bool const hasFilter_;
0123   };
0124 
0125   //------------------------------------------------------------------------
0126   //
0127   // Implementation
0128 
0129   template <class HAD, class DEC>
0130   ConcurrentHadronizerFilter<HAD, DEC>::ConcurrentHadronizerFilter(ParameterSet const& ps)
0131       : config_(ps),
0132         runInfoProductTag_(),
0133         runInfoProductToken_(),
0134         eventProductToken_(),
0135         counterRunInfoProducts_(0),
0136         nAttempts_(1),
0137         hasFilter_(ps.exists("HepMCFilter")) {
0138     auto ptrThis = this;
0139     this->callWhenNewProductsRegistered([ptrThis](BranchDescription const& iBD) {
0140       //this is called each time a module registers that it will produce a LHERunInfoProduct
0141       if (iBD.unwrappedTypeID() == edm::TypeID(typeid(LHERunInfoProduct)) && iBD.branchType() == InRun) {
0142         ++(ptrThis->counterRunInfoProducts_);
0143         ptrThis->eventProductToken_ = ptrThis->template consumes<LHEEventProduct>(
0144             InputTag((iBD.moduleLabel() == "externalLHEProducer") ? "externalLHEProducer" : "source"));
0145         ptrThis->runInfoProductTag_ = InputTag(iBD.moduleLabel(), iBD.productInstanceName(), iBD.processName());
0146         ptrThis->runInfoProductToken_ = ptrThis->template consumes<LHERunInfoProduct, InRun>(
0147             InputTag(iBD.moduleLabel(), iBD.productInstanceName(), iBD.processName()));
0148       }
0149     });
0150 
0151     // TODO:
0152     // Put the list of types produced by the filters here.
0153     // The current design calls for:
0154     //   * LHEGeneratorInfo
0155     //   * LHEEvent
0156     //   * HepMCProduct
0157     // But I can not find the LHEGeneratorInfo class; it might need to
0158     // be invented.
0159 
0160     //initialize setting for multiple hadronization attempts
0161     if (ps.exists("nAttempts")) {
0162       nAttempts_ = ps.getParameter<unsigned int>("nAttempts");
0163     }
0164 
0165     this->template produces<edm::HepMCProduct>("unsmeared");
0166     this->template produces<GenEventInfoProduct>();
0167     this->template produces<GenLumiInfoHeader, edm::Transition::BeginLuminosityBlock>();
0168     this->template produces<GenLumiInfoProduct, edm::Transition::EndLuminosityBlock>();
0169     this->template produces<GenRunInfoProduct, edm::Transition::EndRun>();
0170     if (hasFilter_)
0171       this->template produces<GenFilterInfo, edm::Transition::EndLuminosityBlock>();
0172   }
0173 
0174   template <class HAD, class DEC>
0175   std::unique_ptr<gen::StreamCache<HAD, DEC>> ConcurrentHadronizerFilter<HAD, DEC>::beginStream(edm::StreamID) const {
0176     auto cache = std::make_unique<gen::StreamCache<HAD, DEC>>(config_);
0177 
0178     if (config_.exists("ExternalDecays")) {
0179       ParameterSet ps1 = config_.getParameter<ParameterSet>("ExternalDecays");
0180       cache->decayer_.reset(new Decayer(ps1));
0181     }
0182 
0183     if (config_.exists("HepMCFilter")) {
0184       ParameterSet psfilter = config_.getParameter<ParameterSet>("HepMCFilter");
0185       cache->filter_.reset(new HepMCFilterDriver(psfilter));
0186     }
0187 
0188     //We need a hadronizer during globalBeginLumiProduce, doesn't matter which one
0189     gen::StreamCache<HAD, DEC>* expected = nullptr;
0190     useInLumi_.compare_exchange_strong(expected, cache.get());
0191 
0192     return cache;
0193   }
0194 
0195   template <class HAD, class DEC>
0196   bool ConcurrentHadronizerFilter<HAD, DEC>::filter(StreamID id, Event& ev, EventSetup const& /* es */) const {
0197     auto cache = this->streamCache(id);
0198     RandomEngineSentry<HAD> randomEngineSentry(&cache->hadronizer_, ev.streamID());
0199     RandomEngineSentry<DEC> randomEngineSentryDecay(cache->decayer_.get(), ev.streamID());
0200 
0201     cache->hadronizer_.setEDMEvent(ev);
0202 
0203     // get LHE stuff and pass to hadronizer!
0204     //
0205     edm::Handle<LHEEventProduct> product;
0206     ev.getByToken(eventProductToken_, product);
0207 
0208     std::unique_ptr<HepMC::GenEvent> finalEvent;
0209     std::unique_ptr<GenEventInfoProduct> finalGenEventInfo;
0210 
0211     //sum of weights for events passing hadronization
0212     double waccept = 0;
0213     //number of accepted events
0214     unsigned int naccept = 0;
0215 
0216     for (unsigned int itry = 0; itry < nAttempts_; ++itry) {
0217       cache->hadronizer_.setLHEEvent(std::make_unique<lhef::LHEEvent>(cache->hadronizer_.getLHERunInfo(), *product));
0218 
0219       // cache->hadronizer_.generatePartons();
0220       if (!cache->hadronizer_.hadronize())
0221         continue;
0222 
0223       //  this is "fake" stuff
0224       // in principle, decays are done as part of full event generation,
0225       // except for particles that are marked as to be kept stable
0226       // but we currently keep in it the design, because we might want
0227       // to use such feature for other applications
0228       //
0229       if (!cache->hadronizer_.decay())
0230         continue;
0231 
0232       std::unique_ptr<HepMC::GenEvent> event(cache->hadronizer_.getGenEvent());
0233       if (!event.get())
0234         continue;
0235 
0236       // The external decay driver is being added to the system,
0237       // it should be called here
0238       //
0239       if (cache->decayer_) {
0240         auto lheEvent = cache->hadronizer_.getLHEEvent();
0241         auto t = cache->decayer_->decay(event.get(), lheEvent.get());
0242         if (t != event.get()) {
0243           event.reset(t);
0244         }
0245         cache->hadronizer_.setLHEEvent(std::move(lheEvent));
0246       }
0247 
0248       if (!event.get())
0249         continue;
0250 
0251       // check and perform if there're any unstable particles after
0252       // running external decay packges
0253       //
0254       cache->hadronizer_.resetEvent(std::move(event));
0255       if (!cache->hadronizer_.residualDecay())
0256         continue;
0257 
0258       cache->hadronizer_.finalizeEvent();
0259 
0260       event = cache->hadronizer_.getGenEvent();
0261       if (!event.get())
0262         continue;
0263 
0264       event->set_event_number(ev.id().event());
0265 
0266       std::unique_ptr<GenEventInfoProduct> genEventInfo(cache->hadronizer_.getGenEventInfo());
0267       if (!genEventInfo.get()) {
0268         // create GenEventInfoProduct from HepMC event in case hadronizer didn't provide one
0269         genEventInfo = std::make_unique<GenEventInfoProduct>(event.get());
0270       }
0271 
0272       //if HepMCFilter was specified, test event
0273       if (cache->filter_ && !cache->filter_->filter(event.get(), genEventInfo->weight()))
0274         continue;
0275 
0276       waccept += genEventInfo->weight();
0277       ++naccept;
0278 
0279       //keep the LAST accepted event (which is equivalent to choosing randomly from the accepted events)
0280       finalEvent = std::move(event);
0281       finalGenEventInfo = std::move(genEventInfo);
0282     }
0283 
0284     if (!naccept)
0285       return false;
0286 
0287     //adjust event weights if necessary (in case input event was attempted multiple times)
0288     if (nAttempts_ > 1) {
0289       double multihadweight = double(naccept) / double(nAttempts_);
0290 
0291       //adjust weight for GenEventInfoProduct
0292       finalGenEventInfo->weights()[0] *= multihadweight;
0293 
0294       //adjust weight for HepMC GenEvent (used e.g for RIVET)
0295       finalEvent->weights()[0] *= multihadweight;
0296     }
0297 
0298     ev.put(std::move(finalGenEventInfo));
0299 
0300     std::unique_ptr<HepMCProduct> bare_product(new HepMCProduct());
0301     bare_product->addHepMCData(finalEvent.release());
0302     ev.put(std::move(bare_product), "unsmeared");
0303 
0304     return true;
0305   }
0306 
0307   template <class HAD, class DEC>
0308   void ConcurrentHadronizerFilter<HAD, DEC>::streamBeginRun(StreamID id, Run const& run, EventSetup const& es) const {
0309     // this is run-specific
0310 
0311     // get LHE stuff and pass to hadronizer!
0312 
0313     if (counterRunInfoProducts_ > 1)
0314       throw edm::Exception(errors::EventCorruption) << "More than one LHERunInfoProduct present";
0315 
0316     if (counterRunInfoProducts_ == 0)
0317       throw edm::Exception(errors::EventCorruption) << "No LHERunInfoProduct present";
0318 
0319     edm::Handle<LHERunInfoProduct> lheRunInfoProduct;
0320     run.getByLabel(runInfoProductTag_, lheRunInfoProduct);
0321     //TODO: fix so that this actually works with getByToken commented below...
0322     //run.getByToken(runInfoProductToken_, lheRunInfoProduct);
0323     auto& hadronizer = this->streamCache(id)->hadronizer_;
0324 
0325     hadronizer.setLHERunInfo(std::make_unique<lhef::LHERunInfo>(*lheRunInfoProduct));
0326     lhef::LHERunInfo* lheRunInfo = hadronizer.getLHERunInfo().get();
0327     lheRunInfo->initLumi();
0328   }
0329 
0330   template <class HAD, class DEC>
0331   void ConcurrentHadronizerFilter<HAD, DEC>::streamEndRun(StreamID id, Run const& r, EventSetup const&) const {
0332     auto rCache = this->runCache(r.index());
0333     auto cache = this->streamCache(id);
0334 
0335     // Retrieve the LHE run info summary and transfer determined
0336     // cross-section into the generator run info
0337 
0338     const lhef::LHERunInfo* lheRunInfo = cache->hadronizer_.getLHERunInfo().get();
0339     lhef::LHERunInfo::XSec xsec = lheRunInfo->xsec();
0340 
0341     GenRunInfoProduct& genRunInfo = cache->hadronizer_.getGenRunInfo();
0342     genRunInfo.setInternalXSec(GenRunInfoProduct::XSec(xsec.value(), xsec.error()));
0343 
0344     // If relevant, record the integrated luminosity for this run
0345     // here.  To do so, we would need a standard function to invoke on
0346     // the contained hadronizer that would report the integrated
0347     // luminosity.
0348 
0349     if (cache->initialized_) {
0350       cache->hadronizer_.statistics();
0351       if (cache->decayer_)
0352         cache->decayer_->statistics();
0353       if (cache->filter_)
0354         cache->filter_->statistics();
0355       lheRunInfo->statistics();
0356     }
0357     GenRunInfoProduct* expect = nullptr;
0358 
0359     std::unique_ptr<GenRunInfoProduct> griproduct(new GenRunInfoProduct(genRunInfo));
0360     //All the GenRunInfoProducts for all streams shoule be identical, therefore we only
0361     // need one
0362     if (rCache->product_.compare_exchange_strong(expect, griproduct.get())) {
0363       griproduct.release();
0364     }
0365   }
0366 
0367   template <class HAD, class DEC>
0368   std::shared_ptr<gen::RunCache> ConcurrentHadronizerFilter<HAD, DEC>::globalBeginRun(edm::Run const&,
0369                                                                                       edm::EventSetup const&) const {
0370     return std::make_shared<gen::RunCache>();
0371   }
0372 
0373   template <class HAD, class DEC>
0374   void ConcurrentHadronizerFilter<HAD, DEC>::globalEndRun(edm::Run const&, edm::EventSetup const&) const {}
0375 
0376   template <class HAD, class DEC>
0377   void ConcurrentHadronizerFilter<HAD, DEC>::globalEndRunProduce(Run& r, EventSetup const&) const {
0378     r.put(this->runCache(r.index())->release());
0379   }
0380 
0381   template <class HAD, class DEC>
0382   void ConcurrentHadronizerFilter<HAD, DEC>::streamBeginLuminosityBlock(StreamID id,
0383                                                                         LuminosityBlock const& lumi,
0384                                                                         EventSetup const& es) const {
0385     if (useInLumi_ != this->streamCache(id)) {
0386       initLumi(this->streamCache(id), lumi, es);
0387     } else {
0388       useInLumi_.store(nullptr);
0389     }
0390   }
0391 
0392   template <class HAD, class DEC>
0393   void ConcurrentHadronizerFilter<HAD, DEC>::initLumi(gen::StreamCache<HAD, DEC>* cache,
0394                                                       LuminosityBlock const& lumi,
0395                                                       EventSetup const& es) const {
0396     lhef::LHERunInfo* lheRunInfo = cache->hadronizer_.getLHERunInfo().get();
0397     lheRunInfo->initLumi();
0398 
0399     //We need all copies to see same random # for begin lumi
0400     Service<RandomNumberGenerator> rng;
0401     auto enginePtr = rng->cloneEngine(lumi.index());
0402     cache->hadronizer_.setRandomEngine(enginePtr.get());
0403     if (cache->decayer_) {
0404       cache->decayer_->setRandomEngine(enginePtr.get());
0405     }
0406 
0407     auto unsetH = [](HAD* h) { h->setRandomEngine(nullptr); };
0408     auto unsetD = [](DEC* d) {
0409       if (d) {
0410         d->setRandomEngine(nullptr);
0411       }
0412     };
0413 
0414     std::unique_ptr<HAD, decltype(unsetH)> randomEngineSentry(&cache->hadronizer_, unsetH);
0415     std::unique_ptr<DEC, decltype(unsetD)> randomEngineSentryDecay(cache->decayer_.get(), unsetD);
0416 
0417     cache->hadronizer_.randomizeIndex(lumi, enginePtr.get());
0418 
0419     if (!cache->hadronizer_.readSettings(1))
0420       throw edm::Exception(errors::Configuration)
0421           << "Failed to read settings for the hadronizer " << cache->hadronizer_.classname() << " \n";
0422 
0423     if (cache->decayer_) {
0424       cache->decayer_->init(es);
0425       if (!cache->hadronizer_.declareStableParticles(cache->decayer_->operatesOnParticles()))
0426         throw edm::Exception(errors::Configuration)
0427             << "Failed to declare stable particles in hadronizer " << cache->hadronizer_.classname()
0428             << " for internal parton generation\n";
0429       if (!cache->hadronizer_.declareSpecialSettings(cache->decayer_->specialSettings()))
0430         throw edm::Exception(errors::Configuration)
0431             << "Failed to declare special settings in hadronizer " << cache->hadronizer_.classname() << "\n";
0432     }
0433 
0434     if (cache->filter_) {
0435       cache->filter_->resetStatistics();
0436     }
0437 
0438     if (!cache->hadronizer_.initializeForExternalPartons())
0439       throw edm::Exception(errors::Configuration)
0440           << "Failed to initialize hadronizer " << cache->hadronizer_.classname()
0441           << " for external parton generation\n";
0442 
0443     cache->initialized_ = true;
0444   }
0445 
0446   template <class HAD, class DEC>
0447   void ConcurrentHadronizerFilter<HAD, DEC>::globalBeginLuminosityBlockProduce(LuminosityBlock& lumi,
0448                                                                                EventSetup const& es) const {
0449     //need one of the streams to finish
0450     while (useInLumi_.load() == nullptr) {
0451     }
0452     initLumi(useInLumi_, lumi, es);
0453     std::unique_ptr<GenLumiInfoHeader> genLumiInfoHeader(useInLumi_.load()->hadronizer_.getGenLumiInfoHeader());
0454     lumi.put(std::move(genLumiInfoHeader));
0455   }
0456 
0457   template <class HAD, class DEC>
0458   void ConcurrentHadronizerFilter<HAD, DEC>::streamEndLuminosityBlockSummary(StreamID id,
0459                                                                              LuminosityBlock const&,
0460                                                                              EventSetup const&,
0461                                                                              gen::LumiSummary* iSummary) const {
0462     const lhef::LHERunInfo* lheRunInfo = this->streamCache(id)->hadronizer_.getLHERunInfo().get();
0463 
0464     std::vector<lhef::LHERunInfo::Process> LHELumiProcess = lheRunInfo->getLumiProcesses();
0465     std::vector<GenLumiInfoProduct::ProcessInfo> GenLumiProcess;
0466     for (unsigned int i = 0; i < LHELumiProcess.size(); i++) {
0467       lhef::LHERunInfo::Process thisProcess = LHELumiProcess[i];
0468 
0469       GenLumiInfoProduct::ProcessInfo temp;
0470       temp.setProcess(thisProcess.process());
0471       temp.setLheXSec(thisProcess.getLHEXSec().value(), thisProcess.getLHEXSec().error());
0472       temp.setNPassPos(thisProcess.nPassPos());
0473       temp.setNPassNeg(thisProcess.nPassNeg());
0474       temp.setNTotalPos(thisProcess.nTotalPos());
0475       temp.setNTotalNeg(thisProcess.nTotalNeg());
0476       temp.setTried(thisProcess.tried().n(), thisProcess.tried().sum(), thisProcess.tried().sum2());
0477       temp.setSelected(thisProcess.selected().n(), thisProcess.selected().sum(), thisProcess.selected().sum2());
0478       temp.setKilled(thisProcess.killed().n(), thisProcess.killed().sum(), thisProcess.killed().sum2());
0479       temp.setAccepted(thisProcess.accepted().n(), thisProcess.accepted().sum(), thisProcess.accepted().sum2());
0480       temp.setAcceptedBr(thisProcess.acceptedBr().n(), thisProcess.acceptedBr().sum(), thisProcess.acceptedBr().sum2());
0481       GenLumiProcess.push_back(temp);
0482     }
0483     GenLumiInfoProduct genLumiInfo;
0484     genLumiInfo.setHEPIDWTUP(lheRunInfo->getHEPRUP()->IDWTUP);
0485     genLumiInfo.setProcessInfo(GenLumiProcess);
0486 
0487     if (iSummary->lumiInfo_) {
0488       iSummary->lumiInfo_->setHEPIDWTUP(lheRunInfo->getHEPRUP()->IDWTUP);
0489       iSummary->lumiInfo_->mergeProduct(genLumiInfo);
0490     } else {
0491       iSummary->lumiInfo_ = std::make_unique<GenLumiInfoProduct>(std::move(genLumiInfo));
0492     }
0493 
0494     // produce GenFilterInfo if HepMCFilter is called
0495     if (hasFilter_) {
0496       auto filter = this->streamCache(id)->filter_.get();
0497       GenFilterInfo thisProduct(filter->numEventsPassPos(),
0498                                 filter->numEventsPassNeg(),
0499                                 filter->numEventsTotalPos(),
0500                                 filter->numEventsTotalNeg(),
0501                                 filter->sumpass_w(),
0502                                 filter->sumpass_w2(),
0503                                 filter->sumtotal_w(),
0504                                 filter->sumtotal_w2());
0505       if (not iSummary->filterInfo_) {
0506         iSummary->filterInfo_ = std::make_unique<GenFilterInfo>(std::move(thisProduct));
0507       } else {
0508         iSummary->filterInfo_->mergeProduct(thisProduct);
0509       }
0510     }
0511 
0512     gen::StreamCache<HAD, DEC>* expected = nullptr;
0513     //make it available for beginLuminosityBlockProduce
0514     useInLumi_.compare_exchange_strong(expected, this->streamCache(id));
0515   }
0516 
0517   template <class HAD, class DEC>
0518   std::shared_ptr<gen::LumiSummary> ConcurrentHadronizerFilter<HAD, DEC>::globalBeginLuminosityBlockSummary(
0519       edm::LuminosityBlock const&, edm::EventSetup const&) const {
0520     return std::make_shared<gen::LumiSummary>();
0521   }
0522 
0523   template <class HAD, class DEC>
0524   void ConcurrentHadronizerFilter<HAD, DEC>::globalEndLuminosityBlockSummary(edm::LuminosityBlock const&,
0525                                                                              edm::EventSetup const&,
0526                                                                              gen::LumiSummary*) const {}
0527 
0528   template <class HAD, class DEC>
0529   void ConcurrentHadronizerFilter<HAD, DEC>::globalEndLuminosityBlockProduce(LuminosityBlock& lumi,
0530                                                                              EventSetup const&,
0531                                                                              gen::LumiSummary const* iSummary) const {
0532     //Advance the random number generator so next begin lumi starts with new seed
0533     Service<RandomNumberGenerator> rng;
0534     rng->getEngine(lumi.index()).flat();
0535 
0536     lumi.put(std::move(iSummary->lumiInfo_));
0537 
0538     // produce GenFilterInfo if HepMCFilter is called
0539     if (hasFilter_) {
0540       lumi.put(std::move(iSummary->filterInfo_));
0541     }
0542   }
0543 
0544 }  // namespace edm
0545 
0546 #endif  // GeneratorInterface_Core_ConcurrentHadronizerFilter_h