CMS 3D CMS Logo

PFClusterEMEnergyCorrector.cc
Go to the documentation of this file.
2 
3 #include "vdt/vdtMath.h"
4 #include <array>
5 
6 namespace {
8  bool sortByKey(const EEPSPair& a, const EEPSPair& b) {
9  return a.first < b.first;
10  }
11 
12  double getOffset(const double lo, const double hi) { return lo + 0.5*(hi-lo); }
13  double getScale(const double lo, const double hi) { return 0.5*(hi-lo); }
14 }
15 
17  calibrator_(new PFEnergyCalibration) {
18 
19  applyCrackCorrections_ = conf.getParameter<bool>("applyCrackCorrections");
20  applyMVACorrections_ = conf.getParameter<bool>("applyMVACorrections");
21  srfAwareCorrection_ = conf.getParameter<bool>("srfAwareCorrection");
22  setEnergyUncertainty_ = conf.getParameter<bool>("setEnergyUncertainty");
23  maxPtForMVAEvaluation_ = conf.getParameter<double>("maxPtForMVAEvaluation");
24 
25  if (applyMVACorrections_) {
26 
27  meanlimlowEB_ = -0.336;
28  meanlimhighEB_ = 0.916;
31 
32  meanlimlowEE_ = -0.336;
33  meanlimhighEE_ = 0.916;
36 
37  sigmalimlowEB_ = 0.001;
38  sigmalimhighEB_ = 0.4;
41 
42  sigmalimlowEE_ = 0.001;
43  sigmalimhighEE_ = 0.4;
46 
47  recHitsEB_ = cc.consumes<EcalRecHitCollection>(conf.getParameter<edm::InputTag>("recHitsEBLabel"));
48  recHitsEE_ = cc.consumes<EcalRecHitCollection>(conf.getParameter<edm::InputTag>("recHitsEELabel"));
49  autoDetectBunchSpacing_ = conf.getParameter<bool>("autoDetectBunchSpacing");
50 
52  bunchSpacing_ = cc.consumes<unsigned int>(edm::InputTag("bunchSpacingProducer"));
54  } else {
55  bunchSpacingManual_ = conf.getParameter<int>("bunchSpacing");
56  }
57 
59  "ecalPFClusterCorV2_EB_pfSize1_mean_25ns",
60  "ecalPFClusterCorV2_EB_pfSize2_mean_25ns",
61  "ecalPFClusterCorV2_EB_pfSize3_ptbin1_mean_25ns",
62  "ecalPFClusterCorV2_EB_pfSize3_ptbin2_mean_25ns",
63  "ecalPFClusterCorV2_EB_pfSize3_ptbin3_mean_25ns",
64  "ecalPFClusterCorV2_EE_pfSize1_mean_25ns",
65  "ecalPFClusterCorV2_EE_pfSize2_mean_25ns",
66  "ecalPFClusterCorV2_EE_pfSize3_ptbin1_mean_25ns",
67  "ecalPFClusterCorV2_EE_pfSize3_ptbin2_mean_25ns",
68  "ecalPFClusterCorV2_EE_pfSize3_ptbin3_mean_25ns"});
70  "ecalPFClusterCorV2_EB_pfSize1_sigma_25ns",
71  "ecalPFClusterCorV2_EB_pfSize2_sigma_25ns",
72  "ecalPFClusterCorV2_EB_pfSize3_ptbin1_sigma_25ns",
73  "ecalPFClusterCorV2_EB_pfSize3_ptbin2_sigma_25ns",
74  "ecalPFClusterCorV2_EB_pfSize3_ptbin3_sigma_25ns",
75  "ecalPFClusterCorV2_EE_pfSize1_sigma_25ns",
76  "ecalPFClusterCorV2_EE_pfSize2_sigma_25ns",
77  "ecalPFClusterCorV2_EE_pfSize3_ptbin1_sigma_25ns",
78  "ecalPFClusterCorV2_EE_pfSize3_ptbin2_sigma_25ns",
79  "ecalPFClusterCorV2_EE_pfSize3_ptbin3_sigma_25ns"});
81  "ecalPFClusterCorV2_EB_pfSize1_mean_50ns",
82  "ecalPFClusterCorV2_EB_pfSize2_mean_50ns",
83  "ecalPFClusterCorV2_EB_pfSize3_ptbin1_mean_50ns",
84  "ecalPFClusterCorV2_EB_pfSize3_ptbin2_mean_50ns",
85  "ecalPFClusterCorV2_EB_pfSize3_ptbin3_mean_50ns",
86  "ecalPFClusterCorV2_EE_pfSize1_mean_50ns",
87  "ecalPFClusterCorV2_EE_pfSize2_mean_50ns",
88  "ecalPFClusterCorV2_EE_pfSize3_ptbin1_mean_50ns",
89  "ecalPFClusterCorV2_EE_pfSize3_ptbin2_mean_50ns",
90  "ecalPFClusterCorV2_EE_pfSize3_ptbin3_mean_50ns"});
92  "ecalPFClusterCorV2_EB_pfSize1_sigma_50ns",
93  "ecalPFClusterCorV2_EB_pfSize2_sigma_50ns",
94  "ecalPFClusterCorV2_EB_pfSize3_ptbin1_sigma_50ns",
95  "ecalPFClusterCorV2_EB_pfSize3_ptbin2_sigma_50ns",
96  "ecalPFClusterCorV2_EB_pfSize3_ptbin3_sigma_50ns",
97  "ecalPFClusterCorV2_EE_pfSize1_sigma_50ns",
98  "ecalPFClusterCorV2_EE_pfSize2_sigma_50ns",
99  "ecalPFClusterCorV2_EE_pfSize3_ptbin1_sigma_50ns",
100  "ecalPFClusterCorV2_EE_pfSize3_ptbin2_sigma_50ns",
101  "ecalPFClusterCorV2_EE_pfSize3_ptbin3_sigma_50ns"});
102 
103  if (srfAwareCorrection_) {
104 
105  sigmalimlowEE_ = 0.001;
106  sigmalimhighEE_ = 0.1;
109 
110  ebSrFlagToken_ = cc.consumes<EBSrFlagCollection>(conf.getParameter<edm::InputTag>("ebSrFlagLabel"));
111  eeSrFlagToken_ = cc.consumes<EESrFlagCollection>(conf.getParameter<edm::InputTag>("eeSrFlagLabel"));
112 
113  condnames_mean_.insert(condnames_mean_.end(), {
114  "ecalPFClusterCor2017V2_EB_ZS_mean_25ns",
115  "ecalPFClusterCor2017V2_EB_Full_ptbin1_mean_25ns",
116  "ecalPFClusterCor2017V2_EB_Full_ptbin2_mean_25ns",
117  "ecalPFClusterCor2017V2_EB_Full_ptbin3_mean_25ns",
118  "ecalPFClusterCor2017V2_EE_ZS_mean_25ns",
119  "ecalPFClusterCor2017V2_EE_Full_ptbin1_mean_25ns",
120  "ecalPFClusterCor2017V2_EE_Full_ptbin2_mean_25ns",
121  "ecalPFClusterCor2017V2_EE_Full_ptbin3_mean_25ns"});
122 
123  condnames_sigma_.insert(condnames_sigma_.end(), {
124  "ecalPFClusterCor2017V2_EB_ZS_sigma_25ns",
125  "ecalPFClusterCor2017V2_EB_Full_ptbin1_sigma_25ns",
126  "ecalPFClusterCor2017V2_EB_Full_ptbin2_sigma_25ns",
127  "ecalPFClusterCor2017V2_EB_Full_ptbin3_sigma_25ns",
128  "ecalPFClusterCor2017V2_EE_ZS_sigma_25ns",
129  "ecalPFClusterCor2017V2_EE_Full_ptbin1_sigma_25ns",
130  "ecalPFClusterCor2017V2_EE_Full_ptbin2_sigma_25ns",
131  "ecalPFClusterCor2017V2_EE_Full_ptbin3_sigma_25ns"});
132  }
133  }
134 
135 }
136 
138  const edm::EventSetup &es,
141 
142  // First deal with pre-MVA corrections
143  // Kept for backward compatibility (and for HLT)
144  if (!applyMVACorrections_) {
145  for (unsigned int idx = 0; idx<cs.size(); ++idx) {
146  reco::PFCluster &cluster = cs[idx];
147  bool iseb = cluster.layer() == PFLayer::ECAL_BARREL;
148  float ePS1=0., ePS2=0.;
149  if(!iseb)
150  getAssociatedPSEnergy(idx, assoc, ePS1, ePS2);
151  double correctedEnergy = calibrator_->energyEm(cluster,ePS1,ePS2,applyCrackCorrections_);
152  cluster.setCorrectedEnergy(correctedEnergy);
153  }
154  return;
155  }
156 
157  // Common objects for SRF-aware and old style corrections
158  EcalClusterLazyTools lazyTool(evt, es, recHitsEB_, recHitsEE_);
159  EcalReadoutTools readoutTool(evt, es);
160 
161  if (!srfAwareCorrection_) {
162 
163  int bunchspacing = 450;
165  edm::Handle<unsigned int> bunchSpacingH;
166  evt.getByToken(bunchSpacing_,bunchSpacingH);
167  bunchspacing = *bunchSpacingH;
168  }
169  else {
170  bunchspacing = bunchSpacingManual_;
171  }
172 
173  const std::vector<std::string>& condnames_mean = (bunchspacing == 25) ? condnames_mean_25ns_ : condnames_mean_50ns_;
174  const std::vector<std::string>& condnames_sigma = (bunchspacing == 25) ? condnames_sigma_25ns_ : condnames_sigma_50ns_;
175  const unsigned int ncor = condnames_mean.size();
176  std::vector<edm::ESHandle<GBRForestD> > forestH_mean(ncor);
177  std::vector<edm::ESHandle<GBRForestD> > forestH_sigma(ncor);
178 
179  for (unsigned int icor=0; icor<ncor; ++icor) {
180  es.get<GBRDWrapperRcd>().get(condnames_mean[icor],forestH_mean[icor]);
181  es.get<GBRDWrapperRcd>().get(condnames_sigma[icor],forestH_sigma[icor]);
182  }
183 
184  std::array<float,5> eval;
185  for (unsigned int idx = 0; idx<cs.size(); ++idx) {
186  reco::PFCluster &cluster = cs[idx];
187  bool iseb = cluster.layer() == PFLayer::ECAL_BARREL;
188  float ePS1=0., ePS2=0.;
189  if(!iseb)
190  getAssociatedPSEnergy(idx, assoc, ePS1, ePS2);
191 
192  double e = cluster.energy();
193  double pt = cluster.pt();
194  double evale = e;
196  evale *= maxPtForMVAEvaluation_/pt;
197  }
198  double invE = (e == 0.) ? 0. : 1./e; //guard against dividing by 0.
199  int size = lazyTool.n5x5(cluster);
200 
201  int ietaix=0;
202  int iphiiy=0;
203  if (iseb) {
204  EBDetId ebseed(cluster.seed());
205  ietaix = ebseed.ieta();
206  iphiiy = ebseed.iphi();
207  } else {
208  EEDetId eeseed(cluster.seed());
209  ietaix = eeseed.ix();
210  iphiiy = eeseed.iy();
211  }
212 
213  //find index of corrections (0-4 for EB, 5-9 for EE, depending on cluster size and raw pt)
214  int coridx = std::min(size,3)-1;
215  if (coridx==2) {
216  if (pt>4.5) {
217  coridx += 1;
218  }
219  if (pt>18.) {
220  coridx += 1;
221  }
222  }
223  if (!iseb) {
224  coridx += 5;
225  }
226 
227  const GBRForestD &meanforest = *forestH_mean[coridx].product();
228  const GBRForestD &sigmaforest = *forestH_sigma[coridx].product();
229 
230  //fill array for forest evaluation
231  eval[0] = evale;
232  eval[1] = ietaix;
233  eval[2] = iphiiy;
234  if (!iseb) {
235  eval[3] = ePS1*invE;
236  eval[4] = ePS2*invE;
237  }
238 
239  //these are the actual BDT responses
240  double rawmean = meanforest.GetResponse(eval.data());
241  double rawsigma = sigmaforest.GetResponse(eval.data());
242 
243  //apply transformation to limited output range (matching the training)
244  double mean = iseb ? meanoffsetEB_ + meanscaleEB_*vdt::fast_sin(rawmean) : meanoffsetEE_ + meanscaleEE_*vdt::fast_sin(rawmean);
245  double sigma = iseb ? sigmaoffsetEB_ + sigmascaleEB_*vdt::fast_sin(rawsigma) : sigmaoffsetEE_ + sigmascaleEE_*vdt::fast_sin(rawsigma);
246 
247  //regression target is ln(Etrue/Eraw)
248  //so corrected energy is ecor=exp(mean)*e, uncertainty is exp(mean)*eraw*sigma=ecor*sigma
249  double ecor = vdt::fast_exp(mean)*e;
250  double sigmacor = sigma*ecor;
251 
252  cluster.setCorrectedEnergy(ecor);
254  else cluster.setCorrectedEnergyUncertainty(0.);
255 
256  }
257  return;
258  }
259 
260  // Selective Readout Flags
263  evt.getByToken(ebSrFlagToken_, ebSrFlags);
264  evt.getByToken(eeSrFlagToken_, eeSrFlags);
265  if (!ebSrFlags.isValid() || !eeSrFlags.isValid())
266  throw cms::Exception("PFClusterEMEnergyCorrector") << "This version of PFCluster corrections requires the SrFlagCollection information to proceed!\n";
267 
268  const unsigned int ncor = condnames_mean_.size();
269 
270  std::vector<edm::ESHandle<GBRForestD> > forestH_mean(ncor);
271  std::vector<edm::ESHandle<GBRForestD> > forestH_sigma(ncor);
272 
273  for (unsigned int icor=0; icor<ncor; ++icor) {
274  es.get<GBRDWrapperRcd>().get(condnames_mean_[icor],forestH_mean[icor]);
275  es.get<GBRDWrapperRcd>().get(condnames_sigma_[icor],forestH_sigma[icor]);
276  }
277 
278  std::array<float,6> evalEB;
279  std::array<float,5> evalEE;
280 
281  for (unsigned int idx = 0; idx<cs.size(); ++idx) {
282 
283  reco::PFCluster &cluster = cs[idx];
284  bool iseb = cluster.layer() == PFLayer::ECAL_BARREL;
285  float ePS1=0., ePS2=0.;
286  if(!iseb)
287  getAssociatedPSEnergy(idx, assoc, ePS1, ePS2);
288 
289  double e = cluster.energy();
290  double pt = cluster.pt();
291  double evale = e;
293  evale *= maxPtForMVAEvaluation_/pt;
294  }
295  double invE = (e == 0.) ? 0. : 1./e; //guard against dividing by 0.
296  int size = lazyTool.n5x5(cluster);
297  int reducedHits = size;
298  if(size>=3)
299  reducedHits = 3;
300 
301  int ietaix=0;
302  int iphiiy=0;
303  if (iseb) {
304  EBDetId ebseed(cluster.seed());
305  ietaix = ebseed.ieta();
306  iphiiy = ebseed.iphi();
307  } else {
308  EEDetId eeseed(cluster.seed());
309  ietaix = eeseed.ix();
310  iphiiy = eeseed.iy();
311  }
312 
313  // Hardcoded number are positions of modules boundaries of ECAL
314  int signeta = (ietaix > 0) ? 1 : -1;
315  int ietamod20 = (std::abs(ietaix) < 26) ? ietaix - signeta : (ietaix - 26*signeta) % 20;
316  int iphimod20 = (iphiiy-1) % 20;
317 
318  int clusFlag = 0;
319  if (iseb){
320  auto ecalUnit = readoutTool.readOutUnitOf(static_cast<EBDetId>(cluster.seed()));
321  EBSrFlagCollection::const_iterator srf = ebSrFlags->find(ecalUnit);
322  if (srf != ebSrFlags->end())
323  clusFlag = srf->value();
324  else
325  clusFlag = 3;
326  } else {
327  auto ecalUnit = readoutTool.readOutUnitOf(static_cast<EEDetId>(cluster.seed()));
328  EESrFlagCollection::const_iterator srf = eeSrFlags->find(ecalUnit);
329  if (srf != eeSrFlags->end())
330  clusFlag = srf->value();
331  else
332  clusFlag = 3;
333  }
334 
335  //find index of corrections (0-3 for EB, 4-7 for EE, depending on cluster size and raw pt)
336  int coridx = 0;
337  int regind = 0;
338  if (!iseb) regind = 4;
339 
349  int ZS_bit = clusFlag>>0&1;
350  int FR_bit = clusFlag>>1&1;
351 
352 
353 
354  if (ZS_bit!=0 && FR_bit==0)
355  coridx = 0 + regind;
356  else{
357  if (pt<2.5) coridx = 1 + regind;
358  else if (pt>=2.5 && pt<6.) coridx = 2 + regind;
359  else if (pt>=6.) coridx = 3 + regind;
360  }
361  if (ZS_bit==0 || clusFlag > 7) {
362  edm::LogWarning("PFClusterEMEnergyCorrector") << "We can only correct regions readout in ZS (flag 1,5) or FULL readout (flag 3,7). Flag " << clusFlag << " is not recognized."
363  << "\n" << "Assuming FULL readout and continuing";
364  }
365 
366  const GBRForestD &meanforest = *forestH_mean[coridx].product();
367  const GBRForestD &sigmaforest = *forestH_sigma[coridx].product();
368 
369  //fill array for forest evaluation
370  if (iseb) {
371  evalEB[0] = evale;
372  evalEB[1] = ietaix;
373  evalEB[2] = iphiiy;
374  evalEB[3] = ietamod20;
375  evalEB[4] = iphimod20;
376  evalEB[5] = reducedHits;
377  } else {
378  evalEE[0] = evale;
379  evalEE[1] = ietaix;
380  evalEE[2] = iphiiy;
381  evalEE[3] = (ePS1+ePS2)*invE;
382  evalEE[4] = reducedHits;
383  }
384 
385  //these are the actual BDT responses
386  double rawmean = 1;
387  double rawsigma = 0;
388 
389  if(iseb){
390  rawmean = meanforest.GetResponse(evalEB.data());
391  rawsigma = sigmaforest.GetResponse(evalEB.data());
392  } else {
393  rawmean = meanforest.GetResponse(evalEE.data());
394  rawsigma = sigmaforest.GetResponse(evalEE.data());
395  }
396 
397  //apply transformation to limited output range (matching the training)
398  //the training was done with different transformations for EB and EE (width only)
399  //makes a the code a bit more cumbersome, but it is not a problem per se
400  double mean = iseb ? meanoffsetEB_ + meanscaleEB_*vdt::fast_sin(rawmean) : meanoffsetEE_ + meanscaleEE_*vdt::fast_sin(rawmean);
401  double sigma = iseb ? sigmaoffsetEB_ + sigmascaleEB_*vdt::fast_sin(rawsigma) : sigmaoffsetEE_ + sigmascaleEE_*vdt::fast_sin(rawsigma);
402 
403  //regression target is ln(Etrue/Eraw)
404  //so corrected energy is ecor=exp(mean)*e, uncertainty is exp(mean)*eraw*sigma=ecor*sigma
405  double ecor = iseb ? vdt::fast_exp(mean)*e : vdt::fast_exp(mean)*(e+ePS1+ePS2);
406  double sigmacor = sigma*ecor;
407 
408  LogDebug("PFClusterEMEnergyCorrector") << "ieta : iphi : ietamod20 : iphimod20 : size : reducedHits = "
409  << ietaix << " " << iphiiy << " "
410  << ietamod20 << " " << iphimod20 << " "
411  << size << " " << reducedHits
412  << "\n" << "isEB : eraw : ePS1 : ePS2 : (eps1+eps2)/raw : Flag = "
413  << iseb << " " << evale << " " << ePS1 << " " << ePS2 << " " << (ePS1+ePS2)/evale << " " << clusFlag
414  << "\n" << "response : correction = "
415  << exp(mean) << " " << ecor;
416 
417  cluster.setCorrectedEnergy(ecor);
419  else cluster.setCorrectedEnergyUncertainty(0.);
420 
421  }
422 
423 }
424 
425 void PFClusterEMEnergyCorrector::getAssociatedPSEnergy(const size_t clusIdx, const reco::PFCluster::EEtoPSAssociation &assoc, float& e1, float& e2) {
426 
427  e1 = 0;
428  e2 = 0;
429  auto ee_key_val = std::make_pair(clusIdx,edm::Ptr<reco::PFCluster>());
430  const auto clustops = std::equal_range(assoc.begin(),
431  assoc.end(),
432  ee_key_val,
433  sortByKey);
434  for( auto i_ps = clustops.first; i_ps != clustops.second; ++i_ps) {
435  edm::Ptr<reco::PFCluster> psclus(i_ps->second);
436  switch( psclus->layer() ) {
437  case PFLayer::PS1:
438  e1 += psclus->energy();
439  break;
440  case PFLayer::PS2:
441  e2 += psclus->energy();
442  break;
443  default:
444  break;
445  }
446  }
447 
448 }
449 
#define LogDebug(id)
PFLayer::Layer layer() const
cluster layer, see PFLayer.h in this directory
Definition: PFCluster.cc:120
size
Write out results.
T getParameter(std::string const &) const
double GetResponse(const float *vector) const
Definition: GBRForestD.h:51
int ix() const
Definition: EEDetId.h:77
Particle flow cluster, see clustering algorithm in PFClusterAlgo.
Definition: PFCluster.h:47
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:517
unique_ptr< ClusterSequence > cs
EcalTrigTowerDetId readOutUnitOf(const EBDetId &xtalId) const
std::vector< T >::const_iterator const_iterator
PFClusterEMEnergyCorrector(const edm::ParameterSet &conf, edm::ConsumesCollector &&cc)
double pt() const
transverse momentum, massless approximation
Definition: PFCluster.h:139
edm::EDGetTokenT< EESrFlagCollection > eeSrFlagToken_
std::unique_ptr< PFEnergyCalibration > calibrator_
edm::EDGetTokenT< unsigned int > bunchSpacing_
edm::EDGetTokenT< EcalRecHitCollection > recHitsEE_
std::vector< std::string > condnames_mean_50ns_
std::vector< std::string > condnames_sigma_25ns_
std::vector< std::string > condnames_mean_25ns_
void setCorrectedEnergy(double cenergy)
Definition: CaloCluster.h:114
std::vector< std::pair< CaloClusterPtr::key_type, edm::Ptr< PFCluster > > > EEtoPSAssociation
Definition: PFCluster.h:50
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
int ieta() const
get the crystal ieta
Definition: EBDetId.h:49
T min(T a, T b)
Definition: MathUtil.h:58
std::vector< std::string > condnames_sigma_
bool isValid() const
Definition: HandleBase.h:74
double energy() const
cluster energy
Definition: PFCluster.h:82
const_iterator end() const
DetId seed() const
return DetId of seed
Definition: CaloCluster.h:207
edm::EDGetTokenT< EcalRecHitCollection > recHitsEB_
reco::PFCluster::EEtoPSAssociation::value_type EEPSPair
bool sortByKey(const EEPSPair &a, const EEPSPair &b)
double b
Definition: hdecay.h:120
iterator find(key_type k)
double a
Definition: hdecay.h:121
T get() const
Definition: EventSetup.h:71
std::vector< PFCluster > PFClusterCollection
collection of PFCluster objects
Definition: PFClusterFwd.h:9
edm::EDGetTokenT< EBSrFlagCollection > ebSrFlagToken_
std::vector< std::string > condnames_sigma_50ns_
void correctEnergies(const edm::Event &evt, const edm::EventSetup &es, const reco::PFCluster::EEtoPSAssociation &assoc, reco::PFClusterCollection &cs)
void setCorrectedEnergyUncertainty(float energyerr)
Definition: CaloCluster.h:115
void getAssociatedPSEnergy(const size_t clusIdx, const reco::PFCluster::EEtoPSAssociation &assoc, float &e1, float &e2)
std::vector< std::string > condnames_mean_