CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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
98  float computeWorstPFChargedIsolation(const reco::Photon& photon,
99  const edm::View<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 =
198  usesES_ ? noZS::EcalClusterLazyTools(iEvent, ecalClusterToolsESData, ebRecHits_, eeRecHits_, esRecHits_)
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  // reco::Photon::superCluster() is virtual so we can exploit polymorphism
209  for (auto const& iPho : src->ptrs()) {
210  //
211  // Compute full 5x5 quantities
212  //
213  const auto& seed = *(iPho->superCluster()->seed());
214 
215  // For full5x5_sigmaIetaIeta, for 720 we use: lazy tools for AOD,
216  // and userFloats or lazy tools for miniAOD. From some point in 72X and on, one can
217  // retrieve the full5x5 directly from the object with ->full5x5_sigmaIetaIeta()
218  // for both formats.
219  const auto& vCov = lazyToolnoZS.localCovariances(seed);
220  vars[0].push_back(edm::isNotFinite(vCov[0]) ? 0. : sqrt(vCov[0]));
221  vars[1].push_back(vCov[1]);
222  vars[2].push_back(lazyToolnoZS.e1x3(seed));
223  vars[3].push_back(lazyToolnoZS.e2x2(seed));
224  vars[4].push_back(lazyToolnoZS.e2x5Max(seed));
225  vars[5].push_back(lazyToolnoZS.e5x5(seed));
226  vars[6].push_back(lazyToolnoZS.eseffsirir(*(iPho->superCluster())));
227  vars[7].push_back(vars[2].back() / vars[5].back());
228  vars[8].push_back(vars[3].back() / vars[5].back());
229  vars[9].push_back(vars[4].back() / vars[5].back());
230 
231  //
232  // Compute absolute uncorrected isolations with footprint removal
233  //
234 
235  // First, find photon direction with respect to the good PV
236  math::XYZVector phoWrtVtx(
237  iPho->superCluster()->x() - pv.x(), iPho->superCluster()->y() - pv.y(), iPho->superCluster()->z() - pv.z());
238 
239  // isolation sums
240  float chargedIsoSum = 0.;
241  float neutralHadronIsoSum = 0.;
242  float photonIsoSum = 0.;
243 
244  // Loop over all PF candidates
245  for (auto const& iCand : pfCandsHandle->ptrs()) {
246  // Here, the type will be a simple reco::Candidate. We cast it
247  // for full PFCandidate or PackedCandidate below as necessary
248 
249  // One would think that we should check that this iCand from the
250  // generic PF collection is not identical to the iPho photon for
251  // which we are computing the isolations. However, it turns out to
252  // be unnecessary. Below, in the function isInFootprint(), we drop
253  // this iCand if it is in the footprint, and this always removes
254  // the iCand if it matches the iPho. The explicit check at this
255  // point is not totally trivial because of non-triviality of
256  // implementation of this check for miniAOD (PackedCandidates of
257  // the PF collection do not contain the supercluser link, so can't
258  // use that).
259  //
260  // if( isAOD_ ) {
261  // if( ((const edm::Ptr<reco::PFCandidate>)iCand)->superClusterRef() == iPho->superCluster() )
262  // continue;
263  // }
264 
265  // Check if this candidate is within the isolation cone
266  float dR2 = deltaR2(phoWrtVtx.Eta(), phoWrtVtx.Phi(), iCand->eta(), iCand->phi());
267  if (dR2 > coneSizeDR2)
268  continue;
269 
270  // Check if this candidate is not in the footprint
271  if (isAOD_) {
272  if (isInFootprint((*particleBasedIsolationMap)[iPho], iCand))
273  continue;
274  } else {
276  if (isInFootprint(patPhotonPtr->associatedPackedPFCandidates(), iCand))
277  continue;
278  }
279 
280  // Find candidate type
281  reco::PFCandidate::ParticleType thisCandidateType = getCandidatePdgId(&*iCand, isAOD_);
282 
283  // Increment the appropriate isolation sum
284  if (thisCandidateType == reco::PFCandidate::h) {
285  // for charged hadrons, additionally check consistency
286  // with the PV
287  float dxy = -999;
288  float dz = -999;
289 
290  getImpactParameters(CachingPtrCandidate(&*iCand, isAOD_), pv, dxy, dz);
291 
292  if (fabs(dxy) > dxyMax || fabs(dz) > dzMax)
293  continue;
294 
295  // The candidate is eligible, increment the isolaiton
296  chargedIsoSum += iCand->pt();
297  }
298 
299  if (thisCandidateType == reco::PFCandidate::h0)
300  neutralHadronIsoSum += iCand->pt();
301 
302  if (thisCandidateType == reco::PFCandidate::gamma)
303  photonIsoSum += iCand->pt();
304  }
305 
306  vars[10].push_back(chargedIsoSum);
307  vars[11].push_back(neutralHadronIsoSum);
308  vars[12].push_back(photonIsoSum);
309 
310  // Worst isolation computed with no vetos or ptMin cut, as in Run 1 Hgg code.
311  unsigned char options = 0;
312  vars[13].push_back(computeWorstPFChargedIsolation(*iPho, *pfCandsHandle, *vertices, pv, options, isAOD_));
313 
314  // Worst isolation computed with cone vetos and a ptMin cut, as in Run 2 Hgg code.
315  options |= PT_MIN_THRESH | DR_VETO;
316  vars[14].push_back(computeWorstPFChargedIsolation(*iPho, *pfCandsHandle, *vertices, pv, options, isAOD_));
317 
318  // Like before, but adding primary vertex constraint
319  options |= PV_CONSTRAINT;
320  vars[15].push_back(computeWorstPFChargedIsolation(*iPho, *pfCandsHandle, *vertices, pv, options, isAOD_));
321 
322  // PFCluster Isolations
323  vars[16].push_back(iPho->trkSumPtSolidConeDR04());
324  if (isAOD_) {
325  vars[17].push_back(0.f);
326  vars[18].push_back(0.f);
327  } else {
329  vars[17].push_back(patPhotonPtr->hcalPFClusterIso());
330  vars[18].push_back(patPhotonPtr->ecalPFClusterIso());
331  }
332  }
333 
334  // write the value maps
335  for (int i = 0; i < nVars_; ++i) {
336  auto valMap = std::make_unique<edm::ValueMap<float>>();
337  typename edm::ValueMap<float>::Filler filler(*valMap);
338  filler.insert(src, vars[i].begin(), vars[i].end());
339  filler.fill();
340  iEvent.put(std::move(valMap), names[i]);
341  }
342 }
343 
345  // photonIDValueMapProducer
347  desc.add<edm::InputTag>("particleBasedIsolation", edm::InputTag("particleBasedIsolation", "gedPhotons"));
348  desc.add<edm::InputTag>("src", edm::InputTag("slimmedPhotons", "", "@skipCurrentProcess"));
349  desc.add<edm::InputTag>("esReducedRecHitCollection", edm::InputTag("reducedEgamma", "reducedESRecHits"));
350  desc.add<edm::InputTag>("ebReducedRecHitCollection", edm::InputTag("reducedEgamma", "reducedEBRecHits"));
351  desc.add<edm::InputTag>("eeReducedRecHitCollection", edm::InputTag("reducedEgamma", "reducedEERecHits"));
352  desc.add<edm::InputTag>("pfCandidates", edm::InputTag("packedPFCandidates"));
353  desc.add<edm::InputTag>("vertices", edm::InputTag("offlineSlimmedPrimaryVertices"));
354  desc.add<bool>("isAOD", false);
355  descriptions.add("photonIDValueMapProducer", desc);
356 }
357 
358 // Charged isolation with respect to the worst vertex. See more
359 // comments above at the function declaration.
361  const edm::View<reco::Candidate>& pfCands,
363  const reco::Vertex& pv,
364  unsigned char options,
365  bool isAOD) const {
366  float worstIsolation = 0.0;
367 
368  const float dRveto2 = photon.isEB() ? dRveto2Barrel : dRveto2Endcap;
369 
370  std::vector<CachingPtrCandidate> chargedCands;
371  chargedCands.reserve(pfCands.size());
372  for (auto const& aCand : pfCands) {
373  // require that PFCandidate is a charged hadron
374  reco::PFCandidate::ParticleType thisCandidateType = getCandidatePdgId(&aCand, isAOD);
375  if (thisCandidateType != reco::PFCandidate::h)
376  continue;
377 
378  if ((options & PT_MIN_THRESH) && aCand.pt() < ptMin)
379  continue;
380 
381  chargedCands.emplace_back(&aCand, isAOD);
382  }
383 
384  // Calculate isolation sum separately for each vertex
385  for (unsigned int ivtx = 0; ivtx < vertices.size(); ++ivtx) {
386  // Shift the photon according to the vertex
387  const reco::VertexRef vtx(&vertices, ivtx);
388  math::XYZVector phoWrtVtx(photon.superCluster()->x() - vtx->x(),
389  photon.superCluster()->y() - vtx->y(),
390  photon.superCluster()->z() - vtx->z());
391 
392  const float phoWrtVtxPhi = phoWrtVtx.phi();
393  const float phoWrtVtxEta = phoWrtVtx.eta();
394 
395  float sum = 0;
396  // Loop over the PFCandidates
397  for (auto const& aCCand : chargedCands) {
398  auto iCand = aCCand.candidate;
399  float dR2 = deltaR2(phoWrtVtxEta, phoWrtVtxPhi, iCand->eta(), iCand->phi());
400  if (dR2 > coneSizeDR2 || (options & DR_VETO && dR2 < dRveto2))
401  continue;
402 
403  float dxy = -999;
404  float dz = -999;
405  if (options & PV_CONSTRAINT)
406  getImpactParameters(aCCand, pv, dxy, dz);
407  else
408  getImpactParameters(aCCand, *vtx, dxy, dz);
409 
410  if (fabs(dxy) > dxyMax || fabs(dz) > dzMax)
411  continue;
412 
413  sum += iCand->pt();
414  }
415 
416  worstIsolation = std::max(sum, worstIsolation);
417  }
418 
419  return worstIsolation;
420 }
421 
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
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:133
ParticleType
particle types
Definition: PFCandidate.h:44
void produce(edm::StreamID, edm::Event &, const edm::EventSetup &) const override
tuple cfg
Definition: looper.py:296
const unsigned char PV_CONSTRAINT
key_type key() const
Definition: Ptr.h:163
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:539
constexpr bool isNotFinite(T x)
Definition: isFinite.h:9
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
double y() const
y coordinate
Definition: Vertex.h:131
constexpr float ptMin
PhotonIDValueMapProducer(const edm::ParameterSet &)
size_type size() const
std::vector< Vertex > VertexCollection
collection of Vertex objects
Definition: VertexFwd.h:9
constexpr float dRveto2Endcap
constexpr float coneSizeDR2
EcalClusterLazyToolsT< noZS::EcalClusterTools > EcalClusterLazyTools
const Point & position() const
position
Definition: Vertex.h:127
const std::string names[nVars_]
constexpr float dzMax
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
const unsigned char PT_MIN_THRESH
const edm::EDGetTokenT< EcalRecHitCollection > eeRecHits_
char const * label
Handle< PROD > getHandle(EDGetTokenT< PROD > token) const
Definition: Event.h:563
int iEvent
Definition: GenABIO.cc:224
constexpr float dxyMax
reco::SuperClusterRef superCluster() const override
Ref to SuperCluster.
const EcalClusterLazyTools::ESGetTokens ecalClusterToolsESGetTokens_
ConsumesCollector consumesCollector()
Use a ConsumesCollector to gather consumes information from helper functions.
T sqrt(T t)
Definition: SSEVec.h:19
def move
Definition: eostools.py:511
const edm::EDGetTokenT< EcalRecHitCollection > ebRecHits_
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
double z() const
z coordinate
Definition: Vertex.h:133
ParameterDescriptionBase * add(U const &iLabel, T const &value)
constexpr float dRveto2Barrel
ESData get(edm::EventSetup const &eventSetup) const
double x() const
x coordinate
Definition: Vertex.h:129
constexpr auto deltaR2(const T1 &t1, const T2 &t2) -> decltype(t1.eta())
Definition: deltaR.h:16
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_
bool isEB() const
Definition: Photon.h:120
edm::Ptr< pat::Photon > patPhotonPtr
Particle reconstructed by the particle flow algorithm.
Definition: PFCandidate.h:41
constexpr int nVars_
string end
Definition: dataset.py:937
const edm::EDGetToken particleBasedIsolationToken_
vars
Definition: DeepTauId.cc:164
edm::Ref< l1t::PFCandidateCollection > PFCandidateRef
Definition: PFCandidate.h:58
long double T
const edm::EDGetTokenT< edm::View< reco::Photon > > src_