CMS 3D CMS Logo

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