CMS 3D CMS Logo

PATTauDiscriminationByMVAIsolationRun2.cc
Go to the documentation of this file.
1 
2 /*
3  * \class PATTauDiscriminationByMVAIsolationRun2
4  *
5  * MVA based discriminator against jet -> tau fakes
6  *
7  * Adopted from RecoTauTag/RecoTau/plugins/PFRecoTauDiscriminationByMVAIsolationRun2.cc
8  * to enable computation of MVA isolation on MiniAOD
9  *
10  * \author Alexander Nehrkorn, RWTH Aachen
11  */
12 
13 // todo 1: remove leadingTrackChi2 as input variable from:
14 // - here
15 // - TauPFEssential
16 // - PFRecoTauDiscriminationByMVAIsolationRun2
17 // - Training of BDT
18 
20 
26 
28 
34 
38 
39 #include <TFile.h>
40 
41 #include <iostream>
42 
43 using namespace pat;
44 
45 namespace
46 {
47  const GBRForest* loadMVAfromFile(const edm::FileInPath& inputFileName, const std::string& mvaName, std::vector<TFile*>& inputFilesToDelete)
48  {
49  if ( inputFileName.location() == edm::FileInPath::Unknown ) throw cms::Exception("PATTauDiscriminationByIsolationMVARun2::loadMVA")
50  << " Failed to find File = " << inputFileName << " !!\n";
51  TFile* inputFile = new TFile(inputFileName.fullPath().data());
52 
53  //const GBRForest* mva = dynamic_cast<GBRForest*>(inputFile->Get(mvaName.data())); // CV: dynamic_cast<GBRForest*> fails for some reason ?!
54  const GBRForest* mva = (GBRForest*)inputFile->Get(mvaName.data());
55  if ( !mva )
56  throw cms::Exception("PATTauDiscriminationByIsolationMVARun2::loadMVA")
57  << " Failed to load MVA = " << mvaName.data() << " from file = " << inputFileName.fullPath().data() << " !!\n";
58 
59  inputFilesToDelete.push_back(inputFile);
60 
61  return mva;
62  }
63 
64  const GBRForest* loadMVAfromDB(const edm::EventSetup& es, const std::string& mvaName)
65  {
67  es.get<GBRWrapperRcd>().get(mvaName, mva);
68  return mva.product();
69  }
70 }
71 
73 {
74  public:
77  moduleLabel_(cfg.getParameter<std::string>("@module_label")),
78  mvaReader_(nullptr),
79  mvaInput_(nullptr),
80  category_output_()
81  {
82  mvaName_ = cfg.getParameter<std::string>("mvaName");
83  loadMVAfromDB_ = cfg.exists("loadMVAfromDB") ? cfg.getParameter<bool>("loadMVAfromDB") : false;
84  if ( !loadMVAfromDB_ ) {
85  if(cfg.exists("inputFileName")){
86  inputFileName_ = cfg.getParameter<edm::FileInPath>("inputFileName");
87  }else throw cms::Exception("MVA input not defined") << "Requested to load tau MVA input from ROOT file but no file provided in cfg file";
88  }
89  std::string mvaOpt_string = cfg.getParameter<std::string>("mvaOpt");
90  if ( mvaOpt_string == "oldDMwoLT" ) mvaOpt_ = kOldDMwoLT;
91  else if ( mvaOpt_string == "oldDMwLT" ) mvaOpt_ = kOldDMwLT;
92  else if ( mvaOpt_string == "newDMwoLT" ) mvaOpt_ = kNewDMwoLT;
93  else if ( mvaOpt_string == "newDMwLT" ) mvaOpt_ = kNewDMwLT;
94  else if ( mvaOpt_string == "DBoldDMwLT" ) mvaOpt_ = kDBoldDMwLT;
95  else if ( mvaOpt_string == "DBnewDMwLT" ) mvaOpt_ = kDBnewDMwLT;
96  else if ( mvaOpt_string == "PWoldDMwLT" ) mvaOpt_ = kPWoldDMwLT;
97  else if ( mvaOpt_string == "PWnewDMwLT" ) mvaOpt_ = kPWnewDMwLT;
98  else if ( mvaOpt_string == "DBoldDMwLTwGJ" ) mvaOpt_ = kDBoldDMwLTwGJ;
99  else if ( mvaOpt_string == "DBnewDMwLTwGJ" ) mvaOpt_ = kDBnewDMwLTwGJ;
100  else throw cms::Exception("PATTauDiscriminationByMVAIsolationRun2")
101  << " Invalid Configuration Parameter 'mvaOpt' = " << mvaOpt_string << " !!\n";
102 
103  if ( mvaOpt_ == kOldDMwoLT || mvaOpt_ == kNewDMwoLT ) mvaInput_ = new float[6];
104  else if ( mvaOpt_ == kOldDMwLT || mvaOpt_ == kNewDMwLT ) mvaInput_ = new float[12];
105  else if ( mvaOpt_ == kDBoldDMwLT || mvaOpt_ == kDBnewDMwLT ||
106  mvaOpt_ == kPWoldDMwLT || mvaOpt_ == kPWnewDMwLT ||
107  mvaOpt_ == kDBoldDMwLTwGJ || mvaOpt_ == kDBnewDMwLTwGJ) mvaInput_ = new float[23];
108  else assert(0);
109 
110  chargedIsoPtSums_ = cfg.getParameter<std::string>("srcChargedIsoPtSum");
111  neutralIsoPtSums_ = cfg.getParameter<std::string>("srcNeutralIsoPtSum");
112  puCorrPtSums_ = cfg.getParameter<std::string>("srcPUcorrPtSum");
113  photonPtSumOutsideSignalCone_ = cfg.getParameter<std::string>("srcPhotonPtSumOutsideSignalCone");
114  footprintCorrection_ = cfg.getParameter<std::string>("srcFootprintCorrection");
115 
116  verbosity_ = ( cfg.exists("verbosity") ) ?
117  cfg.getParameter<int>("verbosity") : 0;
118 
119  produces<pat::PATTauDiscriminator>("category");
120  }
121 
122  void beginEvent(const edm::Event&, const edm::EventSetup&) override;
123 
124  double discriminate(const TauRef&) const override;
125 
126  void endEvent(edm::Event&) override;
127 
129  {
130  if(!loadMVAfromDB_) delete mvaReader_;
131  delete[] mvaInput_;
132  for ( std::vector<TFile*>::iterator it = inputFilesToDelete_.begin();
133  it != inputFilesToDelete_.end(); ++it ) {
134  delete (*it);
135  }
136  }
137 
138  private:
139 
141 
146  enum { kOldDMwoLT, kOldDMwLT, kNewDMwoLT, kNewDMwLT, kDBoldDMwLT, kDBnewDMwLT, kPWoldDMwLT, kPWnewDMwLT, kDBoldDMwLTwGJ, kDBnewDMwLTwGJ };
147  int mvaOpt_;
148  float* mvaInput_;
149 
155 
157  std::unique_ptr<pat::PATTauDiscriminator> category_output_;
158  std::vector<TFile*> inputFilesToDelete_;
160 
162 };
163 
165 {
166  if( !mvaReader_ ) {
167  if ( loadMVAfromDB_ ) {
168  mvaReader_ = loadMVAfromDB(es, mvaName_);
169  } else {
170  mvaReader_ = loadMVAfromFile(inputFileName_, mvaName_, inputFilesToDelete_);
171  }
172  }
173 
174  evt.getByToken(Tau_token, taus_);
175  category_output_.reset(new pat::PATTauDiscriminator(TauRefProd(taus_)));
176 }
177 
179 {
180  // CV: define dummy category index in order to use RecoTauDiscriminantCutMultiplexer module to appy WP cuts
181  double category = 0.;
182  category_output_->setValue(tauIndex_, category);
183 
184  // CV: computation of MVA value requires presence of leading charged hadron
185  if ( tau->leadChargedHadrCand().isNull() ) return 0.;
186 
187  int tauDecayMode = tau->decayMode();
188 
189  if ( ((mvaOpt_ == kOldDMwoLT || mvaOpt_ == kOldDMwLT || mvaOpt_ == kDBoldDMwLT || mvaOpt_ == kPWoldDMwLT || mvaOpt_ == kDBoldDMwLTwGJ)
190  && (tauDecayMode == 0 || tauDecayMode == 1 || tauDecayMode == 2 || tauDecayMode == 10))
191  ||
192  ((mvaOpt_ == kNewDMwoLT || mvaOpt_ == kNewDMwLT || mvaOpt_ == kDBnewDMwLT || mvaOpt_ == kPWnewDMwLT || mvaOpt_ == kDBnewDMwLTwGJ)
193  && (tauDecayMode == 0 || tauDecayMode == 1 || tauDecayMode == 2 || tauDecayMode == 5 || tauDecayMode == 6 || tauDecayMode == 10 || tauDecayMode == 11))
194  ) {
195 
196  float chargedIsoPtSum = tau->tauID(chargedIsoPtSums_);
197  float neutralIsoPtSum = tau->tauID(neutralIsoPtSums_);
198  float puCorrPtSum = tau->tauID(puCorrPtSums_);
199  float photonPtSumOutsideSignalCone = tau->tauID(photonPtSumOutsideSignalCone_);
200  float footprintCorrection = tau->tauID(footprintCorrection_);
201 
202  float decayDistX = tau->flightLength().x();
203  float decayDistY = tau->flightLength().y();
204  float decayDistZ = tau->flightLength().z();
205  float decayDistMag = std::sqrt(decayDistX*decayDistX + decayDistY*decayDistY + decayDistZ*decayDistZ);
206 
207  // --- The following 5 variables differ slightly between AOD & MiniAOD
208  // because they are recomputed using packedCandidates saved in the tau
209  float nPhoton = (float)clusterVariables_.tau_n_photons_total(*tau);
210  float ptWeightedDetaStrip = clusterVariables_.tau_pt_weighted_deta_strip(*tau, tauDecayMode);
211  float ptWeightedDphiStrip = clusterVariables_.tau_pt_weighted_dphi_strip(*tau, tauDecayMode);
212  float ptWeightedDrSignal = clusterVariables_.tau_pt_weighted_dr_signal(*tau, tauDecayMode);
213  float ptWeightedDrIsolation = clusterVariables_.tau_pt_weighted_dr_iso(*tau, tauDecayMode);
214  // ---
215  float leadingTrackChi2 = tau->leadingTrackNormChi2();
216  float eRatio = clusterVariables_.tau_Eratio(*tau);
217 
218  // Difference between measured and maximally allowed Gottfried-Jackson angle
219  float gjAngleDiff = -999;
220  if ( tauDecayMode == 10 ) {
221  double mTau = 1.77682;
222  double mAOne = tau->p4().M();
223  double pAOneMag = tau->p();
224  double argumentThetaGJmax = (std::pow(mTau,2) - std::pow(mAOne,2) ) / ( 2 * mTau * pAOneMag );
225  double argumentThetaGJmeasured = ( tau->p4().px() * decayDistX + tau->p4().py() * decayDistY + tau->p4().pz() * decayDistZ ) / ( pAOneMag * decayDistMag );
226  if ( std::abs(argumentThetaGJmax) <= 1. && std::abs(argumentThetaGJmeasured) <= 1. ) {
227  double thetaGJmax = std::asin( argumentThetaGJmax );
228  double thetaGJmeasured = std::acos( argumentThetaGJmeasured );
229  gjAngleDiff = thetaGJmeasured - thetaGJmax;
230  }
231  }
232 
233  if ( mvaOpt_ == kOldDMwoLT || mvaOpt_ == kNewDMwoLT ) {
234  mvaInput_[0] = std::log(std::max(1.f, (float)tau->pt()));
235  mvaInput_[1] = std::abs((float)tau->eta());
236  mvaInput_[2] = std::log(std::max(1.e-2f, chargedIsoPtSum));
237  mvaInput_[3] = std::log(std::max(1.e-2f, neutralIsoPtSum - 0.125f*puCorrPtSum));
238  mvaInput_[4] = std::log(std::max(1.e-2f, puCorrPtSum));
239  mvaInput_[5] = tauDecayMode;
240  } else if ( mvaOpt_ == kOldDMwLT || mvaOpt_ == kNewDMwLT ) {
241  mvaInput_[0] = std::log(std::max(1.f, (float)tau->pt()));
242  mvaInput_[1] = std::abs((float)tau->eta());
243  mvaInput_[2] = std::log(std::max(1.e-2f, chargedIsoPtSum));
244  mvaInput_[3] = std::log(std::max(1.e-2f, neutralIsoPtSum - 0.125f*puCorrPtSum));
245  mvaInput_[4] = std::log(std::max(1.e-2f, puCorrPtSum));
246  mvaInput_[5] = tauDecayMode;
247  mvaInput_[6] = std::copysign(+1.f, tau->dxy());
248  mvaInput_[7] = std::sqrt(std::min(1.f, std::abs(tau->dxy())));
249  mvaInput_[8] = std::min(10.f, std::abs(tau->dxy_Sig()));
250  mvaInput_[9] = ( tau->hasSecondaryVertex() ) ? 1. : 0.;
251  mvaInput_[10] = std::sqrt(decayDistMag);
252  mvaInput_[11] = std::min(10.f, tau->flightLengthSig());
253  } else if ( mvaOpt_ == kDBoldDMwLT || mvaOpt_ == kDBnewDMwLT ) {
254  mvaInput_[0] = std::log(std::max(1.f, (float)tau->pt()));
255  mvaInput_[1] = std::abs((float)tau->eta());
256  mvaInput_[2] = std::log(std::max(1.e-2f, chargedIsoPtSum));
257  mvaInput_[3] = std::log(std::max(1.e-2f, neutralIsoPtSum));
258  mvaInput_[4] = std::log(std::max(1.e-2f, puCorrPtSum));
259  mvaInput_[5] = std::log(std::max(1.e-2f, photonPtSumOutsideSignalCone));
260  mvaInput_[6] = tauDecayMode;
261  mvaInput_[7] = std::min(30.f, nPhoton);
262  mvaInput_[8] = std::min(0.5f, ptWeightedDetaStrip);
263  mvaInput_[9] = std::min(0.5f, ptWeightedDphiStrip);
264  mvaInput_[10] = std::min(0.5f, ptWeightedDrSignal);
265  mvaInput_[11] = std::min(0.5f, ptWeightedDrIsolation);
266  mvaInput_[12] = std::min(100.f, leadingTrackChi2);
267  mvaInput_[13] = std::min(1.f, eRatio);
268  mvaInput_[14] = std::copysign(+1.f, tau->dxy());
269  mvaInput_[15] = std::sqrt(std::min(1.f, std::abs(tau->dxy())));
270  mvaInput_[16] = std::min(10.f, std::abs(tau->dxy_Sig()));
271  mvaInput_[17] = std::copysign(+1.f, tau->ip3d());
272  mvaInput_[18] = std::sqrt(std::min(1.f, std::abs(tau->ip3d())));
273  mvaInput_[19] = std::min(10.f, std::abs(tau->ip3d_Sig()));
274  mvaInput_[20] = ( tau->hasSecondaryVertex() ) ? 1. : 0.;
275  mvaInput_[21] = std::sqrt(decayDistMag);
276  mvaInput_[22] = std::min(10.f, tau->flightLengthSig());
277  } else if ( mvaOpt_ == kPWoldDMwLT || mvaOpt_ == kPWnewDMwLT ) {
278  mvaInput_[0] = std::log(std::max(1.f, (float)tau->pt()));
279  mvaInput_[1] = std::abs((float)tau->eta());
280  mvaInput_[2] = std::log(std::max(1.e-2f, chargedIsoPtSum));
281  mvaInput_[3] = std::log(std::max(1.e-2f, neutralIsoPtSum));
282  mvaInput_[4] = std::log(std::max(1.e-2f, footprintCorrection));
283  mvaInput_[5] = std::log(std::max(1.e-2f, photonPtSumOutsideSignalCone));
284  mvaInput_[6] = tauDecayMode;
285  mvaInput_[7] = std::min(30.f, nPhoton);
286  mvaInput_[8] = std::min(0.5f, ptWeightedDetaStrip);
287  mvaInput_[9] = std::min(0.5f, ptWeightedDphiStrip);
288  mvaInput_[10] = std::min(0.5f, ptWeightedDrSignal);
289  mvaInput_[11] = std::min(0.5f, ptWeightedDrIsolation);
290  mvaInput_[12] = std::min(100.f, leadingTrackChi2);
291  mvaInput_[13] = std::min(1.f, eRatio);
292  mvaInput_[14] = std::copysign(+1.f, tau->dxy());
293  mvaInput_[15] = std::sqrt(std::min(1.f, std::abs(tau->dxy())));
294  mvaInput_[16] = std::min(10.f, std::abs(tau->dxy_Sig()));
295  mvaInput_[17] = std::copysign(+1.f, tau->ip3d());
296  mvaInput_[18] = std::sqrt(std::min(1.f, std::abs(tau->ip3d())));
297  mvaInput_[19] = std::min(10.f, std::abs(tau->ip3d_Sig()));
298  mvaInput_[20] = ( tau->hasSecondaryVertex() ) ? 1. : 0.;
299  mvaInput_[21] = std::sqrt(decayDistMag);
300  mvaInput_[22] = std::min(10.f, tau->flightLengthSig());
301  } else if ( mvaOpt_ == kDBoldDMwLTwGJ || mvaOpt_ == kDBnewDMwLTwGJ ) {
302  mvaInput_[0] = std::log(std::max(1.f, (float)tau->pt()));
303  mvaInput_[1] = std::abs((float)tau->eta());
304  mvaInput_[2] = std::log(std::max(1.e-2f, chargedIsoPtSum));
305  mvaInput_[3] = std::log(std::max(1.e-2f, neutralIsoPtSum));
306  mvaInput_[4] = std::log(std::max(1.e-2f, puCorrPtSum));
307  mvaInput_[5] = std::log(std::max(1.e-2f, photonPtSumOutsideSignalCone));
308  mvaInput_[6] = tauDecayMode;
309  mvaInput_[7] = std::min(30.f, nPhoton);
310  mvaInput_[8] = std::min(0.5f, ptWeightedDetaStrip);
311  mvaInput_[9] = std::min(0.5f, ptWeightedDphiStrip);
312  mvaInput_[10] = std::min(0.5f, ptWeightedDrSignal);
313  mvaInput_[11] = std::min(0.5f, ptWeightedDrIsolation);
314  mvaInput_[12] = std::min(1.f, eRatio);
315  mvaInput_[13] = std::copysign(+1.f, tau->dxy());
316  mvaInput_[14] = std::sqrt(std::min(1.f, std::abs(tau->dxy())));
317  mvaInput_[15] = std::min(10.f, std::abs(tau->dxy_Sig()));
318  mvaInput_[16] = std::copysign(+1.f, tau->ip3d());
319  mvaInput_[17] = std::sqrt(std::min(1.f, std::abs(tau->ip3d())));
320  mvaInput_[18] = std::min(10.f, std::abs(tau->ip3d_Sig()));
321  mvaInput_[19] = ( tau->hasSecondaryVertex() ) ? 1. : 0.;
322  mvaInput_[20] = std::sqrt(decayDistMag);
323  mvaInput_[21] = std::min(10.f, tau->flightLengthSig());
324  mvaInput_[22] = std::max(-1.f, gjAngleDiff);
325  }
326 
327  double mvaValue = mvaReader_->GetClassifier(mvaInput_);
328  if ( verbosity_ ) {
329  edm::LogPrint("PATTauDiscByMVAIsolRun2") << "<PATTauDiscriminationByMVAIsolationRun2::discriminate>:";
330  edm::LogPrint("PATTauDiscByMVAIsolRun2") << " tau: Pt = " << tau->pt() << ", eta = " << tau->eta();
331  edm::LogPrint("PATTauDiscByMVAIsolRun2") << " isolation: charged = " << chargedIsoPtSum << ", neutral = " << neutralIsoPtSum << ", PUcorr = " << puCorrPtSum;
332  edm::LogPrint("PATTauDiscByMVAIsolRun2") << " decay mode = " << tauDecayMode;
333  edm::LogPrint("PATTauDiscByMVAIsolRun2") << " impact parameter: distance = " << tau->dxy() << ", significance = " << tau->dxy_Sig();
334  edm::LogPrint("PATTauDiscByMVAIsolRun2") << " has decay vertex = " << tau->hasSecondaryVertex() << ":"
335  << " distance = " << decayDistMag << ", significance = " << tau->flightLengthSig();
336  edm::LogPrint("PATTauDiscByMVAIsolRun2") << "--> mvaValue = " << mvaValue;
337  }
338  return mvaValue;
339  } else {
340  return -1.;
341  }
342 }
343 
345 {
346  // add all category indices to event
347  evt.put(std::move(category_output_), "category");
348 }
349 
T getParameter(std::string const &) const
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:136
edm::RefProd< TauCollection > TauRefProd
Definition: Tau.h:39
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:519
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:17
bool exists(std::string const &parameterName) const
checks if a parameter exists
#define nullptr
Definition: HeavyIon.h:7
T sqrt(T t)
Definition: SSEVec.h:18
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
double f[11][100]
T min(T a, T b)
Definition: MathUtil.h:58
LocationCode location() const
Where was the file found?
Definition: FileInPath.cc:191
bool isNull() const
Checks for null.
Definition: Ref.h:250
std::unique_ptr< pat::PATTauDiscriminator > category_output_
const T & get() const
Definition: EventSetup.h:59
std::string fullPath() const
Definition: FileInPath.cc:197
T const * product() const
Definition: ESHandle.h:86
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:40
def move(src, dest)
Definition: eostools.py:510
void beginEvent(const edm::Event &, const edm::EventSetup &) override