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