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
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 
117  const bool isAOD_;
118 };
119 
120 constexpr int nVars_ = 19;
121 
123  // Cluster shapes
124  "phoFull5x5SigmaIEtaIEta", // 0
125  "phoFull5x5SigmaIEtaIPhi",
126  "phoFull5x5E1x3",
127  "phoFull5x5E2x2",
128  "phoFull5x5E2x5Max",
129  "phoFull5x5E5x5", // 5
130  "phoESEffSigmaRR",
131  // Cluster shape ratios
132  "phoFull5x5E1x3byE5x5",
133  "phoFull5x5E2x2byE5x5",
134  "phoFull5x5E2x5byE5x5",
135  // Isolations
136  "phoChargedIsolation", // 10
137  "phoNeutralHadronIsolation",
138  "phoPhotonIsolation",
139  "phoWorstChargedIsolation",
140  "phoWorstChargedIsolationConeVeto",
141  "phoWorstChargedIsolationConeVetoPVConstr", // 15
142  // PFCluster Isolation
143  "phoTrkIsolation",
144  "phoHcalPFClIsolation",
145  "phoEcalPFClIsolation"};
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  src_(consumes<edm::View<reco::Photon>>(cfg.getParameter<edm::InputTag>("src"))),
162  ebRecHits_(consumes<EcalRecHitCollection>(cfg.getParameter<edm::InputTag>("ebReducedRecHitCollection"))),
163  eeRecHits_(consumes<EcalRecHitCollection>(cfg.getParameter<edm::InputTag>("eeReducedRecHitCollection"))),
164  esRecHits_(consumes<EcalRecHitCollection>(cfg.getParameter<edm::InputTag>("esReducedRecHitCollection"))),
165  vtxToken_(consumes<reco::VertexCollection>(cfg.getParameter<edm::InputTag>("vertices"))),
166  pfCandsToken_(consumes<edm::View<reco::Candidate>>(cfg.getParameter<edm::InputTag>("pfCandidates"))),
167  particleBasedIsolationToken_(mayConsume<edm::ValueMap<std::vector<reco::PFCandidateRef>>>(
168  cfg.getParameter<edm::InputTag>("particleBasedIsolation")) /* ...only for AOD... */),
169  isAOD_(cfg.getParameter<bool>("isAOD")) {
170  // Declare producibles
171  for (int i = 0; i < nVars_; ++i)
173 }
174 
176  // Get the handles
177  auto src = iEvent.getHandle(src_);
178  auto vertices = iEvent.getHandle(vtxToken_);
179  auto pfCandsHandle = iEvent.getHandle(pfCandsToken_);
180 
182  if (isAOD_) { // this exists only in AOD
183  iEvent.getByToken(particleBasedIsolationToken_, particleBasedIsolationMap);
184  } else if (!src->empty()) {
185  edm::Ptr<pat::Photon> test(src->ptrAt(0));
186  if (test.isNull() || !test.isAvailable()) {
187  throw cms::Exception("InvalidConfiguration")
188  << "DataFormat is detected as miniAOD but cannot cast to pat::Photon!";
189  }
190  }
191 
192  // Configure Lazy Tools, which will compute 5x5 quantities
193  auto lazyToolnoZS = usesES_ ? noZS::EcalClusterLazyTools(iEvent, iSetup, ebRecHits_, eeRecHits_, esRecHits_)
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 (auto const& iPho : src->ptrs()) {
205  //
206  // Compute full 5x5 quantities
207  //
208  const auto& seed = *(iPho->superCluster()->seed());
209 
210  // For full5x5_sigmaIetaIeta, for 720 we use: lazy tools for AOD,
211  // and userFloats or lazy tools for miniAOD. From some point in 72X and on, one can
212  // retrieve the full5x5 directly from the object with ->full5x5_sigmaIetaIeta()
213  // for both formats.
214  std::vector<float> vCov = lazyToolnoZS.localCovariances(seed);
215  vars[0].push_back(edm::isNotFinite(vCov[0]) ? 0. : sqrt(vCov[0]));
216  vars[1].push_back(vCov[1]);
217  vars[2].push_back(lazyToolnoZS.e1x3(seed));
218  vars[3].push_back(lazyToolnoZS.e2x2(seed));
219  vars[4].push_back(lazyToolnoZS.e2x5Max(seed));
220  vars[5].push_back(lazyToolnoZS.e5x5(seed));
221  vars[6].push_back(lazyToolnoZS.eseffsirir(*(iPho->superCluster())));
222  vars[7].push_back(vars[2].back() / vars[5].back());
223  vars[8].push_back(vars[3].back() / vars[5].back());
224  vars[9].push_back(vars[4].back() / vars[5].back());
225 
226  //
227  // Compute absolute uncorrected isolations with footprint removal
228  //
229 
230  // First, find photon direction with respect to the good PV
231  math::XYZVector phoWrtVtx(
232  iPho->superCluster()->x() - pv.x(), iPho->superCluster()->y() - pv.y(), iPho->superCluster()->z() - pv.z());
233 
234  // isolation sums
235  float chargedIsoSum = 0.;
236  float neutralHadronIsoSum = 0.;
237  float photonIsoSum = 0.;
238 
239  // Loop over all PF candidates
240  for (auto const& iCand : pfCandsHandle->ptrs()) {
241  // Here, the type will be a simple reco::Candidate. We cast it
242  // for full PFCandidate or PackedCandidate below as necessary
243 
244  // One would think that we should check that this iCand from the
245  // generic PF collection is not identical to the iPho photon for
246  // which we are computing the isolations. However, it turns out to
247  // be unnecessary. Below, in the function isInFootprint(), we drop
248  // this iCand if it is in the footprint, and this always removes
249  // the iCand if it matches the iPho. The explicit check at this
250  // point is not totally trivial because of non-triviality of
251  // implementation of this check for miniAOD (PackedCandidates of
252  // the PF collection do not contain the supercluser link, so can't
253  // use that).
254  //
255  // if( isAOD_ ) {
256  // if( ((const edm::Ptr<reco::PFCandidate>)iCand)->superClusterRef() == iPho->superCluster() )
257  // continue;
258  // }
259 
260  // Check if this candidate is within the isolation cone
261  float dR2 = deltaR2(phoWrtVtx.Eta(), phoWrtVtx.Phi(), iCand->eta(), iCand->phi());
262  if (dR2 > coneSizeDR2)
263  continue;
264 
265  // Check if this candidate is not in the footprint
266  if (isAOD_) {
267  if (isInFootprint((*particleBasedIsolationMap)[iPho], iCand))
268  continue;
269  } else {
271  if (isInFootprint(patPhotonPtr->associatedPackedPFCandidates(), iCand))
272  continue;
273  }
274 
275  // Find candidate type
276  reco::PFCandidate::ParticleType thisCandidateType = getCandidatePdgId(&*iCand, isAOD_);
277 
278  // Increment the appropriate isolation sum
279  if (thisCandidateType == reco::PFCandidate::h) {
280  // for charged hadrons, additionally check consistency
281  // with the PV
282  float dxy = -999;
283  float dz = -999;
284 
285  getImpactParameters(CachingPtrCandidate(&*iCand, isAOD_), pv, dxy, dz);
286 
287  if (fabs(dxy) > dxyMax || fabs(dz) > dzMax)
288  continue;
289 
290  // The candidate is eligible, increment the isolaiton
291  chargedIsoSum += iCand->pt();
292  }
293 
294  if (thisCandidateType == reco::PFCandidate::h0)
295  neutralHadronIsoSum += iCand->pt();
296 
297  if (thisCandidateType == reco::PFCandidate::gamma)
298  photonIsoSum += iCand->pt();
299  }
300 
301  vars[10].push_back(chargedIsoSum);
302  vars[11].push_back(neutralHadronIsoSum);
303  vars[12].push_back(photonIsoSum);
304 
305  // Worst isolation computed with no vetos or ptMin cut, as in Run 1 Hgg code.
306  unsigned char options = 0;
307  vars[13].push_back(computeWorstPFChargedIsolation(*iPho, *pfCandsHandle, *vertices, pv, options, isAOD_));
308 
309  // Worst isolation computed with cone vetos and a ptMin cut, as in Run 2 Hgg code.
310  options |= PT_MIN_THRESH | DR_VETO;
311  vars[14].push_back(computeWorstPFChargedIsolation(*iPho, *pfCandsHandle, *vertices, pv, options, isAOD_));
312 
313  // Like before, but adding primary vertex constraint
314  options |= PV_CONSTRAINT;
315  vars[15].push_back(computeWorstPFChargedIsolation(*iPho, *pfCandsHandle, *vertices, pv, options, isAOD_));
316 
317  // PFCluster Isolations
318  vars[16].push_back(iPho->trkSumPtSolidConeDR04());
319  if (isAOD_) {
320  vars[17].push_back(0.f);
321  vars[18].push_back(0.f);
322  } else {
324  vars[17].push_back(patPhotonPtr->hcalPFClusterIso());
325  vars[18].push_back(patPhotonPtr->ecalPFClusterIso());
326  }
327  }
328 
329  // write the value maps
330  for (int i = 0; i < nVars_; ++i) {
331  auto valMap = std::make_unique<edm::ValueMap<float>>();
332  typename edm::ValueMap<float>::Filler filler(*valMap);
333  filler.insert(src, vars[i].begin(), vars[i].end());
334  filler.fill();
335  iEvent.put(std::move(valMap), names[i]);
336  }
337 }
338 
340  // photonIDValueMapProducer
342  desc.add<edm::InputTag>("particleBasedIsolation", edm::InputTag("particleBasedIsolation", "gedPhotons"));
343  desc.add<edm::InputTag>("src", edm::InputTag("slimmedPhotons", "", "@skipCurrentProcess"));
344  desc.add<edm::InputTag>("esReducedRecHitCollection", edm::InputTag("reducedEgamma", "reducedESRecHits"));
345  desc.add<edm::InputTag>("ebReducedRecHitCollection", edm::InputTag("reducedEgamma", "reducedEBRecHits"));
346  desc.add<edm::InputTag>("eeReducedRecHitCollection", edm::InputTag("reducedEgamma", "reducedEERecHits"));
347  desc.add<edm::InputTag>("pfCandidates", edm::InputTag("packedPFCandidates"));
348  desc.add<edm::InputTag>("vertices", edm::InputTag("offlineSlimmedPrimaryVertices"));
349  desc.add<bool>("isAOD", false);
350  descriptions.add("photonIDValueMapProducer", desc);
351 }
352 
353 // Charged isolation with respect to the worst vertex. See more
354 // comments above at the function declaration.
356  const edm::View<reco::Candidate>& pfCands,
358  const reco::Vertex& pv,
359  unsigned char options,
360  bool isAOD) const {
361  float worstIsolation = 0.0;
362 
363  const float dRveto2 = photon.isEB() ? dRveto2Barrel : dRveto2Endcap;
364 
365  std::vector<CachingPtrCandidate> chargedCands;
366  chargedCands.reserve(pfCands.size());
367  for (auto const& aCand : pfCands) {
368  // require that PFCandidate is a charged hadron
369  reco::PFCandidate::ParticleType thisCandidateType = getCandidatePdgId(&aCand, isAOD);
370  if (thisCandidateType != reco::PFCandidate::h)
371  continue;
372 
373  if ((options & PT_MIN_THRESH) && aCand.pt() < ptMin)
374  continue;
375 
376  chargedCands.emplace_back(&aCand, isAOD);
377  }
378 
379  // Calculate isolation sum separately for each vertex
380  for (unsigned int ivtx = 0; ivtx < vertices.size(); ++ivtx) {
381  // Shift the photon according to the vertex
382  const reco::VertexRef vtx(&vertices, ivtx);
383  math::XYZVector phoWrtVtx(photon.superCluster()->x() - vtx->x(),
384  photon.superCluster()->y() - vtx->y(),
385  photon.superCluster()->z() - vtx->z());
386 
387  const float phoWrtVtxPhi = phoWrtVtx.phi();
388  const float phoWrtVtxEta = phoWrtVtx.eta();
389 
390  float sum = 0;
391  // Loop over the PFCandidates
392  for (auto const& aCCand : chargedCands) {
393  auto iCand = aCCand.candidate;
394  float dR2 = deltaR2(phoWrtVtxEta, phoWrtVtxPhi, iCand->eta(), iCand->phi());
395  if (dR2 > coneSizeDR2 || (options & DR_VETO && dR2 < dRveto2))
396  continue;
397 
398  float dxy = -999;
399  float dz = -999;
400  if (options & PV_CONSTRAINT)
401  getImpactParameters(aCCand, pv, dxy, dz);
402  else
403  getImpactParameters(aCCand, *vtx, dxy, dz);
404 
405  if (fabs(dxy) > dxyMax || fabs(dz) > dzMax)
406  continue;
407 
408  sum += iCand->pt();
409  }
410 
411  worstIsolation = std::max(sum, worstIsolation);
412  }
413 
414  return worstIsolation;
415 }
416 
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
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:131
ParticleType
particle types
Definition: PFCandidate.h:43
Definition: Photon.py:1
const unsigned char PV_CONSTRAINT
key_type key() const
Definition: Ptr.h:163
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:525
constexpr bool isNotFinite(T x)
Definition: isFinite.h:9
double y() const
y coordinate
Definition: Vertex.h:117
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 &)
size_type size() const
std::vector< Vertex > VertexCollection
collection of Vertex objects
Definition: VertexFwd.h:9
reco::SuperClusterRef superCluster() const override
Ref to SuperCluster.
EcalClusterLazyToolsT< noZS::EcalClusterTools > EcalClusterLazyTools
float dRveto2Barrel
const Point & position() const
position
Definition: Vertex.h:113
const std::string names[nVars_]
Definition: HeavyIon.h:7
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:547
float coneSizeDR2
int iEvent
Definition: GenABIO.cc:224
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
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 z() const
z coordinate
Definition: Vertex.h:119
double f[11][100]
#define end
Definition: vmac.h:39
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:115
const edm::EDGetTokenT< reco::VertexCollection > vtxToken_
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
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)
void produce(edm::StreamID, edm::Event &, const edm::EventSetup &) const override
const edm::EDGetTokenT< EcalRecHitCollection > esRecHits_
bool isEB() const
Definition: Photon.h:119
edm::Ptr< pat::Photon > patPhotonPtr
Particle reconstructed by the particle flow algorithm.
Definition: PFCandidate.h:40
fixed size matrix
#define begin
Definition: vmac.h:32
HLT enums.
const edm::EDGetToken particleBasedIsolationToken_
vars
Definition: DeepTauId.cc:158
long double T
const edm::EDGetTokenT< edm::View< reco::Photon > > src_
def move(src, dest)
Definition: eostools.py:511
#define constexpr