Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-09-29 01:11:55

0001 // -*- C++ -*-
0002 //
0003 //
0004 
0005 // class template ConcurrentGeneratorFilter<HAD> provides an EDFilter which uses
0006 // the hadronizer type HAD to generate partons, 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_ConcurrentGeneratorFilter_h
0047 #define GeneratorInterface_Core_ConcurrentGeneratorFilter_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 // LHE Run
0071 #include "SimDataFormats/GeneratorProducts/interface/LHERunInfoProduct.h"
0072 #include "GeneratorInterface/LHEInterface/interface/LHERunInfo.h"
0073 
0074 // LHE Event
0075 #include "SimDataFormats/GeneratorProducts/interface/LHEEventProduct.h"
0076 #include "GeneratorInterface/LHEInterface/interface/LHEEvent.h"
0077 
0078 #include "SimDataFormats/GeneratorProducts/interface/HepMCProduct.h"
0079 #include "SimDataFormats/GeneratorProducts/interface/GenRunInfoProduct.h"
0080 #include "SimDataFormats/GeneratorProducts/interface/GenLumiInfoHeader.h"
0081 #include "SimDataFormats/GeneratorProducts/interface/GenLumiInfoProduct.h"
0082 #include "SimDataFormats/GeneratorProducts/interface/GenEventInfoProduct.h"
0083 
0084 namespace edm {
0085   namespace gen {
0086     struct GenRunCache {
0087       mutable std::atomic<GenRunInfoProduct*> product_{nullptr};
0088       ~GenRunCache() { delete product_.load(); }
0089 
0090       // This is called from globalEndRunProduce which is known to
0091       // be safe as the framework would not be calling any other
0092       // methods of this module using this run at that time
0093       std::unique_ptr<GenRunInfoProduct> release() const noexcept {
0094         auto retValue = product_.load();
0095         product_.store(nullptr);
0096         return std::unique_ptr<GenRunInfoProduct>(retValue);
0097       }
0098     };
0099     struct GenLumiSummary {
0100       mutable std::unique_ptr<GenLumiInfoProduct> lumiInfo_;
0101     };
0102     template <typename HAD, typename DEC>
0103     struct GenStreamCache {
0104       GenStreamCache(ParameterSet const& iPSet) : hadronizer_{iPSet}, nEventsInLumiBlock_{0} {}
0105       HAD hadronizer_;
0106       std::unique_ptr<DEC> decayer_;
0107       unsigned int nEventsInLumiBlock_;
0108       unsigned long long nStreamEndLumis_{0};
0109       bool initialized_ = false;
0110     };
0111     template <typename HAD, typename DEC>
0112     struct GenLumiCache {
0113       gen::GenStreamCache<HAD, DEC>* useInLumi_{nullptr};
0114     };
0115   }  // namespace gen
0116 
0117   template <class HAD, class DEC>
0118   class ConcurrentGeneratorFilter : public global::EDFilter<EndRunProducer,
0119                                                             BeginLuminosityBlockProducer,
0120                                                             EndLuminosityBlockProducer,
0121                                                             RunCache<gen::GenRunCache>,
0122                                                             LuminosityBlockCache<gen::GenLumiCache<HAD, DEC>>,
0123                                                             LuminosityBlockSummaryCache<gen::GenLumiSummary>,
0124                                                             StreamCache<gen::GenStreamCache<HAD, DEC>>> {
0125   public:
0126     typedef HAD Hadronizer;
0127     typedef DEC Decayer;
0128 
0129     // The given ParameterSet will be passed to the contained Hadronizer object.
0130     explicit ConcurrentGeneratorFilter(ParameterSet const& ps);
0131 
0132     bool filter(StreamID id, Event& e, EventSetup const& es) const override;
0133     std::unique_ptr<gen::GenStreamCache<HAD, DEC>> beginStream(StreamID) const override;
0134     std::shared_ptr<gen::GenRunCache> globalBeginRun(Run const&, EventSetup const&) const override;
0135     std::shared_ptr<gen::GenLumiSummary> globalBeginLuminosityBlockSummary(LuminosityBlock const&,
0136                                                                            EventSetup const&) const override;
0137     std::shared_ptr<gen::GenLumiCache<HAD, DEC>> globalBeginLuminosityBlock(LuminosityBlock const&,
0138                                                                             EventSetup const&) const override;
0139     void globalBeginLuminosityBlockProduce(LuminosityBlock&, EventSetup const&) const override;
0140     void streamBeginLuminosityBlock(StreamID, LuminosityBlock const&, EventSetup const&) const override;
0141     void streamEndLuminosityBlock(StreamID, LuminosityBlock const&, EventSetup const&) const override;
0142     void streamEndLuminosityBlockSummary(StreamID,
0143                                          LuminosityBlock const&,
0144                                          EventSetup const&,
0145                                          gen::GenLumiSummary*) const override;
0146     void globalEndLuminosityBlock(LuminosityBlock const&, EventSetup const&) const override;
0147     void globalEndLuminosityBlockSummary(LuminosityBlock const&,
0148                                          EventSetup const&,
0149                                          gen::GenLumiSummary*) const override;
0150     void globalEndLuminosityBlockProduce(LuminosityBlock&,
0151                                          EventSetup const&,
0152                                          gen::GenLumiSummary const*) const override;
0153     void streamEndRun(StreamID, Run const&, EventSetup const&) const override;
0154     void globalEndRun(Run const&, EventSetup const&) const override;
0155     void globalEndRunProduce(Run&, EventSetup const&) const override;
0156 
0157   private:
0158     void initLumi(gen::GenStreamCache<HAD, DEC>* cache, LuminosityBlock const& index, EventSetup const& es) const;
0159     ParameterSet config_;
0160     mutable std::atomic<gen::GenStreamCache<HAD, DEC>*> useInLumi_{nullptr};
0161     mutable std::atomic<unsigned long long> greatestNStreamEndLumis_{0};
0162     mutable std::atomic<bool> streamEndRunComplete_{true};
0163     // The next two data members are thread safe and can be safely mutable because
0164     // they are only modified/read in globalBeginRun and globalBeginLuminosityBlock.
0165     mutable unsigned long long nGlobalBeginRuns_{0};
0166     mutable unsigned long long nInitializedInGlobalLumiAfterNewRun_{0};
0167   };
0168 
0169   //------------------------------------------------------------------------
0170   //
0171   // Implementation
0172 
0173   template <class HAD, class DEC>
0174   ConcurrentGeneratorFilter<HAD, DEC>::ConcurrentGeneratorFilter(ParameterSet const& ps) : config_(ps) {
0175     // TODO:
0176     // Put the list of types produced by the filters here.
0177     // The current design calls for:
0178     //   * LHEGeneratorInfo
0179     //   * LHEEvent
0180     //   * HepMCProduct
0181     // But I can not find the LHEGeneratorInfo class; it might need to
0182     // be invented.
0183 
0184     this->template produces<HepMCProduct>("unsmeared");
0185     this->template produces<GenEventInfoProduct>();
0186     this->template produces<GenLumiInfoHeader, edm::Transition::BeginLuminosityBlock>();
0187     this->template produces<GenLumiInfoProduct, edm::Transition::EndLuminosityBlock>();
0188     this->template produces<GenRunInfoProduct, edm::Transition::EndRun>();
0189   }
0190 
0191   template <class HAD, class DEC>
0192   std::unique_ptr<gen::GenStreamCache<HAD, DEC>> ConcurrentGeneratorFilter<HAD, DEC>::beginStream(StreamID) const {
0193     auto cache = std::make_unique<gen::GenStreamCache<HAD, DEC>>(config_);
0194 
0195     if (config_.exists("ExternalDecays")) {
0196       ParameterSet ps1 = config_.getParameter<ParameterSet>("ExternalDecays");
0197       cache->decayer_.reset(new Decayer(ps1));
0198     }
0199 
0200     // We need a hadronizer during globalBeginLumiProduce, doesn't matter which one
0201     gen::GenStreamCache<HAD, DEC>* expected = nullptr;
0202     useInLumi_.compare_exchange_strong(expected, cache.get());
0203 
0204     return cache;
0205   }
0206 
0207   template <class HAD, class DEC>
0208   std::shared_ptr<gen::GenRunCache> ConcurrentGeneratorFilter<HAD, DEC>::globalBeginRun(Run const&,
0209                                                                                         EventSetup const&) const {
0210     ++nGlobalBeginRuns_;
0211     return std::make_shared<gen::GenRunCache>();
0212   }
0213 
0214   template <class HAD, class DEC>
0215   std::shared_ptr<gen::GenLumiSummary> ConcurrentGeneratorFilter<HAD, DEC>::globalBeginLuminosityBlockSummary(
0216       LuminosityBlock const&, EventSetup const&) const {
0217     return std::make_shared<gen::GenLumiSummary>();
0218   }
0219 
0220   template <class HAD, class DEC>
0221   void ConcurrentGeneratorFilter<HAD, DEC>::initLumi(gen::GenStreamCache<HAD, DEC>* cache,
0222                                                      LuminosityBlock const& lumi,
0223                                                      EventSetup const& es) const {
0224     cache->nEventsInLumiBlock_ = 0;
0225 
0226     // We need all copies to see same random # for begin lumi
0227     Service<RandomNumberGenerator> rng;
0228     auto enginePtr = rng->cloneEngine(lumi.index());
0229     cache->hadronizer_.setRandomEngine(enginePtr.get());
0230     if (cache->decayer_) {
0231       cache->decayer_->setRandomEngine(enginePtr.get());
0232     }
0233 
0234     auto unsetH = [](HAD* h) { h->setRandomEngine(nullptr); };
0235     auto unsetD = [](DEC* d) {
0236       if (d) {
0237         d->setRandomEngine(nullptr);
0238       }
0239     };
0240 
0241     std::unique_ptr<HAD, decltype(unsetH)> randomEngineSentry(&cache->hadronizer_, unsetH);
0242     std::unique_ptr<DEC, decltype(unsetD)> randomEngineSentryDecay(cache->decayer_.get(), unsetD);
0243 
0244     cache->hadronizer_.randomizeIndex(lumi, enginePtr.get());
0245 
0246     if (!cache->hadronizer_.readSettings(0))
0247       throw edm::Exception(errors::Configuration)
0248           << "Failed to read settings for the hadronizer " << cache->hadronizer_.classname() << " \n";
0249 
0250     if (cache->decayer_) {
0251       cache->decayer_->init(es);
0252       if (!cache->hadronizer_.declareStableParticles(cache->decayer_->operatesOnParticles()))
0253         throw edm::Exception(errors::Configuration)
0254             << "Failed to declare stable particles in hadronizer " << cache->hadronizer_.classname()
0255             << " for internal parton generation\n";
0256       if (!cache->hadronizer_.declareSpecialSettings(cache->decayer_->specialSettings()))
0257         throw edm::Exception(errors::Configuration)
0258             << "Failed to declare special settings in hadronizer " << cache->hadronizer_.classname() << "\n";
0259     }
0260 
0261     if (!cache->hadronizer_.initializeForInternalPartons())
0262       throw edm::Exception(errors::Configuration)
0263           << "Failed to initialize hadronizer " << cache->hadronizer_.classname()
0264           << " for internal parton generation\n";
0265 
0266     cache->initialized_ = true;
0267   }
0268 
0269   template <class HAD, class DEC>
0270   bool ConcurrentGeneratorFilter<HAD, DEC>::filter(StreamID id, Event& ev, EventSetup const& /* es */) const {
0271     auto cache = this->streamCache(id);
0272     RandomEngineSentry<HAD> randomEngineSentry(&cache->hadronizer_, ev.streamID());
0273     RandomEngineSentry<DEC> randomEngineSentryDecay(cache->decayer_.get(), ev.streamID());
0274 
0275     cache->hadronizer_.setEDMEvent(ev);
0276 
0277     bool passEvtGenSelector = false;
0278     std::unique_ptr<HepMC::GenEvent> event(nullptr);
0279 
0280     while (!passEvtGenSelector) {
0281       event.reset();
0282       cache->hadronizer_.setEDMEvent(ev);
0283 
0284       if (!cache->hadronizer_.generatePartonsAndHadronize())
0285         return false;
0286 
0287       // this is "fake" stuff
0288       // in principle, decays are done as part of full event generation,
0289       // except for particles that are marked as to be kept stable
0290       // but we currently keep in it the design, because we might want
0291       // to use such feature for other applications
0292       //
0293       if (!cache->hadronizer_.decay())
0294         return false;
0295 
0296       event = cache->hadronizer_.getGenEvent();
0297       if (!event.get())
0298         return false;
0299 
0300       //
0301       // The external decay driver is being added to the system, it should be called here
0302       //
0303       if (cache->decayer_) {
0304         auto t = cache->decayer_->decay(event.get());
0305         if (t != event.get()) {
0306           event.reset(t);
0307         }
0308       }
0309       if (!event.get())
0310         return false;
0311 
0312       passEvtGenSelector = cache->hadronizer_.select(event.get());
0313     }
0314 
0315     // check and perform if there're any unstable particles after
0316     // running external decay packages
0317     //
0318     // fisrt of all, put back modified event tree (after external decay)
0319     //
0320     cache->hadronizer_.resetEvent(std::move(event));
0321 
0322     //
0323     // now run residual decays
0324     //
0325     if (!cache->hadronizer_.residualDecay())
0326       return false;
0327 
0328     cache->hadronizer_.finalizeEvent();
0329 
0330     event = cache->hadronizer_.getGenEvent();
0331     if (!event.get())
0332       return false;
0333 
0334     event->set_event_number(ev.id().event());
0335 
0336     //
0337     // finally, form up EDM products !
0338     //
0339     std::unique_ptr<GenEventInfoProduct> genEventInfo(cache->hadronizer_.getGenEventInfo());
0340     if (!genEventInfo.get()) {
0341       // create GenEventInfoProduct from HepMC event in case hadronizer didn't provide one
0342       genEventInfo = std::make_unique<GenEventInfoProduct>(event.get());
0343     }
0344 
0345     ev.put(std::move(genEventInfo));
0346 
0347     std::unique_ptr<HepMCProduct> bare_product(new HepMCProduct());
0348     bare_product->addHepMCData(event.release());
0349     ev.put(std::move(bare_product), "unsmeared");
0350     cache->nEventsInLumiBlock_++;
0351     return true;
0352   }
0353 
0354   template <class HAD, class DEC>
0355   std::shared_ptr<gen::GenLumiCache<HAD, DEC>> ConcurrentGeneratorFilter<HAD, DEC>::globalBeginLuminosityBlock(
0356       edm::LuminosityBlock const&, edm::EventSetup const&) const {
0357     //need one of the streams to finish
0358     while (useInLumi_.load() == nullptr) {
0359     }
0360 
0361     // streamEndRun also uses the hadronizer in the stream cache
0362     // so we also need to wait for it to finish if there is a new run
0363     if (nInitializedInGlobalLumiAfterNewRun_ < nGlobalBeginRuns_) {
0364       while (!streamEndRunComplete_.load()) {
0365       }
0366       nInitializedInGlobalLumiAfterNewRun_ = nGlobalBeginRuns_;
0367     }
0368 
0369     auto lumiCache = std::make_shared<gen::GenLumiCache<HAD, DEC>>();
0370     lumiCache->useInLumi_ = useInLumi_.load();
0371     return lumiCache;
0372   }
0373 
0374   template <class HAD, class DEC>
0375   void ConcurrentGeneratorFilter<HAD, DEC>::globalBeginLuminosityBlockProduce(LuminosityBlock& lumi,
0376                                                                               EventSetup const& es) const {
0377     initLumi(useInLumi_, lumi, es);
0378     std::unique_ptr<GenLumiInfoHeader> genLumiInfoHeader(useInLumi_.load()->hadronizer_.getGenLumiInfoHeader());
0379     lumi.put(std::move(genLumiInfoHeader));
0380     useInLumi_.store(nullptr);
0381   }
0382 
0383   template <class HAD, class DEC>
0384   void ConcurrentGeneratorFilter<HAD, DEC>::streamBeginLuminosityBlock(StreamID id,
0385                                                                        LuminosityBlock const& lumi,
0386                                                                        EventSetup const& es) const {
0387     gen::GenStreamCache<HAD, DEC>* streamCachePtr = this->streamCache(id);
0388     if (this->luminosityBlockCache(lumi.index())->useInLumi_ != streamCachePtr) {
0389       initLumi(streamCachePtr, lumi, es);
0390     }
0391   }
0392 
0393   template <class HAD, class DEC>
0394   void ConcurrentGeneratorFilter<HAD, DEC>::streamEndLuminosityBlock(StreamID id,
0395                                                                      LuminosityBlock const&,
0396                                                                      EventSetup const&) const {
0397     this->streamCache(id)->hadronizer_.cleanLHE();
0398   }
0399 
0400   template <class HAD, class DEC>
0401   void ConcurrentGeneratorFilter<HAD, DEC>::streamEndLuminosityBlockSummary(StreamID id,
0402                                                                             LuminosityBlock const&,
0403                                                                             EventSetup const&,
0404                                                                             gen::GenLumiSummary* iSummary) const {
0405     auto cache = this->streamCache(id);
0406     cache->hadronizer_.statistics();
0407     if (cache->decayer_)
0408       cache->decayer_->statistics();
0409 
0410     GenRunInfoProduct genRunInfo = GenRunInfoProduct(cache->hadronizer_.getGenRunInfo());
0411     std::vector<GenLumiInfoProduct::ProcessInfo> GenLumiProcess;
0412     const GenRunInfoProduct::XSec& xsec = genRunInfo.internalXSec();
0413     GenLumiInfoProduct::ProcessInfo temp;
0414     unsigned int nEvtInLumiBlock_ = cache->nEventsInLumiBlock_;
0415     temp.setProcess(0);
0416     temp.setLheXSec(xsec.value(), xsec.error());  // Pythia gives error of -1
0417     temp.setNPassPos(nEvtInLumiBlock_);
0418     temp.setNPassNeg(0);
0419     temp.setNTotalPos(nEvtInLumiBlock_);
0420     temp.setNTotalNeg(0);
0421     temp.setTried(nEvtInLumiBlock_, nEvtInLumiBlock_, nEvtInLumiBlock_);
0422     temp.setSelected(nEvtInLumiBlock_, nEvtInLumiBlock_, nEvtInLumiBlock_);
0423     temp.setKilled(nEvtInLumiBlock_, nEvtInLumiBlock_, nEvtInLumiBlock_);
0424     temp.setAccepted(0, -1, -1);
0425     temp.setAcceptedBr(0, -1, -1);
0426     GenLumiProcess.push_back(temp);
0427 
0428     GenLumiInfoProduct genLumiInfo;
0429     genLumiInfo.setHEPIDWTUP(-1);
0430     genLumiInfo.setProcessInfo(GenLumiProcess);
0431 
0432     if (iSummary->lumiInfo_) {
0433       iSummary->lumiInfo_->mergeProduct(genLumiInfo);
0434     } else {
0435       iSummary->lumiInfo_ = std::make_unique<GenLumiInfoProduct>(std::move(genLumiInfo));
0436     }
0437 
0438     cache->nEventsInLumiBlock_ = 0;
0439 
0440     // The next section of code depends on the Framework behavior that the stream
0441     // lumi transitions are executed for all streams for every lumi even when
0442     // there are no events for a stream to process.
0443     gen::GenStreamCache<HAD, DEC>* streamCachePtr = this->streamCache(id);
0444     unsigned long long expected = streamCachePtr->nStreamEndLumis_;
0445     ++streamCachePtr->nStreamEndLumis_;
0446     if (greatestNStreamEndLumis_.compare_exchange_strong(expected, streamCachePtr->nStreamEndLumis_)) {
0447       streamEndRunComplete_ = false;
0448       useInLumi_ = streamCachePtr;
0449     }
0450   }
0451 
0452   template <class HAD, class DEC>
0453   void ConcurrentGeneratorFilter<HAD, DEC>::globalEndLuminosityBlock(edm::LuminosityBlock const&,
0454                                                                      edm::EventSetup const&) const {}
0455 
0456   template <class HAD, class DEC>
0457   void ConcurrentGeneratorFilter<HAD, DEC>::globalEndLuminosityBlockSummary(LuminosityBlock const&,
0458                                                                             EventSetup const&,
0459                                                                             gen::GenLumiSummary*) const {}
0460 
0461   template <class HAD, class DEC>
0462   void ConcurrentGeneratorFilter<HAD, DEC>::globalEndLuminosityBlockProduce(LuminosityBlock& lumi,
0463                                                                             EventSetup const&,
0464                                                                             gen::GenLumiSummary const* iSummary) const {
0465     lumi.put(std::move(iSummary->lumiInfo_));
0466   }
0467 
0468   template <class HAD, class DEC>
0469   void ConcurrentGeneratorFilter<HAD, DEC>::streamEndRun(StreamID id, Run const& run, EventSetup const&) const {
0470     auto rCache = this->runCache(run.index());
0471     auto cache = this->streamCache(id);
0472 
0473     // If relevant, record the integrated luminosity for this run
0474     // here.  To do so, we would need a standard function to invoke on
0475     // the contained hadronizer that would report the integrated
0476     // luminosity.
0477 
0478     if (cache->initialized_) {
0479       cache->hadronizer_.statistics();
0480       if (cache->decayer_)
0481         cache->decayer_->statistics();
0482     }
0483     GenRunInfoProduct& genRunInfo = cache->hadronizer_.getGenRunInfo();
0484     GenRunInfoProduct* expect = nullptr;
0485 
0486     std::unique_ptr<GenRunInfoProduct> griproduct(new GenRunInfoProduct(genRunInfo));
0487     // All the GenRunInfoProducts for all streams shoule be identical, therefore we only need one
0488     if (rCache->product_.compare_exchange_strong(expect, griproduct.get())) {
0489       griproduct.release();
0490     }
0491     if (cache == useInLumi_.load()) {
0492       streamEndRunComplete_ = true;
0493     }
0494   }
0495 
0496   template <class HAD, class DEC>
0497   void ConcurrentGeneratorFilter<HAD, DEC>::globalEndRun(Run const&, EventSetup const&) const {}
0498 
0499   template <class HAD, class DEC>
0500   void ConcurrentGeneratorFilter<HAD, DEC>::globalEndRunProduce(Run& run, EventSetup const&) const {
0501     run.put(this->runCache(run.index())->release());
0502   }
0503 
0504 }  // namespace edm
0505 
0506 #endif  // GeneratorInterface_Core_ConcurrentGeneratorFilter_h