CMS 3D CMS Logo

TauDiscriminantCutMultiplexer.cc
Go to the documentation of this file.
1 /*
2  * TauDiscriminantCutMultiplexerT
3  *
4  * Authors: Evan K. Friis, UW; Sebastian Wozniewski, KIT
5  *
6  * Takes a PFTauDiscriminatorContainer with two raw values: The toMultiplex diescriminator is expected at rawValues[0] and the key (needed by certain discriminators) is expected at rawValues[1].
7  *
8  * The "key" discriminantor is rounded to the nearest integer.
9  *
10  * A set of cuts for different keys on the "toMultiplex" discriminantor is
11  * provided in the config file.
12  *
13  * Both the key and toMultiplex discriminators should map to the same PFTau
14  * collection.
15  *
16  */
22 
25 
26 #include <memory>
27 
32 
33 #include "TGraph.h"
34 #include "TFormula.h"
35 #include "TFile.h"
36 
37 template <class TauType, class TauTypeRef, class ParentClass>
38 class TauDiscriminantCutMultiplexerT : public ParentClass {
39 public:
41 
43  reco::SingleTauDiscriminatorContainer discriminate(const TauTypeRef&) const override;
44  void beginEvent(const edm::Event& event, const edm::EventSetup& eventSetup) override;
45 
46  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
47 
48 private:
50 
53 
57  double cutValue_;
60  std::unique_ptr<StringObjectFunction<TauType>> cutVariable_;
61  std::unique_ptr<const TGraph> cutFunction_;
63  int mode_;
64  };
65  typedef std::map<int, std::vector<std::unique_ptr<DiscriminantCutEntry>>> DiscriminantCutMap;
70 
73  std::unique_ptr<const TFormula> mvaOutput_normalization_;
74 
76 
80 
82 };
83 
84 namespace {
85  std::unique_ptr<TFile> openInputFile(const edm::FileInPath& inputFileName) {
86  if (inputFileName.location() == edm::FileInPath::Unknown) {
87  throw cms::Exception("TauDiscriminantCutMultiplexerT::loadObjectFromFile")
88  << " Failed to find File = " << inputFileName << " !!\n";
89  }
90  return std::make_unique<TFile>(inputFileName.fullPath().data());
91  }
92 
93  template <typename T>
94  std::unique_ptr<const T> loadObjectFromFile(TFile& inputFile, const std::string& objectName) {
95  const T* object = dynamic_cast<T*>(inputFile.Get(objectName.data()));
96  if (!object)
97  throw cms::Exception("TauDiscriminantCutMultiplexerT::loadObjectFromFile")
98  << " Failed to load Object = " << objectName.data() << " from file = " << inputFile.GetName() << " !!\n";
99  //Need to use TObject::Clone since the type T might be a base class
100  return std::unique_ptr<const T>{static_cast<T*>(object->Clone())};
101  }
102 
103  std::unique_ptr<const TGraph> loadTGraphFromDB(
104  const edm::EventSetup& es,
105  const std::string& graphName,
107  const int& verbosity_ = 0) {
108  if (verbosity_) {
109  std::cout << "<loadTGraphFromDB>:" << std::endl;
110  std::cout << " graphName = " << graphName << std::endl;
111  }
112  return std::make_unique<TGraph>(es.getData(graphToken));
113  }
114 
115  std::unique_ptr<TFormula> loadTFormulaFromDB(
116  const edm::EventSetup& es,
117  const std::string& formulaName,
119  const TString& newName,
120  const int& verbosity_ = 0) {
121  if (verbosity_) {
122  std::cout << "<loadTFormulaFromDB>:" << std::endl;
123  std::cout << " formulaName = " << formulaName << std::endl;
124  }
125  auto const& formulaPayload = es.getData(formulaToken_);
126 
127  if (formulaPayload.formulas().size() == 1 && formulaPayload.limits().size() == 1) {
128  return std::make_unique<TFormula>(newName, formulaPayload.formulas().at(0).data());
129  } else {
130  throw cms::Exception("TauDiscriminantCutMultiplexerT::loadTFormulaFromDB")
131  << "Failed to load TFormula = " << formulaName << " from Database !!\n";
132  }
133  return std::unique_ptr<TFormula>{};
134  }
135 } // namespace
136 
137 template <class TauType, class TauTypeRef, class ParentClass>
139  const edm::ParameterSet& cfg)
140  : ParentClass(cfg),
141  moduleLabel_(cfg.getParameter<std::string>("@module_label")),
142  mvaOutput_normalization_(),
143  isInitialized_(false) {
144  toMultiplex_ = cfg.getParameter<edm::InputTag>("toMultiplex");
145  toMultiplex_token = this->template consumes<reco::TauDiscriminatorContainer>(toMultiplex_);
146 
147  verbosity_ = cfg.getParameter<int>("verbosity");
148 
149  mvaOutputNormalizationName_ = cfg.getParameter<std::string>("mvaOutput_normalization");
150 
151  loadMVAfromDB_ = cfg.getParameter<bool>("loadMVAfromDB");
152  if (!loadMVAfromDB_) {
153  inputFileName_ = cfg.getParameter<edm::FileInPath>("inputFileName");
154  } else if (not mvaOutputNormalizationName_.empty()) {
156  }
157  if (verbosity_)
158  std::cout << moduleLabel_ << " loadMVA = " << loadMVAfromDB_ << std::endl;
159 
160  // Setup our cut map, first raw values then working points
161  typedef std::vector<edm::ParameterSet> VPSet;
162  typedef std::vector<std::string> VString;
163  typedef std::vector<double> VDouble;
164  VString rawValueConfig = cfg.getParameter<VString>("rawValues");
165  for (uint i = 0; i < rawValueConfig.size(); i++) {
166  if (rawValueConfig[i] == "discriminator")
168  else if (rawValueConfig[i] == "category")
170  else
171  throw cms::Exception("TauDiscriminantCutMultiplexerT")
172  << " Configuration Parameter 'rawValues' containes unknown values. Must be 'discriminator' or 'category'!!\n";
173  }
174  n_raws_ = rawValueConfig.size();
175  VPSet mapping = cfg.getParameter<VPSet>("mapping");
176  for (auto const& mappingEntry : mapping) {
177  unsigned category = mappingEntry.getParameter<uint32_t>("category");
178  std::vector<std::unique_ptr<DiscriminantCutEntry>> cutWPs;
179  std::string categoryname = mappingEntry.getParameter<std::string>("cut");
180  bool localWPs = false;
181  bool wpsAsDouble = false;
182  if (mappingEntry.exists("workingPoints")) {
183  localWPs = true;
184  if (mappingEntry.existsAs<VDouble>("workingPoints")) {
185  wpsAsDouble = true;
186  } else if (mappingEntry.existsAs<VString>("workingPoints")) {
187  wpsAsDouble = false;
188  } else {
189  throw cms::Exception("TauDiscriminantCutMultiplexerT")
190  << " Configuration Parameter 'workingPoints' must be filled with cms.string or cms.double!!\n";
191  }
192  } else if (cfg.exists("workingPoints")) {
193  localWPs = false;
194  if (cfg.existsAs<VDouble>("workingPoints")) {
195  wpsAsDouble = true;
196  } else if (cfg.existsAs<VString>("workingPoints")) {
197  wpsAsDouble = false;
198  } else {
199  throw cms::Exception("TauDiscriminantCutMultiplexerT")
200  << " Configuration Parameter 'workingPoints' must be filled with cms.string or cms.double!!\n";
201  }
202  } else {
203  throw cms::Exception("TauDiscriminantCutMultiplexerT")
204  << " Undefined Configuration Parameter 'workingPoints' !!\n";
205  }
206  if (wpsAsDouble) {
207  VDouble workingPoints;
208  if (localWPs)
209  workingPoints = mappingEntry.getParameter<VDouble>("workingPoints");
210  else
211  workingPoints = cfg.getParameter<VDouble>("workingPoints");
212  for (auto const& wp : workingPoints) {
213  std::unique_ptr<DiscriminantCutEntry> cut{new DiscriminantCutEntry()};
214  cut->cutValue_ = wp;
216  cutWPs.push_back(std::move(cut));
217  }
218  } else {
219  VString workingPoints;
220  if (localWPs)
221  workingPoints = mappingEntry.getParameter<VString>("workingPoints");
222  else
223  workingPoints = cfg.getParameter<VString>("workingPoints");
224  for (auto const& wp : workingPoints) {
225  std::unique_ptr<DiscriminantCutEntry> cut{new DiscriminantCutEntry()};
226  cut->cutName_ = categoryname + wp;
227  if (loadMVAfromDB_) {
228  cut->cutToken_ = this->esConsumes(edm::ESInputTag{"", cut->cutName_});
229  }
230  std::string cutVariable_string = mappingEntry.getParameter<std::string>("variable");
231  cut->cutVariable_.reset(new StringObjectFunction<TauType>(cutVariable_string));
233  cutWPs.push_back(std::move(cut));
234  }
235  }
236  cuts_[category] = std::move(cutWPs);
237  }
238 
239  verbosity_ = cfg.getParameter<int>("verbosity");
240  if (verbosity_)
241  std::cout << "constructed " << moduleLabel_ << std::endl;
242 }
243 
244 template <class TauType, class TauTypeRef, class ParentClass>
246 
247 template <class TauType, class TauTypeRef, class ParentClass>
249  const edm::EventSetup& es) {
250  if (verbosity_)
251  std::cout << " begin! " << moduleLabel_ << " " << isInitialized_ << std::endl;
252  if (!isInitialized_) {
253  //Only open the file once and we can close it when this routine is done
254  // since all objects gotten from the file will have been copied
255  std::unique_ptr<TFile> inputFile;
256  if (!mvaOutputNormalizationName_.empty()) {
257  if (!loadMVAfromDB_) {
258  inputFile = openInputFile(inputFileName_);
259  mvaOutput_normalization_ = loadObjectFromFile<TFormula>(*inputFile, mvaOutputNormalizationName_);
260  } else {
261  auto temp = loadTFormulaFromDB(es,
262  mvaOutputNormalizationName_,
263  formulaToken_,
264  Form("%s_mvaOutput_normalization", moduleLabel_.data()),
265  verbosity_);
266  mvaOutput_normalization_ = std::move(temp);
267  }
268  }
269  for (auto const& cutWPs : cuts_) {
270  for (auto const& cut : cutWPs.second) {
271  if (cut->mode_ == DiscriminantCutEntry::kVariableCut) {
272  if (!loadMVAfromDB_) {
273  if (not inputFile) {
274  inputFile = openInputFile(inputFileName_);
275  }
276  if (verbosity_)
277  std::cout << "Loading from file" << inputFileName_ << std::endl;
278  cut->cutFunction_ = loadObjectFromFile<TGraph>(*inputFile, cut->cutName_);
279  } else {
280  if (verbosity_)
281  std::cout << "Loading from DB" << std::endl;
282  cut->cutFunction_ = loadTGraphFromDB(es, cut->cutName_, cut->cutToken_, verbosity_);
283  }
284  }
285  }
286  }
287  isInitialized_ = true;
288  }
289 
290  evt.getByToken(toMultiplex_token, toMultiplexHandle_);
291 }
292 
293 template <class TauType, class TauTypeRef, class ParentClass>
295  const TauTypeRef& tau) const {
296  if (verbosity_) {
297  std::cout << "<TauDiscriminantCutMultiplexerT::discriminate>:" << std::endl;
298  std::cout << " moduleLabel = " << moduleLabel_ << std::endl;
299  }
300 
302  result.rawValues.resize(n_raws_);
303  double disc_result = (*toMultiplexHandle_)[tau].rawValues.at(0);
304  if (verbosity_) {
305  std::cout << "disc_result = " << disc_result << std::endl;
306  }
307  if (raw_discriminator_idx_ >= 0)
308  result.rawValues[raw_discriminator_idx_] = disc_result;
309  if (mvaOutput_normalization_) {
310  disc_result = mvaOutput_normalization_->Eval(disc_result);
311  if (verbosity_) {
312  std::cout << "disc_result (normalized) = " << disc_result << std::endl;
313  }
314  }
315  double key_result = 0.0;
316  if ((*toMultiplexHandle_)[tau].rawValues.size() == 2) {
317  key_result = (*toMultiplexHandle_)[tau].rawValues.at(1);
318  if (raw_category_idx_ >= 0)
319  result.rawValues[raw_category_idx_] = key_result;
320  }
321  typename DiscriminantCutMap::const_iterator cutWPsIter = cuts_.find(std::round(key_result));
322 
323  // Return null if it doesn't exist
324  if (cutWPsIter == cuts_.end()) {
325  return result;
326  }
327  // See if the discriminator passes our cuts
328  for (auto const& cutIter : cutWPsIter->second) {
329  bool passesCuts = false;
330  if (cutIter->mode_ == DiscriminantCutEntry::kFixedCut) {
331  passesCuts = (disc_result > cutIter->cutValue_);
332  if (verbosity_) {
333  std::cout << "cutValue (fixed) = " << cutIter->cutValue_ << " --> passesCuts = " << passesCuts << std::endl;
334  }
335  } else if (cutIter->mode_ == DiscriminantCutEntry::kVariableCut) {
336  double cutVariable = (*cutIter->cutVariable_)(*tau);
337  double xMin, xMax, dummy;
338  cutIter->cutFunction_->GetPoint(0, xMin, dummy);
339  cutIter->cutFunction_->GetPoint(cutIter->cutFunction_->GetN() - 1, xMax, dummy);
340  const double epsilon = 1.e-3;
341  if (cutVariable < (xMin + epsilon))
342  cutVariable = xMin + epsilon;
343  else if (cutVariable > (xMax - epsilon))
344  cutVariable = xMax - epsilon;
345  double cutValue = cutIter->cutFunction_->Eval(cutVariable);
346  passesCuts = (disc_result > cutValue);
347  if (verbosity_) {
348  std::cout << "cutValue (@" << cutVariable << ") = " << cutValue << " --> passesCuts = " << passesCuts
349  << std::endl;
350  }
351  }
352  result.workingPoints.push_back(passesCuts);
353  }
354  return result;
355 }
356 
357 // template specialization to get the correct default config names in the following fillDescriptions
358 template <class TauType>
360  // this generic one shoudl never be called.
361  // these are specialized in TauDiscriminationProducerBase.cc
362  throw cms::Exception("TauDiscriminantCutMultiplexerT")
363  << "Unsupported TauType used. You must use either PFTau or PATTau.";
364 }
365 
366 template <>
367 std::string getDefaultConfigString<reco::PFTau>() {
368  return "recoTauDiscriminantCutMultiplexerDefault";
369 }
370 template <>
371 std::string getDefaultConfigString<pat::Tau>() {
372  return "patTauDiscriminantCutMultiplexerDefault";
373 }
374 
375 template <class TauType, class TauTypeRef, class ParentClass>
377  edm::ConfigurationDescriptions& descriptions) {
378  // recoTauDiscriminantCutMultiplexer
380  desc.add<edm::InputTag>("toMultiplex", edm::InputTag("fixme"));
381  desc.add<int>("verbosity", 0);
382 
383  {
384  edm::ParameterSet pset_mapping;
385  pset_mapping.addParameter<unsigned int>("category", 0);
386  pset_mapping.addParameter<std::string>("cut", "fixme");
387  edm::ParameterSetDescription desc_mapping;
388  desc_mapping.add<unsigned int>("category", 0);
389  desc_mapping.add<std::string>("cut");
390  // it seems the parameter string "variable" exists only when workingPoints are string
391  // see hpsPFTauDiscriminationByVLooseIsolationMVArun2v1DBdR03oldDMwLT in RecoTauTag/Configuration/python/HPSPFTaus_cff.py
392  desc_mapping.addOptional<std::string>("variable")
393  ->setComment("the parameter is required when \"workingPoints\" are string");
394  std::vector<edm::ParameterSet> vpsd_mapping;
395  vpsd_mapping.push_back(pset_mapping);
396  desc.addVPSet("mapping", desc_mapping, vpsd_mapping);
397  }
398 
399  std::vector<std::string> defaultRaws{"discriminator"};
400  desc.add<std::vector<std::string>>("rawValues", defaultRaws);
401  std::vector<double> defaultWP{0.0};
402  desc.addNode(edm::ParameterDescription<std::vector<double>>("workingPoints", defaultWP, true) xor
403  edm::ParameterDescription<std::vector<std::string>>("workingPoints", true));
404  desc.add<edm::FileInPath>("inputFileName", edm::FileInPath("RecoTauTag/RecoTau/data/emptyMVAinputFile"));
405  desc.add<bool>("loadMVAfromDB", true);
406  ParentClass::fillProducerDescriptions(desc); // inherited from the base
407  desc.add<std::string>("mvaOutput_normalization", "");
408  descriptions.add(getDefaultConfigString<TauType>(), desc);
409 }
410 
411 // define our implementations
416 
ESGetTokenH3DDVariant esConsumes(std::string const &Record, edm::ConsumesCollector &)
Definition: DeDxTools.cc:283
edm::EDGetTokenT< reco::TauDiscriminatorContainer > toMultiplex_token
edm::ESGetToken< PhysicsTFormulaPayload, PhysicsTFormulaPayloadRcd > formulaToken_
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
string newName
Definition: mps_merge.py:86
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:539
std::map< int, std::vector< std::unique_ptr< DiscriminantCutEntry > > > DiscriminantCutMap
TauDiscriminantCutMultiplexerT(const edm::ParameterSet &pset)
TauDiscriminantCutMultiplexerT< pat::Tau, pat::TauRef, PATTauDiscriminationContainerProducerBase > PATTauDiscriminantCutMultiplexer
std::string getDefaultConfigString()
edm::Handle< reco::TauDiscriminatorContainer > toMultiplexHandle_
TauDiscriminantCutMultiplexerT< reco::PFTau, reco::PFTauRef, PFTauDiscriminationContainerProducerBase > RecoTauDiscriminantCutMultiplexer
void addParameter(std::string const &name, T const &value)
Definition: ParameterSet.h:135
reco::SingleTauDiscriminatorContainer discriminate(const TauTypeRef &) const override
bool getData(T &iHolder) const
Definition: EventSetup.h:122
ParameterDescriptionBase * add(U const &iLabel, T const &value)
void beginEvent(const edm::Event &event, const edm::EventSetup &eventSetup) override
std::unique_ptr< const TFormula > mvaOutput_normalization_
edm::ESGetToken< PhysicsTGraphPayload, PhysicsTGraphPayloadRcd > cutToken_
void add(std::string const &label, ParameterSetDescription const &psetDescription)
std::unique_ptr< StringObjectFunction< TauType > > cutVariable_
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
long double T
def move(src, dest)
Definition: eostools.py:511
Definition: event.py:1