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 coneSizeDR2 = 0.3*0.3;
149 constexpr float dxyMax = 0.1;
150 constexpr float dzMax = 0.2;
151 constexpr float dRveto2Barrel = 0.02*0.02;
152 constexpr float dRveto2Endcap = 0.02*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  auto lazyToolnoZS = usesES_ ? noZS::EcalClusterLazyTools(iEvent, iSetup,
198  ebRecHits_.get(iEvent), eeRecHits_.get(iEvent), esRecHits_.get(iEvent))
199  : noZS::EcalClusterLazyTools(iEvent, iSetup,
200  ebRecHits_.get(iEvent), eeRecHits_.get(iEvent));
201 
202  // Get PV
203  if (vertices->empty())
204  return; // skip the event if no PV found
205  const reco::Vertex& pv = vertices->front();
206 
207  std::vector<float> vars[nVars_];
208 
209  // reco::Photon::superCluster() is virtual so we can exploit polymorphism
210  for(auto const& iPho : src->ptrs())
211  {
212  //
213  // Compute full 5x5 quantities
214  //
215  const auto& seed = *(iPho->superCluster()->seed());
216 
217  // For full5x5_sigmaIetaIeta, for 720 we use: lazy tools for AOD,
218  // and userFloats or lazy tools for miniAOD. From some point in 72X and on, one can
219  // retrieve the full5x5 directly from the object with ->full5x5_sigmaIetaIeta()
220  // for both formats.
221  std::vector<float> vCov = lazyToolnoZS.localCovariances(seed);
222  vars[0].push_back(edm::isNotFinite(vCov[0]) ? 0. : sqrt(vCov[0]));
223  vars[1].push_back(vCov[1]);
224  vars[2].push_back(lazyToolnoZS.e1x3(seed));
225  vars[3].push_back(lazyToolnoZS.e2x2(seed));
226  vars[4].push_back(lazyToolnoZS.e2x5Max(seed));
227  vars[5].push_back(lazyToolnoZS.e5x5(seed));
228  vars[6].push_back(lazyToolnoZS.eseffsirir(*(iPho->superCluster())));
229  vars[7].push_back(vars[2].back() / vars[5].back());
230  vars[8].push_back(vars[3].back() / vars[5].back());
231  vars[9].push_back(vars[4].back() / vars[5].back());
232 
233  //
234  // Compute absolute uncorrected isolations with footprint removal
235  //
236 
237  // First, find photon direction with respect to the good PV
238  math::XYZVector phoWrtVtx(
239  iPho->superCluster()->x() - pv.x(), iPho->superCluster()->y() - pv.y(), iPho->superCluster()->z() - pv.z());
240 
241  // isolation sums
242  float chargedIsoSum = 0.;
243  float neutralHadronIsoSum = 0.;
244  float photonIsoSum = 0.;
245 
246  // Loop over all PF candidates
247  for(auto const& iCand : pfCandsHandle->ptrs())
248  {
249  // Here, the type will be a simple reco::Candidate. We cast it
250  // for full PFCandidate or PackedCandidate below as necessary
251 
252  // One would think that we should check that this iCand from the
253  // generic PF collection is not identical to the iPho photon for
254  // which we are computing the isolations. However, it turns out to
255  // be unnecessary. Below, in the function isInFootprint(), we drop
256  // this iCand if it is in the footprint, and this always removes
257  // the iCand if it matches the iPho. The explicit check at this
258  // point is not totally trivial because of non-triviality of
259  // implementation of this check for miniAOD (PackedCandidates of
260  // the PF collection do not contain the supercluser link, so can't
261  // use that).
262  //
263  // if( isAOD ) {
264  // if( ((const edm::Ptr<reco::PFCandidate>)iCand)->superClusterRef() == iPho->superCluster() )
265  // continue;
266  // }
267 
268  // Check if this candidate is within the isolation cone
269  float dR2 = deltaR2(phoWrtVtx.Eta(), phoWrtVtx.Phi(), iCand->eta(), iCand->phi());
270  if (dR2 > coneSizeDR2)
271  continue;
272 
273  // Check if this candidate is not in the footprint
274  if (isAOD) {
275  if(isInFootprint((*particleBasedIsolationMap)[iPho], iCand))
276  continue;
277  } else {
279  if(isInFootprint(patPhotonPtr->associatedPackedPFCandidates(), iCand))
280  continue;
281  }
282 
283  // Find candidate type
284  reco::PFCandidate::ParticleType thisCandidateType = getCandidatePdgId(&*iCand, isAOD);
285 
286  // Increment the appropriate isolation sum
287  if (thisCandidateType == reco::PFCandidate::h) {
288  // for charged hadrons, additionally check consistency
289  // with the PV
290  float dxy = -999;
291  float dz = -999;
292 
293  getImpactParameters(CachingPtrCandidate(&*iCand, isAOD), pv, dxy, dz);
294 
295  if (fabs(dxy) > dxyMax || fabs(dz) > dzMax)
296  continue;
297 
298  // The candidate is eligible, increment the isolaiton
299  chargedIsoSum += iCand->pt();
300  }
301 
302  if (thisCandidateType == reco::PFCandidate::h0)
303  neutralHadronIsoSum += iCand->pt();
304 
305  if (thisCandidateType == reco::PFCandidate::gamma)
306  photonIsoSum += iCand->pt();
307  }
308 
309  vars[10].push_back(chargedIsoSum);
310  vars[11].push_back(neutralHadronIsoSum);
311  vars[12].push_back(photonIsoSum);
312 
313  // Worst isolation computed with no vetos or ptMin cut, as in Run 1 Hgg code.
314  unsigned char options = 0;
315  vars[13].push_back(computeWorstPFChargedIsolation(*iPho, *pfCandsHandle, *vertices, pv, options, isAOD));
316 
317  // Worst isolation computed with cone vetos and a ptMin cut, as in Run 2 Hgg code.
318  options |= PT_MIN_THRESH | DR_VETO;
319  vars[14].push_back(computeWorstPFChargedIsolation(*iPho, *pfCandsHandle, *vertices, pv, options, isAOD));
320 
321  // Like before, but adding primary vertex constraint
322  options |= PV_CONSTRAINT;
323  vars[15].push_back(computeWorstPFChargedIsolation(*iPho, *pfCandsHandle, *vertices, pv, options, isAOD));
324 
325  // PFCluster Isolations
326  vars[16].push_back(iPho->trkSumPtSolidConeDR04());
327  if (isAOD) {
328  vars[17].push_back(0.f);
329  vars[18].push_back(0.f);
330  } else {
332  vars[17].push_back(patPhotonPtr->hcalPFClusterIso());
333  vars[18].push_back(patPhotonPtr->ecalPFClusterIso());
334  }
335  }
336 
337  // write the value maps
338  for (int i = 0; i < nVars_; ++i) {
339  writeValueMap(iEvent, src, vars[i], names[i]);
340  }
341 }
342 
344  // photonIDValueMapProducer
346  desc.add<edm::InputTag>("particleBasedIsolation", edm::InputTag("particleBasedIsolation","gedPhotons"));
347  desc.add<edm::InputTag>("src", edm::InputTag("gedPhotons"));
348  desc.add<edm::InputTag>("srcMiniAOD", edm::InputTag("slimmedPhotons","","@skipCurrentProcess"));
349  desc.add<edm::InputTag>("esReducedRecHitCollectionMiniAOD", edm::InputTag("reducedEgamma","reducedESRecHits"));
350  desc.add<edm::InputTag>("eeReducedRecHitCollection", edm::InputTag("reducedEcalRecHitsEE"));
351  desc.add<edm::InputTag>("pfCandidates", edm::InputTag("particleFlow"));
352  desc.add<edm::InputTag>("vertices", edm::InputTag("offlinePrimaryVertices"));
353  desc.add<edm::InputTag>("ebReducedRecHitCollectionMiniAOD", edm::InputTag("reducedEgamma","reducedEBRecHits"));
354  desc.add<edm::InputTag>("eeReducedRecHitCollectionMiniAOD", edm::InputTag("reducedEgamma","reducedEERecHits"));
355  desc.add<edm::InputTag>("esReducedRecHitCollection", edm::InputTag("reducedEcalRecHitsES"));
356  desc.add<edm::InputTag>("pfCandidatesMiniAOD", edm::InputTag("packedPFCandidates"));
357  desc.add<edm::InputTag>("verticesMiniAOD", edm::InputTag("offlineSlimmedPrimaryVertices"));
358  desc.add<edm::InputTag>("ebReducedRecHitCollection", edm::InputTag("reducedEcalRecHitsEB"));
359  descriptions.add("photonIDValueMapProducer", desc);
360 }
361 
362 
363 // Charged isolation with respect to the worst vertex. See more
364 // comments above at the function declaration.
366  const reco::VertexCollection& vertices, const reco::Vertex& pv, unsigned char options, bool isAOD) const
367 {
368  float worstIsolation = 0.0;
369 
370  const float dRveto2 = photon.isEB() ? dRveto2Barrel : dRveto2Endcap;
371 
372  std::vector<CachingPtrCandidate> chargedCands;
373  chargedCands.reserve(pfCands.size());
374  for (auto const& aCand : pfCands){
375 
376  // require that PFCandidate is a charged hadron
377  reco::PFCandidate::ParticleType thisCandidateType = getCandidatePdgId(&aCand, isAOD);
378  if (thisCandidateType != reco::PFCandidate::h)
379  continue;
380 
381  if ((options & PT_MIN_THRESH) && aCand.pt() < ptMin)
382  continue;
383 
384  chargedCands.emplace_back(&aCand, isAOD);
385  }
386 
387  // Calculate isolation sum separately for each vertex
388  for (unsigned int ivtx = 0; ivtx < vertices.size(); ++ivtx) {
389 
390  // Shift the photon according to the vertex
391  const reco::VertexRef vtx(&vertices, ivtx);
392  math::XYZVector phoWrtVtx(photon.superCluster()->x() - vtx->x(),
393  photon.superCluster()->y() - vtx->y(), photon.superCluster()->z() - vtx->z());
394 
395  const float phoWrtVtxPhi = phoWrtVtx.phi();
396  const float phoWrtVtxEta = phoWrtVtx.eta();
397 
398  float sum = 0;
399  // Loop over the PFCandidates
400  for (auto const& aCCand : chargedCands) {
401 
402  auto iCand = aCCand.candidate;
403  float dR2 = deltaR2(phoWrtVtxEta, phoWrtVtxPhi, iCand->eta(), iCand->phi());
404  if (dR2 > coneSizeDR2 ||
405  (options & DR_VETO && dR2 < dRveto2))
406  continue;
407 
408  float dxy = -999;
409  float dz = -999;
410  if (options & PV_CONSTRAINT)
411  getImpactParameters(aCCand, pv, dxy, dz);
412  else
413  getImpactParameters(aCCand, *vtx, dxy, dz);
414 
415  if (fabs(dxy) > dxyMax || fabs(dz) > dzMax)
416  continue;
417 
418 
419  sum += iCand->pt();
420  }
421 
422  worstIsolation = std::max(sum, worstIsolation);
423  }
424 
425  return worstIsolation;
426 }
427 
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:517
constexpr bool isNotFinite(T x)
Definition: isFinite.h:9
double y() const
y coordinate
Definition: Vertex.h:113
float dRveto2Endcap
#define nullptr
edm::RefVector< pat::PackedCandidateCollection > associatedPackedPFCandidates() const
References to PFCandidates linked to this object (e.g. for isolation vetos or masking before jet recl...
PhotonIDValueMapProducer(const edm::ParameterSet &)
const MultiTokenT< EcalRecHitCollection > ebRecHits_
size_type size() const
std::vector< Vertex > VertexCollection
collection of Vertex objects
Definition: VertexFwd.h:9
reco::SuperClusterRef superCluster() const override
Ref to SuperCluster.
const MultiTokenT< edm::View< reco::Photon > > src_
EcalClusterLazyToolsT< noZS::EcalClusterTools > EcalClusterLazyTools
float dRveto2Barrel
const Point & position() const
position
Definition: Vertex.h:109
const std::string names[nVars_]
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
char const * label
float coneSizeDR2
int iEvent
Definition: GenABIO.cc:224
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
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
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)
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)
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_
vars
Definition: DeepTauId.cc:77
const MultiTokenT< edm::View< reco::Candidate > > pfCandsToken_
long double T
const MultiTokenT< reco::VertexCollection > vtxToken_
#define constexpr