CMS 3D CMS Logo

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