Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:13:25

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       bool initialized_ = false;
0113     };
0114     template <typename HAD, typename DEC>
0115     struct LumiCache {
0116       gen::StreamCache<HAD, DEC>* useInLumi_{nullptr};
0117       unsigned long long nGlobalBeginRuns_{0};
0118       unsigned long long nGlobalBeginLumis_{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     // The following six variables depend on the fact that the Framework does
0170     // not execute global begin lumi transitions and global begin run transitions
0171     // concurrently. Within a transition, modules might execute concurrently,
0172     // but only one such transition will be active at a time.
0173     mutable std::atomic<gen::StreamCache<HAD, DEC>*> useInLumi_{nullptr};
0174     mutable std::atomic<unsigned long long> nextNGlobalBeginLumis_{1};
0175     mutable std::atomic<bool> streamEndRunComplete_{true};
0176     mutable unsigned long long nGlobalBeginRuns_{0};
0177     mutable unsigned long long nInitializedWithLHERunInfo_{0};
0178     mutable unsigned long long nGlobalBeginLumis_{0};
0179 
0180     bool const hasFilter_;
0181   };
0182 
0183   //------------------------------------------------------------------------
0184   //
0185   // Implementation
0186 
0187   template <class HAD, class DEC>
0188   ConcurrentHadronizerFilter<HAD, DEC>::ConcurrentHadronizerFilter(ParameterSet const& ps)
0189       : config_(ps),
0190         runInfoProductTag_(),
0191         runInfoProductToken_(),
0192         eventProductToken_(),
0193         counterRunInfoProducts_(0),
0194         nAttempts_(1),
0195         hasFilter_(ps.exists("HepMCFilter")) {
0196     auto ptrThis = this;
0197     this->callWhenNewProductsRegistered([ptrThis](BranchDescription const& iBD) {
0198       //this is called each time a module registers that it will produce a LHERunInfoProduct
0199       if (iBD.unwrappedTypeID() == edm::TypeID(typeid(LHERunInfoProduct)) && iBD.branchType() == InRun) {
0200         ++(ptrThis->counterRunInfoProducts_);
0201         ptrThis->eventProductToken_ = ptrThis->template consumes<LHEEventProduct>(
0202             InputTag((iBD.moduleLabel() == "externalLHEProducer") ? "externalLHEProducer" : "source"));
0203         ptrThis->runInfoProductTag_ = InputTag(iBD.moduleLabel(), iBD.productInstanceName(), iBD.processName());
0204         ptrThis->runInfoProductToken_ = ptrThis->template consumes<LHERunInfoProduct, InRun>(
0205             InputTag(iBD.moduleLabel(), iBD.productInstanceName(), iBD.processName()));
0206       }
0207     });
0208 
0209     // TODO:
0210     // Put the list of types produced by the filters here.
0211     // The current design calls for:
0212     //   * LHEGeneratorInfo
0213     //   * LHEEvent
0214     //   * HepMCProduct
0215     // But I can not find the LHEGeneratorInfo class; it might need to
0216     // be invented.
0217 
0218     //initialize setting for multiple hadronization attempts
0219     if (ps.exists("nAttempts")) {
0220       nAttempts_ = ps.getParameter<unsigned int>("nAttempts");
0221     }
0222 
0223     this->template produces<edm::HepMCProduct>("unsmeared");
0224     this->template produces<GenEventInfoProduct>();
0225     this->template produces<GenLumiInfoHeader, edm::Transition::BeginLuminosityBlock>();
0226     this->template produces<GenLumiInfoProduct, edm::Transition::EndLuminosityBlock>();
0227     this->template produces<GenRunInfoProduct, edm::Transition::EndRun>();
0228     if (hasFilter_)
0229       this->template produces<GenFilterInfo, edm::Transition::EndLuminosityBlock>();
0230   }
0231 
0232   template <class HAD, class DEC>
0233   std::unique_ptr<gen::StreamCache<HAD, DEC>> ConcurrentHadronizerFilter<HAD, DEC>::beginStream(edm::StreamID) const {
0234     auto cache = std::make_unique<gen::StreamCache<HAD, DEC>>(config_);
0235 
0236     if (config_.exists("ExternalDecays")) {
0237       ParameterSet ps1 = config_.getParameter<ParameterSet>("ExternalDecays");
0238       cache->decayer_.reset(new Decayer(ps1));
0239     }
0240 
0241     if (config_.exists("HepMCFilter")) {
0242       ParameterSet psfilter = config_.getParameter<ParameterSet>("HepMCFilter");
0243       cache->filter_.reset(new HepMCFilterDriver(psfilter));
0244     }
0245 
0246     //We need a hadronizer during globalBeginLumiProduce, doesn't matter which one
0247     gen::StreamCache<HAD, DEC>* expected = nullptr;
0248     useInLumi_.compare_exchange_strong(expected, cache.get());
0249 
0250     return cache;
0251   }
0252 
0253   template <class HAD, class DEC>
0254   bool ConcurrentHadronizerFilter<HAD, DEC>::filter(StreamID id, Event& ev, EventSetup const& /* es */) const {
0255     auto cache = this->streamCache(id);
0256     RandomEngineSentry<HAD> randomEngineSentry(&cache->hadronizer_, ev.streamID());
0257     RandomEngineSentry<DEC> randomEngineSentryDecay(cache->decayer_.get(), ev.streamID());
0258 
0259     cache->hadronizer_.setEDMEvent(ev);
0260 
0261     // get LHE stuff and pass to hadronizer!
0262     //
0263     edm::Handle<LHEEventProduct> product;
0264     ev.getByToken(eventProductToken_, product);
0265 
0266     std::unique_ptr<HepMC::GenEvent> finalEvent;
0267     std::unique_ptr<GenEventInfoProduct> finalGenEventInfo;
0268 
0269     //number of accepted events
0270     unsigned int naccept = 0;
0271 
0272     for (unsigned int itry = 0; itry < nAttempts_; ++itry) {
0273       cache->hadronizer_.setLHEEvent(std::make_unique<lhef::LHEEvent>(cache->hadronizer_.getLHERunInfo(), *product));
0274 
0275       // cache->hadronizer_.generatePartons();
0276       if (!cache->hadronizer_.hadronize())
0277         continue;
0278 
0279       //  this is "fake" stuff
0280       // in principle, decays are done as part of full event generation,
0281       // except for particles that are marked as to be kept stable
0282       // but we currently keep in it the design, because we might want
0283       // to use such feature for other applications
0284       //
0285       if (!cache->hadronizer_.decay())
0286         continue;
0287 
0288       std::unique_ptr<HepMC::GenEvent> event(cache->hadronizer_.getGenEvent());
0289       if (!event.get())
0290         continue;
0291 
0292       // The external decay driver is being added to the system,
0293       // it should be called here
0294       //
0295       if (cache->decayer_) {
0296         auto lheEvent = cache->hadronizer_.getLHEEvent();
0297         auto t = cache->decayer_->decay(event.get(), lheEvent.get());
0298         if (t != event.get()) {
0299           event.reset(t);
0300         }
0301         cache->hadronizer_.setLHEEvent(std::move(lheEvent));
0302       }
0303 
0304       if (!event.get())
0305         continue;
0306 
0307       // check and perform if there're any unstable particles after
0308       // running external decay packges
0309       //
0310       cache->hadronizer_.resetEvent(std::move(event));
0311       if (!cache->hadronizer_.residualDecay())
0312         continue;
0313 
0314       cache->hadronizer_.finalizeEvent();
0315 
0316       event = cache->hadronizer_.getGenEvent();
0317       if (!event.get())
0318         continue;
0319 
0320       event->set_event_number(ev.id().event());
0321 
0322       std::unique_ptr<GenEventInfoProduct> genEventInfo(cache->hadronizer_.getGenEventInfo());
0323       if (!genEventInfo.get()) {
0324         // create GenEventInfoProduct from HepMC event in case hadronizer didn't provide one
0325         genEventInfo = std::make_unique<GenEventInfoProduct>(event.get());
0326       }
0327 
0328       //if HepMCFilter was specified, test event
0329       if (cache->filter_ && !cache->filter_->filter(event.get(), genEventInfo->weight()))
0330         continue;
0331 
0332       ++naccept;
0333 
0334       //keep the LAST accepted event (which is equivalent to choosing randomly from the accepted events)
0335       finalEvent = std::move(event);
0336       finalGenEventInfo = std::move(genEventInfo);
0337     }
0338 
0339     if (!naccept)
0340       return false;
0341 
0342     //adjust event weights if necessary (in case input event was attempted multiple times)
0343     if (nAttempts_ > 1) {
0344       double multihadweight = double(naccept) / double(nAttempts_);
0345 
0346       //adjust weight for GenEventInfoProduct
0347       finalGenEventInfo->weights()[0] *= multihadweight;
0348 
0349       //adjust weight for HepMC GenEvent (used e.g for RIVET)
0350       finalEvent->weights()[0] *= multihadweight;
0351     }
0352 
0353     ev.put(std::move(finalGenEventInfo));
0354 
0355     std::unique_ptr<HepMCProduct> bare_product(new HepMCProduct());
0356     bare_product->addHepMCData(finalEvent.release());
0357     ev.put(std::move(bare_product), "unsmeared");
0358 
0359     return true;
0360   }
0361 
0362   template <class HAD, class DEC>
0363   void ConcurrentHadronizerFilter<HAD, DEC>::streamEndRun(StreamID id, Run const& r, EventSetup const&) const {
0364     auto rCache = this->runCache(r.index());
0365     auto cache = this->streamCache(id);
0366 
0367     // Retrieve the LHE run info summary and transfer determined
0368     // cross-section into the generator run info
0369 
0370     const lhef::LHERunInfo* lheRunInfo = cache->hadronizer_.getLHERunInfo().get();
0371     if (lheRunInfo) {
0372       lhef::LHERunInfo::XSec xsec = lheRunInfo->xsec();
0373 
0374       GenRunInfoProduct& genRunInfo = cache->hadronizer_.getGenRunInfo();
0375       genRunInfo.setInternalXSec(GenRunInfoProduct::XSec(xsec.value(), xsec.error()));
0376 
0377       // If relevant, record the integrated luminosity for this run
0378       // here.  To do so, we would need a standard function to invoke on
0379       // the contained hadronizer that would report the integrated
0380       // luminosity.
0381 
0382       if (cache->initialized_) {
0383         cache->hadronizer_.statistics();
0384         if (cache->decayer_)
0385           cache->decayer_->statistics();
0386         if (cache->filter_)
0387           cache->filter_->statistics();
0388         lheRunInfo->statistics();
0389       }
0390       GenRunInfoProduct* expect = nullptr;
0391 
0392       std::unique_ptr<GenRunInfoProduct> griproduct(new GenRunInfoProduct(genRunInfo));
0393       //All the GenRunInfoProducts for all streams shoule be identical, therefore we only
0394       // need one
0395       if (rCache->product_.compare_exchange_strong(expect, griproduct.get())) {
0396         griproduct.release();
0397       }
0398     }
0399     if (cache == useInLumi_.load()) {
0400       streamEndRunComplete_ = true;
0401     }
0402   }
0403 
0404   template <class HAD, class DEC>
0405   std::shared_ptr<gen::RunCache> ConcurrentHadronizerFilter<HAD, DEC>::globalBeginRun(edm::Run const&,
0406                                                                                       edm::EventSetup const&) const {
0407     ++nGlobalBeginRuns_;
0408 
0409     if (counterRunInfoProducts_ > 1)
0410       throw edm::Exception(errors::EventCorruption) << "More than one LHERunInfoProduct present";
0411 
0412     if (counterRunInfoProducts_ == 0)
0413       throw edm::Exception(errors::EventCorruption) << "No LHERunInfoProduct present";
0414 
0415     return std::make_shared<gen::RunCache>();
0416   }
0417 
0418   template <class HAD, class DEC>
0419   void ConcurrentHadronizerFilter<HAD, DEC>::globalEndRun(edm::Run const&, edm::EventSetup const&) const {}
0420 
0421   template <class HAD, class DEC>
0422   void ConcurrentHadronizerFilter<HAD, DEC>::globalEndRunProduce(Run& r, EventSetup const&) const {
0423     auto c = this->runCache(r.index());
0424     if (c) {
0425       r.put(c->release());
0426     }
0427   }
0428 
0429   template <class HAD, class DEC>
0430   void ConcurrentHadronizerFilter<HAD, DEC>::streamBeginLuminosityBlock(StreamID id,
0431                                                                         LuminosityBlock const& lumi,
0432                                                                         EventSetup const& es) const {
0433     gen::StreamCache<HAD, DEC>* streamCachePtr = this->streamCache(id);
0434     bool newRun =
0435         streamCachePtr->nInitializedWithLHERunInfo_ < this->luminosityBlockCache(lumi.index())->nGlobalBeginRuns_;
0436     if (newRun) {
0437       streamCachePtr->nInitializedWithLHERunInfo_ = this->luminosityBlockCache(lumi.index())->nGlobalBeginRuns_;
0438     }
0439     if (this->luminosityBlockCache(lumi.index())->useInLumi_ != streamCachePtr) {
0440       if (newRun) {
0441         initializeWithLHERunInfo(streamCachePtr, lumi);
0442       }
0443       initLumi(streamCachePtr, lumi, es);
0444     }
0445   }
0446 
0447   template <class HAD, class DEC>
0448   void ConcurrentHadronizerFilter<HAD, DEC>::initializeWithLHERunInfo(gen::StreamCache<HAD, DEC>* streamCachePtr,
0449                                                                       edm::LuminosityBlock const& lumi) const {
0450     edm::Handle<LHERunInfoProduct> lheRunInfoProduct;
0451     lumi.getRun().getByLabel(runInfoProductTag_, lheRunInfoProduct);
0452     //TODO: fix so that this actually works with getByToken commented below...
0453     //run.getByToken(runInfoProductToken_, lheRunInfoProduct);
0454     auto& hadronizer = streamCachePtr->hadronizer_;
0455 
0456     hadronizer.setLHERunInfo(std::make_unique<lhef::LHERunInfo>(*lheRunInfoProduct));
0457     lhef::LHERunInfo* lheRunInfo = hadronizer.getLHERunInfo().get();
0458     lheRunInfo->initLumi();
0459   }
0460 
0461   template <class HAD, class DEC>
0462   void ConcurrentHadronizerFilter<HAD, DEC>::initLumi(gen::StreamCache<HAD, DEC>* cache,
0463                                                       LuminosityBlock const& lumi,
0464                                                       EventSetup const& es) const {
0465     lhef::LHERunInfo* lheRunInfo = cache->hadronizer_.getLHERunInfo().get();
0466     lheRunInfo->initLumi();
0467 
0468     //We need all copies to see same random # for begin lumi
0469     Service<RandomNumberGenerator> rng;
0470     auto enginePtr = rng->cloneEngine(lumi.index());
0471     cache->hadronizer_.setRandomEngine(enginePtr.get());
0472     if (cache->decayer_) {
0473       cache->decayer_->setRandomEngine(enginePtr.get());
0474     }
0475 
0476     auto unsetH = [](HAD* h) { h->setRandomEngine(nullptr); };
0477     auto unsetD = [](DEC* d) {
0478       if (d) {
0479         d->setRandomEngine(nullptr);
0480       }
0481     };
0482 
0483     std::unique_ptr<HAD, decltype(unsetH)> randomEngineSentry(&cache->hadronizer_, unsetH);
0484     std::unique_ptr<DEC, decltype(unsetD)> randomEngineSentryDecay(cache->decayer_.get(), unsetD);
0485 
0486     cache->hadronizer_.randomizeIndex(lumi, enginePtr.get());
0487 
0488     if (!cache->hadronizer_.readSettings(1))
0489       throw edm::Exception(errors::Configuration)
0490           << "Failed to read settings for the hadronizer " << cache->hadronizer_.classname() << " \n";
0491 
0492     if (cache->decayer_) {
0493       cache->decayer_->init(es);
0494       if (!cache->hadronizer_.declareStableParticles(cache->decayer_->operatesOnParticles()))
0495         throw edm::Exception(errors::Configuration)
0496             << "Failed to declare stable particles in hadronizer " << cache->hadronizer_.classname()
0497             << " for internal parton generation\n";
0498       if (!cache->hadronizer_.declareSpecialSettings(cache->decayer_->specialSettings()))
0499         throw edm::Exception(errors::Configuration)
0500             << "Failed to declare special settings in hadronizer " << cache->hadronizer_.classname() << "\n";
0501     }
0502 
0503     if (cache->filter_) {
0504       cache->filter_->resetStatistics();
0505     }
0506 
0507     if (!cache->hadronizer_.initializeForExternalPartons())
0508       throw edm::Exception(errors::Configuration)
0509           << "Failed to initialize hadronizer " << cache->hadronizer_.classname()
0510           << " for external parton generation\n";
0511 
0512     cache->initialized_ = true;
0513   }
0514 
0515   template <class HAD, class DEC>
0516   std::shared_ptr<gen::LumiCache<HAD, DEC>> ConcurrentHadronizerFilter<HAD, DEC>::globalBeginLuminosityBlock(
0517       edm::LuminosityBlock const& lumi, edm::EventSetup const&) const {
0518     //need one of the streams to finish
0519     while (useInLumi_.load() == nullptr) {
0520     }
0521 
0522     ++nGlobalBeginLumis_;
0523 
0524     // streamEndRun also uses the hadronizer in the stream cache
0525     // so we also need to wait for it to finish if there is a new run
0526     if (nInitializedWithLHERunInfo_ < nGlobalBeginRuns_) {
0527       while (!streamEndRunComplete_.load()) {
0528       }
0529       nInitializedWithLHERunInfo_ = nGlobalBeginRuns_;
0530       initializeWithLHERunInfo(useInLumi_.load(), lumi);
0531     }
0532 
0533     auto lumiCache = std::make_shared<gen::LumiCache<HAD, DEC>>();
0534     lumiCache->useInLumi_ = useInLumi_.load();
0535     lumiCache->nGlobalBeginRuns_ = nGlobalBeginRuns_;
0536     lumiCache->nGlobalBeginLumis_ = nGlobalBeginLumis_;
0537     return lumiCache;
0538   }
0539 
0540   template <class HAD, class DEC>
0541   void ConcurrentHadronizerFilter<HAD, DEC>::globalBeginLuminosityBlockProduce(LuminosityBlock& lumi,
0542                                                                                EventSetup const& es) const {
0543     initLumi(useInLumi_, lumi, es);
0544     std::unique_ptr<GenLumiInfoHeader> genLumiInfoHeader(useInLumi_.load()->hadronizer_.getGenLumiInfoHeader());
0545     lumi.put(std::move(genLumiInfoHeader));
0546     useInLumi_.store(nullptr);
0547   }
0548 
0549   template <class HAD, class DEC>
0550   void ConcurrentHadronizerFilter<HAD, DEC>::streamEndLuminosityBlockSummary(StreamID id,
0551                                                                              LuminosityBlock const& lumi,
0552                                                                              EventSetup const&,
0553                                                                              gen::LumiSummary* iSummary) const {
0554     const lhef::LHERunInfo* lheRunInfo = this->streamCache(id)->hadronizer_.getLHERunInfo().get();
0555 
0556     std::vector<lhef::LHERunInfo::Process> LHELumiProcess = lheRunInfo->getLumiProcesses();
0557     std::vector<GenLumiInfoProduct::ProcessInfo> GenLumiProcess;
0558     for (unsigned int i = 0; i < LHELumiProcess.size(); i++) {
0559       lhef::LHERunInfo::Process thisProcess = LHELumiProcess[i];
0560 
0561       GenLumiInfoProduct::ProcessInfo temp;
0562       temp.setProcess(thisProcess.process());
0563       temp.setLheXSec(thisProcess.getLHEXSec().value(), thisProcess.getLHEXSec().error());
0564       temp.setNPassPos(thisProcess.nPassPos());
0565       temp.setNPassNeg(thisProcess.nPassNeg());
0566       temp.setNTotalPos(thisProcess.nTotalPos());
0567       temp.setNTotalNeg(thisProcess.nTotalNeg());
0568       temp.setTried(thisProcess.tried().n(), thisProcess.tried().sum(), thisProcess.tried().sum2());
0569       temp.setSelected(thisProcess.selected().n(), thisProcess.selected().sum(), thisProcess.selected().sum2());
0570       temp.setKilled(thisProcess.killed().n(), thisProcess.killed().sum(), thisProcess.killed().sum2());
0571       temp.setAccepted(thisProcess.accepted().n(), thisProcess.accepted().sum(), thisProcess.accepted().sum2());
0572       temp.setAcceptedBr(thisProcess.acceptedBr().n(), thisProcess.acceptedBr().sum(), thisProcess.acceptedBr().sum2());
0573       GenLumiProcess.push_back(temp);
0574     }
0575     GenLumiInfoProduct genLumiInfo;
0576     genLumiInfo.setHEPIDWTUP(lheRunInfo->getHEPRUP()->IDWTUP);
0577     genLumiInfo.setProcessInfo(GenLumiProcess);
0578 
0579     if (iSummary->lumiInfo_) {
0580       iSummary->lumiInfo_->setHEPIDWTUP(lheRunInfo->getHEPRUP()->IDWTUP);
0581       iSummary->lumiInfo_->mergeProduct(genLumiInfo);
0582     } else {
0583       iSummary->lumiInfo_ = std::make_unique<GenLumiInfoProduct>(std::move(genLumiInfo));
0584     }
0585 
0586     // produce GenFilterInfo if HepMCFilter is called
0587     if (hasFilter_) {
0588       auto filter = this->streamCache(id)->filter_.get();
0589       GenFilterInfo thisProduct(filter->numEventsPassPos(),
0590                                 filter->numEventsPassNeg(),
0591                                 filter->numEventsTotalPos(),
0592                                 filter->numEventsTotalNeg(),
0593                                 filter->sumpass_w(),
0594                                 filter->sumpass_w2(),
0595                                 filter->sumtotal_w(),
0596                                 filter->sumtotal_w2());
0597       if (not iSummary->filterInfo_) {
0598         iSummary->filterInfo_ = std::make_unique<GenFilterInfo>(std::move(thisProduct));
0599       } else {
0600         iSummary->filterInfo_->mergeProduct(thisProduct);
0601       }
0602     }
0603 
0604     gen::StreamCache<HAD, DEC>* streamCachePtr = this->streamCache(id);
0605     unsigned long long expected = this->luminosityBlockCache(lumi.index())->nGlobalBeginLumis_;
0606     unsigned long long nextValue = expected + 1;
0607     // This exchange should succeed and the conditional block should be executed only
0608     // for the first stream to try for each lumi.
0609     if (nextNGlobalBeginLumis_.compare_exchange_strong(expected, nextValue)) {
0610       streamEndRunComplete_ = false;
0611       useInLumi_ = streamCachePtr;
0612     }
0613   }
0614 
0615   template <class HAD, class DEC>
0616   std::shared_ptr<gen::LumiSummary> ConcurrentHadronizerFilter<HAD, DEC>::globalBeginLuminosityBlockSummary(
0617       edm::LuminosityBlock const&, edm::EventSetup const&) const {
0618     return std::make_shared<gen::LumiSummary>();
0619   }
0620 
0621   template <class HAD, class DEC>
0622   void ConcurrentHadronizerFilter<HAD, DEC>::globalEndLuminosityBlock(edm::LuminosityBlock const&,
0623                                                                       edm::EventSetup const&) const {}
0624 
0625   template <class HAD, class DEC>
0626   void ConcurrentHadronizerFilter<HAD, DEC>::globalEndLuminosityBlockSummary(edm::LuminosityBlock const&,
0627                                                                              edm::EventSetup const&,
0628                                                                              gen::LumiSummary*) const {}
0629 
0630   template <class HAD, class DEC>
0631   void ConcurrentHadronizerFilter<HAD, DEC>::globalEndLuminosityBlockProduce(LuminosityBlock& lumi,
0632                                                                              EventSetup const&,
0633                                                                              gen::LumiSummary const* iSummary) const {
0634     //Advance the random number generator so next begin lumi starts with new seed
0635     Service<RandomNumberGenerator> rng;
0636     rng->getEngine(lumi.index()).flat();
0637 
0638     lumi.put(std::move(iSummary->lumiInfo_));
0639 
0640     // produce GenFilterInfo if HepMCFilter is called
0641     if (hasFilter_) {
0642       lumi.put(std::move(iSummary->filterInfo_));
0643     }
0644   }
0645 
0646 }  // namespace edm
0647 
0648 #endif  // GeneratorInterface_Core_ConcurrentHadronizerFilter_h