CMS 3D CMS Logo

EGRegressionModifierV3.cc
Go to the documentation of this file.
2 
7 
13 
19 
20 #include <vdt/vdtMath.h>
21 
23 public:
24  struct EleRegs {
25  EleRegs(const edm::ParameterSet& iConfig);
26  void setEventContent(const edm::EventSetup& iSetup);
30  };
31 
32  struct PhoRegs {
33  PhoRegs(const edm::ParameterSet& iConfig);
34  void setEventContent(const edm::EventSetup& iSetup);
37  };
38 
40  ~EGRegressionModifierV3() override;
41 
42  void setEvent(const edm::Event&) final;
43  void setEventContent(const edm::EventSetup&) final;
44 
45  void modifyObject(reco::GsfElectron&) const final;
46  void modifyObject(reco::Photon&) const final;
47 
48  // just calls reco versions
49  void modifyObject(pat::Electron&) const final;
50  void modifyObject(pat::Photon&) const final;
51 
52 private:
53  std::array<float, 32> getRegData(const reco::GsfElectron& ele) const;
54  std::array<float, 32> getRegData(const reco::Photon& pho) const;
55  void getSeedCrysCoord(const reco::CaloCluster& clus, int& iEtaOrX, int& iPhiOrY) const;
56 
57  std::unique_ptr<EleRegs> eleRegs_;
58  std::unique_ptr<PhoRegs> phoRegs_;
59 
60  float rhoValue_;
61  edm::EDGetTokenT<double> rhoToken_;
62 
67 };
68 
70 
71 EGRegressionModifierV3::EGRegressionModifierV3(const edm::ParameterSet& conf, edm::ConsumesCollector& cc)
72  : ModifyObjectValueBase(conf),
73  rhoValue_(0.),
74  rhoToken_(cc.consumes<double>(conf.getParameter<edm::InputTag>("rhoTag"))),
75  useClosestToCentreSeedCrysDef_(conf.getParameter<bool>("useClosestToCentreSeedCrysDef")),
76  maxRawEnergyForLowPtEBSigma_(conf.getParameter<double>("maxRawEnergyForLowPtEBSigma")),
77  maxRawEnergyForLowPtEESigma_(conf.getParameter<double>("maxRawEnergyForLowPtEESigma")) {
78  if (conf.exists("eleRegs")) {
79  eleRegs_ = std::make_unique<EleRegs>(conf.getParameter<edm::ParameterSet>("eleRegs"));
80  }
81  if (conf.exists("phoRegs")) {
82  phoRegs_ = std::make_unique<PhoRegs>(conf.getParameter<edm::ParameterSet>("phoRegs"));
83  }
84 }
85 
87 
89  edm::Handle<double> rhoHandle;
90  evt.getByToken(rhoToken_, rhoHandle);
91  rhoValue_ = *rhoHandle;
92 }
93 
95  if (eleRegs_)
96  eleRegs_->setEventContent(iSetup);
97  if (phoRegs_)
98  phoRegs_->setEventContent(iSetup);
100  iSetup.get<CaloGeometryRecord>().get(caloGeomHandle_);
101 }
102 
104  //check if we have specified an electron regression correction and
105  //return the object unmodified if so
106  if (!eleRegs_)
107  return;
108 
109  const reco::SuperClusterRef& superClus = ele.superCluster();
110 
111  // skip HGCAL for now
112  if (superClus->seed()->seed().det() == DetId::Forward)
113  return;
114 
115  // do not apply corrections in case of missing info (slimmed MiniAOD electrons)
116  if (!superClus->clusters().isAvailable())
117  return;
118 
119  //check if fbrem is filled as its needed for E/p combination so abort if its set to the default value
120  //this will be the case for <5 (or current cuts) for miniAOD electrons
122  return;
123 
124  auto regData = getRegData(ele);
125  const float rawEnergy = superClus->rawEnergy();
126  const float rawESEnergy = superClus->preshowerEnergy();
127  //bug here, it should include the ES, kept for backwards compat
128  const float rawEt = rawEnergy * superClus->position().rho() / superClus->position().r();
129  const bool isSaturated = ele.nSaturatedXtals() != 0;
130 
131  const float ecalMean = eleRegs_->ecalOnlyMean(rawEt, ele.isEB(), isSaturated, regData.data());
132  const float ecalMeanCorr = ecalMean > 0. ? ecalMean : 1.0;
133  //as the sample is trained flat in pt, the regression's only source of very high energy
134  //electrons is in the high endcap and therefore it gives a very poor resolution estimate
135  //to any electrons with this energy, regardless of their actual eta
136  //hence this lovely hack
137  if (ele.isEB() && maxRawEnergyForLowPtEBSigma_ >= 0 && eleRegs_->ecalOnlySigma.useLowEtBin(rawEt, isSaturated)) {
138  regData[0] = std::min(regData[0], maxRawEnergyForLowPtEBSigma_);
139  }
140  if (!ele.isEB() && maxRawEnergyForLowPtEESigma_ >= 0 && eleRegs_->ecalOnlySigma.useLowEtBin(rawEt, isSaturated)) {
141  regData[0] = std::min(regData[0], maxRawEnergyForLowPtEESigma_);
142  }
143  const float ecalSigma = eleRegs_->ecalOnlySigma(rawEt, ele.isEB(), isSaturated, regData.data());
144 
145  const float corrEnergy = (rawEnergy + rawESEnergy) * ecalMeanCorr;
146  const float corrEnergyErr = corrEnergy * ecalSigma;
147 
148  ele.setCorrectedEcalEnergy(corrEnergy);
149  ele.setCorrectedEcalEnergyError(corrEnergyErr);
150 
151  std::pair<float, float> combEnergyAndErr = eleRegs_->epComb.combine(ele);
152  const math::XYZTLorentzVector newP4 = ele.p4() * combEnergyAndErr.first / ele.p4().t();
153  ele.correctMomentum(newP4, ele.trackMomentumError(), combEnergyAndErr.second);
154 }
155 
157  modifyObject(static_cast<reco::GsfElectron&>(ele));
158 }
159 
161  //check if we have specified an photon regression correction and
162  //return the object unmodified if so
163  if (!phoRegs_)
164  return;
165 
166  const reco::SuperClusterRef& superClus = pho.superCluster();
167 
168  // skip HGCAL for now
169  if (superClus->seed()->seed().det() == DetId::Forward)
170  return;
171 
172  // do not apply corrections in case of missing info (happens for some slimmed MiniAOD photons)
173  if (!superClus->clusters().isAvailable())
174  return;
175 
176  auto regData = getRegData(pho);
177 
178  const float rawEnergy = superClus->rawEnergy();
179  const float rawESEnergy = superClus->preshowerEnergy();
180  //bug here, it should include the ES, kept for backwards compat
181  const float rawEt = rawEnergy * superClus->position().rho() / superClus->position().r();
182  const bool isSaturated = pho.nSaturatedXtals();
183  const float ecalMean = phoRegs_->ecalOnlyMean(rawEt, pho.isEB(), isSaturated, regData.data());
184  const float ecalMeanCorr = ecalMean > 0. ? ecalMean : 1.0;
185 
186  //see the electrons for explaination of this lovely feature
187  if (pho.isEB() && maxRawEnergyForLowPtEBSigma_ >= 0 && phoRegs_->ecalOnlySigma.useLowEtBin(rawEt, isSaturated)) {
188  regData[0] = std::min(regData[0], maxRawEnergyForLowPtEBSigma_);
189  }
190  if (!pho.isEB() && maxRawEnergyForLowPtEESigma_ >= 0 && phoRegs_->ecalOnlySigma.useLowEtBin(rawEt, isSaturated)) {
191  regData[0] = std::min(regData[0], maxRawEnergyForLowPtEESigma_);
192  }
193  const float ecalSigma = phoRegs_->ecalOnlySigma(rawEt, pho.isEB(), isSaturated, regData.data());
194 
195  const double corrEnergy = (rawEnergy + rawESEnergy) * ecalMeanCorr;
196  const double corrEnergyErr = corrEnergy * ecalSigma;
197 
198  pho.setCorrectedEnergy(reco::Photon::P4type::regression2, corrEnergy, corrEnergyErr, true);
199 }
200 
201 void EGRegressionModifierV3::modifyObject(pat::Photon& pho) const { modifyObject(static_cast<reco::Photon&>(pho)); }
202 
203 std::array<float, 32> EGRegressionModifierV3::getRegData(const reco::GsfElectron& ele) const {
204  std::array<float, 32> data;
205 
206  const reco::SuperClusterRef& superClus = ele.superCluster();
207  const edm::Ptr<reco::CaloCluster>& seedClus = superClus->seed();
208 
209  const bool isEB = ele.isEB();
210  const double rawEnergy = superClus->rawEnergy();
211  const double rawESEnergy = superClus->preshowerEnergy();
212  const int numberOfClusters = superClus->clusters().size();
213  const auto& ssFull5x5 = ele.full5x5_showerShape();
214 
215  float e5x5Inverse = ssFull5x5.e5x5 != 0. ? vdt::fast_inv(ssFull5x5.e5x5) : 0.;
216 
217  data[0] = rawEnergy;
218  data[1] = superClus->etaWidth();
219  data[2] = superClus->phiWidth();
220  data[3] = superClus->seed()->energy() / rawEnergy;
221  data[4] = ssFull5x5.e5x5 / rawEnergy;
222  data[5] = ele.hcalOverEcalBc();
223  data[6] = rhoValue_;
224  data[7] = seedClus->eta() - superClus->position().Eta();
225  data[8] = reco::deltaPhi(seedClus->phi(), superClus->position().Phi());
226  data[9] = ssFull5x5.r9;
227  data[10] = ssFull5x5.sigmaIetaIeta;
228  data[11] = ssFull5x5.sigmaIetaIphi;
229  data[12] = ssFull5x5.sigmaIphiIphi;
230  data[13] = ssFull5x5.eMax * e5x5Inverse;
231  data[14] = ssFull5x5.e2nd * e5x5Inverse;
232  data[15] = ssFull5x5.eTop * e5x5Inverse;
233  data[16] = ssFull5x5.eBottom * e5x5Inverse;
234  data[17] = ssFull5x5.eLeft * e5x5Inverse;
235  data[18] = ssFull5x5.eRight * e5x5Inverse;
236  data[19] = ssFull5x5.e2x5Max * e5x5Inverse;
237  data[20] = ssFull5x5.e2x5Left * e5x5Inverse;
238  data[21] = ssFull5x5.e2x5Right * e5x5Inverse;
239  data[22] = ssFull5x5.e2x5Top * e5x5Inverse;
240  data[23] = ssFull5x5.e2x5Bottom * e5x5Inverse;
241  data[24] = ele.nSaturatedXtals();
242  data[25] = std::max(0, numberOfClusters);
243 
244  if (isEB) {
245  int iEta, iPhi;
246  getSeedCrysCoord(*seedClus, iEta, iPhi);
247  int signIEta = iEta > 0 ? +1 : -1;
248  data[26] = iEta;
249  data[27] = iPhi;
250  data[28] = (iEta - signIEta) % 5;
251  data[29] = (iPhi - 1) % 2;
252  const int iEtaCorr = iEta - (iEta > 0 ? +1 : -1);
253  const int iEtaCorr26 = iEta - (iEta > 0 ? +26 : -26);
254  data[30] = std::abs(iEta) <= 25 ? iEtaCorr % 20 : iEtaCorr26 % 20;
255  data[31] = (iPhi - 1) % 20;
256  } else {
257  int iX, iY;
258  getSeedCrysCoord(*seedClus, iX, iY);
259  data[26] = iX;
260  data[27] = iY;
261  data[28] = rawESEnergy / rawEnergy;
262  }
263 
264  return data;
265 }
266 
267 std::array<float, 32> EGRegressionModifierV3::getRegData(const reco::Photon& pho) const {
268  std::array<float, 32> data;
269 
270  const reco::SuperClusterRef& superClus = pho.superCluster();
271  const edm::Ptr<reco::CaloCluster>& seedClus = superClus->seed();
272 
273  const bool isEB = pho.isEB();
274  const double rawEnergy = superClus->rawEnergy();
275  const double rawESEnergy = superClus->preshowerEnergy();
276  const int numberOfClusters = superClus->clusters().size();
277  const auto& ssFull5x5 = pho.full5x5_showerShapeVariables();
278 
279  float e5x5Inverse = ssFull5x5.e5x5 != 0. ? vdt::fast_inv(ssFull5x5.e5x5) : 0.;
280 
281  data[0] = rawEnergy;
282  data[1] = superClus->etaWidth();
283  data[2] = superClus->phiWidth();
284  data[3] = superClus->seed()->energy() / rawEnergy;
285  data[4] = ssFull5x5.e5x5 / rawEnergy;
286  //interestingly enough this differs from electrons where it uses cone based
287  //naively Sam would have thought using cone based is even worse than tower based
288  data[5] = pho.hadronicOverEm();
289  data[6] = rhoValue_;
290  data[7] = seedClus->eta() - superClus->position().Eta();
291  data[8] = reco::deltaPhi(seedClus->phi(), superClus->position().Phi());
292  data[9] = pho.full5x5_r9();
293  data[10] = ssFull5x5.sigmaIetaIeta;
294  //interestingly sigmaIEtaIPhi differs in defination here from
295  //electron & sc definations of sigmaIEtaIPhi
296  data[11] = ssFull5x5.sigmaIetaIphi;
297  data[12] = ssFull5x5.sigmaIphiIphi;
298  data[13] = ssFull5x5.maxEnergyXtal * e5x5Inverse;
299  data[14] = ssFull5x5.e2nd * e5x5Inverse;
300  data[15] = ssFull5x5.eTop * e5x5Inverse;
301  data[16] = ssFull5x5.eBottom * e5x5Inverse;
302  data[17] = ssFull5x5.eLeft * e5x5Inverse;
303  data[18] = ssFull5x5.eRight * e5x5Inverse;
304  data[19] = ssFull5x5.e2x5Max * e5x5Inverse;
305  data[20] = ssFull5x5.e2x5Left * e5x5Inverse;
306  data[21] = ssFull5x5.e2x5Right * e5x5Inverse;
307  data[22] = ssFull5x5.e2x5Top * e5x5Inverse;
308  data[23] = ssFull5x5.e2x5Bottom * e5x5Inverse;
309  data[24] = pho.nSaturatedXtals();
310  data[25] = std::max(0, numberOfClusters);
311 
312  if (isEB) {
313  int iEta, iPhi;
314  getSeedCrysCoord(*seedClus, iEta, iPhi);
315  data[26] = iEta;
316  data[27] = iPhi;
317  int signIEta = iEta > 0 ? +1 : -1;
318  data[28] = (iEta - signIEta) % 5;
319  data[29] = (iPhi - 1) % 2;
320  const int iEtaCorr = iEta - (iEta > 0 ? +1 : -1);
321  const int iEtaCorr26 = iEta - (iEta > 0 ? +26 : -26);
322  data[30] = std::abs(iEta) <= 25 ? iEtaCorr % 20 : iEtaCorr26 % 20;
323  data[31] = (iPhi - 1) % 20;
324  } else {
325  int iX, iY;
326  getSeedCrysCoord(*seedClus, iX, iY);
327  data[26] = iX;
328  data[27] = iY;
329  data[28] = rawESEnergy / rawEnergy;
330  }
331 
332  return data;
333 }
334 
335 void EGRegressionModifierV3::getSeedCrysCoord(const reco::CaloCluster& clus, int& iEtaOrX, int& iPhiOrY) const {
336  iEtaOrX = 0;
337  iPhiOrY = 0;
338 
339  const bool isEB = clus.seed().subdetId() == EcalBarrel;
340 
342  float dummy;
343  if (isEB) {
344  egammaTools::localEcalClusterCoordsEB(clus, *caloGeomHandle_, dummy, dummy, iEtaOrX, iPhiOrY, dummy, dummy);
345  } else {
346  egammaTools::localEcalClusterCoordsEE(clus, *caloGeomHandle_, dummy, dummy, iEtaOrX, iPhiOrY, dummy, dummy);
347  }
348  } else {
349  if (isEB) {
350  const EBDetId ebId(clus.seed());
351  iEtaOrX = ebId.ieta();
352  iPhiOrY = ebId.iphi();
353  } else {
354  const EEDetId eeId(clus.seed());
355  iEtaOrX = eeId.ix();
356  iPhiOrY = eeId.iy();
357  }
358  }
359 }
360 
362  : ecalOnlyMean(iConfig.getParameter<edm::ParameterSet>("ecalOnlyMean")),
363  ecalOnlySigma(iConfig.getParameter<edm::ParameterSet>("ecalOnlySigma")),
364  epComb(iConfig.getParameter<edm::ParameterSet>("epComb")) {}
365 
369  epComb.setEventContent(iSetup);
370 }
371 
373  : ecalOnlyMean(iConfig.getParameter<edm::ParameterSet>("ecalOnlyMean")),
374  ecalOnlySigma(iConfig.getParameter<edm::ParameterSet>("ecalOnlySigma")) {}
375 
379 }
constexpr double deltaPhi(double phi1, double phi2)
Definition: deltaPhi.h:26
void setEventContent(const edm::EventSetup &iSetup)
Analysis-level Photon class.
Definition: Photon.h:46
void localEcalClusterCoordsEB(const reco::CaloCluster &bclus, const CaloGeometry &geom, float &etacry, float &phicry, int &ieta, int &iphi, float &thetatilt, float &phitilt)
float nSaturatedXtals() const
Definition: GsfElectron.h:489
float trackMomentumError() const
Definition: GsfElectron.h:800
Definition: Photon.py:1
int ix() const
Definition: EEDetId.h:77
const LorentzVector & p4(P4Kind kind) const
Definition: GsfElectron.cc:211
void setCorrectedEnergy(P4type type, float E, float dE, bool toCand=true)
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:525
void setEventContent(const edm::EventSetup &iSetup)
EgammaRegressionContainer ecalOnlySigma
edm::EDGetTokenT< double > rhoToken_
EgammaRegressionContainer ecalOnlyMean
void correctMomentum(const LorentzVector &p4, float trackMomentumError, float p4Error)
Definition: GsfElectron.h:821
void modifyObject(reco::GsfElectron &) const final
float fbrem() const
Definition: GsfElectron.h:726
std::unique_ptr< PhoRegs > phoRegs_
reco::SuperClusterRef superCluster() const override
Ref to SuperCluster.
EgammaRegressionContainer ecalOnlySigma
bool isAvailable() const
Definition: Ref.h:537
bool isEB() const
Definition: GsfElectron.h:328
double eta() const
pseudorapidity of cluster centroid
Definition: CaloCluster.h:180
EgammaRegressionContainer ecalOnlyMean
Definition: HeavyIon.h:7
XYZTLorentzVectorD XYZTLorentzVector
Lorentz vector with cylindrical internal representation using pseudorapidity.
Definition: LorentzVector.h:29
float full5x5_r9() const
Definition: Photon.h:252
void setCorrectedEcalEnergyError(float newEnergyError)
Definition: GsfElectron.cc:170
void getSeedCrysCoord(const reco::CaloCluster &clus, int &iEtaOrX, int &iPhiOrY) const
void setEventContent(const edm::EventSetup &iSetup)
EGRegressionModifierV3(const edm::ParameterSet &conf, edm::ConsumesCollector &cc)
EleRegs(const edm::ParameterSet &iConfig)
edm::ESHandle< CaloGeometry > caloGeomHandle_
constexpr int subdetId() const
get the contents of the subdetector field (not cast into any detector&#39;s numbering enum) ...
Definition: DetId.h:48
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
void localEcalClusterCoordsEE(const reco::CaloCluster &bclus, const CaloGeometry &geom, float &xcry, float &ycry, int &ix, int &iy, float &thetatilt, float &phitilt)
int ieta() const
get the crystal ieta
Definition: EBDetId.h:49
T min(T a, T b)
Definition: MathUtil.h:58
float hadronicOverEm() const
the total hadronic over electromagnetic fraction
Definition: Photon.h:208
float hcalOverEcalBc() const
Definition: GsfElectron.h:425
void setEventContent(const edm::EventSetup &iSetup)
std::unique_ptr< EleRegs > eleRegs_
DetId seed() const
return DetId of seed
Definition: CaloCluster.h:218
void setEventContent(const edm::EventSetup &) final
Analysis-level electron class.
Definition: Electron.h:51
bool isEB() const
Definition: Photon.h:119
void setCorrectedEcalEnergy(float newEnergy)
Definition: GsfElectron.cc:174
bool isSaturated(const Digi &digi, const int &maxADCvalue, int ifirst, int n)
const ShowerShape & full5x5_showerShape() const
Definition: GsfElectron.h:456
fixed size matrix
HLT enums.
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:79
const ShowerShape & full5x5_showerShapeVariables() const
Definition: Photon.h:202
void setEvent(const edm::Event &) final
T get() const
Definition: EventSetup.h:73
SuperClusterRef superCluster() const override
reference to a SuperCluster
Definition: GsfElectron.h:155
std::array< float, 32 > getRegData(const reco::GsfElectron &ele) const
#define DEFINE_EDM_PLUGIN(factory, type, name)
PhoRegs(const edm::ParameterSet &iConfig)
double phi() const
azimuthal angle of cluster centroid
Definition: CaloCluster.h:183
float nSaturatedXtals() const
Definition: Photon.h:265