CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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;
58  FFTJetPileupProcessor& operator=(const FFTJetPileupProcessor&) = delete;
59  ~FFTJetPileupProcessor() override;
60 
61 protected:
62  // methods
63  void beginJob() override;
64  void produce(edm::Event&, const edm::EventSetup&) override;
65  void endJob() override;
66 
67 private:
68  void buildKernelConvolver(const edm::ParameterSet&);
69  void mixExtraGrid();
70  void loadFlatteningFactors(const edm::EventSetup& iSetup);
71 
72  // The FFT engine
73  std::unique_ptr<MyFFTEngine> engine;
74 
75  // The pattern recognition kernel(s)
76  std::unique_ptr<fftjet::AbsFrequencyKernel> kernel2d;
77 
78  // The kernel convolver
79  std::unique_ptr<fftjet::AbsConvolverBase<Real>> convolver;
80 
81  // Storage for convolved energy flow
82  std::unique_ptr<fftjet::Grid2d<fftjetcms::Real>> convolvedFlow;
83 
84  // Filtering scales
85  std::unique_ptr<fftjet::EquidistantInLogSpace> filterScales;
86 
87  // Eta-dependent factors to use for flattening the distribution
88  // _after_ the filtering
89  std::vector<double> etaFlatteningFactors;
90 
91  // Number of percentile points to use
92  unsigned nPercentiles;
93 
94  // Bin range. Both values of 0 means use the whole range.
95  unsigned convolverMinBin;
96  unsigned convolverMaxBin;
97 
98  // Density conversion factor
100 
101  // Variable related to mixing additional grids
102  std::vector<std::string> externalGridFiles;
103  std::ifstream gridStream;
105  unsigned currentFileNum;
106 
107  // Some memory to hold the percentiles found
108  std::vector<double> percentileData;
109 
110  // Variables to load the flattening factors from
111  // the calibration database (this has to be done
112  // in sync with configuring the appropriate event
113  // setup source)
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 
166  percentileData.resize(nScales * nPercentiles);
167 
168  produces<reco::DiscretizedEnergyFlow>(outputLabel);
169  produces<std::pair<double, double>>(outputLabel);
170 }
171 
173  // Get the eta and phi scales for the kernel(s)
174  double kernelEtaScale = ps.getParameter<double>("kernelEtaScale");
175  const double kernelPhiScale = ps.getParameter<double>("kernelPhiScale");
176  if (kernelEtaScale <= 0.0 || kernelPhiScale <= 0.0)
177  throw cms::Exception("FFTJetBadConfig") << "invalid kernel scales" << std::endl;
178 
181  throw cms::Exception("FFTJetBadConfig") << "invalid convolver bin range" << std::endl;
182 
183  // FFT assumes that the grid extent in eta is 2*Pi. Adjust the
184  // kernel scale in eta to compensate.
185  kernelEtaScale *= (2.0 * M_PI / (energyFlow->etaMax() - energyFlow->etaMin()));
186 
187  // Build the FFT engine
188  engine = std::make_unique<MyFFTEngine>(energyFlow->nEta(), energyFlow->nPhi());
189 
190  // 2d kernel
191  kernel2d = std::unique_ptr<fftjet::AbsFrequencyKernel>(
192  new fftjet::DiscreteGauss2d(kernelEtaScale, kernelPhiScale, energyFlow->nEta(), energyFlow->nPhi()));
193 
194  // 2d convolver
195  convolver = std::unique_ptr<fftjet::AbsConvolverBase<Real>>(new fftjet::FrequencyKernelConvolver<Real, Complex>(
196  engine.get(), kernel2d.get(), convolverMinBin, convolverMaxBin));
197 }
198 
200 
201 // ------------ method called to produce the data ------------
203  loadInputCollection(iEvent);
205 
206  // Determine the average Et density for this event.
207  // Needs to be done here, before mixing in another grid.
208  const fftjet::Grid2d<Real>& g(*energyFlow);
209  const double densityBeforeMixing = g.sum() / pileupEtaPhiArea;
210 
211  // Mix an extra grid (if requested)
212  double densityAfterMixing = -1.0;
213  if (!externalGridFiles.empty()) {
214  mixExtraGrid();
215  densityAfterMixing = g.sum() / pileupEtaPhiArea;
216  }
217 
218  // Various useful variables
219  const unsigned nScales = filterScales->size();
220  const double* scales = &(*filterScales)[0];
221  Real* convData = const_cast<Real*>(convolvedFlow->data());
222  Real* sortData = convData + convolverMinBin * convolvedFlow->nPhi();
223  const unsigned dataLen = convolverMaxBin ? (convolverMaxBin - convolverMinBin) * convolvedFlow->nPhi()
224  : convolvedFlow->nEta() * convolvedFlow->nPhi();
225 
226  // Load flattenning factors from DB (if requested)
228  loadFlatteningFactors(iSetup);
229 
230  // Go over all scales and perform the convolutions
231  convolver->setEventData(g.data(), g.nEta(), g.nPhi());
232  for (unsigned iscale = 0; iscale < nScales; ++iscale) {
233  // Perform the convolution
234  convolver->convolveWithKernel(scales[iscale], convData, convolvedFlow->nEta(), convolvedFlow->nPhi());
235 
236  // Apply the flattening factors
237  if (!etaFlatteningFactors.empty())
239 
240  // Sort the convolved data
241  std::sort(sortData, sortData + dataLen);
242 
243  // Determine the percentile points
244  for (unsigned iper = 0; iper < nPercentiles; ++iper) {
245  // Map percentile 0 into point number 0,
246  // 1 into point number dataLen-1
247  const double q = (iper + 0.5) / nPercentiles;
248  const double dindex = q * (dataLen - 1U);
249  const unsigned ilow = static_cast<unsigned>(std::floor(dindex));
250  const double percentile =
251  fftjet::lin_interpolate_1d(ilow, ilow + 1U, sortData[ilow], sortData[ilow + 1U], dindex);
252 
253  // Store the calculated percentile
254  percentileData[iscale * nPercentiles + iper] = percentile;
255  }
256  }
257 
258  // Convert percentile data into a more convenient storable object
259  // and put it into the event record
260  iEvent.put(std::make_unique<reco::DiscretizedEnergyFlow>(
261  &percentileData[0], "FFTJetPileupProcessor", -0.5, nScales - 0.5, 0.0, nScales, nPercentiles),
262  outputLabel);
263 
264  iEvent.put(std::make_unique<std::pair<double, double>>(densityBeforeMixing, densityAfterMixing), outputLabel);
265 }
266 
268  const unsigned nFiles = externalGridFiles.size();
269  if (currentFileNum > nFiles) {
270  // This is the first time this function is called
271  currentFileNum = 0;
272  gridStream.open(externalGridFiles[currentFileNum].c_str(), std::ios_base::in | std::ios_base::binary);
273  if (!gridStream.is_open())
274  throw cms::Exception("FFTJetBadConfig") << "ERROR in FFTJetPileupProcessor::mixExtraGrid():"
275  " failed to open external grid file "
276  << externalGridFiles[currentFileNum] << std::endl;
277  }
278 
279  const fftjet::Grid2d<float>* g = nullptr;
280  const unsigned maxFail = 100U;
281  unsigned nEnergyRejected = 0;
282 
283  while (!g) {
285 
286  // If we can't read the grid, we need to switch to another file
287  for (unsigned ntries = 0; ntries < nFiles && g == nullptr; ++ntries) {
288  gridStream.close();
289  currentFileNum = (currentFileNum + 1U) % nFiles;
290  gridStream.open(externalGridFiles[currentFileNum].c_str(), std::ios_base::in | std::ios_base::binary);
291  if (!gridStream.is_open())
292  throw cms::Exception("FFTJetBadConfig") << "ERROR in FFTJetPileupProcessor::mixExtraGrid():"
293  " failed to open external grid file "
294  << externalGridFiles[currentFileNum] << std::endl;
296  }
297 
298  if (g)
299  if (g->sum() > externalGridMaxEnergy) {
300  delete g;
301  g = nullptr;
302  if (++nEnergyRejected >= maxFail)
303  throw cms::Exception("FFTJetBadConfig") << "ERROR in FFTJetPileupProcessor::mixExtraGrid():"
304  " too many grids in a row ("
305  << nEnergyRejected << ") failed the maximum energy cut" << std::endl;
306  }
307  }
308 
309  if (g) {
310  add_Grid2d_data(energyFlow.get(), *g);
311  delete g;
312  } else {
313  // Too bad, no useful file found
314  throw cms::Exception("FFTJetBadConfig") << "ERROR in FFTJetPileupProcessor::mixExtraGrid():"
315  " no valid grid records found"
316  << std::endl;
317  }
318 }
319 
320 // ------------ method called once each job just before starting event loop
322 
323 // ------------ method called once each job just after ending the event loop
325 
329  std::shared_ptr<npstat::StorableMultivariateFunctor> f = (*h)[flatteningTableCategory][flatteningTableName];
330 
331  // Fill out the table of flattening factors as a function of eta
332  const unsigned nEta = energyFlow->nEta();
333  etaFlatteningFactors.clear();
334  etaFlatteningFactors.reserve(nEta);
335  for (unsigned ieta = 0; ieta < nEta; ++ieta) {
336  const double eta = energyFlow->etaBinCenter(ieta);
337  etaFlatteningFactors.push_back((*f)(&eta, 1U));
338  }
339 }
340 
341 //define this as a plug-in
std::unique_ptr< fftjet::AbsConvolverBase< Real > > convolver
std::vector< std::string > externalGridFiles
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:133
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
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)
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
void beginJob()
Definition: Breakpoints.cc:14
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
tuple nFiles
Definition: cmsBatch.py:308
std::unique_ptr< fftjet::EquidistantInLogSpace > filterScales
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
T getParameter(std::string const &) const
Definition: ParameterSet.h:303
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
static const Mapper & instance()
void add_Grid2d_data(fftjet::Grid2d< F2 > *to, const fftjet::Grid2d< F1 > &from)
tuple size
Write out results.
const std::string outputLabel
std::unique_ptr< fftjet::AbsFrequencyKernel > kernel2d