CMS 3D CMS Logo

FFTJetPileupProcessor.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: RecoJets/FFTJetProducers
4 // Class: FFTJetPileupProcessor
5 //
13 //
14 // Original Author: Igor Volobouev
15 // Created: Wed Apr 20 13:52:23 CDT 2011
16 //
17 //
18 
19 #include <cmath>
20 #include <fstream>
21 #include <memory>
22 
23 // FFTJet headers
24 #include "fftjet/FrequencyKernelConvolver.hh"
25 #include "fftjet/DiscreteGauss2d.hh"
26 #include "fftjet/EquidistantSequence.hh"
27 #include "fftjet/interpolate.hh"
28 
29 // framework include files
33 
36 
38 
39 // parameter parser header
41 
42 // useful utilities collected in the second base
44 
45 // Loader for the lookup tables
47 
48 using namespace fftjetcms;
49 
50 //
51 // class declaration
52 //
54 public:
56  FFTJetPileupProcessor() = delete;
59  ~FFTJetPileupProcessor() override;
60 
61 protected:
62  // methods
63  void produce(edm::Event&, const edm::EventSetup&) override;
64 
65 private:
66  void buildKernelConvolver(const edm::ParameterSet&);
67  void mixExtraGrid();
68  void loadFlatteningFactors(const edm::EventSetup& iSetup);
69 
70  // The FFT engine
71  std::unique_ptr<MyFFTEngine> engine;
72 
73  // The pattern recognition kernel(s)
74  std::unique_ptr<fftjet::AbsFrequencyKernel> kernel2d;
75 
76  // The kernel convolver
77  std::unique_ptr<fftjet::AbsConvolverBase<Real>> convolver;
78 
79  // Storage for convolved energy flow
80  std::unique_ptr<fftjet::Grid2d<fftjetcms::Real>> convolvedFlow;
81 
82  // Filtering scales
83  std::unique_ptr<fftjet::EquidistantInLogSpace> filterScales;
84 
85  // Eta-dependent factors to use for flattening the distribution
86  // _after_ the filtering
87  std::vector<double> etaFlatteningFactors;
88 
89  // Number of percentile points to use
90  unsigned nPercentiles;
91 
92  // Bin range. Both values of 0 means use the whole range.
93  unsigned convolverMinBin;
94  unsigned convolverMaxBin;
95 
96  // Density conversion factor
98 
99  // Variable related to mixing additional grids
100  std::vector<std::string> externalGridFiles;
101  std::ifstream gridStream;
103  unsigned currentFileNum;
104 
105  // Some memory to hold the percentiles found
106  std::vector<double> percentileData;
107 
108  // Variables to load the flattening factors from
109  // the calibration database (this has to be done
110  // in sync with configuring the appropriate event
111  // setup source)
116 
118 };
119 
120 //
121 // constructors and destructor
122 //
124  : FFTJetInterface(ps),
125  etaFlatteningFactors(ps.getParameter<std::vector<double>>("etaFlatteningFactors")),
126  nPercentiles(ps.getParameter<unsigned>("nPercentiles")),
127  convolverMinBin(ps.getParameter<unsigned>("convolverMinBin")),
128  convolverMaxBin(ps.getParameter<unsigned>("convolverMaxBin")),
129  pileupEtaPhiArea(ps.getParameter<double>("pileupEtaPhiArea")),
130  externalGridFiles(ps.getParameter<std::vector<std::string>>("externalGridFiles")),
131  externalGridMaxEnergy(ps.getParameter<double>("externalGridMaxEnergy")),
132  currentFileNum(externalGridFiles.size() + 1U),
133  flatteningTableRecord(ps.getParameter<std::string>("flatteningTableRecord")),
134  flatteningTableName(ps.getParameter<std::string>("flatteningTableName")),
135  flatteningTableCategory(ps.getParameter<std::string>("flatteningTableCategory")),
136  loadFlatteningFactorsFromDB(ps.getParameter<bool>("loadFlatteningFactorsFromDB")) {
137  // Build the discretization grid
139  checkConfig(energyFlow, "invalid discretization grid");
140 
141  // Copy of the grid which will be used for convolutions
142  convolvedFlow = std::make_unique<fftjet::Grid2d<fftjetcms::Real>>(*energyFlow);
143 
144  // Make sure the size of flattening factors is appropriate
145  if (!etaFlatteningFactors.empty()) {
146  if (etaFlatteningFactors.size() != convolvedFlow->nEta())
147  throw cms::Exception("FFTJetBadConfig") << "ERROR in FFTJetPileupProcessor constructor:"
148  " number of elements in the \"etaFlatteningFactors\""
149  " vector is inconsistent with the discretization grid binning"
150  << std::endl;
151  }
152 
153  // Build the FFT engine(s), pattern recognition kernel(s),
154  // and the kernel convolver
156 
157  // Build the set of pattern recognition scales
158  const unsigned nScales = ps.getParameter<unsigned>("nScales");
159  const double minScale = ps.getParameter<double>("minScale");
160  const double maxScale = ps.getParameter<double>("maxScale");
161  if (minScale <= 0.0 || maxScale < minScale || nScales == 0U)
162  throw cms::Exception("FFTJetBadConfig") << "invalid filter scales" << std::endl;
163 
164  filterScales = std::make_unique<fftjet::EquidistantInLogSpace>(minScale, maxScale, nScales);
165 
167 
168  produces<reco::DiscretizedEnergyFlow>(outputLabel);
169  produces<std::pair<double, double>>(outputLabel);
170 
171  esLoader.acquireToken(flatteningTableRecord, consumesCollector());
172 }
173 
175  // Get the eta and phi scales for the kernel(s)
176  double kernelEtaScale = ps.getParameter<double>("kernelEtaScale");
177  const double kernelPhiScale = ps.getParameter<double>("kernelPhiScale");
178  if (kernelEtaScale <= 0.0 || kernelPhiScale <= 0.0)
179  throw cms::Exception("FFTJetBadConfig") << "invalid kernel scales" << std::endl;
180 
183  throw cms::Exception("FFTJetBadConfig") << "invalid convolver bin range" << std::endl;
184 
185  // FFT assumes that the grid extent in eta is 2*Pi. Adjust the
186  // kernel scale in eta to compensate.
187  kernelEtaScale *= (2.0 * M_PI / (energyFlow->etaMax() - energyFlow->etaMin()));
188 
189  // Build the FFT engine
190  engine = std::make_unique<MyFFTEngine>(energyFlow->nEta(), energyFlow->nPhi());
191 
192  // 2d kernel
193  kernel2d = std::unique_ptr<fftjet::AbsFrequencyKernel>(
194  new fftjet::DiscreteGauss2d(kernelEtaScale, kernelPhiScale, energyFlow->nEta(), energyFlow->nPhi()));
195 
196  // 2d convolver
197  convolver = std::unique_ptr<fftjet::AbsConvolverBase<Real>>(new fftjet::FrequencyKernelConvolver<Real, Complex>(
199 }
200 
202 
203 // ------------ method called to produce the data ------------
207 
208  // Determine the average Et density for this event.
209  // Needs to be done here, before mixing in another grid.
210  const fftjet::Grid2d<Real>& g(*energyFlow);
211  const double densityBeforeMixing = g.sum() / pileupEtaPhiArea;
212 
213  // Mix an extra grid (if requested)
214  double densityAfterMixing = -1.0;
215  if (!externalGridFiles.empty()) {
216  mixExtraGrid();
217  densityAfterMixing = g.sum() / pileupEtaPhiArea;
218  }
219 
220  // Various useful variables
221  const unsigned nScales = filterScales->size();
222  const double* scales = &(*filterScales)[0];
223  Real* convData = const_cast<Real*>(convolvedFlow->data());
224  Real* sortData = convData + convolverMinBin * convolvedFlow->nPhi();
225  const unsigned dataLen = convolverMaxBin ? (convolverMaxBin - convolverMinBin) * convolvedFlow->nPhi()
226  : convolvedFlow->nEta() * convolvedFlow->nPhi();
227 
228  // Load flattenning factors from DB (if requested)
230  loadFlatteningFactors(iSetup);
231 
232  // Go over all scales and perform the convolutions
233  convolver->setEventData(g.data(), g.nEta(), g.nPhi());
234  for (unsigned iscale = 0; iscale < nScales; ++iscale) {
235  // Perform the convolution
236  convolver->convolveWithKernel(scales[iscale], convData, convolvedFlow->nEta(), convolvedFlow->nPhi());
237 
238  // Apply the flattening factors
239  if (!etaFlatteningFactors.empty())
241 
242  // Sort the convolved data
243  std::sort(sortData, sortData + dataLen);
244 
245  // Determine the percentile points
246  for (unsigned iper = 0; iper < nPercentiles; ++iper) {
247  // Map percentile 0 into point number 0,
248  // 1 into point number dataLen-1
249  const double q = (iper + 0.5) / nPercentiles;
250  const double dindex = q * (dataLen - 1U);
251  const unsigned ilow = static_cast<unsigned>(std::floor(dindex));
252  const double percentile =
253  fftjet::lin_interpolate_1d(ilow, ilow + 1U, sortData[ilow], sortData[ilow + 1U], dindex);
254 
255  // Store the calculated percentile
256  percentileData[iscale * nPercentiles + iper] = percentile;
257  }
258  }
259 
260  // Convert percentile data into a more convenient storable object
261  // and put it into the event record
262  iEvent.put(std::make_unique<reco::DiscretizedEnergyFlow>(
263  &percentileData[0], "FFTJetPileupProcessor", -0.5, nScales - 0.5, 0.0, nScales, nPercentiles),
264  outputLabel);
265 
266  iEvent.put(std::make_unique<std::pair<double, double>>(densityBeforeMixing, densityAfterMixing), outputLabel);
267 }
268 
270  const unsigned nFiles = externalGridFiles.size();
271  if (currentFileNum > nFiles) {
272  // This is the first time this function is called
273  currentFileNum = 0;
274  gridStream.open(externalGridFiles[currentFileNum].c_str(), std::ios_base::in | std::ios_base::binary);
275  if (!gridStream.is_open())
276  throw cms::Exception("FFTJetBadConfig") << "ERROR in FFTJetPileupProcessor::mixExtraGrid():"
277  " failed to open external grid file "
278  << externalGridFiles[currentFileNum] << std::endl;
279  }
280 
281  const fftjet::Grid2d<float>* g = nullptr;
282  const unsigned maxFail = 100U;
283  unsigned nEnergyRejected = 0;
284 
285  while (!g) {
287 
288  // If we can't read the grid, we need to switch to another file
289  for (unsigned ntries = 0; ntries < nFiles && g == nullptr; ++ntries) {
290  gridStream.close();
292  gridStream.open(externalGridFiles[currentFileNum].c_str(), std::ios_base::in | std::ios_base::binary);
293  if (!gridStream.is_open())
294  throw cms::Exception("FFTJetBadConfig") << "ERROR in FFTJetPileupProcessor::mixExtraGrid():"
295  " failed to open external grid file "
296  << externalGridFiles[currentFileNum] << std::endl;
298  }
299 
300  if (g)
301  if (g->sum() > externalGridMaxEnergy) {
302  delete g;
303  g = nullptr;
304  if (++nEnergyRejected >= maxFail)
305  throw cms::Exception("FFTJetBadConfig") << "ERROR in FFTJetPileupProcessor::mixExtraGrid():"
306  " too many grids in a row ("
307  << nEnergyRejected << ") failed the maximum energy cut" << std::endl;
308  }
309  }
310 
311  if (g) {
312  add_Grid2d_data(energyFlow.get(), *g);
313  delete g;
314  } else {
315  // Too bad, no useful file found
316  throw cms::Exception("FFTJetBadConfig") << "ERROR in FFTJetPileupProcessor::mixExtraGrid():"
317  " no valid grid records found"
318  << std::endl;
319  }
320 }
321 
324  std::shared_ptr<npstat::StorableMultivariateFunctor> f = (*h)[flatteningTableCategory][flatteningTableName];
325 
326  // Fill out the table of flattening factors as a function of eta
327  const unsigned nEta = energyFlow->nEta();
328  etaFlatteningFactors.clear();
329  etaFlatteningFactors.reserve(nEta);
330  for (unsigned ieta = 0; ieta < nEta; ++ieta) {
331  const double eta = energyFlow->etaBinCenter(ieta);
332  etaFlatteningFactors.push_back((*f)(&eta, 1U));
333  }
334 }
335 
336 //define this as a plug-in
edm::ESHandle< DataType > load(const std::string &record, const edm::EventSetup &iSetup) const
std::unique_ptr< fftjet::AbsConvolverBase< Real > > convolver
std::vector< std::string > externalGridFiles
T getParameter(std::string const &) const
Definition: ParameterSet.h:307
Basic3DVector & operator=(const Basic3DVector &)=default
Assignment operator.
void loadInputCollection(const edm::Event &)
void checkConfig(const Ptr &ptr, const char *message)
std::unique_ptr< fftjet::Grid2d< Real > > fftjet_Grid2d_parser(const edm::ParameterSet &ps)
void acquireToken(const std::string &record, edm::ConsumesCollector iC)
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e g
Definition: Activities.doc:4
FFTJetLookupTableSequenceLoader esLoader
FFTJetPileupProcessor()=delete
std::unique_ptr< fftjet::Grid2d< fftjetcms::Real > > convolvedFlow
int iEvent
Definition: GenABIO.cc:224
std::vector< double > percentileData
std::unique_ptr< fftjet::Grid2d< fftjetcms::Real > > energyFlow
std::unique_ptr< fftjet::EquidistantInLogSpace > filterScales
double f[11][100]
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
std::unique_ptr< MyFFTEngine > engine
void buildKernelConvolver(const edm::ParameterSet &)
#define M_PI
std::vector< double > etaFlatteningFactors
void loadFlatteningFactors(const edm::EventSetup &iSetup)
double Real
void produce(edm::Event &, const edm::EventSetup &) override
The Signals That Services Can Subscribe To This is based on ActivityRegistry h
Helper function to determine trigger accepts.
Definition: Activities.doc:4
void add_Grid2d_data(fftjet::Grid2d< F2 > *to, const fftjet::Grid2d< F1 > &from)
const std::string outputLabel
std::unique_ptr< fftjet::AbsFrequencyKernel > kernel2d