CMS 3D CMS Logo

FFTJetPatRecoProducer.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: FFTJetProducers
4 // Class: FFTJetPatRecoProducer
5 //
13 //
14 // Original Author: Igor Volobouev
15 // Created: Tue Jun 15 12:45:45 CDT 2010
16 //
17 //
18 
19 #include <fstream>
20 #include <memory>
21 
22 // FFTJet headers
23 #include "fftjet/ProximityClusteringTree.hh"
24 #include "fftjet/ClusteringSequencer.hh"
25 #include "fftjet/ClusteringTreeSparsifier.hh"
26 #include "fftjet/FrequencyKernelConvolver.hh"
27 #include "fftjet/FrequencySequentialConvolver.hh"
28 #include "fftjet/DiscreteGauss1d.hh"
29 #include "fftjet/DiscreteGauss2d.hh"
30 
31 // framework include files
35 
43 
44 // Energy flow object
46 
47 // parameter parser header
49 
50 // functions which manipulate storable trees
52 
53 // functions which manipulate energy discretization grids
55 
56 // useful utilities collected in the second base
58 
59 using namespace fftjetcms;
60 
61 //
62 // class declaration
63 //
65 public:
67  FFTJetPatRecoProducer() = delete;
69  FFTJetPatRecoProducer& operator=(const FFTJetPatRecoProducer&) = delete;
70  ~FFTJetPatRecoProducer() override;
71 
72 protected:
73  // Useful local typedefs
74  typedef fftjet::ProximityClusteringTree<fftjet::Peak, long> ClusteringTree;
75  typedef fftjet::SparseClusteringTree<fftjet::Peak, long> SparseTree;
76  typedef fftjet::ClusteringSequencer<Real> Sequencer;
77  typedef fftjet::ClusteringTreeSparsifier<fftjet::Peak, long> Sparsifier;
78 
79  // methods
80  void produce(edm::Event&, const edm::EventSetup&) override;
81 
82  void buildKernelConvolver(const edm::ParameterSet&);
83  fftjet::PeakFinder buildPeakFinder(const edm::ParameterSet&);
84 
85  template <class Real>
86  void buildSparseProduct(edm::Event&) const;
87 
88  template <class Real>
89  void buildDenseProduct(edm::Event&) const;
90 
91  // The complete clustering tree
93 
94  // Basically, we need to create FFTJet objects
95  // ClusteringSequencer and ClusteringTreeSparsifier
96  // which will subsequently perform most of the work
97  std::unique_ptr<Sequencer> sequencer;
98  std::unique_ptr<Sparsifier> sparsifier;
99 
100  // The FFT engine(s)
101  std::unique_ptr<MyFFTEngine> engine;
102  std::unique_ptr<MyFFTEngine> anotherEngine;
103 
104  // The pattern recognition kernel(s)
105  std::unique_ptr<fftjet::AbsFrequencyKernel> kernel2d;
106  std::unique_ptr<fftjet::AbsFrequencyKernel1d> etaKernel;
107  std::unique_ptr<fftjet::AbsFrequencyKernel1d> phiKernel;
108 
109  // The kernel convolver
110  std::unique_ptr<fftjet::AbsConvolverBase<Real> > convolver;
111 
112  // The peak selector for the clustering tree
113  std::unique_ptr<fftjet::Functor1<bool, fftjet::Peak> > peakSelector;
114 
115  // Distance calculator for the clustering tree
116  std::unique_ptr<fftjet::AbsDistanceCalculator<fftjet::Peak> > distanceCalc;
117 
118  // The sparse clustering tree
120 
121  // The following parameters will define the behavior
122  // of the algorithm wrt insertion of the complete event
123  // into the clustering tree
125 
126  // Are we going to make clustering trees?
127  const bool makeClusteringTree;
128 
129  // Are we going to verify the data conversion for double precision
130  // storage?
132 
133  // Are we going to store the discretization grid?
135 
136  // Sparsify the clustering tree?
137  const bool sparsify;
138 
139 private:
140  // Members needed for storing grids externally
141  std::ofstream externalGridStream;
143  fftjet::Grid2d<float>* extGrid;
144 };
145 
146 //
147 // constructors and destructor
148 //
150  : FFTJetInterface(ps),
151  clusteringTree(nullptr),
152  completeEventDataCutoff(ps.getParameter<double>("completeEventDataCutoff")),
153  makeClusteringTree(ps.getParameter<bool>("makeClusteringTree")),
154  verifyDataConversion(ps.getUntrackedParameter<bool>("verifyDataConversion", false)),
155  storeDiscretizationGrid(ps.getParameter<bool>("storeDiscretizationGrid")),
156  sparsify(ps.getParameter<bool>("sparsify")),
157  extGrid(nullptr) {
158  // register your products
159  if (makeClusteringTree) {
161  produces<reco::PattRecoTree<float, reco::PattRecoPeak<float> > >(outputLabel);
162  else
163  produces<reco::PattRecoTree<double, reco::PattRecoPeak<double> > >(outputLabel);
164  }
166  produces<reco::DiscretizedEnergyFlow>(outputLabel);
167 
168  // Check if we want to write the grids into an external file
169  const std::string externalGridFile(ps.getParameter<std::string>("externalGridFile"));
171  if (storeGridsExternally) {
172  externalGridStream.open(externalGridFile.c_str(), std::ios_base::out | std::ios_base::binary);
173  if (!externalGridStream.is_open())
174  throw cms::Exception("FFTJetBadConfig")
175  << "FFTJetPatRecoProducer failed to open file " << externalGridFile << std::endl;
176  }
177 
179  throw cms::Exception("FFTJetBadConfig")
180  << "FFTJetPatRecoProducer is not configured to produce anything" << std::endl;
181  }
182 
183  // now do whatever other initialization is needed
184 
185  // Build the discretization grid
187  checkConfig(energyFlow, "invalid discretization grid");
188 
189  // Build the FFT engine(s), pattern recognition kernel(s),
190  // and the kernel convolver
192 
193  // Build the peak selector
194  peakSelector = fftjet_PeakSelector_parser(ps.getParameter<edm::ParameterSet>("PeakSelectorConfiguration"));
195  checkConfig(peakSelector, "invalid peak selector");
196 
197  // Build the initial set of pattern recognition scales
198  std::unique_ptr<std::vector<double> > iniScales =
200  checkConfig(iniScales, "invalid set of scales");
201 
202  // Do we want to use the adaptive clustering tree algorithm?
203  const unsigned maxAdaptiveScales = ps.getParameter<unsigned>("maxAdaptiveScales");
204  const double minAdaptiveRatioLog = ps.getParameter<double>("minAdaptiveRatioLog");
205  if (minAdaptiveRatioLog <= 0.0)
206  throw cms::Exception("FFTJetBadConfig") << "bad adaptive ratio logarithm limit" << std::endl;
207 
208  // Make sure that all standard scales are larger than the
209  // complete event scale
210  if (getEventScale() > 0.0) {
211  const double cs = getEventScale();
212  const unsigned nscales = iniScales->size();
213  for (unsigned i = 0; i < nscales; ++i)
214  if (cs >= (*iniScales)[i])
215  throw cms::Exception("FFTJetBadConfig") << "incompatible scale for complete event" << std::endl;
216  }
217 
218  // At this point we are ready to build the clustering sequencer
219  sequencer = std::make_unique<Sequencer>(
221 
222  // Build the clustering tree sparsifier
223  const edm::ParameterSet& SparsifierConfiguration(ps.getParameter<edm::ParameterSet>("SparsifierConfiguration"));
225  checkConfig(sparsifier, "invalid sparsifier parameters");
226 
227  // Build the distance calculator for the clustering tree
228  const edm::ParameterSet& TreeDistanceCalculator(ps.getParameter<edm::ParameterSet>("TreeDistanceCalculator"));
230  checkConfig(distanceCalc, "invalid tree distance calculator");
231 
232  // Build the clustering tree itself
234 }
235 
237  // Check the parameter named "etaDependentScaleFactors". If the vector
238  // of scales is empty we will use 2d kernel, otherwise use 1d kernels
239  const std::vector<double> etaDependentScaleFactors(ps.getParameter<std::vector<double> >("etaDependentScaleFactors"));
240 
241  // Make sure that the number of scale factors provided is correct
242  const bool use2dKernel = etaDependentScaleFactors.empty();
243  if (!use2dKernel)
244  if (etaDependentScaleFactors.size() != energyFlow->nEta())
245  throw cms::Exception("FFTJetBadConfig") << "invalid number of eta-dependent scale factors" << std::endl;
246 
247  // Get the eta and phi scales for the kernel(s)
248  double kernelEtaScale = ps.getParameter<double>("kernelEtaScale");
249  const double kernelPhiScale = ps.getParameter<double>("kernelPhiScale");
250  if (kernelEtaScale <= 0.0 || kernelPhiScale <= 0.0)
251  throw cms::Exception("FFTJetBadConfig") << "invalid kernel scale" << std::endl;
252 
253  // FFT assumes that the grid extent in eta is 2*Pi. Adjust the
254  // kernel scale in eta to compensate.
255  kernelEtaScale *= (2.0 * M_PI / (energyFlow->etaMax() - energyFlow->etaMin()));
256 
257  // Are we going to try to fix the efficiency near detector edges?
258  const bool fixEfficiency = ps.getParameter<bool>("fixEfficiency");
259 
260  // Minimum and maximum eta bin for the convolver
261  unsigned convolverMinBin = 0, convolverMaxBin = 0;
262  if (fixEfficiency || !use2dKernel) {
263  convolverMinBin = ps.getParameter<unsigned>("convolverMinBin");
264  convolverMaxBin = ps.getParameter<unsigned>("convolverMaxBin");
265  }
266 
267  if (use2dKernel) {
268  // Build the FFT engine
269  engine = std::make_unique<MyFFTEngine>(energyFlow->nEta(), energyFlow->nPhi());
270 
271  // 2d kernel
272  kernel2d = std::unique_ptr<fftjet::AbsFrequencyKernel>(
273  new fftjet::DiscreteGauss2d(kernelEtaScale, kernelPhiScale, energyFlow->nEta(), energyFlow->nPhi()));
274 
275  // 2d convolver
276  convolver = std::unique_ptr<fftjet::AbsConvolverBase<Real> >(new fftjet::FrequencyKernelConvolver<Real, Complex>(
278  } else {
279  // Need separate FFT engines for eta and phi
280  engine = std::make_unique<MyFFTEngine>(1, energyFlow->nEta());
281  anotherEngine = std::make_unique<MyFFTEngine>(1, energyFlow->nPhi());
282 
283  // 1d kernels
284  etaKernel =
285  std::unique_ptr<fftjet::AbsFrequencyKernel1d>(new fftjet::DiscreteGauss1d(kernelEtaScale, energyFlow->nEta()));
286 
287  phiKernel =
288  std::unique_ptr<fftjet::AbsFrequencyKernel1d>(new fftjet::DiscreteGauss1d(kernelPhiScale, energyFlow->nPhi()));
289 
290  // Sequential convolver
291  convolver = std::unique_ptr<fftjet::AbsConvolverBase<Real> >(
292  new fftjet::FrequencySequentialConvolver<Real, Complex>(engine.get(),
293  anotherEngine.get(),
294  etaKernel.get(),
295  phiKernel.get(),
299  fixEfficiency));
300  }
301 }
302 
304  const double peakFinderMaxEta = ps.getParameter<double>("peakFinderMaxEta");
305  if (peakFinderMaxEta <= 0.0)
306  throw cms::Exception("FFTJetBadConfig") << "invalid peak finder eta cut" << std::endl;
307  const double maxMagnitude = ps.getParameter<double>("peakFinderMaxMagnitude");
308  int minBin = energyFlow->getEtaBin(-peakFinderMaxEta);
309  if (minBin < 0)
310  minBin = 0;
311  int maxBin = energyFlow->getEtaBin(peakFinderMaxEta) + 1;
312  if (maxBin < 0)
313  maxBin = 0;
314  return fftjet::PeakFinder(maxMagnitude, true, minBin, maxBin);
315 }
316 
318  // do anything here that needs to be done at desctruction time
319  // (e.g. close files, deallocate resources etc.)
321  externalGridStream.close();
322  delete clusteringTree;
323  delete extGrid;
324 }
325 
326 //
327 // member functions
328 //
329 template <class Real>
332 
333  auto tree = std::make_unique<StoredTree>();
334 
335  sparsePeakTreeToStorable(sparseTree, sequencer->maxAdaptiveScales(), tree.get());
336 
337  // Check that we can restore the tree
340  const std::vector<double>& scalesUsed(sequencer->getInitialScales());
342  if (sparseTree != check)
343  throw cms::Exception("FFTJetInterface") << "Data conversion failed for sparse clustering tree" << std::endl;
344  }
345 
346  ev.put(std::move(tree), outputLabel);
347 }
348 
349 template <class Real>
352 
353  auto tree = std::make_unique<StoredTree>();
354 
355  densePeakTreeToStorable(*clusteringTree, sequencer->maxAdaptiveScales(), tree.get());
356 
357  // Check that we can restore the tree
360  const std::vector<double>& scalesUsed(sequencer->getInitialScales());
362  if (*clusteringTree != check)
363  throw cms::Exception("FFTJetInterface") << "Data conversion failed for dense clustering tree" << std::endl;
364  }
365 
366  ev.put(std::move(tree), outputLabel);
367 }
368 
369 // ------------ method called to produce the data ------------
373 
374  if (makeClusteringTree) {
376  if (getEventScale() > 0.0)
378 
379  if (sparsify) {
380  sparsifier->sparsify(*clusteringTree, &sparseTree);
381 
382  // Do not call the "sortNodes" method of the sparse tree here.
383  // Currently, the nodes are sorted by daughter number.
384  // This is the way we want it in storage because the stored
385  // tree does not include daughter ordering info explicitly.
386 
388  buildSparseProduct<float>(iEvent);
389  else
390  buildSparseProduct<double>(iEvent);
391  } else {
393  buildDenseProduct<float>(iEvent);
394  else
395  buildDenseProduct<double>(iEvent);
396  }
397  }
398 
400  const fftjet::Grid2d<Real>& g(*energyFlow);
401 
402  auto flow = std::make_unique<reco::DiscretizedEnergyFlow>(
403  g.data(), g.title(), g.etaMin(), g.etaMax(), g.phiBin0Edge(), g.nEta(), g.nPhi());
404 
405  if (verifyDataConversion) {
406  fftjet::Grid2d<Real> check(
407  flow->nEtaBins(), flow->etaMin(), flow->etaMax(), flow->nPhiBins(), flow->phiBin0Edge(), flow->title());
408  check.blockSet(flow->data(), flow->nEtaBins(), flow->nPhiBins());
409  assert(g == check);
410  }
411 
413  }
414 
415  if (storeGridsExternally) {
416  if (extGrid)
418  else
420  if (!extGrid->write(externalGridStream)) {
421  throw cms::Exception("FFTJetPatRecoProducer::produce")
422  << "Failed to write grid data into an external file" << std::endl;
423  }
424  }
425 }
426 
427 //define this as a plug-in
fftjet::Grid2d< float > * convert_Grid2d_to_float(const fftjet::Grid2d< Numeric > &grid)
std::unique_ptr< Sparsifier > sparsifier
T getParameter(std::string const &) const
Definition: ParameterSet.h:307
std::unique_ptr< fftjet::AbsFrequencyKernel1d > etaKernel
Class for storing FFTJet sparse clustering trees.
Definition: PattRecoTree.h:20
constexpr unsigned int minBin
void loadInputCollection(const edm::Event &)
void buildKernelConvolver(const edm::ParameterSet &)
void checkConfig(const Ptr &ptr, const char *message)
std::unique_ptr< fftjet::Grid2d< Real > > fftjet_Grid2d_parser(const edm::ParameterSet &ps)
constexpr unsigned int maxBin
fftjet::SparseClusteringTree< fftjet::Peak, long > SparseTree
std::unique_ptr< fftjet::AbsDistanceCalculator< fftjet::Peak > > distanceCalc
assert(be >=bs)
fftjet::ClusteringTreeSparsifier< fftjet::Peak, long > Sparsifier
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
std::unique_ptr< fftjet::AbsFrequencyKernel1d > phiKernel
FFTJetPatRecoProducer()=delete
std::unique_ptr< Sequencer > sequencer
std::unique_ptr< fftjet::Functor1< bool, fftjet::Peak > > peakSelector
int iEvent
Definition: GenABIO.cc:224
void produce(edm::Event &, const edm::EventSetup &) override
std::unique_ptr< fftjet::Grid2d< fftjetcms::Real > > energyFlow
void sparsePeakTreeToStorable(const fftjet::SparseClusteringTree< fftjet::Peak, long > &in, bool writeOutScaleInfo, reco::PattRecoTree< Real, reco::PattRecoPeak< Real > > *out)
std::unique_ptr< MyFFTEngine > anotherEngine
ClusteringTree * clusteringTree
fftjet::ClusteringSequencer< Real > Sequencer
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
std::unique_ptr< fftjet::AbsDistanceCalculator< fftjet::Peak > > fftjet_DistanceCalculator_parser(const edm::ParameterSet &ps)
void buildSparseProduct(edm::Event &) const
#define M_PI
void densePeakTreeToStorable(const fftjet::AbsClusteringTree< fftjet::Peak, long > &in, bool writeOutScaleInfo, reco::PattRecoTree< Real, reco::PattRecoPeak< Real > > *out)
void sparsePeakTreeFromStorable(const reco::PattRecoTree< Real, reco::PattRecoPeak< Real > > &in, const std::vector< double > *scaleSetIfNotAdaptive, double completeEventScale, fftjet::SparseClusteringTree< fftjet::Peak, long > *out)
void densePeakTreeFromStorable(const reco::PattRecoTree< Real, reco::PattRecoPeak< Real > > &in, const std::vector< double > *scaleSetIfNotAdaptive, double completeEventScale, fftjet::AbsClusteringTree< fftjet::Peak, long > *out)
std::unique_ptr< fftjet::AbsConvolverBase< Real > > convolver
void buildDenseProduct(edm::Event &) const
void copy_Grid2d_data(fftjet::Grid2d< F2 > *to, const fftjet::Grid2d< F1 > &from)
std::unique_ptr< fftjet::AbsFrequencyKernel > kernel2d
fftjet::PeakFinder buildPeakFinder(const edm::ParameterSet &)
std::unique_ptr< fftjet::Functor1< bool, fftjet::Peak > > fftjet_PeakSelector_parser(const edm::ParameterSet &ps)
Definition: tree.py:1
std::unique_ptr< fftjet::ClusteringTreeSparsifier< fftjet::Peak, long > > fftjet_ClusteringTreeSparsifier_parser(const edm::ParameterSet &ps)
fftjet::ProximityClusteringTree< fftjet::Peak, long > ClusteringTree
fftjet::Grid2d< float > * extGrid
std::unique_ptr< std::vector< double > > fftjet_ScaleSet_parser(const edm::ParameterSet &ps)
const std::string outputLabel
def move(src, dest)
Definition: eostools.py:511
std::unique_ptr< MyFFTEngine > engine