Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-02-08 03:12:18

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