Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-04-04 01:27:00

0001 #include <iostream>
0002 #include <memory>
0003 
0004 #include "FWCore/Framework/interface/stream/EDProducer.h"
0005 #include "FWCore/Framework/interface/Event.h"
0006 #include "FWCore/Framework/interface/MakerMacros.h"
0007 #include "FWCore/Framework/interface/EventSetup.h"
0008 #include "FWCore/Framework/interface/Run.h"
0009 
0010 #include "FWCore/PluginManager/interface/PluginManager.h"
0011 #include "FWCore/Framework/interface/MakerMacros.h"
0012 #include "FWCore/Framework/interface/ConsumesCollector.h"
0013 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0014 
0015 #include "FWCore/AbstractServices/interface/RandomNumberGenerator.h"
0016 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0017 #include "FWCore/ServiceRegistry/interface/Service.h"
0018 #include "FWCore/ServiceRegistry/interface/ServiceRegistry.h"
0019 #include "FWCore/Utilities/interface/Exception.h"
0020 
0021 #include "SimG4Core/Application/interface/OscarMTMasterThread.h"
0022 #include "SimG4Core/Application/interface/RunManagerMT.h"
0023 #include "SimG4Core/Application/interface/RunManagerMTWorker.h"
0024 #include "SimG4Core/Notification/interface/TmpSimEvent.h"
0025 #include "SimG4Core/Notification/interface/TmpSimVertex.h"
0026 
0027 #include "SimG4Core/SensitiveDetector/interface/SensitiveTkDetector.h"
0028 #include "SimG4Core/SensitiveDetector/interface/SensitiveCaloDetector.h"
0029 
0030 #include "SimG4Core/Watcher/interface/SimProducer.h"
0031 
0032 #include "SimDataFormats/Track/interface/SimTrackContainer.h"
0033 #include "SimDataFormats/Vertex/interface/SimVertexContainer.h"
0034 #include "SimDataFormats/TrackingHit/interface/PSimHitContainer.h"
0035 #include "SimDataFormats/CaloHit/interface/PCaloHitContainer.h"
0036 
0037 #include "SimG4Core/Application/interface/ThreadHandoff.h"
0038 
0039 #include "Randomize.hh"
0040 
0041 // for some reason void doesn't compile
0042 class OscarMTProducer : public edm::stream::EDProducer<edm::GlobalCache<OscarMTMasterThread>, edm::RunCache<int>> {
0043 public:
0044   typedef std::vector<std::shared_ptr<SimProducer>> Producers;
0045 
0046   explicit OscarMTProducer(edm::ParameterSet const& p, const OscarMTMasterThread*);
0047   ~OscarMTProducer() override;
0048 
0049   static std::unique_ptr<OscarMTMasterThread> initializeGlobalCache(const edm::ParameterSet& iConfig);
0050   static std::shared_ptr<int> globalBeginRun(const edm::Run& iRun,
0051                                              const edm::EventSetup& iSetup,
0052                                              const OscarMTMasterThread* masterThread);
0053   static void globalEndRun(const edm::Run& iRun, const edm::EventSetup& iSetup, const RunContext* iContext);
0054   static void globalEndJob(OscarMTMasterThread* masterThread);
0055 
0056   void beginRun(const edm::Run& r, const edm::EventSetup& c) override;
0057   void endRun(const edm::Run& r, const edm::EventSetup& c) override;
0058   void produce(edm::Event& e, const edm::EventSetup& c) override;
0059 
0060 private:
0061   omt::ThreadHandoff m_handoff;
0062   std::unique_ptr<RunManagerMTWorker> m_runManagerWorker;
0063   const OscarMTMasterThread* m_masterThread;
0064   const edm::ParameterSetID m_psetID;
0065   int m_verbose;
0066   CMS_SA_ALLOW static const OscarMTMasterThread* s_masterThread;
0067   CMS_SA_ALLOW static edm::ParameterSetID s_psetID;
0068 };
0069 
0070 const OscarMTMasterThread* OscarMTProducer::s_masterThread = nullptr;
0071 edm::ParameterSetID OscarMTProducer::s_psetID{};
0072 
0073 namespace edm {
0074   class StreamID;
0075 }
0076 
0077 namespace {
0078   //
0079   // this machinery allows to set CLHEP static engine
0080   // to the one defined by RandomNumberGenerator service
0081   // at the beginning of an event, and reset it back to
0082   // "default-default" at the end of the event;
0083   // Dave D. has decided to implement it this way because
0084   // we don't know if there're other modules using CLHEP
0085   // static engine, thus we want to ensure that the one
0086   // we use for OscarMTProducer is unique to OscarMTProducer
0087   //
0088   // !!! This not only sets the random engine used by GEANT.
0089   // There are a few SimWatchers/SimProducers that generate
0090   // random number and also use the global CLHEP random engine
0091   // set by this code. If we ever change this design be careful
0092   // not to forget about them!!!
0093 
0094   class StaticRandomEngineSetUnset {
0095   public:
0096     StaticRandomEngineSetUnset(edm::StreamID const&);
0097     explicit StaticRandomEngineSetUnset(CLHEP::HepRandomEngine* engine);
0098     ~StaticRandomEngineSetUnset();
0099 
0100     CLHEP::HepRandomEngine* currentEngine() { return m_currentEngine; }
0101 
0102   private:
0103     CLHEP::HepRandomEngine* m_currentEngine;
0104     CLHEP::HepRandomEngine* m_previousEngine;
0105   };
0106 }  // namespace
0107 
0108 OscarMTProducer::OscarMTProducer(edm::ParameterSet const& p, const OscarMTMasterThread* ms)
0109     : m_handoff{p.getUntrackedParameter<int>("workerThreadStackSize", 10 * 1024 * 1024)}, m_psetID{p.id()} {
0110   m_verbose = p.getParameter<int>("EventVerbose");
0111   // Random number generation not allowed here
0112   StaticRandomEngineSetUnset random(nullptr);
0113 
0114   auto token = edm::ServiceRegistry::instance().presentToken();
0115   m_handoff.runAndWait([this, &p, token]() {
0116     edm::ServiceRegistry::Operate guard{token};
0117     StaticRandomEngineSetUnset random(nullptr);
0118     m_runManagerWorker = std::make_unique<RunManagerMTWorker>(p, consumesCollector());
0119   });
0120   m_masterThread = (nullptr != ms) ? ms : s_masterThread;
0121   assert(m_masterThread);
0122   m_masterThread->callConsumes(consumesCollector());
0123 
0124   // declair hit collections
0125   produces<edm::SimTrackContainer>().setBranchAlias("SimTracks");
0126   produces<edm::SimVertexContainer>().setBranchAlias("SimVertices");
0127 
0128   auto trackHits = p.getParameter<std::vector<std::string>>("TrackHits");
0129   for (auto const& ss : trackHits) {
0130     produces<edm::PSimHitContainer>(ss);
0131   }
0132 
0133   auto caloHits = p.getParameter<std::vector<std::string>>("CaloHits");
0134   for (auto const& ss : caloHits) {
0135     produces<edm::PCaloHitContainer>(ss);
0136   }
0137 
0138   //register any products
0139   auto& producers = m_runManagerWorker->producers();
0140   for (auto& ptr : producers) {
0141     ptr->registerProducts(producesCollector());
0142   }
0143   edm::LogVerbatim("SimG4CoreApplication")
0144       << "OscarMTProducer is constructed with hit collections:" << trackHits.size() << " tracking type; "
0145       << caloHits.size() << " calo type; " << producers.size() << " watcher type.";
0146 }
0147 
0148 OscarMTProducer::~OscarMTProducer() {
0149   auto token = edm::ServiceRegistry::instance().presentToken();
0150   m_handoff.runAndWait([this, token]() {
0151     edm::ServiceRegistry::Operate guard{token};
0152     m_runManagerWorker.reset();
0153   });
0154 }
0155 
0156 std::unique_ptr<OscarMTMasterThread> OscarMTProducer::initializeGlobalCache(const edm::ParameterSet& iConfig) {
0157   // Random number generation not allowed here
0158   StaticRandomEngineSetUnset random(nullptr);
0159   edm::LogVerbatim("SimG4CoreApplication") << "OscarMTProducer::initializeGlobalCache";
0160   if (nullptr == s_masterThread) {
0161     auto ret = std::make_unique<OscarMTMasterThread>(iConfig);
0162     s_masterThread = ret.get();
0163     s_psetID = iConfig.id();
0164     return ret;
0165   }
0166   return {};
0167 }
0168 
0169 std::shared_ptr<int> OscarMTProducer::globalBeginRun(const edm::Run&,
0170                                                      const edm::EventSetup& iSetup,
0171                                                      const OscarMTMasterThread* masterThread) {
0172   // Random number generation not allowed here
0173   StaticRandomEngineSetUnset random(nullptr);
0174   edm::LogVerbatim("SimG4CoreApplication") << "OscarMTProducer::globalBeginRun";
0175   if (masterThread) {
0176     masterThread->beginRun(iSetup);
0177   }
0178   edm::LogVerbatim("SimG4CoreApplication") << "OscarMTProducer::globalBeginRun done";
0179   return std::shared_ptr<int>();
0180 }
0181 
0182 void OscarMTProducer::globalEndRun(const edm::Run&, const edm::EventSetup&, const RunContext* iContext) {
0183   edm::LogVerbatim("SimG4CoreApplication") << "OscarMTProducer::globalEndRun";
0184   if (nullptr != iContext->global()) {
0185     iContext->global()->endRun();
0186   }
0187 }
0188 
0189 void OscarMTProducer::globalEndJob(OscarMTMasterThread* masterThread) {
0190   edm::LogVerbatim("SimG4CoreApplication") << "OscarMTProducer::globalEndJob";
0191   if (masterThread) {
0192     masterThread->stopThread();
0193   }
0194 }
0195 
0196 void OscarMTProducer::beginRun(const edm::Run&, const edm::EventSetup& es) {
0197   if (s_psetID != m_psetID) {
0198     throw cms::Exception("DiffOscarMTProducers")
0199         << "At least two different OscarMTProducer instances have been"
0200            "loaded into the job and they have different configurations.\n"
0201            " All OscarMTProducers in a job must have exactly the same configuration.";
0202   }
0203   int id = m_runManagerWorker->getThreadIndex();
0204   edm::LogVerbatim("SimG4CoreApplication") << "OscarMTProducer::beginRun threadID=" << id;
0205   auto token = edm::ServiceRegistry::instance().presentToken();
0206   m_handoff.runAndWait([this, &es, token]() {
0207     edm::ServiceRegistry::Operate guard{token};
0208     m_runManagerWorker->beginRun(es);
0209     m_runManagerWorker->initializeG4(m_masterThread->runManagerMasterPtr(), es);
0210   });
0211   edm::LogVerbatim("SimG4CoreApplication") << "OscarMTProducer::beginRun done threadID=" << id;
0212 }
0213 
0214 void OscarMTProducer::endRun(const edm::Run&, const edm::EventSetup&) {
0215   StaticRandomEngineSetUnset random(nullptr);
0216   int id = m_runManagerWorker->getThreadIndex();
0217   edm::LogVerbatim("SimG4CoreApplication") << "OscarMTProducer::endRun threadID=" << id;
0218   auto token = edm::ServiceRegistry::instance().presentToken();
0219   m_handoff.runAndWait([this, token]() {
0220     edm::ServiceRegistry::Operate guard{token};
0221     m_runManagerWorker->endRun();
0222   });
0223   edm::LogVerbatim("SimG4CoreApplication") << "OscarMTProducer::endRun done threadID=" << id;
0224 }
0225 
0226 void OscarMTProducer::produce(edm::Event& e, const edm::EventSetup& es) {
0227   StaticRandomEngineSetUnset random(e.streamID());
0228   auto engine = random.currentEngine();
0229   int id = m_runManagerWorker->getThreadIndex();
0230   if (0 < m_verbose) {
0231     edm::LogVerbatim("SimG4CoreApplication")
0232         << "Produce event " << e.id() << " stream " << e.streamID() << " threadID=" << id;
0233     //edm::LogVerbatim("SimG4CoreApplication") << " rand= " << G4UniformRand();
0234   }
0235 
0236   auto& sTk = m_runManagerWorker->sensTkDetectors();
0237   auto& sCalo = m_runManagerWorker->sensCaloDetectors();
0238 
0239   TmpSimEvent* evt = nullptr;
0240   auto token = edm::ServiceRegistry::instance().presentToken();
0241   m_handoff.runAndWait([this, &e, &es, &evt, token, engine]() {
0242     edm::ServiceRegistry::Operate guard{token};
0243     StaticRandomEngineSetUnset random(engine);
0244     evt = m_runManagerWorker->produce(e, es, m_masterThread->runManagerMaster());
0245   });
0246 
0247   std::unique_ptr<edm::SimTrackContainer> p1(new edm::SimTrackContainer);
0248   std::unique_ptr<edm::SimVertexContainer> p2(new edm::SimVertexContainer);
0249   evt->load(*p1);
0250   evt->load(*p2);
0251 
0252   if (0 < m_verbose) {
0253     edm::LogVerbatim("SimG4CoreApplication")
0254         << "Produced " << p2->size() << " SimVertices: position(cm), time(s), parentID, vertexID, processType";
0255     if (1 < m_verbose) {
0256       int nn = p2->size();
0257       for (int i = 0; i < nn; ++i) {
0258         edm::LogVerbatim("Vertex") << " " << i << ". " << (*p2)[i] << " " << (*p2)[i].processType();
0259       }
0260     }
0261     edm::LogVerbatim("SimG4CoreApplication")
0262         << "Produced " << p1->size()
0263         << " SimTracks: G4 Id, pdg, 4-momentum(GeV), vertexID, mcTruthID, crossedBoundary -> trackID at boundary, from "
0264            "backscattering, isPrimary -> getPrimary";
0265     if (1 < m_verbose) {
0266       int nn = p1->size();
0267       for (int i = 0; i < nn; ++i) {
0268         edm::LogVerbatim("Track") << " " << i << ". " << (*p1)[i].trackId() << ", " << (*p1)[i] << ", "
0269                                   << (*p1)[i].crossedBoundary() << "-> " << (*p1)[i].getIDAtBoundary() << ", "
0270                                   << (*p1)[i].isFromBackScattering() << ", " << (*p1)[i].isPrimary() << "-> "
0271                                   << (*p1)[i].getPrimaryID();
0272       }
0273     }
0274   }
0275   e.put(std::move(p1));
0276   e.put(std::move(p2));
0277 
0278   for (auto const& tracker : sTk) {
0279     const std::vector<std::string>& v = tracker->getNames();
0280     for (auto const& name : v) {
0281       std::unique_ptr<edm::PSimHitContainer> product(new edm::PSimHitContainer);
0282       tracker->fillHits(*product, name);
0283       if (0 < m_verbose && product != nullptr && !product->empty())
0284         edm::LogVerbatim("SimG4CoreApplication") << "Produced " << product->size() << " tracker hits <" << name << ">";
0285       e.put(std::move(product), name);
0286     }
0287   }
0288   for (auto const& calo : sCalo) {
0289     const std::vector<std::string>& v = calo->getNames();
0290     for (auto const& name : v) {
0291       std::unique_ptr<edm::PCaloHitContainer> product(new edm::PCaloHitContainer);
0292       calo->fillHits(*product, name);
0293       if (0 < m_verbose && product != nullptr && !product->empty())
0294         edm::LogVerbatim("SimG4CoreApplication") << "Produced " << product->size() << " calo hits <" << name << ">";
0295       e.put(std::move(product), name);
0296     }
0297   }
0298 
0299   auto& producers = m_runManagerWorker->producers();
0300   for (auto& prod : producers) {
0301     prod.get()->produce(e, es);
0302   }
0303   if (0 < m_verbose) {
0304     edm::LogVerbatim("SimG4CoreApplication")
0305         << "Event is produced event " << e.id() << " streamID=" << e.streamID() << " threadID=" << id;
0306     //edm::LogWarning("SimG4CoreApplication") << "EventID=" << e.id() << " rand=" << G4UniformRand();
0307   }
0308 }
0309 
0310 StaticRandomEngineSetUnset::StaticRandomEngineSetUnset(edm::StreamID const& streamID) {
0311   edm::Service<edm::RandomNumberGenerator> rng;
0312   if (!rng.isAvailable()) {
0313     throw cms::Exception("Configuration")
0314         << "The OscarMTProducer module requires the RandomNumberGeneratorService\n"
0315            "which is not present in the configuration file.  You must add the service\n"
0316            "in the configuration file if you want to run OscarMTProducer";
0317   }
0318   m_currentEngine = &(rng->getEngine(streamID));
0319 
0320   m_previousEngine = G4Random::getTheEngine();
0321   G4Random::setTheEngine(m_currentEngine);
0322 }
0323 
0324 StaticRandomEngineSetUnset::StaticRandomEngineSetUnset(CLHEP::HepRandomEngine* engine) {
0325   m_currentEngine = engine;
0326   m_previousEngine = G4Random::getTheEngine();
0327   G4Random::setTheEngine(m_currentEngine);
0328 }
0329 
0330 StaticRandomEngineSetUnset::~StaticRandomEngineSetUnset() { G4Random::setTheEngine(m_previousEngine); }
0331 
0332 DEFINE_FWK_MODULE(OscarMTProducer);