CMS 3D CMS Logo

PhotonIDValueMapProducer.cc
Go to the documentation of this file.
18 
19 // This template function finds whether theCandidate is in thefootprint
20 // collection. It is templated to be able to handle both reco and pat
21 // photons (from AOD and miniAOD, respectively).
22 template <class T, class U>
23 bool isInFootprint(const T& footprint, const U& candidate)
24 {
25  for (auto& it : footprint) {
26  if (it.key() == candidate.key())
27  return true;
28  }
29  return false;
30 }
31 
33 
34 public:
36  ~PhotonIDValueMapProducer() override;
37 
38  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
39 
40 private:
41  void produce(edm::Event&, const edm::EventSetup&) override;
42 
43  // This function computes charged hadron isolation with respect to multiple
44  // PVs and returns the worst of the found isolation values. The function
45  // implements the computation method taken directly from Run 1 code of
46  // H->gamma gamma, specifically from the class CiCPhotonID of the
47  // HiggsTo2photons anaysis code. Template is introduced to handle reco/pat
48  // photons and aod/miniAOD PF candidates collections
49  template <class T, class U>
51  const T& photon,
52  const U& pfCands,
54  const reco::Vertex& pv,
55  unsigned char options);
56 
57  // Some helper functions that are needed to access info in
58  // AOD vs miniAOD
60 
63  const edm::Ptr<reco::Candidate>& candidate, const reco::Vertex& pv, float& dxy, float& dz);
64 
65  // check whether a non-null preshower is there
66  const bool usesES_;
67 
68  // Dual Tokens for AOD and MiniAOD case
76 
77  bool isAOD_;
78 };
79 
80 constexpr int nVars_ = 19;
81 
83  // Cluster shapes
84  "phoFull5x5SigmaIEtaIEta", // 0
85  "phoFull5x5SigmaIEtaIPhi",
86  "phoFull5x5E1x3",
87  "phoFull5x5E2x2",
88  "phoFull5x5E2x5Max",
89  "phoFull5x5E5x5", // 5
90  "phoESEffSigmaRR",
91  // Cluster shape ratios
92  "phoFull5x5E1x3byE5x5",
93  "phoFull5x5E2x2byE5x5",
94  "phoFull5x5E2x5byE5x5",
95  // Isolations
96  "phoChargedIsolation", // 10
97  "phoNeutralHadronIsolation",
98  "phoPhotonIsolation",
99  "phoWorstChargedIsolation",
100  "phoWorstChargedIsolationConeVeto",
101  "phoWorstChargedIsolationConeVetoPVConstr", // 15
102  // PFCluster Isolation
103  "phoTrkIsolation",
104  "phoHcalPFClIsolation",
105  "phoEcalPFClIsolation"
106 };
107 
108 // options and bitflags
109 constexpr float coneSizeDR = 0.3;
110 constexpr float dxyMax = 0.1;
111 constexpr float dzMax = 0.2;
112 constexpr float dRvetoBarrel = 0.02;
113 constexpr float dRvetoEndcap = 0.02;
114 constexpr float ptMin = 0.1;
115 
116 const unsigned char PV_CONSTRAINT = 0x1;
117 const unsigned char DR_VETO = 0x2;
118 const unsigned char PT_MIN_THRESH = 0x8;
119 
121  : usesES_(!cfg.getParameter<edm::InputTag>("esReducedRecHitCollection").label().empty()
122  || !cfg.getParameter<edm::InputTag>("esReducedRecHitCollectionMiniAOD").label().empty())
123  , src_( consumesCollector(), cfg, "src", "srcMiniAOD")
124  , ebRecHits_ (src_, consumesCollector(), cfg, "ebReducedRecHitCollection", "ebReducedRecHitCollectionMiniAOD")
125  , eeRecHits_ (src_, consumesCollector(), cfg, "eeReducedRecHitCollection", "eeReducedRecHitCollectionMiniAOD")
126  , esRecHits_ (src_, consumesCollector(), cfg, "esReducedRecHitCollection", "esReducedRecHitCollectionMiniAOD")
127  , vtxToken_ (src_, consumesCollector(), cfg, "vertices", "verticesMiniAOD")
128  , pfCandsToken_(src_, consumesCollector(), cfg, "pfCandidates", "pfCandidatesMiniAOD")
129  , particleBasedIsolationToken_(mayConsume<edm::ValueMap<std::vector<reco::PFCandidateRef>>>(
130  cfg.getParameter<edm::InputTag>("particleBasedIsolation")) /* ...only for AOD... */ )
131 {
132 
133  // Declare producibles
134  for (int i = 0; i < nVars_; ++i)
135  produces<edm::ValueMap<float>>(names[i]);
136 }
137 
139 
141 {
142  // Get the handles
143  auto src = src_.getValidHandle(iEvent);
144  auto vertices = vtxToken_.getValidHandle(iEvent);
145  auto pfCandsHandle = pfCandsToken_.getValidHandle(iEvent);
146 
147  isAOD_ = src_.getGoodTokenIndex() == 0;
149  if (isAOD_) { // this exists only in AOD
150  iEvent.getByToken(particleBasedIsolationToken_, particleBasedIsolationMap);
151  }
152  if (!isAOD_ && !src->empty()) {
153  edm::Ptr<pat::Photon> test(src->ptrAt(0));
154  if (test.isNull() || !test.isAvailable()) {
155  throw cms::Exception("InvalidConfiguration")
156  << "DataFormat is detected as miniAOD but cannot cast to pat::Photon!";
157  }
158  }
159 
160  // Configure Lazy Tools, which will compute 5x5 quantities
161  std::unique_ptr<noZS::EcalClusterLazyTools> lazyToolnoZS;
162 
163  if (usesES_) {
164  lazyToolnoZS = std::make_unique<noZS::EcalClusterLazyTools>(
165  iEvent, iSetup, ebRecHits_.get(iEvent), eeRecHits_.get(iEvent), esRecHits_.get(iEvent));
166  } else {
167  lazyToolnoZS = std::make_unique<noZS::EcalClusterLazyTools>(
168  iEvent, iSetup, ebRecHits_.get(iEvent), eeRecHits_.get(iEvent));
169  }
170 
171  // Get PV
172  if (vertices->empty())
173  return; // skip the event if no PV found
174  const reco::Vertex& pv = vertices->front();
175 
176  std::vector<float> vars[nVars_];
177 
178  // reco::Photon::superCluster() is virtual so we can exploit polymorphism
179  for (unsigned i = 0; i < src->size(); ++i) {
180  const auto& iPho = src->ptrAt(i);
181 
182  //
183  // Compute full 5x5 quantities
184  //
185  const auto& theseed = *(iPho->superCluster()->seed());
186 
187  // For full5x5_sigmaIetaIeta, for 720 we use: lazy tools for AOD,
188  // and userFloats or lazy tools for miniAOD. From some point in 72X and on, one can
189  // retrieve the full5x5 directly from the object with ->full5x5_sigmaIetaIeta()
190  // for both formats.
191  std::vector<float> vCov = lazyToolnoZS->localCovariances(theseed);
192  vars[0].push_back(isnan(vCov[0]) ? 0. : sqrt(vCov[0]));
193  vars[1].push_back(vCov[1]);
194  vars[2].push_back(lazyToolnoZS->e1x3(theseed));
195  vars[3].push_back(lazyToolnoZS->e2x2(theseed));
196  vars[4].push_back(lazyToolnoZS->e2x5Max(theseed));
197  vars[5].push_back(lazyToolnoZS->e5x5(theseed));
198  vars[6].push_back(lazyToolnoZS->eseffsirir(*(iPho->superCluster())));
199  vars[7].push_back(vars[2][i] / vars[5][i]);
200  vars[8].push_back(vars[3][i] / vars[5][i]);
201  vars[9].push_back(vars[4][i] / vars[5][i]);
202 
203  //
204  // Compute absolute uncorrected isolations with footprint removal
205  //
206 
207  // First, find photon direction with respect to the good PV
208  math::XYZVector phoWrtVtx(
209  iPho->superCluster()->x() - pv.x(), iPho->superCluster()->y() - pv.y(), iPho->superCluster()->z() - pv.z());
210 
211  // isolation sums
212  float chargedIsoSum = 0.;
213  float neutralHadronIsoSum = 0.;
214  float photonIsoSum = 0.;
215 
216  // Loop over all PF candidates
217  for (unsigned int idxcand = 0; idxcand < pfCandsHandle->size(); ++idxcand) {
218 
219  // Here, the type will be a simple reco::Candidate. We cast it
220  // for full PFCandidate or PackedCandidate below as necessary
221  const auto& iCand = pfCandsHandle->ptrAt(idxcand);
222 
223  // One would think that we should check that this iCand from the
224  // generic PF collection is not identical to the iPho photon for
225  // which we are computing the isolations. However, it turns out to
226  // be unnecessary. Below, in the function isInFootprint(), we drop
227  // this iCand if it is in the footprint, and this always removes
228  // the iCand if it matches the iPho. The explicit check at this
229  // point is not totally trivial because of non-triviality of
230  // implementation of this check for miniAOD (PackedCandidates of
231  // the PF collection do not contain the supercluser link, so can't
232  // use that).
233  //
234  // if( isAOD_ ) {
235  // if( ((const edm::Ptr<reco::PFCandidate>)iCand)->superClusterRef() == iPho->superCluster() )
236  // continue;
237  // }
238 
239  // Check if this candidate is within the isolation cone
240  float dR2 = deltaR2(phoWrtVtx.Eta(), phoWrtVtx.Phi(), iCand->eta(), iCand->phi());
241  if (dR2 > coneSizeDR * coneSizeDR)
242  continue;
243 
244  // Check if this candidate is not in the footprint
245  if (isAOD_) {
246  if(isInFootprint((*particleBasedIsolationMap)[iPho], iCand))
247  continue;
248  } else {
250  if(isInFootprint(patPhotonPtr->associatedPackedPFCandidates(), iCand))
251  continue;
252  }
253 
254  // Find candidate type
255  reco::PFCandidate::ParticleType thisCandidateType = candidatePdgId(iCand);
256 
257  // Increment the appropriate isolation sum
258  if (thisCandidateType == reco::PFCandidate::h) {
259  // for charged hadrons, additionally check consistency
260  // with the PV
261  float dxy = -999;
262  float dz = -999;
263  getImpactParameters(iCand, pv, dxy, dz);
264 
265  if (fabs(dxy) > dxyMax || fabs(dz) > dzMax)
266  continue;
267 
268  // The candidate is eligible, increment the isolaiton
269  chargedIsoSum += iCand->pt();
270  }
271 
272  if (thisCandidateType == reco::PFCandidate::h0)
273  neutralHadronIsoSum += iCand->pt();
274 
275  if (thisCandidateType == reco::PFCandidate::gamma)
276  photonIsoSum += iCand->pt();
277  }
278 
279  vars[10].push_back(chargedIsoSum);
280  vars[11].push_back(neutralHadronIsoSum);
281  vars[12].push_back(photonIsoSum);
282 
283  // Worst isolation computed with no vetos or ptMin cut, as in Run 1 Hgg code.
284  unsigned char options = 0;
285  vars[13].push_back(computeWorstPFChargedIsolation(iPho, pfCandsHandle, vertices, pv, options));
286 
287  // Worst isolation computed with cone vetos and a ptMin cut, as in Run 2 Hgg code.
288  options |= PT_MIN_THRESH | DR_VETO;
289  vars[14].push_back(computeWorstPFChargedIsolation(iPho, pfCandsHandle, vertices, pv, options));
290 
291  // Like before, but adding primary vertex constraint
292  options |= PV_CONSTRAINT;
293  vars[15].push_back(computeWorstPFChargedIsolation(iPho, pfCandsHandle, vertices, pv, options));
294 
295  // PFCluster Isolations
296  vars[16].push_back(iPho->trkSumPtSolidConeDR04());
297  if (isAOD_) {
298  vars[17].push_back(0.f);
299  vars[18].push_back(0.f);
300  } else {
302  vars[17].push_back(patPhotonPtr->hcalPFClusterIso());
303  vars[18].push_back(patPhotonPtr->ecalPFClusterIso());
304  }
305  }
306 
307  // write the value maps
308  for (int i = 0; i < nVars_; ++i) {
309  writeValueMap(iEvent, src, vars[i], names[i]);
310  }
311 }
312 
314  // photonIDValueMapProducer
316  desc.add<edm::InputTag>("particleBasedIsolation", edm::InputTag("particleBasedIsolation","gedPhotons"));
317  desc.add<edm::InputTag>("src", edm::InputTag("gedPhotons"));
318  desc.add<edm::InputTag>("srcMiniAOD", edm::InputTag("slimmedPhotons","","@skipCurrentProcess"));
319  desc.add<edm::InputTag>("esReducedRecHitCollectionMiniAOD", edm::InputTag("reducedEgamma","reducedESRecHits"));
320  desc.add<edm::InputTag>("eeReducedRecHitCollection", edm::InputTag("reducedEcalRecHitsEE"));
321  desc.add<edm::InputTag>("pfCandidates", edm::InputTag("particleFlow"));
322  desc.add<edm::InputTag>("vertices", edm::InputTag("offlinePrimaryVertices"));
323  desc.add<edm::InputTag>("ebReducedRecHitCollectionMiniAOD", edm::InputTag("reducedEgamma","reducedEBRecHits"));
324  desc.add<edm::InputTag>("eeReducedRecHitCollectionMiniAOD", edm::InputTag("reducedEgamma","reducedEERecHits"));
325  desc.add<edm::InputTag>("esReducedRecHitCollection", edm::InputTag("reducedEcalRecHitsES"));
326  desc.add<edm::InputTag>("pfCandidatesMiniAOD", edm::InputTag("packedPFCandidates"));
327  desc.add<edm::InputTag>("verticesMiniAOD", edm::InputTag("offlineSlimmedPrimaryVertices"));
328  desc.add<edm::InputTag>("ebReducedRecHitCollection", edm::InputTag("reducedEcalRecHitsEB"));
329  descriptions.add("photonIDValueMapProducer", desc);
330 }
331 
332 
333 // Charged isolation with respect to the worst vertex. See more
334 // comments above at the function declaration.
335 template <class T, class U>
338 {
339  float worstIsolation = 0.0;
340 
341  const float dRveto = photon->isEB() ? dRvetoBarrel : dRvetoEndcap;
342 
343  // Calculate isolation sum separately for each vertex
344  for (unsigned int ivtx = 0; ivtx < vertices->size(); ++ivtx) {
345 
346  // Shift the photon according to the vertex
347  reco::VertexRef vtx(vertices, ivtx);
348  math::XYZVector phoWrtVtx(photon->superCluster()->x() - vtx->x(),
349  photon->superCluster()->y() - vtx->y(), photon->superCluster()->z() - vtx->z());
350 
351  float sum = 0;
352  // Loop over the PFCandidates
353  for (unsigned int i = 0; i < pfCands->size(); i++) {
354 
355  const auto& iCand = pfCands->ptrAt(i);
356 
357  // require that PFCandidate is a charged hadron
358  reco::PFCandidate::ParticleType thisCandidateType = candidatePdgId(iCand);
359  if (thisCandidateType != reco::PFCandidate::h)
360  continue;
361 
362  if ((options & PT_MIN_THRESH) && iCand->pt() < ptMin)
363  continue;
364 
365  float dxy = -999;
366  float dz = -999;
367  if (options & PV_CONSTRAINT)
368  getImpactParameters(iCand, pv, dxy, dz);
369  else
370  getImpactParameters(iCand, *vtx, dxy, dz);
371 
372  if (fabs(dxy) > dxyMax || fabs(dz) > dzMax)
373  continue;
374 
375  float dR2 = deltaR2(phoWrtVtx.Eta(), phoWrtVtx.Phi(), iCand->eta(), iCand->phi());
376  if (dR2 > coneSizeDR * coneSizeDR ||
377  (options & DR_VETO && dR2 < dRveto * dRveto))
378  continue;
379 
380  sum += iCand->pt();
381  }
382 
383  worstIsolation = std::max(sum, worstIsolation);
384  }
385 
386  return worstIsolation;
387 }
388 
390  const edm::Ptr<reco::Candidate> candidate)
391 {
392  if (isAOD_)
393  return ((const edm::Ptr<reco::PFCandidate>)candidate)->particleId();
394 
395  // the neutral hadrons and charged hadrons can be of pdgId types
396  // only 130 (K0L) and +-211 (pi+-) in packed candidates
397  const int pdgId = ((const edm::Ptr<pat::PackedCandidate>)candidate)->pdgId();
398  if (pdgId == 22)
400  else if (abs(pdgId) == 130) // PDG ID for K0L
401  return reco::PFCandidate::h0;
402  else if (abs(pdgId) == 211) // PDG ID for pi+-
403  return reco::PFCandidate::h;
404  else
405  return reco::PFCandidate::X;
406 }
407 
409 {
410  return isAOD_ ?
411  &*(((const edm::Ptr<reco::PFCandidate>)candidate)->trackRef()) :
412  &(((const edm::Ptr<pat::PackedCandidate>)candidate)->pseudoTrack());
413 }
414 
416  const edm::Ptr<reco::Candidate>& candidate, const reco::Vertex& pv, float& dxy, float& dz)
417 {
418  if (isAOD_) {
419  auto const& theTrack = *static_cast<const edm::Ptr<reco::PFCandidate>>(candidate)->trackRef();
420  dxy = theTrack.dxy(pv.position());
421  dz = theTrack.dz(pv.position());
422  } else {
423  auto const& aCand = *static_cast<const edm::Ptr<pat::PackedCandidate>>(candidate);
424  dxy = aCand.dxy(pv.position());
425  dz = aCand.dz(pv.position());
426  }
427 }
428 
float dRvetoEndcap
const unsigned char DR_VETO
ParticleType
particle types
Definition: PFCandidate.h:45
const unsigned char PV_CONSTRAINT
float computeWorstPFChargedIsolation(const T &photon, const U &pfCands, const edm::Handle< reco::VertexCollection > vertices, const reco::Vertex &pv, unsigned char options)
MultiTokenT< edm::View< reco::Candidate > > pfCandsToken_
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:579
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:17
double y() const
y coordinate
Definition: Vertex.h:113
MultiTokenT< EcalRecHitCollection > esRecHits_
PhotonIDValueMapProducer(const edm::ParameterSet &)
bool isInFootprint(const T &footprint, const U &candidate)
const Point & position() const
position
Definition: Vertex.h:109
const std::string names[nVars_]
#define constexpr
void writeValueMap(edm::Event &iEvent, const edm::Handle< HandleType > &handle, const std::vector< ValueType > &values, const std::string &label)
Definition: Utils.h:13
edm::EDGetToken particleBasedIsolationToken_
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
const unsigned char PT_MIN_THRESH
int iEvent
Definition: GenABIO.cc:230
float coneSizeDR
MultiTokenT< edm::View< reco::Photon > > src_
bool isnan(float x)
Definition: math.h:13
T sqrt(T t)
Definition: SSEVec.h:18
def pv(vc)
Definition: MetAnalyzer.py:7
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
double z() const
z coordinate
Definition: Vertex.h:115
void produce(edm::Event &, const edm::EventSetup &) override
double f[11][100]
MultiTokenT< EcalRecHitCollection > eeRecHits_
edm::Ref< PFCandidateCollection > PFCandidateRef
persistent reference to a PFCandidate
ParameterDescriptionBase * add(U const &iLabel, T const &value)
MultiTokenT< reco::VertexCollection > vtxToken_
float dRvetoBarrel
edm::Handle< T > getValidHandle(const edm::Event &iEvent)
Definition: MultiToken.h:83
double x() const
x coordinate
Definition: Vertex.h:111
constexpr auto deltaR2(const T1 &t1, const T2 &t2) -> decltype(t1.eta())
Definition: deltaR.h:16
XYZVectorD XYZVector
spatial vector with cartesian internal representation
Definition: Vector3D.h:30
void add(std::string const &label, ParameterSetDescription const &psetDescription)
MultiTokenT< EcalRecHitCollection > ebRecHits_
const reco::Track * getTrackPointer(const edm::Ptr< reco::Candidate > candidate)
edm::Ptr< pat::Photon > patPhotonPtr
fixed size matrix
HLT enums.
int getGoodTokenIndex() const
Definition: MultiToken.h:135
reco::PFCandidate::ParticleType candidatePdgId(const edm::Ptr< reco::Candidate > candidate)
void getImpactParameters(const edm::Ptr< reco::Candidate > &candidate, const reco::Vertex &pv, float &dxy, float &dz)
long double T