CMS 3D CMS Logo

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