CMS 3D CMS Logo

PFRecoTauDiscriminationByHPSSelection.cc
Go to the documentation of this file.
3 
6 
9 
13 
14 namespace {
15  // Apply a hypothesis on the mass of the strips.
16  math::XYZTLorentzVector applyMassConstraint(const math::XYZTLorentzVector& vec, double mass) {
17  double factor = sqrt(vec.energy() * vec.energy() - mass * mass) / vec.P();
18  return math::XYZTLorentzVector(vec.px() * factor, vec.py() * factor, vec.pz() * factor, vec.energy());
19  }
20 } // namespace
21 
23 public:
26  double discriminate(const reco::PFTauRef&) const override;
27 
28  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
29 
30 private:
32 
33  struct DecayModeCuts {
34  DecayModeCuts() : maxMass_(nullptr) {}
35  ~DecayModeCuts() {} // CV: maxMass object gets deleted by PFRecoTauDiscriminationByHPSSelection destructor
36  unsigned nTracksMin_;
38  double minMass_;
43  double minPi0Mass_;
44  double maxPi0Mass_;
46  };
47 
48  typedef std::pair<unsigned int, unsigned int> IntPair;
49  typedef std::pair<double, double> DoublePair;
50  typedef std::map<IntPair, DecayModeCuts> DecayModeCutMap;
51 
53  double matchingCone_;
54  double minPt_;
55 
57 
59 
61 };
62 
65  // Get the matchign cut
66  matchingCone_ = pset.getParameter<double>("matchingCone");
67  minPt_ = pset.getParameter<double>("minTauPt");
68  // Get the mass cuts for each decay mode
69  typedef std::vector<edm::ParameterSet> VPSet;
70  const VPSet& decayModes = pset.getParameter<VPSet>("decayModes");
71  for (auto const& decayMode : decayModes) {
72  // The mass window(s)
74  cuts.nTracksMin_ = decayMode.getParameter<unsigned>("nTracksMin");
75  cuts.nChargedPFCandsMin_ = decayMode.getParameter<unsigned>("nChargedPFCandsMin");
76  cuts.minMass_ = decayMode.getParameter<double>("minMass");
77  cuts.maxMass_ = new TauFunc(decayMode.getParameter<std::string>("maxMass"));
78  edm::ParameterSet applyBendCorrection = decayMode.getParameter<edm::ParameterSet>("applyBendCorrection");
79  cuts.applyBendCorrection_eta_ = applyBendCorrection.getParameter<bool>("eta");
80  cuts.applyBendCorrection_phi_ = applyBendCorrection.getParameter<bool>("phi");
81  cuts.applyBendCorrection_mass_ = applyBendCorrection.getParameter<bool>("mass");
82  cuts.minPi0Mass_ = decayMode.getParameter<double>("minPi0Mass");
83  cuts.maxPi0Mass_ = decayMode.getParameter<double>("maxPi0Mass");
84  cuts.assumeStripMass_ = decayMode.getParameter<double>("assumeStripMass");
85  decayModeCuts_.insert(std::make_pair(
86  // The decay mode as a key
87  std::make_pair(decayMode.getParameter<uint32_t>("nCharged"), decayMode.getParameter<uint32_t>("nPiZeros")),
88  cuts));
89  }
90  requireTauChargedHadronsToBeChargedPFCands_ = pset.getParameter<bool>("requireTauChargedHadronsToBeChargedPFCands");
91  minPixelHits_ = pset.getParameter<int>("minPixelHits");
92  verbosity_ = pset.getParameter<int>("verbosity");
93 }
94 
96  for (DecayModeCutMap::iterator it = decayModeCuts_.begin(); it != decayModeCuts_.end(); ++it) {
97  delete it->second.maxMass_;
98  }
99 }
100 
101 namespace {
102  inline const reco::Track* getTrack(const reco::Candidate& cand) {
103  const reco::PFCandidate* pfCandPtr = dynamic_cast<const reco::PFCandidate*>(&cand);
104  if (pfCandPtr) {
105  if (pfCandPtr->trackRef().isNonnull())
106  return pfCandPtr->trackRef().get();
107  else if (pfCandPtr->gsfTrackRef().isNonnull())
108  return pfCandPtr->gsfTrackRef().get();
109  else
110  return nullptr;
111  }
112  const pat::PackedCandidate* packedCand = dynamic_cast<const pat::PackedCandidate*>(&cand);
113  if (packedCand && packedCand->hasTrackDetails())
114  return &packedCand->pseudoTrack();
115 
116  return nullptr;
117  }
118 } // namespace
119 
121  if (verbosity_) {
122  edm::LogPrint("PFTauByHPSSelect") << "<PFRecoTauDiscriminationByHPSSelection::discriminate>:";
123  edm::LogPrint("PFTauByHPSSelect") << " nCharged = " << tau->signalTauChargedHadronCandidates().size();
124  edm::LogPrint("PFTauByHPSSelect") << " nPiZeros = " << tau->signalPiZeroCandidates().size();
125  }
126 
127  // Check if we pass the min pt
128  if (tau->pt() < minPt_) {
129  if (verbosity_) {
130  edm::LogPrint("PFTauByHPSSelect") << " fails minPt cut.";
131  }
132  return 0.0;
133  }
134 
135  // See if we select this decay mode
136  DecayModeCutMap::const_iterator massWindowIter = decayModeCuts_.find(
137  std::make_pair(tau->signalTauChargedHadronCandidates().size(), tau->signalPiZeroCandidates().size()));
138  // Check if decay mode is supported
139  if (massWindowIter == decayModeCuts_.end()) {
140  if (verbosity_) {
141  edm::LogPrint("PFTauByHPSSelect") << " fails mass-window definition requirement.";
142  }
143  return 0.0;
144  }
145  const DecayModeCuts& massWindow = massWindowIter->second;
146 
147  if (massWindow.nTracksMin_ > 0) {
148  unsigned int nTracks = 0;
149  const std::vector<reco::PFRecoTauChargedHadron>& chargedHadrons = tau->signalTauChargedHadronCandidates();
150  for (std::vector<reco::PFRecoTauChargedHadron>::const_iterator chargedHadron = chargedHadrons.begin();
151  chargedHadron != chargedHadrons.end();
152  ++chargedHadron) {
155  ++nTracks;
156  }
157  }
158  if (verbosity_) {
159  edm::LogPrint("PFTauByHPSSelect") << "nTracks = " << nTracks << " (min = " << massWindow.nTracksMin_ << ")";
160  }
161  if (nTracks < massWindow.nTracksMin_) {
162  if (verbosity_) {
163  edm::LogPrint("PFTauByHPSSelect") << " fails nTracks requirement for mass-window.";
164  }
165  return 0.0;
166  }
167  }
168  if (massWindow.nChargedPFCandsMin_ > 0) {
169  unsigned int nChargedPFCands = 0;
170  const std::vector<reco::PFRecoTauChargedHadron>& chargedHadrons = tau->signalTauChargedHadronCandidates();
171  for (std::vector<reco::PFRecoTauChargedHadron>::const_iterator chargedHadron = chargedHadrons.begin();
172  chargedHadron != chargedHadrons.end();
173  ++chargedHadron) {
175  ++nChargedPFCands;
176  }
177  }
178  if (verbosity_) {
179  edm::LogPrint("PFTauByHPSSelect") << "nChargedPFCands = " << nChargedPFCands
180  << " (min = " << massWindow.nChargedPFCandsMin_ << ")";
181  }
182  if (nChargedPFCands < massWindow.nChargedPFCandsMin_) {
183  if (verbosity_) {
184  edm::LogPrint("PFTauByHPSSelect") << " fails nChargedPFCands requirement for mass-window.";
185  }
186  return 0.0;
187  }
188  }
189 
190  math::XYZTLorentzVector tauP4 = tau->p4();
191  if (verbosity_) {
192  edm::LogPrint("PFTauByHPSSelect") << "tau: Pt = " << tauP4.pt() << ", eta = " << tauP4.eta()
193  << ", phi = " << tauP4.phi() << ", mass = " << tauP4.mass();
194  }
195  // Find the total pizero p4
197  for (auto const& cand : tau->signalPiZeroCandidates()) {
198  const math::XYZTLorentzVector& candP4 = cand.p4();
199  stripsP4 += candP4;
200  }
201 
202  // Apply strip mass assumption corrections
203  if (massWindow.assumeStripMass_ >= 0) {
204  for (auto const& cand : tau->signalPiZeroCandidates()) {
205  const math::XYZTLorentzVector& uncorrected = cand.p4();
206  math::XYZTLorentzVector corrected = applyMassConstraint(uncorrected, massWindow.assumeStripMass_);
207  math::XYZTLorentzVector correction = corrected - uncorrected;
208  tauP4 += correction;
209  stripsP4 += correction;
210  }
211  }
212  if (verbosity_) {
213  edm::LogPrint("PFTauByHPSSelect") << "strips: Pt = " << stripsP4.pt() << ", eta = " << stripsP4.eta()
214  << ", phi = " << stripsP4.phi() << ", mass = " << stripsP4.mass();
215  }
216 
217  // Check if tau fails mass cut
218  double maxMass_value = (*massWindow.maxMass_)(*tau);
219  double bendCorrection_mass = (massWindow.applyBendCorrection_mass_) ? tau->bendCorrMass() : 0.;
220  if (!((tauP4.M() - bendCorrection_mass) < maxMass_value && (tauP4.M() + bendCorrection_mass) > massWindow.minMass_)) {
221  if (verbosity_) {
222  edm::LogPrint("PFTauByHPSSelect") << " fails tau mass-window cut.";
223  }
224  return 0.0;
225  }
226  // CV: require that mass of charged tau decay products is always within specified mass window,
227  // irrespective of bendCorrection_mass
228  reco::Candidate::LorentzVector tauP4_charged;
229  const std::vector<reco::PFRecoTauChargedHadron>& signalChargedHadrons = tau->signalTauChargedHadronCandidates();
230  for (std::vector<reco::PFRecoTauChargedHadron>::const_iterator signalChargedHadron = signalChargedHadrons.begin();
231  signalChargedHadron != signalChargedHadrons.end();
232  ++signalChargedHadron) {
233  tauP4_charged += signalChargedHadron->p4();
234  }
235  if (!(tauP4_charged.mass() < maxMass_value)) {
236  if (verbosity_) {
237  edm::LogPrint("PFTauByHPSSelect") << " fails tau mass-window cut.";
238  }
239  return 0.0;
240  }
241 
242  // Check if it fails the pi0 IM cut
243  if (stripsP4.M() > massWindow.maxPi0Mass_ || stripsP4.M() < massWindow.minPi0Mass_) {
244  if (verbosity_) {
245  edm::LogPrint("PFTauByHPSSelect") << " fails strip mass-window cut.";
246  }
247  return 0.0;
248  }
249 
250  // Check if tau passes matching cone cut
251  //edm::LogPrint("PFTauByHPSSelect") << "dR(tau, jet) = " << deltaR(tauP4, tau->jetRef()->p4()) ;
252  if (deltaR(tauP4, tau->jetRef()->p4()) > matchingCone_) {
253  if (verbosity_) {
254  edm::LogPrint("PFTauByHPSSelect") << " fails matching-cone cut.";
255  }
256  return 0.0;
257  }
258 
259  // Check if tau passes cone cut
260  double cone_size = tau->signalConeSize();
261  // Check if any charged objects fail the signal cone cut
262  for (auto const& cand : tau->signalTauChargedHadronCandidates()) {
263  if (verbosity_) {
264  edm::LogPrint("PFTauByHPSSelect") << "dR(tau, signalPFChargedHadr) = " << deltaR(cand.p4(), tauP4);
265  }
266  if (deltaR(cand.p4(), tauP4) > cone_size) {
267  if (verbosity_) {
268  edm::LogPrint("PFTauByHPSSelect") << " fails signal-cone cut for charged hadron(s).";
269  }
270  return 0.0;
271  }
272  }
273  // Now check the pizeros
274  for (auto const& cand : tau->signalPiZeroCandidates()) {
275  double bendCorrection_eta = (massWindow.applyBendCorrection_eta_) ? cand.bendCorrEta() : 0.;
276  double dEta = std::max(0., fabs(cand.eta() - tauP4.eta()) - bendCorrection_eta);
277  double bendCorrection_phi = (massWindow.applyBendCorrection_phi_) ? cand.bendCorrPhi() : 0.;
278  double dPhi = std::max(0., std::abs(reco::deltaPhi(cand.phi(), tauP4.phi())) - bendCorrection_phi);
279  double dR2 = dEta * dEta + dPhi * dPhi;
280  if (verbosity_) {
281  edm::LogPrint("PFTauByHPSSelect") << "dR2(tau, signalPiZero) = " << dR2;
282  }
283  if (dR2 > cone_size * cone_size) {
284  if (verbosity_) {
285  edm::LogPrint("PFTauByHPSSelect") << " fails signal-cone cut for strip(s).";
286  }
287  return 0.0;
288  }
289  }
290 
292  for (auto const& cand : tau->signalTauChargedHadronCandidates()) {
293  if (verbosity_) {
294  std::string algo_string;
296  algo_string = "ChargedPFCandidate";
297  else if (cand.algo() == reco::PFRecoTauChargedHadron::kTrack)
298  algo_string = "Track";
300  algo_string = "PFNeutralHadron";
301  else
302  algo_string = "Undefined";
303  edm::LogPrint("PFTauByHPSSelect") << "algo(signalPFChargedHadr) = " << algo_string;
304  }
306  if (verbosity_) {
307  edm::LogPrint("PFTauByHPSSelect") << " fails cut on PFRecoTauChargedHadron algo.";
308  }
309  return 0.0;
310  }
311  }
312  }
313 
314  if (minPixelHits_ > 0) {
315  int numPixelHits = 0;
316  const int nProngs = tau->decayMode() / 5 + 1; //no. of charged prongs expected for this tau
317  int nTracks = 0;
318  for (const auto& chargedHadrCand : tau->signalChargedHadrCands()) {
319  const reco::Track* track = getTrack(*chargedHadrCand);
320  if (track != nullptr) {
321  numPixelHits += track->hitPattern().numberOfValidPixelHits();
322  nTracks++;
323  }
324  }
325  //MB: how to deal with tau@miniAOD case?
326  if (nTracks < nProngs) { //"lost track" probably used to build this tau
327  for (const auto& track : tau->signalTracks()) {
328  if (track.isNonnull()) {
329  numPixelHits += track->hitPattern().numberOfValidPixelHits();
330  nTracks++;
331  }
332  }
333  }
334  if (!(numPixelHits >= minPixelHits_)) {
335  if (verbosity_) {
336  edm::LogPrint("PFTauByHPSSelect") << " fails cut on sum of pixel hits.";
337  }
338  return 0.0;
339  }
340  }
341 
342  // Otherwise, we pass!
343  if (verbosity_) {
344  edm::LogPrint("PFTauByHPSSelect") << " passes all cuts.";
345  }
346  return 1.0;
347 }
348 
350  // hpsSelectionDiscriminator
352  desc.add<edm::InputTag>("PFTauProducer", edm::InputTag("combinatoricRecoTaus"));
353  desc.add<int>("verbosity", 0);
354  desc.add<double>("minTauPt", 0.0);
355  {
357  psd0.add<std::string>("BooleanOperator", "and");
358  desc.add<edm::ParameterSetDescription>("Prediscriminants", psd0);
359  }
360 
361  {
362  edm::ParameterSetDescription vpset_decayModes;
363  vpset_decayModes.add<double>("minPi0Mass", -1.e3);
364  vpset_decayModes.add<std::string>("maxMass");
365  vpset_decayModes.add<double>("maxPi0Mass", 1.e9);
366  vpset_decayModes.add<unsigned int>("nPiZeros");
367  vpset_decayModes.add<double>("minMass");
368  vpset_decayModes.add<unsigned int>("nChargedPFCandsMin", 0);
369  vpset_decayModes.add<unsigned int>("nTracksMin", 0);
370  vpset_decayModes.add<unsigned int>("nCharged");
371  {
373  psd0.add<bool>("phi");
374  psd0.add<bool>("eta");
375  psd0.add<bool>("mass");
376  vpset_decayModes.add<edm::ParameterSetDescription>("applyBendCorrection", psd0);
377  }
378  vpset_decayModes.add<double>("assumeStripMass", -1.0);
379  std::vector<edm::ParameterSet> vpset_default;
380  {
382  pset.addParameter<double>("minPi0Mass", -1.e3);
383  pset.addParameter<double>("maxPi0Mass", 1.e9);
384  pset.addParameter<unsigned int>("nChargedPFCandsMin", 0);
385  pset.addParameter<unsigned int>("nTracksMin", 0);
386  pset.addParameter<double>("assumeStripMass", -1.0);
387  vpset_default.push_back(pset);
388  }
389  desc.addVPSet("decayModes", vpset_decayModes, vpset_default);
390  }
391 
392  desc.add<double>("matchingCone", 0.5);
393  desc.add<int>("minPixelHits", 1);
394  desc.add<bool>("requireTauChargedHadronsToBeChargedPFCands", false);
395  descriptions.add("hpsSelectionDiscriminator", desc);
396 }
397 
constexpr double deltaPhi(double phi1, double phi2)
Definition: deltaPhi.h:26
reco::GsfTrackRef gsfTrackRef() const
Definition: PFCandidate.cc:469
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
bool isNonnull() const
Checks for non-null.
Definition: Ref.h:238
XYZTLorentzVectorD XYZTLorentzVector
Lorentz vector with cylindrical internal representation using pseudorapidity.
Definition: LorentzVector.h:29
T sqrt(T t)
Definition: SSEVec.h:19
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
ParameterDescriptionBase * add(U const &iLabel, T const &value)
Log< level::Warning, true > LogPrint
static const TrackGhostTrackState * getTrack(const BasicGhostTrackState *basic)
void add(std::string const &label, ParameterSetDescription const &psetDescription)
math::XYZTLorentzVector LorentzVector
Lorentz vector.
Definition: Candidate.h:36
Particle reconstructed by the particle flow algorithm.
Definition: PFCandidate.h:41
T const * get() const
Returns C++ pointer to the item.
Definition: Ref.h:232
reco::TrackRef trackRef() const
Definition: PFCandidate.cc:437
double discriminate(const reco::PFTauRef &) const override
virtual const reco::Track & pseudoTrack() const
bool hasTrackDetails() const
Return true if a bestTrack can be extracted from this Candidate.