File indexing completed on 2024-04-06 12:25:23
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include <cmath>
0020 #include <fstream>
0021 #include <memory>
0022
0023
0024 #include "fftjet/FrequencyKernelConvolver.hh"
0025 #include "fftjet/DiscreteGauss2d.hh"
0026 #include "fftjet/EquidistantSequence.hh"
0027 #include "fftjet/interpolate.hh"
0028
0029
0030 #include "FWCore/Framework/interface/Frameworkfwd.h"
0031 #include "FWCore/Framework/interface/MakerMacros.h"
0032 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0033
0034 #include "DataFormats/Common/interface/View.h"
0035 #include "DataFormats/JetReco/interface/DiscretizedEnergyFlow.h"
0036
0037 #include "RecoJets/FFTJetAlgorithms/interface/gridConverters.h"
0038
0039
0040 #include "RecoJets/FFTJetProducers/interface/FFTJetParameterParser.h"
0041
0042
0043 #include "RecoJets/FFTJetProducers/interface/FFTJetInterface.h"
0044
0045
0046 #include "JetMETCorrections/FFTJetObjects/interface/FFTJetLookupTableSequenceLoader.h"
0047
0048 using namespace fftjetcms;
0049
0050
0051
0052
0053 class FFTJetPileupProcessor : public FFTJetInterface {
0054 public:
0055 explicit FFTJetPileupProcessor(const edm::ParameterSet&);
0056 FFTJetPileupProcessor() = delete;
0057 FFTJetPileupProcessor(const FFTJetPileupProcessor&) = delete;
0058 FFTJetPileupProcessor& operator=(const FFTJetPileupProcessor&) = delete;
0059 ~FFTJetPileupProcessor() override;
0060
0061 protected:
0062
0063 void produce(edm::Event&, const edm::EventSetup&) override;
0064
0065 private:
0066 void buildKernelConvolver(const edm::ParameterSet&);
0067 void mixExtraGrid();
0068 void loadFlatteningFactors(const edm::EventSetup& iSetup);
0069
0070
0071 std::unique_ptr<MyFFTEngine> engine;
0072
0073
0074 std::unique_ptr<fftjet::AbsFrequencyKernel> kernel2d;
0075
0076
0077 std::unique_ptr<fftjet::AbsConvolverBase<Real>> convolver;
0078
0079
0080 std::unique_ptr<fftjet::Grid2d<fftjetcms::Real>> convolvedFlow;
0081
0082
0083 std::unique_ptr<fftjet::EquidistantInLogSpace> filterScales;
0084
0085
0086
0087 std::vector<double> etaFlatteningFactors;
0088
0089
0090 unsigned nPercentiles;
0091
0092
0093 unsigned convolverMinBin;
0094 unsigned convolverMaxBin;
0095
0096
0097 double pileupEtaPhiArea;
0098
0099
0100 std::vector<std::string> externalGridFiles;
0101 std::ifstream gridStream;
0102 double externalGridMaxEnergy;
0103 unsigned currentFileNum;
0104
0105
0106 std::vector<double> percentileData;
0107
0108
0109
0110
0111
0112 std::string flatteningTableRecord;
0113 std::string flatteningTableName;
0114 std::string flatteningTableCategory;
0115 bool loadFlatteningFactorsFromDB;
0116
0117 FFTJetLookupTableSequenceLoader esLoader;
0118 };
0119
0120
0121
0122
0123 FFTJetPileupProcessor::FFTJetPileupProcessor(const edm::ParameterSet& ps)
0124 : FFTJetInterface(ps),
0125 etaFlatteningFactors(ps.getParameter<std::vector<double>>("etaFlatteningFactors")),
0126 nPercentiles(ps.getParameter<unsigned>("nPercentiles")),
0127 convolverMinBin(ps.getParameter<unsigned>("convolverMinBin")),
0128 convolverMaxBin(ps.getParameter<unsigned>("convolverMaxBin")),
0129 pileupEtaPhiArea(ps.getParameter<double>("pileupEtaPhiArea")),
0130 externalGridFiles(ps.getParameter<std::vector<std::string>>("externalGridFiles")),
0131 externalGridMaxEnergy(ps.getParameter<double>("externalGridMaxEnergy")),
0132 currentFileNum(externalGridFiles.size() + 1U),
0133 flatteningTableRecord(ps.getParameter<std::string>("flatteningTableRecord")),
0134 flatteningTableName(ps.getParameter<std::string>("flatteningTableName")),
0135 flatteningTableCategory(ps.getParameter<std::string>("flatteningTableCategory")),
0136 loadFlatteningFactorsFromDB(ps.getParameter<bool>("loadFlatteningFactorsFromDB")) {
0137
0138 energyFlow = fftjet_Grid2d_parser(ps.getParameter<edm::ParameterSet>("GridConfiguration"));
0139 checkConfig(energyFlow, "invalid discretization grid");
0140
0141
0142 convolvedFlow = std::make_unique<fftjet::Grid2d<fftjetcms::Real>>(*energyFlow);
0143
0144
0145 if (!etaFlatteningFactors.empty()) {
0146 if (etaFlatteningFactors.size() != convolvedFlow->nEta())
0147 throw cms::Exception("FFTJetBadConfig") << "ERROR in FFTJetPileupProcessor constructor:"
0148 " number of elements in the \"etaFlatteningFactors\""
0149 " vector is inconsistent with the discretization grid binning"
0150 << std::endl;
0151 }
0152
0153
0154
0155 buildKernelConvolver(ps);
0156
0157
0158 const unsigned nScales = ps.getParameter<unsigned>("nScales");
0159 const double minScale = ps.getParameter<double>("minScale");
0160 const double maxScale = ps.getParameter<double>("maxScale");
0161 if (minScale <= 0.0 || maxScale < minScale || nScales == 0U)
0162 throw cms::Exception("FFTJetBadConfig") << "invalid filter scales" << std::endl;
0163
0164 filterScales = std::make_unique<fftjet::EquidistantInLogSpace>(minScale, maxScale, nScales);
0165
0166 percentileData.resize(nScales * nPercentiles);
0167
0168 produces<reco::DiscretizedEnergyFlow>(outputLabel);
0169 produces<std::pair<double, double>>(outputLabel);
0170
0171 esLoader.acquireToken(flatteningTableRecord, consumesCollector());
0172 }
0173
0174 void FFTJetPileupProcessor::buildKernelConvolver(const edm::ParameterSet& ps) {
0175
0176 double kernelEtaScale = ps.getParameter<double>("kernelEtaScale");
0177 const double kernelPhiScale = ps.getParameter<double>("kernelPhiScale");
0178 if (kernelEtaScale <= 0.0 || kernelPhiScale <= 0.0)
0179 throw cms::Exception("FFTJetBadConfig") << "invalid kernel scales" << std::endl;
0180
0181 if (convolverMinBin || convolverMaxBin)
0182 if (convolverMinBin >= convolverMaxBin || convolverMaxBin > energyFlow->nEta())
0183 throw cms::Exception("FFTJetBadConfig") << "invalid convolver bin range" << std::endl;
0184
0185
0186
0187 kernelEtaScale *= (2.0 * M_PI / (energyFlow->etaMax() - energyFlow->etaMin()));
0188
0189
0190 engine = std::make_unique<MyFFTEngine>(energyFlow->nEta(), energyFlow->nPhi());
0191
0192
0193 kernel2d = std::unique_ptr<fftjet::AbsFrequencyKernel>(
0194 new fftjet::DiscreteGauss2d(kernelEtaScale, kernelPhiScale, energyFlow->nEta(), energyFlow->nPhi()));
0195
0196
0197 convolver = std::unique_ptr<fftjet::AbsConvolverBase<Real>>(new fftjet::FrequencyKernelConvolver<Real, Complex>(
0198 engine.get(), kernel2d.get(), convolverMinBin, convolverMaxBin));
0199 }
0200
0201 FFTJetPileupProcessor::~FFTJetPileupProcessor() {}
0202
0203
0204 void FFTJetPileupProcessor::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) {
0205 loadInputCollection(iEvent);
0206 discretizeEnergyFlow();
0207
0208
0209
0210 const fftjet::Grid2d<Real>& g(*energyFlow);
0211 const double densityBeforeMixing = g.sum() / pileupEtaPhiArea;
0212
0213
0214 double densityAfterMixing = -1.0;
0215 if (!externalGridFiles.empty()) {
0216 mixExtraGrid();
0217 densityAfterMixing = g.sum() / pileupEtaPhiArea;
0218 }
0219
0220
0221 const unsigned nScales = filterScales->size();
0222 const double* scales = &(*filterScales)[0];
0223 Real* convData = const_cast<Real*>(convolvedFlow->data());
0224 Real* sortData = convData + convolverMinBin * convolvedFlow->nPhi();
0225 const unsigned dataLen = convolverMaxBin ? (convolverMaxBin - convolverMinBin) * convolvedFlow->nPhi()
0226 : convolvedFlow->nEta() * convolvedFlow->nPhi();
0227
0228
0229 if (loadFlatteningFactorsFromDB)
0230 loadFlatteningFactors(iSetup);
0231
0232
0233 convolver->setEventData(g.data(), g.nEta(), g.nPhi());
0234 for (unsigned iscale = 0; iscale < nScales; ++iscale) {
0235
0236 convolver->convolveWithKernel(scales[iscale], convData, convolvedFlow->nEta(), convolvedFlow->nPhi());
0237
0238
0239 if (!etaFlatteningFactors.empty())
0240 convolvedFlow->scaleData(&etaFlatteningFactors[0], etaFlatteningFactors.size());
0241
0242
0243 std::sort(sortData, sortData + dataLen);
0244
0245
0246 for (unsigned iper = 0; iper < nPercentiles; ++iper) {
0247
0248
0249 const double q = (iper + 0.5) / nPercentiles;
0250 const double dindex = q * (dataLen - 1U);
0251 const unsigned ilow = static_cast<unsigned>(std::floor(dindex));
0252 const double percentile =
0253 fftjet::lin_interpolate_1d(ilow, ilow + 1U, sortData[ilow], sortData[ilow + 1U], dindex);
0254
0255
0256 percentileData[iscale * nPercentiles + iper] = percentile;
0257 }
0258 }
0259
0260
0261
0262 iEvent.put(std::make_unique<reco::DiscretizedEnergyFlow>(
0263 &percentileData[0], "FFTJetPileupProcessor", -0.5, nScales - 0.5, 0.0, nScales, nPercentiles),
0264 outputLabel);
0265
0266 iEvent.put(std::make_unique<std::pair<double, double>>(densityBeforeMixing, densityAfterMixing), outputLabel);
0267 }
0268
0269 void FFTJetPileupProcessor::mixExtraGrid() {
0270 const unsigned nFiles = externalGridFiles.size();
0271 if (currentFileNum > nFiles) {
0272
0273 currentFileNum = 0;
0274 gridStream.open(externalGridFiles[currentFileNum].c_str(), std::ios_base::in | std::ios_base::binary);
0275 if (!gridStream.is_open())
0276 throw cms::Exception("FFTJetBadConfig") << "ERROR in FFTJetPileupProcessor::mixExtraGrid():"
0277 " failed to open external grid file "
0278 << externalGridFiles[currentFileNum] << std::endl;
0279 }
0280
0281 const fftjet::Grid2d<float>* g = nullptr;
0282 const unsigned maxFail = 100U;
0283 unsigned nEnergyRejected = 0;
0284
0285 while (!g) {
0286 g = fftjet::Grid2d<float>::read(gridStream);
0287
0288
0289 for (unsigned ntries = 0; ntries < nFiles && g == nullptr; ++ntries) {
0290 gridStream.close();
0291 currentFileNum = (currentFileNum + 1U) % nFiles;
0292 gridStream.open(externalGridFiles[currentFileNum].c_str(), std::ios_base::in | std::ios_base::binary);
0293 if (!gridStream.is_open())
0294 throw cms::Exception("FFTJetBadConfig") << "ERROR in FFTJetPileupProcessor::mixExtraGrid():"
0295 " failed to open external grid file "
0296 << externalGridFiles[currentFileNum] << std::endl;
0297 g = fftjet::Grid2d<float>::read(gridStream);
0298 }
0299
0300 if (g)
0301 if (g->sum() > externalGridMaxEnergy) {
0302 delete g;
0303 g = nullptr;
0304 if (++nEnergyRejected >= maxFail)
0305 throw cms::Exception("FFTJetBadConfig") << "ERROR in FFTJetPileupProcessor::mixExtraGrid():"
0306 " too many grids in a row ("
0307 << nEnergyRejected << ") failed the maximum energy cut" << std::endl;
0308 }
0309 }
0310
0311 if (g) {
0312 add_Grid2d_data(energyFlow.get(), *g);
0313 delete g;
0314 } else {
0315
0316 throw cms::Exception("FFTJetBadConfig") << "ERROR in FFTJetPileupProcessor::mixExtraGrid():"
0317 " no valid grid records found"
0318 << std::endl;
0319 }
0320 }
0321
0322 void FFTJetPileupProcessor::loadFlatteningFactors(const edm::EventSetup& iSetup) {
0323 edm::ESHandle<FFTJetLookupTableSequence> h = esLoader.load(flatteningTableRecord, iSetup);
0324 std::shared_ptr<npstat::StorableMultivariateFunctor> f = (*h)[flatteningTableCategory][flatteningTableName];
0325
0326
0327 const unsigned nEta = energyFlow->nEta();
0328 etaFlatteningFactors.clear();
0329 etaFlatteningFactors.reserve(nEta);
0330 for (unsigned ieta = 0; ieta < nEta; ++ieta) {
0331 const double eta = energyFlow->etaBinCenter(ieta);
0332 etaFlatteningFactors.push_back((*f)(&eta, 1U));
0333 }
0334 }
0335
0336
0337 DEFINE_FWK_MODULE(FFTJetPileupProcessor);