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