CMS 3D CMS Logo

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