CMS 3D CMS Logo

RecoTauConstructor.cc
Go to the documentation of this file.
2 
5 
7 
9 
10 namespace reco::tau {
11 
13  const edm::Handle<edm::View<reco::Candidate> >& pfCands,
14  bool copyGammasFromPiZeros,
20  : signalConeSize_(signalConeSize),
21  minAbsPhotonSumPt_insideSignalCone_(minAbsPhotonSumPt_insideSignalCone),
22  minRelPhotonSumPt_insideSignalCone_(minRelPhotonSumPt_insideSignalCone),
23  minAbsPhotonSumPt_outsideSignalCone_(minAbsPhotonSumPt_outsideSignalCone),
24  minRelPhotonSumPt_outsideSignalCone_(minRelPhotonSumPt_outsideSignalCone),
25  pfCands_(pfCands) {
26  // Initialize tau
27  tau_.reset(new PFTau());
28 
29  copyGammas_ = copyGammasFromPiZeros;
30  // Initialize our Accessors
31  collections_[std::make_pair(kSignal, kChargedHadron)] = &tau_->selectedSignalChargedHadrCands_;
32  collections_[std::make_pair(kSignal, kGamma)] = &tau_->selectedSignalGammaCands_;
33  collections_[std::make_pair(kSignal, kNeutralHadron)] = &tau_->selectedSignalNeutrHadrCands_;
34  collections_[std::make_pair(kSignal, kAll)] = &tau_->selectedSignalCands_;
35 
36  collections_[std::make_pair(kIsolation, kChargedHadron)] = &tau_->selectedIsolationChargedHadrCands_;
37  collections_[std::make_pair(kIsolation, kGamma)] = &tau_->selectedIsolationGammaCands_;
38  collections_[std::make_pair(kIsolation, kNeutralHadron)] = &tau_->selectedIsolationNeutrHadrCands_;
39  collections_[std::make_pair(kIsolation, kAll)] = &tau_->selectedIsolationCands_;
40 
41  // Build our temporary sorted collections, since you can't use stl sorts on
42  // RefVectors
43  for (auto const& colkey : collections_) {
44  // Build an empty list for each collection
45  sortedCollections_[colkey.first] = SortedListPtr(new SortedListPtr::element_type);
46  }
47 
48  tau_->setjetRef(jet);
49  }
50 
52  LogDebug("TauConstructorAddPFCand") << " region = " << region << ", type = " << type << ": Pt = " << ptr->pt()
53  << ", eta = " << ptr->eta() << ", phi = " << ptr->phi();
54  if (region == kSignal) {
55  // Keep track of the four vector of the signal vector products added so far.
56  // If a photon add it if we are not using PiZeros to build the gammas
57  if (((type != kGamma) || !copyGammas_) && !skipAddToP4) {
58  LogDebug("TauConstructorAddPFCand") << "--> adding PFCand to tauP4.";
59  p4_ += ptr->p4();
60  }
61  }
62  getSortedCollection(region, type)->push_back(ptr);
63  // Add to global collection
64  getSortedCollection(region, kAll)->push_back(ptr);
65  }
66 
68  getSortedCollection(region, type)->reserve(size);
69  getCollection(region, type)->reserve(size);
70  // Reserve global collection as well
71  getSortedCollection(region, kAll)->reserve(getSortedCollection(region, kAll)->size() + size);
72  getCollection(region, kAll)->reserve(getCollection(region, kAll)->size() + size);
73  }
74 
76  if (region == kSignal) {
77  tau_->signalTauChargedHadronCandidatesRestricted().reserve(size);
78  tau_->selectedSignalChargedHadrCands_.reserve(size);
79  } else {
80  tau_->isolationTauChargedHadronCandidatesRestricted().reserve(size);
81  tau_->selectedIsolationChargedHadrCands_.reserve(size);
82  }
83  }
84 
85  namespace {
86  void checkOverlap(const CandidatePtr& neutral, const std::vector<CandidatePtr>& pfGammas, bool& isUnique) {
87  LogDebug("TauConstructorCheckOverlap") << " pfGammas: #entries = " << pfGammas.size();
88  for (std::vector<CandidatePtr>::const_iterator pfGamma = pfGammas.begin(); pfGamma != pfGammas.end(); ++pfGamma) {
89  LogDebug("TauConstructorCheckOverlap") << "pfGamma = " << pfGamma->id() << ":" << pfGamma->key();
90  if ((*pfGamma).refCore() == neutral.refCore() && (*pfGamma).key() == neutral.key())
91  isUnique = false;
92  }
93  }
94 
95  void checkOverlap(const CandidatePtr& neutral, const std::vector<reco::RecoTauPiZero>& piZeros, bool& isUnique) {
96  LogDebug("TauConstructorCheckOverlap") << " piZeros: #entries = " << piZeros.size();
97  for (std::vector<reco::RecoTauPiZero>::const_iterator piZero = piZeros.begin(); piZero != piZeros.end();
98  ++piZero) {
99  size_t numPFGammas = piZero->numberOfDaughters();
100  for (size_t iPFGamma = 0; iPFGamma < numPFGammas; ++iPFGamma) {
101  reco::CandidatePtr pfGamma = piZero->daughterPtr(iPFGamma);
102  LogDebug("TauConstructorCheckOverlap") << "pfGamma = " << pfGamma.id() << ":" << pfGamma.key();
103  if (pfGamma.id() == neutral.id() && pfGamma.key() == neutral.key())
104  isUnique = false;
105  }
106  }
107  }
108  } // namespace
109 
111  LogDebug("TauConstructorAddChH") << " region = " << region << ": Pt = " << chargedHadron.pt()
112  << ", eta = " << chargedHadron.eta() << ", phi = " << chargedHadron.phi();
113  // CV: need to make sure that PFGammas merged with ChargedHadrons are not part of PiZeros
114  const std::vector<CandidatePtr>& neutrals = chargedHadron.getNeutralPFCandidates();
115  std::vector<CandidatePtr> neutrals_cleaned;
116  for (std::vector<CandidatePtr>::const_iterator neutral = neutrals.begin(); neutral != neutrals.end(); ++neutral) {
117  LogDebug("TauConstructorAddChH") << "neutral = " << neutral->id() << ":" << neutral->key();
118  bool isUnique = true;
119  if (copyGammas_)
120  checkOverlap(*neutral, *getSortedCollection(kSignal, kGamma), isUnique);
121  else
122  checkOverlap(*neutral, tau_->signalPiZeroCandidatesRestricted(), isUnique);
123  if (region == kIsolation) {
124  if (copyGammas_)
125  checkOverlap(*neutral, *getSortedCollection(kIsolation, kGamma), isUnique);
126  else
127  checkOverlap(*neutral, tau_->isolationPiZeroCandidatesRestricted(), isUnique);
128  }
129  LogDebug("TauConstructorAddChH") << "--> isUnique = " << isUnique;
130  if (isUnique)
131  neutrals_cleaned.push_back(*neutral);
132  }
133  PFRecoTauChargedHadron chargedHadron_cleaned = chargedHadron;
134  if (neutrals_cleaned.size() != neutrals.size()) {
135  chargedHadron_cleaned.neutralPFCandidates_ = neutrals_cleaned;
136  setChargedHadronP4(chargedHadron_cleaned);
137  }
138  if (region == kSignal) {
139  tau_->signalTauChargedHadronCandidatesRestricted().push_back(chargedHadron_cleaned);
140  p4_ += chargedHadron_cleaned.p4();
141  if (chargedHadron_cleaned.getChargedPFCandidate().isNonnull()) {
142  addPFCand(kSignal, kChargedHadron, convertToPtr(chargedHadron_cleaned.getChargedPFCandidate()), true);
143  }
144  const std::vector<CandidatePtr>& neutrals = chargedHadron_cleaned.getNeutralPFCandidates();
145  for (std::vector<CandidatePtr>::const_iterator neutral = neutrals.begin(); neutral != neutrals.end(); ++neutral) {
146  if (std::abs((*neutral)->pdgId()) == 22)
147  addPFCand(kSignal, kGamma, convertToPtr(*neutral), true);
148  else if (std::abs((*neutral)->pdgId()) == 130)
149  addPFCand(kSignal, kNeutralHadron, convertToPtr(*neutral), true);
150  };
151  } else {
152  tau_->isolationTauChargedHadronCandidatesRestricted().push_back(chargedHadron_cleaned);
153  if (chargedHadron_cleaned.getChargedPFCandidate().isNonnull()) {
154  if (std::abs(chargedHadron_cleaned.getChargedPFCandidate()->pdgId()) == 211)
156  else if (std::abs(chargedHadron_cleaned.getChargedPFCandidate()->pdgId()) == 130)
158  }
159  const std::vector<CandidatePtr>& neutrals = chargedHadron_cleaned.getNeutralPFCandidates();
160  for (std::vector<CandidatePtr>::const_iterator neutral = neutrals.begin(); neutral != neutrals.end(); ++neutral) {
161  if (std::abs((*neutral)->pdgId()) == 22)
163  else if (std::abs((*neutral)->pdgId()) == 130)
165  };
166  }
167  }
168 
170  if (region == kSignal) {
171  tau_->signalPiZeroCandidatesRestricted().reserve(size);
172  // If we are building the gammas with the pizeros, resize that
173  // vector as well
174  if (copyGammas_)
175  reserve(kSignal, kGamma, 2 * size);
176  } else {
177  tau_->isolationPiZeroCandidatesRestricted().reserve(size);
178  if (copyGammas_)
179  reserve(kIsolation, kGamma, 2 * size);
180  }
181  }
182 
184  LogDebug("TauConstructorAddPi0") << " region = " << region << ": Pt = " << piZero.pt() << ", eta = " << piZero.eta()
185  << ", phi = " << piZero.phi();
186  if (region == kSignal) {
187  tau_->signalPiZeroCandidatesRestricted().push_back(piZero);
188  // Copy the daughter gammas into the gamma collection if desired
189  if (copyGammas_) {
190  // If we are using the pizeros to build the gammas, make sure we update
191  // the four vector correctly.
192  p4_ += piZero.p4();
193  addPFCands(kSignal, kGamma, piZero.daughterPtrVector().begin(), piZero.daughterPtrVector().end());
194  }
195  } else {
196  tau_->isolationPiZeroCandidatesRestricted().push_back(piZero);
197  if (copyGammas_) {
198  addPFCands(kIsolation, kGamma, piZero.daughterPtrVector().begin(), piZero.daughterPtrVector().end());
199  }
200  }
201  }
202 
204  return collections_[std::make_pair(region, type)];
205  }
206 
208  return sortedCollections_[std::make_pair(region, type)];
209  }
210 
211  // Trivial converter needed for polymorphism
212  CandidatePtr RecoTauConstructor::convertToPtr(const CandidatePtr& pfPtr) const { return pfPtr; }
213 
214  namespace {
215  // Make sure the two products come from the same EDM source
216  template <typename T1, typename T2>
217  void checkMatchedProductIds(const T1& t1, const T2& t2) {
218  if (t1.id() != t2.id()) {
219  throw cms::Exception("MismatchedPFCandSrc")
220  << "Error: the input tag"
221  << " for the PF candidate collection provided to the RecoTauBuilder "
222  << " does not match the one that was used to build the source jets."
223  << " Please update the pfCandSrc paramters for the PFTau builders.";
224  }
225  }
226  } // namespace
227 
228  // Convert from a CandidateRef to a Ptr
230  if (candPtr.isNonnull()) {
231  checkMatchedProductIds(candPtr, pfCands_);
232  return CandidatePtr(pfCands_, candPtr.key());
233  } else
234  return PFCandidatePtr();
235  }
236 
237  namespace {
238  template <typename T>
239  bool ptDescending(const T& a, const T& b) {
240  return a.pt() > b.pt();
241  }
242  template <typename T>
243  bool ptDescendingPtr(const T& a, const T& b) {
244  return a->pt() > b->pt();
245  }
246  } // namespace
247 
249  // The charged hadrons and pizeros are a special case, as we can sort them in situ
250  std::sort(tau_->signalTauChargedHadronCandidatesRestricted().begin(),
251  tau_->signalTauChargedHadronCandidatesRestricted().end(),
252  ptDescending<PFRecoTauChargedHadron>);
253  std::sort(tau_->isolationTauChargedHadronCandidatesRestricted().begin(),
254  tau_->isolationTauChargedHadronCandidatesRestricted().end(),
255  ptDescending<PFRecoTauChargedHadron>);
256  std::sort(tau_->signalPiZeroCandidatesRestricted().begin(),
257  tau_->signalPiZeroCandidatesRestricted().end(),
258  ptDescending<RecoTauPiZero>);
259  std::sort(tau_->isolationPiZeroCandidatesRestricted().begin(),
260  tau_->isolationPiZeroCandidatesRestricted().end(),
261  ptDescending<RecoTauPiZero>);
262 
263  // Sort each of our sortable collections, and copy them into the final
264  // tau RefVector.
265  for (auto const& colkey : collections_) {
266  SortedListPtr sortedCollection = sortedCollections_[colkey.first];
267  std::sort(sortedCollection->begin(), sortedCollection->end(), ptDescendingPtr<CandidatePtr>);
268  // Copy into the real tau collection
269  for (std::vector<CandidatePtr>::const_iterator particle = sortedCollection->begin();
270  particle != sortedCollection->end();
271  ++particle) {
272  colkey.second->push_back(*particle);
273  }
274  }
275  }
276 
277  namespace {
278  PFTau::hadronicDecayMode calculateDecayMode(const reco::PFTau& tau,
279  double dRsignalCone,
284  unsigned int nCharged = tau.signalTauChargedHadronCandidates().size();
285  // If no tracks exist, this is definitely not a tau!
286  if (!nCharged)
287  return PFTau::kNull;
288 
289  unsigned int nPiZeros = 0;
290  const std::vector<RecoTauPiZero>& piZeros = tau.signalPiZeroCandidates();
291  for (std::vector<RecoTauPiZero>::const_iterator piZero = piZeros.begin(); piZero != piZeros.end(); ++piZero) {
292  double photonSumPt_insideSignalCone = 0.;
293  double photonSumPt_outsideSignalCone = 0.;
294  int numPhotons = piZero->numberOfDaughters();
295  for (int idxPhoton = 0; idxPhoton < numPhotons; ++idxPhoton) {
296  const reco::Candidate* photon = piZero->daughter(idxPhoton);
297  double dR = deltaR(photon->p4(), tau.p4());
298  if (dR < dRsignalCone) {
299  photonSumPt_insideSignalCone += photon->pt();
300  } else {
301  photonSumPt_outsideSignalCone += photon->pt();
302  }
303  }
304  if (photonSumPt_insideSignalCone > minAbsPhotonSumPt_insideSignalCone ||
305  photonSumPt_insideSignalCone > (minRelPhotonSumPt_insideSignalCone * tau.pt()) ||
306  photonSumPt_outsideSignalCone > minAbsPhotonSumPt_outsideSignalCone ||
307  photonSumPt_outsideSignalCone > (minRelPhotonSumPt_outsideSignalCone * tau.pt()))
308  ++nPiZeros;
309  }
310 
311  // Find the maximum number of PiZeros our parameterization can hold
312  const unsigned int maxPiZeros = PFTau::kOneProngNPiZero;
313 
314  // Determine our track index
315  unsigned int trackIndex = (nCharged - 1) * (maxPiZeros + 1);
316 
317  // Check if we handle the given number of tracks
318  if (trackIndex >= PFTau::kRareDecayMode)
319  return PFTau::kRareDecayMode;
320 
321  if (nPiZeros > maxPiZeros)
322  nPiZeros = maxPiZeros;
323  return static_cast<PFTau::hadronicDecayMode>(trackIndex + nPiZeros);
324  }
325  } // namespace
326 
327  std::unique_ptr<reco::PFTau> RecoTauConstructor::get(bool setupLeadingObjects) {
328  LogDebug("TauConstructorGet") << "Start getting";
329 
330  // Copy the sorted collections into the interal tau refvectors
332 
333  // Setup all the important member variables of the tau
334  // Set charge of tau
335  // tau_->setCharge(
336  // sumPFCandCharge(getCollection(kSignal, kChargedHadron)->begin(),
337  // getCollection(kSignal, kChargedHadron)->end()));
338  // CV: take charge of highest pT charged hadron as charge of tau,
339  // in case tau does not have three reconstructed tracks
340  // (either because tau is reconstructed as 2prong or because PFRecoTauChargedHadron is built from a PFNeutralHadron)
341  unsigned int nCharged = 0;
342  int charge = 0;
343  double leadChargedHadronPt = 0.;
344  int leadChargedHadronCharge = 0;
345  for (std::vector<PFRecoTauChargedHadron>::const_iterator chargedHadron =
346  tau_->signalTauChargedHadronCandidatesRestricted().begin();
347  chargedHadron != tau_->signalTauChargedHadronCandidatesRestricted().end();
348  ++chargedHadron) {
351  ++nCharged;
352  charge += chargedHadron->charge();
353  if (chargedHadron->pt() > leadChargedHadronPt) {
354  leadChargedHadronPt = chargedHadron->pt();
355  leadChargedHadronCharge = chargedHadron->charge();
356  }
357  }
358  }
359  if (nCharged == 3)
360  tau_->setCharge(charge);
361  else
362  tau_->setCharge(leadChargedHadronCharge);
363 
364  // Set PDG id
365  tau_->setPdgId(tau_->charge() < 0 ? 15 : -15);
366 
367  // Set P4
368  tau_->setP4(p4_);
369 
370  // Set Decay Mode
371  double dRsignalCone = (signalConeSize_) ? (*signalConeSize_)(*tau_) : 0.5;
372  tau_->setSignalConeSize(dRsignalCone);
373  PFTau::hadronicDecayMode dm = calculateDecayMode(*tau_,
374  dRsignalCone,
379  tau_->setDecayMode(dm);
380 
381  LogDebug("TauConstructorGet") << "Pt = " << tau_->pt() << ", eta = " << tau_->eta() << ", phi = " << tau_->phi()
382  << ", mass = " << tau_->mass() << ", dm = " << tau_->decayMode();
383 
384  // Set charged isolation quantities
385  tau_->setisolationPFChargedHadrCandsPtSum(sumPFCandPt(getCollection(kIsolation, kChargedHadron)->begin(),
387 
388  // Set gamma isolation quantities
389  tau_->setisolationPFGammaCandsEtSum(
391 
392  // Set em fraction
394  tau_->pt());
395 
396  if (setupLeadingObjects) {
397  typedef std::vector<CandidatePtr>::const_iterator Iter;
398  // Find the highest PT object in the signal cone
399  Iter leadingCand = leadCand(getCollection(kSignal, kAll)->begin(), getCollection(kSignal, kAll)->end());
400 
401  if (leadingCand != getCollection(kSignal, kAll)->end())
402  tau_->setleadCand(*leadingCand);
403 
404  // Hardest charged object in signal cone
405  Iter leadingChargedCand =
407 
408  if (leadingChargedCand != getCollection(kSignal, kChargedHadron)->end())
409  tau_->setleadChargedHadrCand(*leadingChargedCand);
410 
411  // Hardest gamma object in signal cone
412  Iter leadingGammaCand = leadCand(getCollection(kSignal, kGamma)->begin(), getCollection(kSignal, kGamma)->end());
413 
414  if (leadingGammaCand != getCollection(kSignal, kGamma)->end())
415  tau_->setleadNeutralCand(*leadingGammaCand);
416  }
417  return std::move(tau_);
418  }
419 } // end namespace reco::tau
#define LogDebug(id)
void addPFCand(Region region, ParticleType type, const CandidatePtr &ptr, bool skipAddToP4=false)
Append a PFCandidateRef/Ptr to a given collection.
size
Write out results.
type
Definition: HCALResponse.h:21
minRelPhotonSumPt_outsideSignalCone
void addTauChargedHadron(Region region, const PFRecoTauChargedHadron &chargedHadron)
Add a ChargedHadron to the given collection.
reco::Candidate::LorentzVector p4_
void reserve(Region region, ParticleType type, size_t size)
Reserve a set amount of space for a given RefVector.
double eta() const final
momentum pseudorapidity
double sumPFCandPt(InputIterator begin, InputIterator end)
Sum the pT of a collection of PFCandidates.
key_type key() const
Definition: Ptr.h:163
std::vector< CandidatePtr > * getCollection(Region region, ParticleType type)
std::unique_ptr< reco::PFTau > tau_
minAbsPhotonSumPt_insideSignalCone
double pt() const final
transverse momentum
minAbsPhotonSumPt_outsideSignalCone
std::unique_ptr< reco::PFTau > get(bool setupLeadingCandidates=true)
InputIterator leadCand(InputIterator begin, InputIterator end)
virtual const daughters & daughterPtrVector() const
references to daughtes
const edm::Handle< edm::View< reco::Candidate > > & pfCands_
SortedCollectionMap sortedCollections_
virtual const LorentzVector & p4() const =0
four-momentum Lorentz vector
const std::vector< RecoTauPiZero > & signalPiZeroCandidates() const
Retrieve the association of signal region gamma candidates into candidate PiZeros.
Definition: PFTau.cc:239
SortedListPtr getSortedCollection(Region region, ParticleType type)
RefCore const & refCore() const
Definition: Ptr.h:167
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
const LorentzVector & p4() const final
four-momentum Lorentz vector
minRelPhotonSumPt_insideSignalCone
#define end
Definition: vmac.h:39
std::vector< CandidatePtr > neutralPFCandidates_
void addPFCands(Region region, ParticleType type, const InputIterator &begin, const InputIterator &end)
bool isNonnull() const
Checks for non-null.
Definition: Ptr.h:146
constexpr auto deltaR(const T1 &t1, const T2 &t2) -> decltype(t1.eta())
Definition: deltaR.h:30
edm::Ptr< Candidate > CandidatePtr
persistent reference to an object in a collection of Candidate objects
Definition: CandidateFwd.h:25
virtual double pt() const =0
transverse momentum
void reserveTauChargedHadron(Region region, size_t size)
Reserve a set amount of space for the ChargedHadrons.
void reservePiZero(Region region, size_t size)
Reserve a set amount of space for the PiZeros.
double b
Definition: hdecay.h:118
ProductID id() const
Accessor for product ID.
Definition: Ptr.h:158
std::shared_ptr< std::vector< CandidatePtr > > SortedListPtr
def checkOverlap(process)
hadronicDecayMode
Definition: PFTau.h:38
#define begin
Definition: vmac.h:32
double a
Definition: hdecay.h:119
const std::vector< PFRecoTauChargedHadron > & signalTauChargedHadronCandidates() const
Retrieve the association of signal region PF candidates into candidate PFRecoTauChargedHadrons.
Definition: PFTau.cc:286
void addPiZero(Region region, const RecoTauPiZero &piZero)
Add a PiZero to the given collection.
const StringObjectFunction< reco::PFTau > * signalConeSize_
void setChargedHadronP4(reco::PFRecoTauChargedHadron &chargedHadron, double scaleFactor_neutralPFCands=1.0)
CandidatePtr convertToPtr(const PFCandidatePtr &pfPtr) const
long double T
const CandidatePtr & getChargedPFCandidate() const
reference to "charged" PFCandidate (either charged PFCandidate or PFNeutralHadron) ...
edm::Ptr< PFCandidate > PFCandidatePtr
persistent Ptr to a PFCandidate
double phi() const final
momentum azimuthal angle
def move(src, dest)
Definition: eostools.py:511
std::vector< CandidatePtr > pfGammas(const Jet &jet, bool sort=true)
Extract all pfGammas from a PFJet.
const std::vector< CandidatePtr > & getNeutralPFCandidates() const
references to additional neutral PFCandidates
RecoTauConstructor(const JetBaseRef &jetRef, const edm::Handle< edm::View< reco::Candidate > > &pfCands, bool copyGammasFromPiZeros=false, const StringObjectFunction< reco::PFTau > *signalConeSize=0, double minAbsPhotonSumPt_insideSignalCone=2.5, double minRelPhotonSumPt_insideSignalCone=0., double minAbsPhotonSumPt_outsideSignalCone=1.e+9, double minRelPhotonSumPt_outsideSignalCone=1.e+9)
Constructor with PFCandidate Handle.