File indexing completed on 2024-04-06 12:22:36
0001 #include "Mixing/Base/interface/PileUp.h"
0002 #include "DataFormats/Provenance/interface/BranchIDListHelper.h"
0003 #include "DataFormats/Provenance/interface/ModuleDescription.h"
0004 #include "DataFormats/Provenance/interface/ThinnedAssociationsHelper.h"
0005 #include "FWCore/Framework/interface/EventPrincipal.h"
0006 #include "FWCore/Framework/interface/LuminosityBlock.h"
0007 #include "FWCore/Framework/interface/Run.h"
0008 #include "FWCore/Framework/interface/SignallingProductRegistry.h"
0009 #include "FWCore/Framework/interface/ESRecordsToProductResolverIndices.h"
0010 #include "FWCore/ServiceRegistry/interface/ActivityRegistry.h"
0011 #include "FWCore/ServiceRegistry/interface/ProcessContext.h"
0012 #include "FWCore/Sources/interface/VectorInputSourceDescription.h"
0013 #include "FWCore/Sources/interface/VectorInputSourceFactory.h"
0014 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0015 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0016 #include "FWCore/Utilities/interface/Exception.h"
0017 #include "FWCore/Utilities/interface/GetPassID.h"
0018 #include "FWCore/Utilities/interface/StreamID.h"
0019 #include "FWCore/Version/interface/GetReleaseVersion.h"
0020
0021 #include "FWCore/ServiceRegistry/interface/Service.h"
0022 #include "FWCore/Utilities/interface/RandomNumberGenerator.h"
0023
0024 #include "FWCore/Framework/interface/ESHandle.h"
0025 #include "FWCore/Framework/interface/EventSetup.h"
0026 #include "Mixing/Base/src/SecondaryEventProvider.h"
0027 #include "CondFormats/DataRecord/interface/MixingRcd.h"
0028 #include "CondFormats/RunInfo/interface/MixingModuleConfig.h"
0029
0030 #include "CLHEP/Random/RandPoissonQ.h"
0031 #include "CLHEP/Random/RandPoisson.h"
0032
0033 #include "PileupRandomNumberGenerator.h"
0034
0035 #include <algorithm>
0036 #include <memory>
0037 #include "TMath.h"
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051 static Double_t GetRandom(TH1* th1, CLHEP::HepRandomEngine* rng) {
0052 Int_t nbinsx = th1->GetNbinsX();
0053 Double_t* fIntegral = th1->GetIntegral();
0054 Double_t integral = fIntegral[nbinsx];
0055
0056 if (integral == 0)
0057 return 0;
0058
0059 Double_t r1 = rng->flat();
0060 Int_t ibin = TMath::BinarySearch(nbinsx, fIntegral, r1);
0061 Double_t x = th1->GetBinLowEdge(ibin + 1);
0062 if (r1 > fIntegral[ibin])
0063 x += th1->GetBinWidth(ibin + 1) * (r1 - fIntegral[ibin]) / (fIntegral[ibin + 1] - fIntegral[ibin]);
0064 return x;
0065 }
0066
0067
0068 namespace edm {
0069 PileUp::PileUp(ParameterSet const& pset,
0070 const std::shared_ptr<PileUpConfig>& config,
0071 edm::ConsumesCollector iC,
0072 const bool mixingConfigFromDB)
0073 : type_(pset.getParameter<std::string>("type")),
0074 Source_type_(config->sourcename_),
0075 averageNumber_(config->averageNumber_),
0076 intAverage_(static_cast<int>(averageNumber_)),
0077 histo_(std::make_shared<TH1F>(*config->histo_)),
0078 histoDistribution_(type_ == "histo"),
0079 probFunctionDistribution_(type_ == "probFunction"),
0080 poisson_(type_ == "poisson"),
0081 fixed_(type_ == "fixed"),
0082 none_(type_ == "none"),
0083 fileNameHash_(0U),
0084 productRegistry_(new SignallingProductRegistry),
0085 input_(VectorInputSourceFactory::get()
0086 ->makeVectorInputSource(
0087 pset, VectorInputSourceDescription(productRegistry_, edm::PreallocationConfiguration()))
0088 .release()),
0089 processConfiguration_(new ProcessConfiguration(std::string("@MIXING"), getReleaseVersion(), getPassID())),
0090 processContext_(new ProcessContext()),
0091 eventPrincipal_(),
0092 lumiPrincipal_(),
0093 runPrincipal_(),
0094 provider_(),
0095 PoissonDistribution_(),
0096 PoissonDistr_OOT_(),
0097 randomEngine_(),
0098 playback_(config->playback_),
0099 sequential_(pset.getUntrackedParameter<bool>("sequential", false)) {
0100 if (mixingConfigFromDB) {
0101 configToken_ = iC.esConsumes<edm::Transition::BeginLuminosityBlock>();
0102 }
0103
0104
0105 processConfiguration_->setParameterSetID(ParameterSet::emptyParameterSetID());
0106 processContext_->setProcessConfiguration(processConfiguration_.get());
0107
0108 if (pset.existsAs<std::vector<ParameterSet> >("producers", true)) {
0109 std::vector<ParameterSet> producers = pset.getParameter<std::vector<ParameterSet> >("producers");
0110
0111 std::vector<std::string> names;
0112 names.reserve(producers.size());
0113 std::transform(producers.begin(), producers.end(), std::back_inserter(names), [](edm::ParameterSet const& iPSet) {
0114 return iPSet.getParameter<std::string>("@module_label");
0115 });
0116 auto randomGenerator = std::make_unique<PileupRandomNumberGenerator>(names);
0117 randomGenerator_ = randomGenerator.get();
0118 std::unique_ptr<edm::RandomNumberGenerator> baseGen = std::move(randomGenerator);
0119 serviceToken_ = edm::ServiceRegistry::createContaining(
0120 std::move(baseGen), edm::ServiceRegistry::instance().presentToken(), true);
0121
0122 provider_ = std::make_unique<SecondaryEventProvider>(producers, *productRegistry_, processConfiguration_);
0123 }
0124
0125 productRegistry_->setFrozen();
0126
0127
0128 eventPrincipal_ = std::make_unique<EventPrincipal>(input_->productRegistry(),
0129 std::make_shared<BranchIDListHelper>(),
0130 std::make_shared<ThinnedAssociationsHelper>(),
0131 *processConfiguration_,
0132 nullptr);
0133
0134 bool DB = type_ == "readDB";
0135
0136 if (pset.exists("nbPileupEvents")) {
0137 if (0 != pset.getParameter<edm::ParameterSet>("nbPileupEvents").getUntrackedParameter<int>("seed", 0)) {
0138 edm::LogWarning("MixingModule") << "Parameter nbPileupEvents.seed is not supported";
0139 }
0140 }
0141
0142 edm::Service<edm::RandomNumberGenerator> rng;
0143 if (!rng.isAvailable()) {
0144 throw cms::Exception("Configuration")
0145 << "PileUp requires the RandomNumberGeneratorService\n"
0146 "which is not present in the configuration file. You must add the service\n"
0147 "in the configuration file or remove the modules that require it.";
0148 }
0149
0150 if (!(histoDistribution_ || probFunctionDistribution_ || poisson_ || fixed_ || none_) && !DB) {
0151 throw cms::Exception("Illegal parameter value", "PileUp::PileUp(ParameterSet const& pset)")
0152 << "'type' parameter (a string) has a value of '" << type_ << "'.\n"
0153 << "Legal values are 'poisson', 'fixed', or 'none'\n";
0154 }
0155
0156 if (!DB) {
0157 manage_OOT_ = pset.getUntrackedParameter<bool>("manage_OOT", false);
0158
0159
0160 PU_Study_ = false;
0161 Study_type_ = pset.getUntrackedParameter<std::string>("Special_Pileup_Studies", "");
0162
0163 if (Study_type_ == "Fixed_ITPU_Vary_OOTPU") {
0164 PU_Study_ = true;
0165 intFixed_ITPU_ = pset.getUntrackedParameter<int>("intFixed_ITPU", 0);
0166 }
0167
0168 if (manage_OOT_) {
0169
0170
0171
0172
0173 std::string OOT_type = pset.getUntrackedParameter<std::string>("OOT_type");
0174
0175 if (OOT_type == "Poisson" || OOT_type == "poisson") {
0176 poisson_OOT_ = true;
0177 } else if (OOT_type == "Fixed" || OOT_type == "fixed") {
0178 fixed_OOT_ = true;
0179
0180 intFixed_OOT_ = pset.getUntrackedParameter<int>("intFixed_OOT", -1);
0181 if (intFixed_OOT_ < 0) {
0182 throw cms::Exception("Illegal parameter value", "PileUp::PileUp(ParameterSet const& pset)")
0183 << " Fixed out-of-time pileup requested, but no fixed value given ";
0184 }
0185 } else {
0186 throw cms::Exception("Illegal parameter value", "PileUp::PileUp(ParameterSet const& pset)")
0187 << "'OOT_type' parameter (a string) has a value of '" << OOT_type << "'.\n"
0188 << "Legal values are 'poisson' or 'fixed'\n";
0189 }
0190 edm::LogInfo("MixingModule") << " Out-of-time pileup will be generated with a " << OOT_type
0191 << " distribution. ";
0192 }
0193 }
0194
0195 if (Source_type_ == "cosmics") {
0196 minBunch_cosmics_ = pset.getUntrackedParameter<int>("minBunch_cosmics", -1000);
0197 maxBunch_cosmics_ = pset.getUntrackedParameter<int>("maxBunch_cosmics", 1000);
0198 }
0199 }
0200
0201 void PileUp::beginJob(eventsetup::ESRecordsToProductResolverIndices const& iES) {
0202 input_->doBeginJob();
0203 if (provider_.get() != nullptr) {
0204 edm::ServiceRegistry::Operate guard(*serviceToken_);
0205 provider_->beginJob(*productRegistry_, iES);
0206 }
0207 }
0208
0209 void PileUp::beginStream(edm::StreamID) {
0210 auto iID = eventPrincipal_->streamID();
0211 streamContext_.reset(new StreamContext(iID, processContext_.get()));
0212 if (provider_.get() != nullptr) {
0213 edm::ServiceRegistry::Operate guard(*serviceToken_);
0214 provider_->beginStream(iID, *streamContext_);
0215 }
0216 }
0217
0218 void PileUp::endStream() {
0219 if (provider_.get() != nullptr) {
0220 edm::ServiceRegistry::Operate guard(*serviceToken_);
0221 provider_->endStream(streamContext_->streamID(), *streamContext_);
0222 provider_->endJob();
0223 }
0224 input_->doEndJob();
0225 }
0226
0227 void PileUp::beginRun(const edm::Run& run, const edm::EventSetup& setup) {
0228 if (provider_.get() != nullptr) {
0229 runPrincipal_.reset(new RunPrincipal(productRegistry_, *processConfiguration_, nullptr, 0));
0230 runPrincipal_->setAux(run.runAuxiliary());
0231 edm::ServiceRegistry::Operate guard(*serviceToken_);
0232 provider_->beginRun(*runPrincipal_, setup.impl(), run.moduleCallingContext(), *streamContext_);
0233 }
0234 }
0235 void PileUp::beginLuminosityBlock(const edm::LuminosityBlock& lumi, const edm::EventSetup& setup) {
0236 if (provider_.get() != nullptr) {
0237 lumiPrincipal_.reset(new LuminosityBlockPrincipal(productRegistry_, *processConfiguration_, nullptr, 0));
0238 lumiPrincipal_->setAux(lumi.luminosityBlockAuxiliary());
0239 lumiPrincipal_->setRunPrincipal(runPrincipal_);
0240 setRandomEngine(lumi);
0241 edm::ServiceRegistry::Operate guard(*serviceToken_);
0242 provider_->beginLuminosityBlock(*lumiPrincipal_, setup.impl(), lumi.moduleCallingContext(), *streamContext_);
0243 }
0244 }
0245
0246 void PileUp::endRun(const edm::Run& run, const edm::EventSetup& setup) {
0247 if (provider_.get() != nullptr) {
0248 edm::ServiceRegistry::Operate guard(*serviceToken_);
0249 provider_->endRun(*runPrincipal_, setup.impl(), run.moduleCallingContext(), *streamContext_);
0250 }
0251 }
0252 void PileUp::endLuminosityBlock(const edm::LuminosityBlock& lumi, const edm::EventSetup& setup) {
0253 if (provider_.get() != nullptr) {
0254 edm::ServiceRegistry::Operate guard(*serviceToken_);
0255 provider_->endLuminosityBlock(*lumiPrincipal_, setup.impl(), lumi.moduleCallingContext(), *streamContext_);
0256 }
0257 }
0258
0259 void PileUp::setupPileUpEvent(const edm::EventSetup& setup) {
0260 if (provider_.get() != nullptr) {
0261
0262 eventPrincipal_->setLuminosityBlockPrincipal(lumiPrincipal_.get());
0263 eventPrincipal_->setRunAndLumiNumber(lumiPrincipal_->run(), lumiPrincipal_->luminosityBlock());
0264 edm::ServiceRegistry::Operate guard(*serviceToken_);
0265 provider_->setupPileUpEvent(*eventPrincipal_, setup.impl(), *streamContext_);
0266 }
0267 }
0268
0269 void PileUp::reload(const edm::EventSetup& setup) {
0270
0271 const MixingInputConfig& config = setup.getData(configToken_).config(inputType_);
0272
0273
0274 type_ = config.type();
0275
0276 histoDistribution_ = type_ == "histo";
0277 probFunctionDistribution_ = type_ == "probFunction";
0278 poisson_ = type_ == "poisson";
0279 fixed_ = type_ == "fixed";
0280 none_ = type_ == "none";
0281
0282 if (histoDistribution_)
0283 edm::LogError("MisConfiguration") << "type histo cannot be reloaded from DB, yet";
0284
0285 if (fixed_) {
0286 averageNumber_ = averageNumber();
0287 } else if (poisson_) {
0288 averageNumber_ = config.averageNumber();
0289 if (PoissonDistribution_) {
0290 PoissonDistribution_ = std::make_unique<CLHEP::RandPoissonQ>(PoissonDistribution_->engine(), averageNumber_);
0291 }
0292 } else if (probFunctionDistribution_) {
0293
0294 const std::vector<int>& dataProbFunctionVar = config.probFunctionVariable();
0295 std::vector<double> dataProb = config.probValue();
0296
0297 int varSize = (int)dataProbFunctionVar.size();
0298 int probSize = (int)dataProb.size();
0299
0300 if ((dataProbFunctionVar[0] != 0) || (dataProbFunctionVar[varSize - 1] != (varSize - 1)))
0301 throw cms::Exception("BadProbFunction")
0302 << "Please, check the variables of the probability function! The first variable should be 0 and the "
0303 "difference between two variables should be 1."
0304 << std::endl;
0305
0306
0307
0308 if (probSize < varSize) {
0309 edm::LogWarning("MixingModule") << " The probability function data will be completed with "
0310 << (varSize - probSize) << " values 0.";
0311
0312 for (int i = 0; i < (varSize - probSize); i++)
0313 dataProb.push_back(0);
0314
0315 probSize = dataProb.size();
0316 edm::LogInfo("MixingModule") << " The number of the P(x) data set after adding the values 0 is " << probSize;
0317 }
0318
0319
0320 int xmin = (int)dataProbFunctionVar[0];
0321 int xmax = (int)dataProbFunctionVar[varSize - 1] + 1;
0322 int numBins = varSize;
0323
0324 edm::LogInfo("MixingModule") << "An histogram will be created with " << numBins << " bins in the range (" << xmin
0325 << "," << xmax << ")." << std::endl;
0326
0327 histo_.reset(new TH1F("h", "Histo from the user's probability function", numBins, xmin, xmax));
0328
0329 LogDebug("MixingModule") << "Filling histogram with the following data:" << std::endl;
0330
0331 for (int j = 0; j < numBins; j++) {
0332 LogDebug("MixingModule") << " x = " << dataProbFunctionVar[j] << " P(x) = " << dataProb[j];
0333 histo_->Fill(dataProbFunctionVar[j] + 0.5,
0334 dataProb[j]);
0335 }
0336
0337
0338 if (std::abs(histo_->Integral() - 1) > 1.0e-02) {
0339 throw cms::Exception("BadProbFunction") << "The probability function should be normalized!!! " << std::endl;
0340 }
0341 averageNumber_ = histo_->GetMean();
0342 }
0343
0344 int oot = config.outOfTime();
0345 manage_OOT_ = false;
0346 if (oot == 1) {
0347 manage_OOT_ = true;
0348 poisson_OOT_ = false;
0349 fixed_OOT_ = true;
0350 intFixed_OOT_ = config.fixedOutOfTime();
0351 } else if (oot == 2) {
0352 manage_OOT_ = true;
0353 poisson_OOT_ = true;
0354 fixed_OOT_ = false;
0355 }
0356 }
0357 PileUp::~PileUp() {}
0358
0359 std::unique_ptr<CLHEP::RandPoissonQ> const& PileUp::poissonDistribution(StreamID const& streamID) {
0360 if (!PoissonDistribution_) {
0361 CLHEP::HepRandomEngine& engine = *randomEngine(streamID);
0362 PoissonDistribution_ = std::make_unique<CLHEP::RandPoissonQ>(engine, averageNumber_);
0363 }
0364 return PoissonDistribution_;
0365 }
0366
0367 std::unique_ptr<CLHEP::RandPoisson> const& PileUp::poissonDistr_OOT(StreamID const& streamID) {
0368 if (!PoissonDistr_OOT_) {
0369 CLHEP::HepRandomEngine& engine = *randomEngine(streamID);
0370 PoissonDistr_OOT_ = std::make_unique<CLHEP::RandPoisson>(engine);
0371 }
0372 return PoissonDistr_OOT_;
0373 }
0374
0375 CLHEP::HepRandomEngine* PileUp::randomEngine(StreamID const& streamID) {
0376 if (!randomEngine_) {
0377 Service<RandomNumberGenerator> rng;
0378 randomEngine_ = &rng->getEngine(streamID);
0379 }
0380 return randomEngine_;
0381 }
0382
0383 void PileUp::setRandomEngine(StreamID streamID) { randomGenerator_->setEngine(*randomEngine(streamID)); }
0384 void PileUp::setRandomEngine(LuminosityBlock const& iLumi) {
0385 Service<RandomNumberGenerator> rng;
0386 randomGenerator_->setSeed(rng->mySeed());
0387 randomGenerator_->setEngine(rng->getEngine(iLumi.index()));
0388 }
0389
0390 void PileUp::CalculatePileup(int MinBunch,
0391 int MaxBunch,
0392 std::vector<int>& PileupSelection,
0393 std::vector<float>& TrueNumInteractions,
0394 StreamID const& streamID) {
0395
0396
0397
0398 int nzero_crossing = -1;
0399 double Fnzero_crossing = -1;
0400
0401 if (provider_) {
0402 setRandomEngine(streamID);
0403 }
0404
0405 if (manage_OOT_) {
0406 if (none_) {
0407 nzero_crossing = 0;
0408 } else if (poisson_) {
0409 nzero_crossing = poissonDistribution(streamID)->fire();
0410 } else if (fixed_) {
0411 nzero_crossing = intAverage_;
0412 } else if (histoDistribution_ || probFunctionDistribution_) {
0413
0414
0415
0416
0417
0418
0419
0420 double d = GetRandom(histo_.get(), randomEngine(streamID));
0421
0422 Fnzero_crossing = d;
0423 nzero_crossing = int(d);
0424 }
0425 }
0426
0427 for (int bx = MinBunch; bx < MaxBunch + 1; ++bx) {
0428 if (manage_OOT_) {
0429 if (bx == 0 && !poisson_OOT_) {
0430 PileupSelection.push_back(nzero_crossing);
0431 TrueNumInteractions.push_back(nzero_crossing);
0432 } else {
0433 if (poisson_OOT_) {
0434 if (PU_Study_ && (Study_type_ == "Fixed_ITPU_Vary_OOTPU") && bx == 0) {
0435 PileupSelection.push_back(intFixed_ITPU_);
0436 } else {
0437 PileupSelection.push_back(poissonDistr_OOT(streamID)->fire(Fnzero_crossing));
0438 }
0439 TrueNumInteractions.push_back(Fnzero_crossing);
0440 } else {
0441 PileupSelection.push_back(intFixed_OOT_);
0442 TrueNumInteractions.push_back(intFixed_OOT_);
0443 }
0444 }
0445 } else {
0446 if (none_) {
0447 PileupSelection.push_back(0);
0448 TrueNumInteractions.push_back(0.);
0449 } else if (poisson_) {
0450 PileupSelection.push_back(poissonDistribution(streamID)->fire());
0451 TrueNumInteractions.push_back(averageNumber_);
0452 } else if (fixed_) {
0453 PileupSelection.push_back(intAverage_);
0454 TrueNumInteractions.push_back(intAverage_);
0455 } else if (histoDistribution_ || probFunctionDistribution_) {
0456
0457
0458
0459
0460
0461
0462
0463 double d = GetRandom(histo_.get(), randomEngine(streamID));
0464 PileupSelection.push_back(int(d));
0465 TrueNumInteractions.push_back(d);
0466 }
0467 }
0468 }
0469 }
0470
0471 }