diff --git a/CommonTools/CandAlgos/BuildFile.xml b/CommonTools/CandAlgos/BuildFile.xml index 05ec37c249f78..a66b6c8421f4d 100644 --- a/CommonTools/CandAlgos/BuildFile.xml +++ b/CommonTools/CandAlgos/BuildFile.xml @@ -1,6 +1,7 @@ + diff --git a/CommonTools/CandAlgos/interface/ModifyObjectValueBase.h b/CommonTools/CandAlgos/interface/ModifyObjectValueBase.h new file mode 100644 index 0000000000000..f3e4fe65973c9 --- /dev/null +++ b/CommonTools/CandAlgos/interface/ModifyObjectValueBase.h @@ -0,0 +1,61 @@ +#ifndef __CommonTools_CandAlgos_ModifyObjectValueBase_h__ +#define __CommonTools_CandAlgos_ModifyObjectValueBase_h__ + +#include "DataFormats/PatCandidates/interface/Electron.h" +#include "DataFormats/PatCandidates/interface/Photon.h" +#include "DataFormats/PatCandidates/interface/Muon.h" +#include "DataFormats/PatCandidates/interface/Tau.h" +#include "DataFormats/PatCandidates/interface/Jet.h" + +#include "FWCore/Utilities/interface/Exception.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/ConsumesCollector.h" + +#include + +class ModifyObjectValueBase { + public: + ModifyObjectValueBase(const edm::ParameterSet& conf) : + name_( conf.getParameter("modifierName") ) {} + + virtual ~ModifyObjectValueBase() {} + + virtual void setEvent(const edm::Event&) {} + virtual void setEventContent(const edm::EventSetup&) {} + virtual void setConsumes(edm::ConsumesCollector&) {} + + virtual void modifyObject(pat::Electron&) const { + throw cms::Exception("InvalidConfiguration") + << name_ << " is not configured to handle electrons!"; + } + virtual void modifyObject(pat::Photon&) const { + throw cms::Exception("InvalidConfiguration") + << name_ << " is not configured to handle photons!"; + } + virtual void modifyObject(pat::Muon&) const { + throw cms::Exception("InvalidConfiguration") + << name_ << " is not configured to handle muons!"; + } + virtual void modifyObject(pat::Tau&) const { + throw cms::Exception("InvalidConfiguration") + << name_ << " is not configured to handle taus!"; + } + virtual void modifyObject(pat::Jet&) const { + throw cms::Exception("InvalidConfiguration") + << name_ << " is not configured to handle jets!"; + } + + const std::string& name() const { return name_; } + + private: + const std::string name_; +}; + +#if !defined(__CINT__) && !defined(__MAKECINT__) && !defined(__REFLEX__) +#include "FWCore/PluginManager/interface/PluginFactory.h" +typedef edmplugin::PluginFactory< ModifyObjectValueBase* (const edm::ParameterSet&) > ModifyObjectValueFactory; +#endif + +#endif diff --git a/CommonTools/CandAlgos/src/ModifyObjectValueBase.cc b/CommonTools/CandAlgos/src/ModifyObjectValueBase.cc new file mode 100644 index 0000000000000..61b5fbf0bc40c --- /dev/null +++ b/CommonTools/CandAlgos/src/ModifyObjectValueBase.cc @@ -0,0 +1,4 @@ +#include "CommonTools/CandAlgos/interface/ModifyObjectValueBase.h" + +EDM_REGISTER_PLUGINFACTORY(ModifyObjectValueFactory,"ModifyObjectValueFactory"); + diff --git a/CommonTools/Utils/interface/ExpressionEvaluator.h b/CommonTools/Utils/interface/ExpressionEvaluator.h index 6b7260c4ef340..e8a1b7dc8f937 100644 --- a/CommonTools/Utils/interface/ExpressionEvaluator.h +++ b/CommonTools/Utils/interface/ExpressionEvaluator.h @@ -11,7 +11,7 @@ class ExpressionEvaluator { ExpressionEvaluator(const char * pkg, const char * iname, const std::string & iexpr); ~ExpressionEvaluator(); - template< typename EXPR> + template EXPR * expr() const { typedef EXPR * factoryP(); return reinterpret_cast(m_expr)(); diff --git a/CommonTools/Utils/src/ExpressionEvaluator.cc b/CommonTools/Utils/src/ExpressionEvaluator.cc index 6e75c3f9f743b..27f59e7412f54 100644 --- a/CommonTools/Utils/src/ExpressionEvaluator.cc +++ b/CommonTools/Utils/src/ExpressionEvaluator.cc @@ -10,7 +10,7 @@ #include #include -#define VI_DEBUG +// #define VI_DEBUG #ifdef VI_DEBUG #include @@ -40,7 +40,7 @@ namespace { } std::string patchArea() { - auto n1 = execSysCommand("scram tool tag cmssw CMSSW_BASE"); + auto n1 = execSysCommand("pushd $CMSSW_BASE > /dev/null;scram tool tag cmssw CMSSW_BASE; popd > /dev/null"); n1.pop_back(); COUT << "base area " << n1 << std::endl; return n1[0]=='/' ? n1 : std::string(); @@ -89,7 +89,7 @@ ExpressionEvaluator::ExpressionEvaluator(const char * pkg, const char * iname, s } else { // look in release is a patch area auto paDir = patchArea(); - if (paDir.empty()) throw cms::Exception("ExpressionEvaluator", pch + " file not found neither in " + baseDir + " nor in " + relDir); + if (paDir.empty()) throw cms::Exception("ExpressionEvaluator", "error in opening patch area for "+ baseDir); std::string file = paDir + incDir + pch + ".cxxflags"; COUT << "file in base release area: " << file << std::endl; std::ifstream ss(file.c_str()); diff --git a/Configuration/StandardSequences/python/EventInterpretation.py b/Configuration/StandardSequences/python/EventInterpretation.py index 7dc85b6fbf3db..f0f79d35e5f73 100644 --- a/Configuration/StandardSequences/python/EventInterpretation.py +++ b/Configuration/StandardSequences/python/EventInterpretation.py @@ -1,3 +1,4 @@ EventInterpretation = { - 'top' : 'CommonTools.ParticleFlow.EITopPAG_cff' + 'top' : 'CommonTools.ParticleFlow.EITopPAG_cff', + 'MiniAODfromMiniAOD' : 'PhysicsTools.PatAlgos.slimming.MiniAODfromMiniAOD_cff' } diff --git a/DataFormats/EgammaCandidates/interface/Photon.h b/DataFormats/EgammaCandidates/interface/Photon.h index 7245e97c8bd7c..5e9c16458e1e1 100644 --- a/DataFormats/EgammaCandidates/interface/Photon.h +++ b/DataFormats/EgammaCandidates/interface/Photon.h @@ -164,6 +164,9 @@ namespace reco { {} } ; + const ShowerShape& showerShapeVariables() const { return showerShapeBlock_; } + const ShowerShape& full5x5_showerShapeVariables() const { return full5x5_showerShapeBlock_; } + void setShowerShapeVariables ( const ShowerShape& a ) { showerShapeBlock_ = a ;} void full5x5_setShowerShapeVariables ( const ShowerShape& a ) { full5x5_showerShapeBlock_ = a ;} diff --git a/DataFormats/FWLite/python/__init__.py b/DataFormats/FWLite/python/__init__.py index abff1fc6fbd0a..35d18457f78cc 100644 --- a/DataFormats/FWLite/python/__init__.py +++ b/DataFormats/FWLite/python/__init__.py @@ -222,13 +222,18 @@ def getByLabel (self, *args): # handle is always the last argument argsList = list (args) handle = argsList.pop() - if len(argsList)==1 and \ - ( isinstance (argsList[0], tuple) or - isinstance (argsList[0], list) ) : - if len (argsList) > 3: - raise RuntimeError, "getByLabel Error: label tuple has too " \ - "many arguments '%s'" % argsList[0] - argsList = list(argsList[0]) + if len(argsList)==1 : + if( isinstance (argsList[0], tuple) or + isinstance (argsList[0], list) ) : + if len (argsList[0]) > 3: + raise RuntimeError, "getByLabel Error: label tuple has too " \ + "many arguments '%s'" % argsList[0] + argsList = list(*argsList[0]) + if( type(argsList[0]) is str and ":" in argsList[0] ): + if argsList[0].count(":") > 3: + raise RuntimeError, "getByLabel Error: label tuple has too " \ + "many arguments '%s'" % argsList[0].split(":") + argsList = argsList[0].split(":") while len(argsList) < 3: argsList.append ('') (moduleLabel, productInstanceLabel, processLabel) = argsList @@ -375,13 +380,18 @@ def getByLabel (self, *args): # handle is always the last argument argsList = list (args) handle = argsList.pop() - if len(argsList)==1 and \ - ( isinstance (argsList[0], tuple) or - isinstance (argsList[0], list) ) : - if len (argsList) > 3: - raise RuntimeError, "getByLabel Error: label tuple has too " \ - "many arguments '%s'" % argsList[0] - argsList = list(argsList[0]) + if len(argsList)==1 : + if( isinstance (argsList[0], tuple) or + isinstance (argsList[0], list) ) : + if len (argsList[0]) > 3: + raise RuntimeError, "getByLabel Error: label tuple has too " \ + "many arguments '%s'" % argsList[0] + argsList = list(*argsList[0]) + if( type(argsList[0]) is str and ":" in argsList[0] ): + if argsList[0].count(":") > 3: + raise RuntimeError, "getByLabel Error: label tuple has too " \ + "many arguments '%s'" % argsList[0].split(":") + argsList = argsList[0].split(":") while len(argsList) < 3: argsList.append ('') (moduleLabel, productInstanceLabel, processLabel) = argsList @@ -546,13 +556,18 @@ def getByLabel (self, *args): # handle is always the last argument argsList = list (args) handle = argsList.pop() - if len(argsList)==1 and \ - ( isinstance (argsList[0], tuple) or - isinstance (argsList[0], list) ) : - if len (argsList) > 3: - raise RuntimeError, "getByLabel Error: label tuple has too " \ - "many arguments '%s'" % argsList[0] - argsList = list(argsList[0]) + if len(argsList)==1 : + if( isinstance (argsList[0], tuple) or + isinstance (argsList[0], list) ) : + if len (argsList[0]) > 3: + raise RuntimeError, "getByLabel Error: label tuple has too " \ + "many arguments '%s'" % argsList[0] + argsList = list(*argsList[0]) + if( type(argsList[0]) is str and ":" in argsList[0] ): + if argsList[0].count(":") > 3: + raise RuntimeError, "getByLabel Error: label tuple has too " \ + "many arguments '%s'" % argsList[0].split(":") + argsList = argsList[0].split(":") while len(argsList) < 3: argsList.append ('') (moduleLabel, productInstanceLabel, processLabel) = argsList diff --git a/DataFormats/PatCandidates/interface/VIDCutFlowResult.h b/DataFormats/PatCandidates/interface/VIDCutFlowResult.h new file mode 100644 index 0000000000000..fbc4d61df4fbf --- /dev/null +++ b/DataFormats/PatCandidates/interface/VIDCutFlowResult.h @@ -0,0 +1,112 @@ +#ifndef __DataFormats_PatCandidates_VIDResult_H__ +#define __DataFormats_PatCandidates_VIDResult_H__ + +#include +#include +#include + +/********* + * + * Class: vid::CutFlowResult + * Author: L. Gray (FNAL) + * + * A synthesis of the output of a VID selector into an easily + * manipulated class, such that cuts can be masked and sidebands + * created without major intervention on the part of the person + * doing analysis. + * + * The class is self-describing and the original cut-names, the + * values cut upon, the result of each cut used, and final cutflow + * decision can be accessed with this class. Using this information + * the cut flow can be masked interactively by the user, allowing + * for a large degree of flexibility at the analysis level. + * + *********/ + +namespace vid { + class CutFlowResult { + template friend class VersionedSelector; + public: + + CutFlowResult() : bitmap_(0) {} + CutFlowResult(const std::string& name, + const std::string& hash, + const std::map& n2idx, + const std::vector& values, + unsigned bitmap, + unsigned mask = 0); + + // get the original name of this cutflow + const std::string& cutFlowName() const { return name_; } + // get the md5 hash for this cutflow + const std::string& cutFlowHash() const { return hash_; } + // did this cutflow (in its current state!) pass? + bool cutFlowPassed() const { + const unsigned all_pass = (1 << indices_.size()) - 1; + return (all_pass&bitmap_) == all_pass; + } + // how many cuts in this cutflow? + size_t cutFlowSize() const { return indices_.size(); } + + // get the name of a cut in the cutflow + // indexed by order it was executed + const std::string& getNameAtIndex(const unsigned idx) const; + + // get the individual cut result (pass/fail) either by name or by index + bool getCutResultByIndex(const unsigned idx) const; + bool getCutResultByName(const std::string& name) const; + + // return true if the cut as index/name is masked out + bool isCutMasked(const unsigned idx) const; + bool isCutMasked(const std::string& name) const; + + // get the value of variable that was cut on, either by name or by index + double getValueCutUpon(const unsigned idx) const; + double getValueCutUpon(const std::string& name) const; + + // create a new copy of this cutflow masking out the listed cuts + // can be done either by name or by index + CutFlowResult getCutFlowResultMasking(const unsigned idx) const; + CutFlowResult getCutFlowResultMasking(const std::string& name) const; + + CutFlowResult getCutFlowResultMasking(const std::vector& idxs) const; + CutFlowResult getCutFlowResultMasking(const std::vector& names) const; + + private: + std::string name_, hash_; + unsigned bitmap_, mask_; + std::vector values_; + std::vector names_; + std::vector indices_; + + CutFlowResult(const std::string& name, + const std::string& hash, + const std::vector& names, + const std::vector& indices, + const std::vector& values, + unsigned bitmap, + unsigned mask) : + name_(name), + hash_(hash), + bitmap_(bitmap), + mask_(mask), + values_(values), + names_(names), + indices_(indices) {} + + + bool getMaskBit(const unsigned idx) const { + return (bool)(0x1&(mask_>>idx)); + } + + bool getCutBit(const unsigned idx) const { + return (bool)(0x1&(bitmap_>>idx)); + } + + bool getCutValue(const unsigned idx) const { + return values_[idx]; + } + }; +} + +#endif diff --git a/DataFormats/PatCandidates/src/VIDCutFlowResult.cc b/DataFormats/PatCandidates/src/VIDCutFlowResult.cc new file mode 100644 index 0000000000000..2fc9af6f272b8 --- /dev/null +++ b/DataFormats/PatCandidates/src/VIDCutFlowResult.cc @@ -0,0 +1,151 @@ +#include "DataFormats/PatCandidates/interface/VIDCutFlowResult.h" +#include "FWCore/Utilities/interface/Exception.h" + +namespace { + static const std::string empty_str(""); +} + +namespace vid { + + CutFlowResult::CutFlowResult(const std::string& name, + const std::string& hash, + const std::map& n2idx, + const std::vector& values, + unsigned bitmap, + unsigned mask) : + name_(name), + hash_(hash), + bitmap_(bitmap), + mask_(mask), + values_(values) { + for( const auto& val : n2idx ) { + names_.push_back(val.first); + indices_.push_back(val.second); + } + } + + const std::string& CutFlowResult::getNameAtIndex(const unsigned idx) const { + unsigned internal_idx = 0; + for( const auto& value : indices_ ) { + if( value == idx ) return names_[internal_idx]; + ++internal_idx; + } + throw cms::Exception("IndexNotFound") + << "index = " << idx << " has no corresponding cut name!"; + return empty_str; + } + + bool CutFlowResult::getCutResultByIndex(const unsigned idx) const { + if( idx >= indices_.size() ) { + throw cms::Exception("OutOfBounds") + << idx << " is out of bounds for this cut flow!"; + } + return getCutBit(idx); + } + + bool CutFlowResult::getCutResultByName(const std::string& name) const { + auto found_name = std::lower_bound(names_.begin(),names_.end(),name); + if( found_name == names_.end() || *found_name != name ) { + throw cms::Exception("UnknownName") + << "Cut name: " << name + << " is not known for this cutflow!"; + } + return getCutBit(indices_[std::distance(names_.begin(),found_name)]); + } + + bool CutFlowResult::isCutMasked(const unsigned idx) const { + if( idx >= indices_.size() ) { + throw cms::Exception("OutOfBounds") + << idx << " is out of bounds for this cut flow!"; + } + return getMaskBit(idx); + } + + bool CutFlowResult::isCutMasked(const std::string& name) const { + auto found_name = std::lower_bound(names_.begin(),names_.end(),name); + if( found_name == names_.end() || *found_name != name ) { + throw cms::Exception("UnknownName") + << "Cut name: " << name + << " is not known for this cutflow!"; + } + return getMaskBit(indices_[std::distance(names_.begin(),found_name)]); + } + + double CutFlowResult::getValueCutUpon(const unsigned idx) const { + if( idx >= indices_.size() ) { + throw cms::Exception("OutOfBounds") + << idx << " is out of bounds for this cut flow!"; + } + return getCutValue(idx); + } + + double CutFlowResult::getValueCutUpon(const std::string& name) const { + auto found_name = std::lower_bound(names_.begin(),names_.end(),name); + if( found_name == names_.end() || *found_name != name ) { + throw cms::Exception("UnknownName") + << "Cut name: " << name + << " is not known for this cutflow!"; + } + return getCutValue(indices_[std::distance(names_.begin(),found_name)]); + } + + CutFlowResult CutFlowResult:: + getCutFlowResultMasking(const std::vector& idxs) const { + unsigned bitmap = bitmap_; + unsigned mask = mask_; + for( const unsigned idx : idxs ) { + if( idx >= indices_.size() ) { + throw cms::Exception("OutOfBounds") + << idx << " is out of bounds for this cut flow!"; + } + mask = mask | 1 << idx; + } + bitmap = bitmap | mask; + return CutFlowResult(name_,empty_str,names_,indices_,values_,bitmap,mask); + } + + CutFlowResult CutFlowResult:: + getCutFlowResultMasking(const std::vector& names) const { + unsigned bitmap = bitmap_; + unsigned mask = mask_; + for( const std::string& name : names ) { + auto found_name = std::lower_bound(names_.begin(),names_.end(),name); + if( found_name == names_.end() || *found_name != name ) { + throw cms::Exception("UnknownName") + << "Cut name: " << name + << " is not known for this cutflow!"; + } + mask = mask | 1 << indices_[std::distance(names_.begin(),found_name)]; + } + bitmap = bitmap | mask; + return CutFlowResult(name_,empty_str,names_,indices_,values_,bitmap,mask); + } + + CutFlowResult CutFlowResult:: + getCutFlowResultMasking(const unsigned idx) const { + unsigned bitmap = bitmap_; + unsigned mask = mask_; + if( idx >= indices_.size() ) { + throw cms::Exception("OutOfBounds") + << idx << " is out of bounds for this cut flow!"; + } + mask = mask | 1 << idx; + bitmap = bitmap | mask; + return CutFlowResult(name_,empty_str,names_,indices_,values_,bitmap,mask); + } + + CutFlowResult CutFlowResult:: + getCutFlowResultMasking(const std::string& name) const { + unsigned bitmap = bitmap_; + unsigned mask = mask_; + auto found_name = std::lower_bound(names_.begin(),names_.end(),name); + if( found_name == names_.end() || *found_name != name ) { + throw cms::Exception("UnknownName") + << "Cut name: " << name + << " is not known for this cutflow!"; + } + mask = mask | 1 << indices_[std::distance(names_.begin(),found_name)]; + bitmap = bitmap | mask; + return CutFlowResult(name_,empty_str,names_,indices_,values_,bitmap,mask); + } +} diff --git a/DataFormats/PatCandidates/src/classes_def_other.xml b/DataFormats/PatCandidates/src/classes_def_other.xml index 21fe720059310..f6a60bc6658d3 100644 --- a/DataFormats/PatCandidates/src/classes_def_other.xml +++ b/DataFormats/PatCandidates/src/classes_def_other.xml @@ -63,6 +63,14 @@ + + + + + + + + diff --git a/DataFormats/PatCandidates/src/classes_other.h b/DataFormats/PatCandidates/src/classes_other.h index fc556d42ff7bd..786ab4b4d4c14 100644 --- a/DataFormats/PatCandidates/src/classes_other.h +++ b/DataFormats/PatCandidates/src/classes_other.h @@ -7,6 +7,8 @@ #include "DataFormats/PatCandidates/interface/JetCorrFactors.h" #include "DataFormats/PatCandidates/interface/Isolation.h" +#include "DataFormats/PatCandidates/interface/PATObject.h" + #include "DataFormats/PatCandidates/interface/StringMap.h" #include "DataFormats/PatCandidates/interface/EventHypothesis.h" #include "DataFormats/PatCandidates/interface/EventHypothesisLooper.h" @@ -17,6 +19,8 @@ #include "DataFormats/PatCandidates/interface/CandKinResolution.h" +#include "DataFormats/PatCandidates/interface/VIDCutFlowResult.h" + namespace DataFormats_PatCandidates { struct dictionaryother { @@ -51,6 +55,12 @@ namespace DataFormats_PatCandidates { pat::CandKinResolutionValueMap vm_ckr; edm::Wrapper w_vm_ckr; + vid::CutFlowResult vcfr; + edm::ValueMap vm_vcfr; + edm::Wrapper w_vcfr; + edm::Wrapper > w_vm_vcfr; + pat::UserHolder uh_vcfr; + }; } diff --git a/PhysicsTools/PatAlgos/interface/ObjectModifier.h b/PhysicsTools/PatAlgos/interface/ObjectModifier.h new file mode 100644 index 0000000000000..5df6f6132822b --- /dev/null +++ b/PhysicsTools/PatAlgos/interface/ObjectModifier.h @@ -0,0 +1,59 @@ +#ifndef __PhysicsTools_PatAlgos_ObjectModifier_h__ +#define __PhysicsTools_PatAlgos_ObjectModifier_h__ + +#include "CommonTools/CandAlgos/interface/ModifyObjectValueBase.h" +#include + +namespace pat { + template + class ObjectModifier { + public: + typedef std::unique_ptr ModifierPointer; + + ObjectModifier(const edm::ParameterSet& conf); + ~ObjectModifier() {} + + void setEvent(const edm::Event& event) { + for( unsigned i = 0; i < modifiers_.size(); ++i ) + modifiers_[i]->setEvent(event); + } + + void setEventContent(const edm::EventSetup& setup) { + for( unsigned i = 0; i < modifiers_.size(); ++i ) + modifiers_[i]->setEventContent(setup); + } + + void setConsumes(edm::ConsumesCollector& sumes) { + for( unsigned i = 0; i < modifiers_.size(); ++i ) + modifiers_[i]->setConsumes(sumes); + } + + void modify(T& obj) const { + for( unsigned i = 0; i < modifiers_.size(); ++i ) + modifiers_[i]->modifyObject(obj); + } + + private: + std::vector modifiers_; + }; + + template + ObjectModifier::ObjectModifier(const edm::ParameterSet& conf) { + const std::vector& mods = + conf.getParameterSetVector("modifications"); + for(unsigned i = 0; i < mods.size(); ++i ) { + const edm::ParameterSet& iconf = mods[i]; + const std::string& mname = iconf.getParameter("modifierName"); + ModifyObjectValueBase* plugin = + ModifyObjectValueFactory::get()->create(mname,iconf); + if( nullptr != plugin ) { + modifiers_.push_back(ModifierPointer(plugin)); + } else { + throw cms::Exception("BadPluginName") + << "The requested modifier: " << mname << " is not available!"; + } + } + } +} + +#endif diff --git a/PhysicsTools/PatAlgos/plugins/BuildFile.xml b/PhysicsTools/PatAlgos/plugins/BuildFile.xml index c4d92ef359d63..494e8be9f0acc 100644 --- a/PhysicsTools/PatAlgos/plugins/BuildFile.xml +++ b/PhysicsTools/PatAlgos/plugins/BuildFile.xml @@ -16,6 +16,7 @@ + diff --git a/PhysicsTools/PatAlgos/plugins/ModifiedObjectProducer.h b/PhysicsTools/PatAlgos/plugins/ModifiedObjectProducer.h new file mode 100644 index 0000000000000..2e1eb3fdde352 --- /dev/null +++ b/PhysicsTools/PatAlgos/plugins/ModifiedObjectProducer.h @@ -0,0 +1,64 @@ +#ifndef __PhysicsTools_PatAlgos_ModifiedObjectProducer_h__ +#define __PhysicsTools_PatAlgos_ModifiedObjectProducer_h__ + +#include "PhysicsTools/PatAlgos/interface/ObjectModifier.h" + +#include "FWCore/Framework/interface/stream/EDProducer.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/Utilities/interface/InputTag.h" +#include "DataFormats/Common/interface/View.h" + +#include + +namespace pat { + + template + class ModifiedObjectProducer : public edm::stream::EDProducer<> { + public: + typedef std::vector Collection; + typedef pat::ObjectModifier Modifier; + + ModifiedObjectProducer( const edm::ParameterSet& conf ) { + //set our input source + src_ = consumes >(conf.getParameter("src")); + //setup modifier + edm::ConsumesCollector sumes(consumesCollector()); + const edm::ParameterSet& mod_config = + conf.getParameter("modifierConfig"); + modifier_.reset( new Modifier(mod_config) ); + modifier_->setConsumes(sumes); + //declare products + produces(); + } + ~ModifiedObjectProducer() {} + + virtual void beginLuminosityBlock(const edm::LuminosityBlock&, const edm::EventSetup& evs) override final { + modifier_->setEventContent(evs); + } + + virtual void produce(edm::Event& evt,const edm::EventSetup& evs) override final { + edm::Handle > input; + std::auto_ptr output(new Collection); + + evt.getByToken(src_,input); + output->reserve(input->size()); + + modifier_->setEvent(evt); + + for( auto itr = input->begin(); itr != input->end(); ++itr ) { + output->push_back(*itr); + T& obj = output->back(); + modifier_->modify(obj); + } + + evt.put(output); + } + + private: + edm::EDGetTokenT > src_; + std::unique_ptr modifier_; + }; +} + +#endif diff --git a/PhysicsTools/PatAlgos/plugins/ModifiedObjectProducers.cc b/PhysicsTools/PatAlgos/plugins/ModifiedObjectProducers.cc new file mode 100644 index 0000000000000..58e80c10fc768 --- /dev/null +++ b/PhysicsTools/PatAlgos/plugins/ModifiedObjectProducers.cc @@ -0,0 +1,20 @@ +#include "ModifiedObjectProducer.h" + +#include "DataFormats/PatCandidates/interface/Electron.h" +#include "DataFormats/PatCandidates/interface/Photon.h" +#include "DataFormats/PatCandidates/interface/Muon.h" +#include "DataFormats/PatCandidates/interface/Tau.h" +#include "DataFormats/PatCandidates/interface/Jet.h" + +typedef pat::ModifiedObjectProducer ModifiedElectronProducer; +typedef pat::ModifiedObjectProducer ModifiedPhotonProducer; +typedef pat::ModifiedObjectProducer ModifiedMuonProducer; +typedef pat::ModifiedObjectProducer ModifiedTauProducer; +typedef pat::ModifiedObjectProducer ModifiedJetProducer; + +#include "FWCore/Framework/interface/MakerMacros.h" +DEFINE_FWK_MODULE(ModifiedElectronProducer); +DEFINE_FWK_MODULE(ModifiedPhotonProducer); +DEFINE_FWK_MODULE(ModifiedMuonProducer); +DEFINE_FWK_MODULE(ModifiedTauProducer); +DEFINE_FWK_MODULE(ModifiedJetProducer); diff --git a/PhysicsTools/PatAlgos/plugins/PATElectronSlimmer.cc b/PhysicsTools/PatAlgos/plugins/PATElectronSlimmer.cc index c604c60dce9e3..396a31812adb9 100644 --- a/PhysicsTools/PatAlgos/plugins/PATElectronSlimmer.cc +++ b/PhysicsTools/PatAlgos/plugins/PATElectronSlimmer.cc @@ -6,6 +6,7 @@ #include "DataFormats/EgammaCandidates/interface/GsfElectron.h" #include "DataFormats/PatCandidates/interface/Electron.h" +#include "PhysicsTools/PatAlgos/interface/ObjectModifier.h" #include "FWCore/Framework/interface/Frameworkfwd.h" #include "FWCore/Framework/interface/EDProducer.h" @@ -28,6 +29,7 @@ namespace pat { virtual ~PATElectronSlimmer() { } virtual void produce(edm::Event & iEvent, const edm::EventSetup & iSetup); + virtual void beginLuminosityBlock(const edm::LuminosityBlock&, const edm::EventSetup&) override final; private: edm::EDGetTokenT > src_; @@ -41,6 +43,8 @@ namespace pat { bool linkToPackedPF_; StringCutObjectSelector saveNonZSClusterShapes_; edm::EDGetTokenT reducedBarrelRecHitCollectionToken_, reducedEndcapRecHitCollectionToken_; + bool modifyElectron_; + std::unique_ptr > electronModifier_; }; } // namespace @@ -61,8 +65,18 @@ pat::PATElectronSlimmer::PATElectronSlimmer(const edm::ParameterSet & iConfig) : linkToPackedPF_(iConfig.getParameter("linkToPackedPFCandidates")), saveNonZSClusterShapes_(iConfig.getParameter("saveNonZSClusterShapes")), reducedBarrelRecHitCollectionToken_(consumes(iConfig.getParameter("reducedBarrelRecHitCollection"))), - reducedEndcapRecHitCollectionToken_(consumes(iConfig.getParameter("reducedEndcapRecHitCollection"))) + reducedEndcapRecHitCollectionToken_(consumes(iConfig.getParameter("reducedEndcapRecHitCollection"))), + modifyElectron_(iConfig.getParameter("modifyElectrons")) { + edm::ConsumesCollector sumes(consumesCollector()); + if( modifyElectron_ ) { + const edm::ParameterSet& mod_config = iConfig.getParameter("modifierConfig"); + electronModifier_.reset(new pat::ObjectModifier(mod_config) ); + electronModifier_->setConsumes(sumes); + } else { + electronModifier_.reset(nullptr); + } + produces >(); if (linkToPackedPF_) { reco2pf_ = consumes>>(iConfig.getParameter("recoToPFMap")); @@ -73,6 +87,11 @@ pat::PATElectronSlimmer::PATElectronSlimmer(const edm::ParameterSet & iConfig) : mayConsume(edm::InputTag("reducedEcalRecHitsEE")); } +void +pat::PATElectronSlimmer::beginLuminosityBlock(const edm::LuminosityBlock&, const edm::EventSetup& iSetup) { + if( modifyElectron_ ) electronModifier_->setEventContent(iSetup); +} + void pat::PATElectronSlimmer::produce(edm::Event & iEvent, const edm::EventSetup & iSetup) { using namespace edm; @@ -94,10 +113,15 @@ pat::PATElectronSlimmer::produce(edm::Event & iEvent, const edm::EventSetup & iS auto_ptr > out(new vector()); out->reserve(src->size()); + if( modifyElectron_ ) { electronModifier_->setEvent(iEvent); } + std::vector keys; for (View::const_iterator it = src->begin(), ed = src->end(); it != ed; ++it) { out->push_back(*it); pat::Electron & electron = out->back(); + + if( modifyElectron_ ) { electronModifier_->modify(electron); } + if (dropSuperClusters_(electron)) { electron.superCluster_.clear(); electron.embeddedSuperCluster_ = false; } if (dropBasicClusters_(electron)) { electron.basicClusters_.clear(); } if (dropSuperClusters_(electron) || dropPFlowClusters_(electron)) { electron.pflowSuperCluster_.clear(); electron.embeddedPflowSuperCluster_ = false; } @@ -133,7 +157,6 @@ pat::PATElectronSlimmer::produce(edm::Event & iEvent, const edm::EventSetup & iS std::vector vCov = lazyToolsNoZS.localCovariances(*( electron.superCluster()->seed())); electron.full5x5_setSigmaIetaIphi(vCov[1]); } - } iEvent.put(out); diff --git a/PhysicsTools/PatAlgos/plugins/PATJetSlimmer.cc b/PhysicsTools/PatAlgos/plugins/PATJetSlimmer.cc index 7eeff2f0cd077..95775cbd36596 100644 --- a/PhysicsTools/PatAlgos/plugins/PATJetSlimmer.cc +++ b/PhysicsTools/PatAlgos/plugins/PATJetSlimmer.cc @@ -19,6 +19,7 @@ #include "CommonTools/UtilAlgos/interface/StringCutObjectSelector.h" #include "DataFormats/PatCandidates/interface/Jet.h" +#include "PhysicsTools/PatAlgos/interface/ObjectModifier.h" namespace pat { @@ -28,11 +29,14 @@ namespace pat { virtual ~PATJetSlimmer() { } virtual void produce(edm::Event & iEvent, const edm::EventSetup & iSetup); + virtual void beginLuminosityBlock(const edm::LuminosityBlock&, const edm::EventSetup&) override final; private: edm::EDGetTokenT> pf2pc_; edm::EDGetTokenT > jets_; StringCutObjectSelector dropJetVars_,dropDaughters_,rekeyDaughters_,dropTrackRefs_,dropSpecific_,dropTagInfos_; + bool modifyJet_; + std::unique_ptr > jetModifier_; }; } // namespace @@ -46,11 +50,25 @@ pat::PATJetSlimmer::PATJetSlimmer(const edm::ParameterSet & iConfig) : rekeyDaughters_(iConfig.getParameter("rekeyDaughters")), dropTrackRefs_(iConfig.getParameter("dropTrackRefs")), dropSpecific_(iConfig.getParameter("dropSpecific")), - dropTagInfos_(iConfig.getParameter("dropTagInfos")) + dropTagInfos_(iConfig.getParameter("dropTagInfos")), + modifyJet_(iConfig.getParameter("modifyJets")) { + edm::ConsumesCollector sumes(consumesCollector()); + if( modifyJet_ ) { + const edm::ParameterSet& mod_config = iConfig.getParameter("modifierConfig"); + jetModifier_.reset(new pat::ObjectModifier(mod_config) ); + jetModifier_->setConsumes(sumes); + } else { + jetModifier_.reset(nullptr); + } produces >(); } +void +pat::PATJetSlimmer::beginLuminosityBlock(const edm::LuminosityBlock&, const edm::EventSetup& iSetup) { + if( modifyJet_ ) jetModifier_->setEventContent(iSetup); +} + void pat::PATJetSlimmer::produce(edm::Event & iEvent, const edm::EventSetup & iSetup) { using namespace edm; @@ -64,9 +82,14 @@ pat::PATJetSlimmer::produce(edm::Event & iEvent, const edm::EventSetup & iSetup) auto_ptr > out(new vector()); out->reserve(src->size()); + if( modifyJet_ ) { jetModifier_->setEvent(iEvent); } + for (edm::View::const_iterator it = src->begin(), ed = src->end(); it != ed; ++it) { out->push_back(*it); pat::Jet & jet = out->back(); + + if( modifyJet_ ) { jetModifier_->modify(jet); } + if(dropTagInfos_(*it)){ jet.tagInfos_.clear(); jet.tagInfosFwdPtr_.clear(); diff --git a/PhysicsTools/PatAlgos/plugins/PATMuonSlimmer.cc b/PhysicsTools/PatAlgos/plugins/PATMuonSlimmer.cc index 8026faf066c9d..0226731bdddfa 100644 --- a/PhysicsTools/PatAlgos/plugins/PATMuonSlimmer.cc +++ b/PhysicsTools/PatAlgos/plugins/PATMuonSlimmer.cc @@ -14,6 +14,7 @@ #include "DataFormats/Common/interface/RefToPtr.h" #include "DataFormats/PatCandidates/interface/Muon.h" +#include "PhysicsTools/PatAlgos/interface/ObjectModifier.h" #include "DataFormats/ParticleFlowCandidate/interface/PFCandidate.h" #include "DataFormats/ParticleFlowCandidate/interface/PFCandidateFwd.h" #include "DataFormats/PatCandidates/interface/PackedCandidate.h" @@ -27,6 +28,7 @@ namespace pat { virtual ~PATMuonSlimmer() { } virtual void produce(edm::Event & iEvent, const edm::EventSetup & iSetup); + virtual void beginLuminosityBlock(const edm::LuminosityBlock&, const edm::EventSetup&) override final; private: edm::EDGetTokenT src_; @@ -34,6 +36,8 @@ namespace pat { edm::EDGetTokenT> pf2pc_; bool linkToPackedPF_; StringCutObjectSelector saveTeVMuons_; + bool modifyMuon_; + std::unique_ptr > muonModifier_; }; } // namespace @@ -41,8 +45,17 @@ namespace pat { pat::PATMuonSlimmer::PATMuonSlimmer(const edm::ParameterSet & iConfig) : src_(consumes(iConfig.getParameter("src"))), linkToPackedPF_(iConfig.getParameter("linkToPackedPFCandidates")), - saveTeVMuons_(iConfig.getParameter("saveTeVMuons")) + saveTeVMuons_(iConfig.getParameter("saveTeVMuons")), + modifyMuon_(iConfig.getParameter("modifyMuons")) { + edm::ConsumesCollector sumes(consumesCollector()); + if( modifyMuon_ ) { + const edm::ParameterSet& mod_config = iConfig.getParameter("modifierConfig"); + muonModifier_.reset(new pat::ObjectModifier(mod_config) ); + muonModifier_->setConsumes(sumes); + } else { + muonModifier_.reset(nullptr); + } produces >(); if (linkToPackedPF_) { pf_ = consumes(iConfig.getParameter("pfCandidates")); @@ -50,6 +63,11 @@ pat::PATMuonSlimmer::PATMuonSlimmer(const edm::ParameterSet & iConfig) : } } +void +pat::PATMuonSlimmer::beginLuminosityBlock(const edm::LuminosityBlock&, const edm::EventSetup& iSetup) { + if( modifyMuon_ ) muonModifier_->setEventContent(iSetup); +} + void pat::PATMuonSlimmer::produce(edm::Event & iEvent, const edm::EventSetup & iSetup) { using namespace edm; @@ -61,6 +79,8 @@ pat::PATMuonSlimmer::produce(edm::Event & iEvent, const edm::EventSetup & iSetup auto_ptr > out(new vector()); out->reserve(src->size()); + if( modifyMuon_ ) { muonModifier_->setEvent(iEvent); } + std::map mu2pc; if (linkToPackedPF_) { Handle pf; @@ -76,6 +96,9 @@ pat::PATMuonSlimmer::produce(edm::Event & iEvent, const edm::EventSetup & iSetup for (vector::const_iterator it = src->begin(), ed = src->end(); it != ed; ++it) { out->push_back(*it); pat::Muon & mu = out->back(); + + if( modifyMuon_ ) { muonModifier_->modify(mu); } + if (saveTeVMuons_(mu)){mu.embedPickyMuon(); mu.embedTpfmsMuon(); mu.embedDytMuon();} if (linkToPackedPF_) { mu.refToOrig_ = refToPtr(mu2pc[mu.refToOrig_]); diff --git a/PhysicsTools/PatAlgos/plugins/PATPhotonSlimmer.cc b/PhysicsTools/PatAlgos/plugins/PATPhotonSlimmer.cc index ac984ac9e80e7..953cdb668b96d 100644 --- a/PhysicsTools/PatAlgos/plugins/PATPhotonSlimmer.cc +++ b/PhysicsTools/PatAlgos/plugins/PATPhotonSlimmer.cc @@ -13,6 +13,8 @@ #include "DataFormats/PatCandidates/interface/Photon.h" +#include "PhysicsTools/PatAlgos/interface/ObjectModifier.h" + #include "DataFormats/ParticleFlowCandidate/interface/PFCandidate.h" #include "DataFormats/ParticleFlowCandidate/interface/PFCandidateFwd.h" #include "DataFormats/PatCandidates/interface/PackedCandidate.h" @@ -28,6 +30,7 @@ namespace pat { virtual ~PATPhotonSlimmer() { } virtual void produce(edm::Event & iEvent, const edm::EventSetup & iSetup); + virtual void beginLuminosityBlock(const edm::LuminosityBlock&, const edm::EventSetup&) override final; private: edm::EDGetTokenT > src_; @@ -40,6 +43,8 @@ namespace pat { bool linkToPackedPF_; StringCutObjectSelector saveNonZSClusterShapes_; edm::EDGetTokenT reducedBarrelRecHitCollectionToken_, reducedEndcapRecHitCollectionToken_; + bool modifyPhoton_; + std::unique_ptr > photonModifier_; }; } // namespace @@ -54,8 +59,18 @@ pat::PATPhotonSlimmer::PATPhotonSlimmer(const edm::ParameterSet & iConfig) : linkToPackedPF_(iConfig.getParameter("linkToPackedPFCandidates")), saveNonZSClusterShapes_(iConfig.getParameter("saveNonZSClusterShapes")), reducedBarrelRecHitCollectionToken_(consumes(iConfig.getParameter("reducedBarrelRecHitCollection"))), - reducedEndcapRecHitCollectionToken_(consumes(iConfig.getParameter("reducedEndcapRecHitCollection"))) + reducedEndcapRecHitCollectionToken_(consumes(iConfig.getParameter("reducedEndcapRecHitCollection"))), + modifyPhoton_(iConfig.getParameter("modifyPhotons")) { + edm::ConsumesCollector sumes(consumesCollector()); + if( modifyPhoton_ ) { + const edm::ParameterSet& mod_config = iConfig.getParameter("modifierConfig"); + photonModifier_.reset(new pat::ObjectModifier(mod_config) ); + photonModifier_->setConsumes(sumes); + } else { + photonModifier_.reset(nullptr); + } + produces >(); if (linkToPackedPF_) { reco2pf_ = consumes>>(iConfig.getParameter("recoToPFMap")); @@ -66,6 +81,11 @@ pat::PATPhotonSlimmer::PATPhotonSlimmer(const edm::ParameterSet & iConfig) : mayConsume(edm::InputTag("reducedEcalRecHitsEE")); } +void +pat::PATPhotonSlimmer::beginLuminosityBlock(const edm::LuminosityBlock&, const edm::EventSetup& iSetup) { + if( modifyPhoton_ ) photonModifier_->setEventContent(iSetup); +} + void pat::PATPhotonSlimmer::produce(edm::Event & iEvent, const edm::EventSetup & iSetup) { using namespace edm; @@ -87,11 +107,15 @@ pat::PATPhotonSlimmer::produce(edm::Event & iEvent, const edm::EventSetup & iSet auto_ptr > out(new vector()); out->reserve(src->size()); + if( modifyPhoton_ ) { photonModifier_->setEvent(iEvent); } + std::vector keys; for (View::const_iterator it = src->begin(), ed = src->end(); it != ed; ++it) { out->push_back(*it); pat::Photon & photon = out->back(); + if( modifyPhoton_ ) { photonModifier_->modify(photon); } + if (dropSuperClusters_(photon)) { photon.superCluster_.clear(); photon.embeddedSuperCluster_ = false; } if (dropBasicClusters_(photon)) { photon.basicClusters_.clear(); } if (dropPreshowerClusters_(photon)) { photon.preshowerClusters_.clear(); } diff --git a/PhysicsTools/PatAlgos/plugins/PATTauSlimmer.cc b/PhysicsTools/PatAlgos/plugins/PATTauSlimmer.cc index 1ed786dbd71b5..1ee03c23ff2fe 100644 --- a/PhysicsTools/PatAlgos/plugins/PATTauSlimmer.cc +++ b/PhysicsTools/PatAlgos/plugins/PATTauSlimmer.cc @@ -13,6 +13,7 @@ #include "DataFormats/PatCandidates/interface/PackedCandidate.h" #include "DataFormats/PatCandidates/interface/Tau.h" +#include "PhysicsTools/PatAlgos/interface/ObjectModifier.h" namespace pat { @@ -22,6 +23,7 @@ namespace pat { virtual ~PATTauSlimmer() { } virtual void produce(edm::Event & iEvent, const edm::EventSetup & iSetup); + virtual void beginLuminosityBlock(const edm::LuminosityBlock&, const edm::EventSetup&) override final; private: edm::EDGetTokenT > src_; @@ -30,7 +32,8 @@ namespace pat { bool dropPiZeroRefs_; bool dropTauChargedHadronRefs_; bool dropPFSpecific_; - + bool modifyTau_; + std::unique_ptr > tauModifier_; }; @@ -38,8 +41,17 @@ namespace pat { pat::PATTauSlimmer::PATTauSlimmer(const edm::ParameterSet & iConfig) : src_(consumes >(iConfig.getParameter("src"))), - linkToPackedPF_(iConfig.getParameter("linkToPackedPFCandidates")) + linkToPackedPF_(iConfig.getParameter("linkToPackedPFCandidates")), + modifyTau_(iConfig.getParameter("modifyTaus")) { + edm::ConsumesCollector sumes(consumesCollector()); + if( modifyTau_ ) { + const edm::ParameterSet& mod_config = iConfig.getParameter("modifierConfig"); + tauModifier_.reset(new pat::ObjectModifier(mod_config) ); + tauModifier_->setConsumes(sumes); + } else { + tauModifier_.reset(nullptr); + } produces >(); if (linkToPackedPF_) pf2pc_ = consumes>(iConfig.getParameter("packedPFCandidates")); dropPiZeroRefs_ = iConfig.exists("dropPiZeroRefs") ? iConfig.getParameter("dropPiZeroRefs") : true; @@ -48,6 +60,11 @@ pat::PATTauSlimmer::PATTauSlimmer(const edm::ParameterSet & iConfig) : } +void +pat::PATTauSlimmer::beginLuminosityBlock(const edm::LuminosityBlock&, const edm::EventSetup& iSetup) { + if( modifyTau_ ) tauModifier_->setEventContent(iSetup); +} + void pat::PATTauSlimmer::produce(edm::Event & iEvent, const edm::EventSetup & iSetup) { using namespace edm; @@ -62,9 +79,14 @@ pat::PATTauSlimmer::produce(edm::Event & iEvent, const edm::EventSetup & iSetup) auto_ptr > out(new vector()); out->reserve(src->size()); + if( modifyTau_ ) { tauModifier_->setEvent(iEvent); } + for (View::const_iterator it = src->begin(), ed = src->end(); it != ed; ++it) { out->push_back(*it); pat::Tau & tau = out->back(); + + if( modifyTau_ ) { tauModifier_->modify(tau); } + // clearing the pat isolation which is not used by taus tau.isolations_.clear(); tau.isoDeposits_.clear(); diff --git a/PhysicsTools/PatAlgos/python/slimming/MicroEventContent_cff.py b/PhysicsTools/PatAlgos/python/slimming/MicroEventContent_cff.py new file mode 100644 index 0000000000000..17238bc44d563 --- /dev/null +++ b/PhysicsTools/PatAlgos/python/slimming/MicroEventContent_cff.py @@ -0,0 +1,67 @@ +import FWCore.ParameterSet.Config as cms + +MicroEventContent = cms.PSet( + outputCommands = cms.untracked.vstring( + 'drop *', + 'keep *_slimmedPhotons*_*_*', + 'keep *_slimmedElectrons_*_*', + 'keep *_slimmedMuons*_*_*', + 'keep *_slimmedTaus*_*_*', + 'keep *_slimmedJets_*_*', + 'keep *_slimmedJetsAK8_*_*', + 'keep *_slimmedJetsPuppi_*_*', + 'keep *_slimmedMETs*_*_*', + 'keep *_slimmedSecondaryVertices*_*_*', + 'keep *_cmsTopTaggerMap_*_*', + #'keep *_slimmedJetsAK8PFCHSSoftDropSubjets_*_*', + #'keep *_slimmedJetsCMSTopTagCHSSubjets_*_*', + 'keep *_slimmedJetsAK8PFCHSSoftDropPacked_SubJets_*', + 'keep *_slimmedJetsCMSTopTagCHSPacked_SubJets_*', + #'keep *_packedPatJetsAK8_*_*', + ## add extra METs + + 'keep recoPhotonCores_reducedEgamma_*_*', + 'keep recoGsfElectronCores_reducedEgamma_*_*', + 'keep recoConversions_reducedEgamma_*_*', + 'keep recoSuperClusters_reducedEgamma_*_*', + 'keep recoCaloClusters_reducedEgamma_*_*', + 'keep EcalRecHitsSorted_reducedEgamma_*_*', + + + 'drop *_*_caloTowers_*', + 'drop *_*_pfCandidates_*', + 'drop *_*_genJets_*', + + 'keep *_offlineBeamSpot_*_*', + 'keep *_offlineSlimmedPrimaryVertices_*_*', + 'keep patPackedCandidates_packedPFCandidates_*_*', + + 'keep double_fixedGridRho*__*', + + 'keep *_selectedPatTrigger_*_*', + 'keep patPackedTriggerPrescales_patTrigger__*', + 'keep *_l1extraParticles_*_*', + 'keep L1GlobalTriggerReadoutRecord_gtDigis_*_*', + 'keep *_TriggerResults_*_HLT', + 'keep *_TriggerResults_*_*', # for MET filters (a catch all for the moment, but ideally it should be only the current process) + 'keep patPackedCandidates_lostTracks_*_*', + 'keep HcalNoiseSummary_hcalnoise__*', + 'keep *_caTopTagInfosPAT_*_*' + ) +) +MicroEventContentMC = cms.PSet( + outputCommands = cms.untracked.vstring(MicroEventContent.outputCommands) +) +MicroEventContentMC.outputCommands += [ + 'keep *_slimmedGenJets*_*_*', + 'keep patPackedGenParticles_packedGenParticles_*_*', + 'keep recoGenParticles_prunedGenParticles_*_*', + 'keep LHEEventProduct_*_*_*', + 'keep PileupSummaryInfos_*_*_*', + 'keep GenFilterInfo_*_*_*', + 'keep GenEventInfoProduct_generator_*_*', + # RUN + 'keep LHERunInfoProduct_*_*_*', + 'keep GenRunInfoProduct_*_*_*', + 'keep L1GtTriggerMenuLite_l1GtTriggerMenuLite__*', +] diff --git a/PhysicsTools/PatAlgos/python/slimming/MiniAODfromMiniAOD_cff.py b/PhysicsTools/PatAlgos/python/slimming/MiniAODfromMiniAOD_cff.py new file mode 100644 index 0000000000000..70ce3a51253f9 --- /dev/null +++ b/PhysicsTools/PatAlgos/python/slimming/MiniAODfromMiniAOD_cff.py @@ -0,0 +1,6 @@ +import FWCore.ParameterSet.Config as cms + +from PhysicsTools.PatAlgos.slimming.modifyPrimaryPhysicsObjects_cff import * +from PhysicsTools.PatAlgos.slimming.MicroEventContent_cff import * + +EIsequence = cms.Sequence( modifyPrimaryPhysicsObjects ) diff --git a/PhysicsTools/PatAlgos/python/slimming/applySubstructure_cff.py b/PhysicsTools/PatAlgos/python/slimming/applySubstructure_cff.py index 421d9ee61e712..fb63bd362b33d 100644 --- a/PhysicsTools/PatAlgos/python/slimming/applySubstructure_cff.py +++ b/PhysicsTools/PatAlgos/python/slimming/applySubstructure_cff.py @@ -88,6 +88,8 @@ def applySubstructure( process ) : dropTrackRefs = cms.string("1"), dropSpecific = cms.string("1"), dropTagInfos = cms.string("1"), + modifyJets = cms.bool(True), + modifierConfig = cms.PSet( modifications = cms.VPSet() ) ) @@ -133,6 +135,8 @@ def applySubstructure( process ) : dropTrackRefs = cms.string("1"), dropSpecific = cms.string("1"), dropTagInfos = cms.string("1"), + modifyJets = cms.bool(True), + modifierConfig = cms.PSet( modifications = cms.VPSet() ) ) ## Establish references between PATified fat jets and subjets using the BoostedJetMerger diff --git a/PhysicsTools/PatAlgos/python/slimming/miniAOD_tools.py b/PhysicsTools/PatAlgos/python/slimming/miniAOD_tools.py index e2a8e5168c7de..0e70889bf41df 100644 --- a/PhysicsTools/PatAlgos/python/slimming/miniAOD_tools.py +++ b/PhysicsTools/PatAlgos/python/slimming/miniAOD_tools.py @@ -166,26 +166,37 @@ def miniAOD_customizeCommon(process): lazyParser = cms.bool(True) ) process.patJets.userData.userFloats.src += [ cms.InputTag("caloJetMap:pt"), cms.InputTag("caloJetMap:emEnergyFraction") ] + #EGM object modifications + from RecoEgamma.EgammaTools.egammaObjectModificationsInMiniAOD_cff import egamma_modifications + process.slimmedElectrons.modifierConfig.modifications = egamma_modifications + process.slimmedPhotons.modifierConfig.modifications = egamma_modifications + #VID Electron IDs electron_ids = ['RecoEgamma.ElectronIdentification.Identification.cutBasedElectronID_PHYS14_PU20bx25_V2_cff', - 'RecoEgamma.ElectronIdentification.Identification.heepElectronID_HEEPV51_cff'] + 'RecoEgamma.ElectronIdentification.Identification.heepElectronID_HEEPV51_cff', + 'RecoEgamma.ElectronIdentification.Identification.heepElectronID_HEEPV60_cff', + 'RecoEgamma.ElectronIdentification.Identification.mvaElectronID_PHYS14_PU20bx25_nonTrig_V1_cff'] switchOnVIDElectronIdProducer(process,DataFormat.MiniAOD) process.egmGsfElectronIDs.physicsObjectSrc = \ cms.InputTag("reducedEgamma","reducedGedGsfElectrons") + process.electronMVAValueMapProducer.src = \ + cms.InputTag('reducedEgamma','reducedGedGsfElectrons') for idmod in electron_ids: setupAllVIDIdsInModule(process,idmod,setupVIDElectronSelection) #VID Photon IDs - photon_ids = ['RecoEgamma.PhotonIdentification.Identification.cutBasedPhotonID_PHYS14_PU20bx25_V2_cff'] + photon_ids = ['RecoEgamma.PhotonIdentification.Identification.cutBasedPhotonID_PHYS14_PU20bx25_V2_cff', + 'RecoEgamma.PhotonIdentification.Identification.mvaPhotonID_PHYS14_PU20bx25_nonTrig_V1_cff', + 'RecoEgamma.PhotonIdentification.Identification.mvaPhotonID_Spring15_50ns_nonTrig_V0_cff'] switchOnVIDPhotonIdProducer(process,DataFormat.MiniAOD) process.egmPhotonIDs.physicsObjectSrc = \ cms.InputTag("reducedEgamma","reducedGedPhotons") process.photonIDValueMapProducer.src = \ cms.InputTag("reducedEgamma","reducedGedPhotons") - process.photonIDValueMapProducer.srcMiniAOD = \ - cms.InputTag("reducedEgamma","reducedGedPhotons") process.photonIDValueMapProducer.particleBasedIsolation = \ - cms.InputTag("reducedEgamma","reducedPhotonPfCandMap") + cms.InputTag("reducedEgamma","reducedPhotonPfCandMap") + process.photonMVAValueMapProducer.src = \ + cms.InputTag('reducedEgamma','reducedGedPhotons') for idmod in photon_ids: setupAllVIDIdsInModule(process,idmod,setupVIDPhotonSelection) diff --git a/PhysicsTools/PatAlgos/python/slimming/modifiedElectrons_cfi.py b/PhysicsTools/PatAlgos/python/slimming/modifiedElectrons_cfi.py new file mode 100644 index 0000000000000..f24392fb61ebd --- /dev/null +++ b/PhysicsTools/PatAlgos/python/slimming/modifiedElectrons_cfi.py @@ -0,0 +1,10 @@ +import FWCore.ParameterSet.Config as cms + +modifiedElectrons = cms.EDProducer( + "ModifiedElectronProducer", + src = cms.InputTag("slimmedElectrons",processName=cms.InputTag.skipCurrentProcess()), + modifierConfig = cms.PSet( modifications = cms.VPSet() ) +) + +from RecoEgamma.EgammaTools.egammaObjectModificationsPatches_cff import * +modifiedElectrons.modifierConfig.modifications = egamma_modifications diff --git a/PhysicsTools/PatAlgos/python/slimming/modifiedJets_cfi.py b/PhysicsTools/PatAlgos/python/slimming/modifiedJets_cfi.py new file mode 100644 index 0000000000000..ba994990db63b --- /dev/null +++ b/PhysicsTools/PatAlgos/python/slimming/modifiedJets_cfi.py @@ -0,0 +1,7 @@ +import FWCore.ParameterSet.Config as cms + +modifiedJets = cms.EDProducer( + "ModifiedJetProducer", + src = cms.InputTag("slimmedJets",processName=cms.InputTag.skipCurrentProcess()), + modifierConfig = cms.PSet( modifications = cms.VPSet() ) +) diff --git a/PhysicsTools/PatAlgos/python/slimming/modifiedMuons_cfi.py b/PhysicsTools/PatAlgos/python/slimming/modifiedMuons_cfi.py new file mode 100644 index 0000000000000..3c67a631ed76c --- /dev/null +++ b/PhysicsTools/PatAlgos/python/slimming/modifiedMuons_cfi.py @@ -0,0 +1,7 @@ +import FWCore.ParameterSet.Config as cms + +modifiedMuons = cms.EDProducer( + "ModifiedMuonProducer", + src = cms.InputTag("slimmedMuons",processName=cms.InputTag.skipCurrentProcess()), + modifierConfig = cms.PSet( modifications = cms.VPSet() ) +) diff --git a/PhysicsTools/PatAlgos/python/slimming/modifiedPhotons_cfi.py b/PhysicsTools/PatAlgos/python/slimming/modifiedPhotons_cfi.py new file mode 100644 index 0000000000000..88c4b31f3e55a --- /dev/null +++ b/PhysicsTools/PatAlgos/python/slimming/modifiedPhotons_cfi.py @@ -0,0 +1,10 @@ +import FWCore.ParameterSet.Config as cms + +modifiedPhotons = cms.EDProducer( + "ModifiedPhotonProducer", + src = cms.InputTag("slimmedPhotons",processName=cms.InputTag.skipCurrentProcess()), + modifierConfig = cms.PSet( modifications = cms.VPSet() ) +) + +from RecoEgamma.EgammaTools.egammaObjectModificationsPatches_cff import * +modifiedPhotons.modifierConfig.modifications = egamma_modifications diff --git a/PhysicsTools/PatAlgos/python/slimming/modifiedTaus_cfi.py b/PhysicsTools/PatAlgos/python/slimming/modifiedTaus_cfi.py new file mode 100644 index 0000000000000..e02a2e179f67b --- /dev/null +++ b/PhysicsTools/PatAlgos/python/slimming/modifiedTaus_cfi.py @@ -0,0 +1,7 @@ +import FWCore.ParameterSet.Config as cms + +modifiedTaus = cms.EDProducer( + "ModifiedTauProducer", + src = cms.InputTag("slimmedTaus",processName=cms.InputTag.skipCurrentProcess()), + modifierConfig = cms.PSet( modifications = cms.VPSet() ) +) diff --git a/PhysicsTools/PatAlgos/python/slimming/modifyPrimaryPhysicsObjects_cff.py b/PhysicsTools/PatAlgos/python/slimming/modifyPrimaryPhysicsObjects_cff.py new file mode 100644 index 0000000000000..672993885c1f7 --- /dev/null +++ b/PhysicsTools/PatAlgos/python/slimming/modifyPrimaryPhysicsObjects_cff.py @@ -0,0 +1,31 @@ +import FWCore.ParameterSet.Config as cms + +from PhysicsTools.PatAlgos.slimming.modifiedElectrons_cfi import * +from PhysicsTools.PatAlgos.slimming.modifiedPhotons_cfi import * +from PhysicsTools.PatAlgos.slimming.modifiedMuons_cfi import * +from PhysicsTools.PatAlgos.slimming.modifiedTaus_cfi import * +from PhysicsTools.PatAlgos.slimming.modifiedJets_cfi import * + +#get any prereqs from POG areas +from RecoEgamma.ElectronIdentification.ElectronMVAValueMapProducer_cfi import * +from RecoEgamma.PhotonIdentification.PhotonIDValueMapProducer_cfi import * +from RecoEgamma.PhotonIdentification.PhotonMVAValueMapProducer_cfi import * + +#clone modules so we have slimmed* -> slimmed* +slimmedElectrons = modifiedElectrons.clone() +slimmedPhotons = modifiedPhotons.clone() +slimmedMuons = modifiedMuons.clone() +slimmedTaus = modifiedTaus.clone() +slimmedJets = modifiedJets.clone() +slimmedJetsAK8 = modifiedJets.clone( src = cms.InputTag("slimmedJetsAK8",processName=cms.InputTag.skipCurrentProcess()) ) +slimmedJetsPuppi = modifiedJets.clone( src = cms.InputTag("slimmedJetsPuppi",processName=cms.InputTag.skipCurrentProcess()) ) + +modifyPrimaryPhysicsObjects = cms.Sequence( electronMVAValueMapProducer * + photonIDValueMapProducer * photonMVAValueMapProducer * + slimmedElectrons * + slimmedPhotons * + slimmedMuons * + slimmedTaus * + slimmedJets * + slimmedJetsAK8 * + slimmedJetsPuppi ) diff --git a/PhysicsTools/PatAlgos/python/slimming/slimmedElectrons_cfi.py b/PhysicsTools/PatAlgos/python/slimming/slimmedElectrons_cfi.py index 2666820b1d709..578c01aab50c5 100644 --- a/PhysicsTools/PatAlgos/python/slimming/slimmedElectrons_cfi.py +++ b/PhysicsTools/PatAlgos/python/slimming/slimmedElectrons_cfi.py @@ -1,7 +1,7 @@ import FWCore.ParameterSet.Config as cms slimmedElectrons = cms.EDProducer("PATElectronSlimmer", - src = cms.InputTag("selectedPatElectrons"), + src = cms.InputTag("selectedPatElectrons"), dropSuperCluster = cms.string("0"), # you can put a cut to slim selectively, e.g. pt < 10 dropBasicClusters = cms.string("0"), # you can put a cut to slim selectively, e.g. pt < 10 dropPFlowClusters = cms.string("0"), # you can put a cut to slim selectively, e.g. pt < 10 @@ -19,5 +19,7 @@ saveNonZSClusterShapes = cms.string("pt > 5"), # save additional user floats: (sigmaIetaIeta,sigmaIphiIphi,sigmaIetaIphi,r9,e1x5_over_e5x5)_NoZS reducedBarrelRecHitCollection = cms.InputTag("reducedEcalRecHitsEB"), reducedEndcapRecHitCollection = cms.InputTag("reducedEcalRecHitsEE"), + modifyElectrons = cms.bool(True), + modifierConfig = cms.PSet( modifications = cms.VPSet() ) ) diff --git a/PhysicsTools/PatAlgos/python/slimming/slimmedJets_cfi.py b/PhysicsTools/PatAlgos/python/slimming/slimmedJets_cfi.py index 28949cf8d0eb1..bf6547dbe75d8 100644 --- a/PhysicsTools/PatAlgos/python/slimming/slimmedJets_cfi.py +++ b/PhysicsTools/PatAlgos/python/slimming/slimmedJets_cfi.py @@ -9,6 +9,8 @@ dropTrackRefs = cms.string("1"), dropSpecific = cms.string("0"), dropTagInfos = cms.string("1"), + modifyJets = cms.bool(True), + modifierConfig = cms.PSet( modifications = cms.VPSet() ) ) slimmedJetsAK8 = cms.EDProducer("PATJetSlimmer", src = cms.InputTag("packedPatJetsAK8"), @@ -19,5 +21,7 @@ dropTrackRefs = cms.string("1"), dropSpecific = cms.string("0"), dropTagInfos = cms.string("0"), + modifyJets = cms.bool(True), + modifierConfig = cms.PSet( modifications = cms.VPSet() ) ) diff --git a/PhysicsTools/PatAlgos/python/slimming/slimmedMuons_cfi.py b/PhysicsTools/PatAlgos/python/slimming/slimmedMuons_cfi.py index cd7302f4e759f..1d593e081fc11 100644 --- a/PhysicsTools/PatAlgos/python/slimming/slimmedMuons_cfi.py +++ b/PhysicsTools/PatAlgos/python/slimming/slimmedMuons_cfi.py @@ -6,5 +6,7 @@ pfCandidates = cms.InputTag("particleFlow"), packedPFCandidates = cms.InputTag("packedPFCandidates"), saveTeVMuons = cms.string("pt > 100"), # you can put a cut to slim selectively, e.g. pt > 10 + modifyMuons = cms.bool(True), + modifierConfig = cms.PSet( modifications = cms.VPSet() ) ) diff --git a/PhysicsTools/PatAlgos/python/slimming/slimmedPhotons_cfi.py b/PhysicsTools/PatAlgos/python/slimming/slimmedPhotons_cfi.py index aafb4f7409354..909dbb9c6d1ac 100644 --- a/PhysicsTools/PatAlgos/python/slimming/slimmedPhotons_cfi.py +++ b/PhysicsTools/PatAlgos/python/slimming/slimmedPhotons_cfi.py @@ -13,4 +13,6 @@ saveNonZSClusterShapes = cms.string("(r9()>0.8 || chargedHadronIso()<20 || chargedHadronIso()<0.3*pt())"), # save additional user floats: (sigmaIetaIeta,sigmaIphiIphi,sigmaIetaIphi,r9,e1x5_over_e5x5)_NoZS reducedBarrelRecHitCollection = cms.InputTag("reducedEcalRecHitsEB"), reducedEndcapRecHitCollection = cms.InputTag("reducedEcalRecHitsEE"), + modifyPhotons = cms.bool(True), + modifierConfig = cms.PSet( modifications = cms.VPSet() ) ) diff --git a/PhysicsTools/PatAlgos/python/slimming/slimmedTaus_cfi.py b/PhysicsTools/PatAlgos/python/slimming/slimmedTaus_cfi.py index c5c1d867f3718..01fd234a30119 100644 --- a/PhysicsTools/PatAlgos/python/slimming/slimmedTaus_cfi.py +++ b/PhysicsTools/PatAlgos/python/slimming/slimmedTaus_cfi.py @@ -7,5 +7,7 @@ dropTauChargedHadronRefs = cms.bool(True), dropPFSpecific = cms.bool(True), packedPFCandidates = cms.InputTag("packedPFCandidates"), + modifyTaus = cms.bool(True), + modifierConfig = cms.PSet( modifications = cms.VPSet() ) ) diff --git a/PhysicsTools/PatAlgos/python/slimming/slimming_cff.py b/PhysicsTools/PatAlgos/python/slimming/slimming_cff.py index 53de669924988..72379e807bbba 100644 --- a/PhysicsTools/PatAlgos/python/slimming/slimming_cff.py +++ b/PhysicsTools/PatAlgos/python/slimming/slimming_cff.py @@ -15,70 +15,5 @@ from PhysicsTools.PatAlgos.slimming.slimmedSecondaryVertices_cfi import * from PhysicsTools.PatAlgos.slimming.slimmedMETs_cfi import * from PhysicsTools.PatAlgos.slimming.metFilterPaths_cff import * +from PhysicsTools.PatAlgos.slimming.MicroEventContent_cff import * from RecoEgamma.EgammaPhotonProducers.reducedEgamma_cfi import * - -MicroEventContent = cms.PSet( - outputCommands = cms.untracked.vstring( - 'drop *', - 'keep *_slimmedPhotons*_*_*', - 'keep *_slimmedElectrons_*_*', - 'keep *_slimmedMuons*_*_*', - 'keep *_slimmedTaus*_*_*', - 'keep *_slimmedJets_*_*', - 'keep *_slimmedJetsAK8_*_*', - 'keep *_slimmedJetsPuppi_*_*', - 'keep *_slimmedMETs*_*_*', - 'keep *_slimmedSecondaryVertices*_*_*', - 'keep *_cmsTopTaggerMap_*_*', - #'keep *_slimmedJetsAK8PFCHSSoftDropSubjets_*_*', - #'keep *_slimmedJetsCMSTopTagCHSSubjets_*_*', - 'keep *_slimmedJetsAK8PFCHSSoftDropPacked_SubJets_*', - 'keep *_slimmedJetsCMSTopTagCHSPacked_SubJets_*', - #'keep *_packedPatJetsAK8_*_*', - ## add extra METs - - 'keep recoPhotonCores_reducedEgamma_*_*', - 'keep recoGsfElectronCores_reducedEgamma_*_*', - 'keep recoConversions_reducedEgamma_*_*', - 'keep recoSuperClusters_reducedEgamma_*_*', - 'keep recoCaloClusters_reducedEgamma_*_*', - 'keep EcalRecHitsSorted_reducedEgamma_*_*', - - - 'drop *_*_caloTowers_*', - 'drop *_*_pfCandidates_*', - 'drop *_*_genJets_*', - - 'keep *_offlineBeamSpot_*_*', - 'keep *_offlineSlimmedPrimaryVertices_*_*', - 'keep patPackedCandidates_packedPFCandidates_*_*', - - 'keep double_fixedGridRho*__*', - - 'keep *_selectedPatTrigger_*_*', - 'keep patPackedTriggerPrescales_patTrigger__*', - 'keep *_l1extraParticles_*_*', - 'keep L1GlobalTriggerReadoutRecord_gtDigis_*_*', - 'keep *_TriggerResults_*_HLT', - 'keep *_TriggerResults_*_*', # for MET filters (a catch all for the moment, but ideally it should be only the current process) - 'keep patPackedCandidates_lostTracks_*_*', - 'keep HcalNoiseSummary_hcalnoise__*', - 'keep *_caTopTagInfosPAT_*_*' - ) -) -MicroEventContentMC = cms.PSet( - outputCommands = cms.untracked.vstring(MicroEventContent.outputCommands) -) -MicroEventContentMC.outputCommands += [ - 'keep *_slimmedGenJets*_*_*', - 'keep patPackedGenParticles_packedGenParticles_*_*', - 'keep recoGenParticles_prunedGenParticles_*_*', - 'keep LHEEventProduct_*_*_*', - 'keep PileupSummaryInfos_*_*_*', - 'keep GenFilterInfo_*_*_*', - 'keep GenEventInfoProduct_generator_*_*', - # RUN - 'keep LHERunInfoProduct_*_*_*', - 'keep GenRunInfoProduct_*_*_*', - 'keep L1GtTriggerMenuLite_l1GtTriggerMenuLite__*', -] diff --git a/PhysicsTools/SelectorUtils/interface/CandidateCut.h b/PhysicsTools/SelectorUtils/interface/CandidateCut.h index 63bcdf50743c6..3daee99d2e9cb 100644 --- a/PhysicsTools/SelectorUtils/interface/CandidateCut.h +++ b/PhysicsTools/SelectorUtils/interface/CandidateCut.h @@ -7,8 +7,13 @@ namespace candidate_functions { class CandidateCut : public std::unary_function{ public: + CandidateCut() {} virtual result_type operator()(const argument_type&) const = 0; virtual ~CandidateCut() {} + + virtual double value(const reco::CandidatePtr&) const = 0; + + virtual const std::string& name() const = 0; }; } diff --git a/PhysicsTools/SelectorUtils/interface/CutApplicatorBase.h b/PhysicsTools/SelectorUtils/interface/CutApplicatorBase.h index bcc2fa9802fea..b46b77d4fb5ba 100644 --- a/PhysicsTools/SelectorUtils/interface/CutApplicatorBase.h +++ b/PhysicsTools/SelectorUtils/interface/CutApplicatorBase.h @@ -47,7 +47,9 @@ class CutApplicatorBase : public candf::CandidateCut { enum CandidateType{NONE, ELECTRON,MUON,PHOTON,TAU, PATELECTRON,PATMUON,PATPHOTON,PATTAU}; - + + CutApplicatorBase(): CandidateCut() {} + CutApplicatorBase(const edm::ParameterSet& c) : _name(c.getParameter("cutName")) { } @@ -84,7 +86,7 @@ class CutApplicatorBase : public candf::CandidateCut { virtual CandidateType candidateType() const { return NONE; } - const std::string& name() const { return _name; } + virtual const std::string& name() const { return _name; } //! Destructor virtual ~CutApplicatorBase(){}; diff --git a/PhysicsTools/SelectorUtils/interface/CutApplicatorWithEventContentBase.h b/PhysicsTools/SelectorUtils/interface/CutApplicatorWithEventContentBase.h index 8b8554ca29095..1421b76e8fceb 100644 --- a/PhysicsTools/SelectorUtils/interface/CutApplicatorWithEventContentBase.h +++ b/PhysicsTools/SelectorUtils/interface/CutApplicatorWithEventContentBase.h @@ -7,6 +7,7 @@ #include "PhysicsTools/SelectorUtils/interface/CutApplicatorBase.h" #include "DataFormats/Common/interface/ValueMap.h" +#include "DataFormats/Provenance/interface/ProductID.h" #if !defined(__CINT__) && !defined(__MAKECINT__) && !defined(__REFLEX__) #include "FWCore/Framework/interface/ConsumesCollector.h" @@ -17,6 +18,9 @@ class CutApplicatorWithEventContentBase : public CutApplicatorBase { public: + + CutApplicatorWithEventContentBase(): CutApplicatorBase() {} + CutApplicatorWithEventContentBase(const edm::ParameterSet& c) : CutApplicatorBase(c) { } diff --git a/PhysicsTools/SelectorUtils/interface/VersionedIdProducer.h b/PhysicsTools/SelectorUtils/interface/VersionedIdProducer.h index 2315e830c9de4..8f392249d09d9 100644 --- a/PhysicsTools/SelectorUtils/interface/VersionedIdProducer.h +++ b/PhysicsTools/SelectorUtils/interface/VersionedIdProducer.h @@ -12,7 +12,11 @@ #include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "DataFormats/PatCandidates/interface/VIDCutFlowResult.h" +#include "DataFormats/PatCandidates/interface/UserData.h" + #include "DataFormats/Common/interface/View.h" +#include "DataFormats/Common/interface/RefToPtr.h" #include "PhysicsTools/SelectorUtils/interface/VersionedSelector.h" @@ -118,6 +122,9 @@ VersionedIdProducer(const edm::ParameterSet& iConfig) { produces >(idname); // for PAT produces >(idname); produces >(idname+std::string(bitmap_label)); + produces >(idname); + produces(idname); + produces > >(idname); } } @@ -136,16 +143,23 @@ produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { std::auto_ptr > outPassf(new edm::ValueMap() ); std::auto_ptr > outHowFar(new edm::ValueMap() ); std::auto_ptr > outBitmap(new edm::ValueMap() ); + std::auto_ptr > out_cfrs(new edm::ValueMap() ); + std::auto_ptr out_usrd(new pat::UserDataCollection); + std::vector passfail; std::vector passfailf; std::vector howfar; std::vector bitmap; + std::vector cfrs; + for(size_t i = 0; i < physicsobjects.size(); ++i) { auto po = physicsobjects.ptrAt(i); passfail.push_back((*id)(po,iEvent)); passfailf.push_back(passfail.back()); howfar.push_back(id->howFarInCutFlow()); bitmap.push_back(id->bitMap()); + cfrs.push_back(id->cutFlowResult()); + out_usrd->push_back(pat::UserData::make(cfrs.back(),false)); } edm::ValueMap::Filler fillerpassfail(*outPass); @@ -164,13 +178,30 @@ produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { fillerbitmap.insert(physicsObjectsHandle, bitmap.begin(), bitmap.end() ); fillerbitmap.fill(); + edm::ValueMap::Filler fillercfr(*out_cfrs); + fillercfr.insert(physicsObjectsHandle, cfrs.begin(), cfrs.end() ); + fillercfr.fill(); + iEvent.put(outPass,id->name()); iEvent.put(outPassf,id->name()); iEvent.put(outHowFar,id->name()); iEvent.put(outBitmap,id->name()+std::string(bitmap_label)); + iEvent.put(out_cfrs,id->name()); iEvent.put(std::auto_ptr(new std::string(id->md5String())), id->name()); - + auto usrd_handle = iEvent.put(out_usrd,id->name()); + //now add the value map of ptrs to user datas + std::auto_ptr > > out_usrdptrs(new edm::ValueMap >); + std::vector > usrdptrs; + for( unsigned i = 0; i < usrd_handle->size(); ++i ){ + usrdptrs.push_back(edm::Ptr(usrd_handle,i)); + } + + edm::ValueMap >::Filler fillerusrdptrs(*out_usrdptrs); + fillerusrdptrs.insert(physicsObjectsHandle, usrdptrs.begin(), usrdptrs.end()); + fillerusrdptrs.fill(); + + iEvent.put(out_usrdptrs,id->name()); } } diff --git a/PhysicsTools/SelectorUtils/interface/VersionedSelector.h b/PhysicsTools/SelectorUtils/interface/VersionedSelector.h index e78d075a15d4e..8c48695845133 100644 --- a/PhysicsTools/SelectorUtils/interface/VersionedSelector.h +++ b/PhysicsTools/SelectorUtils/interface/VersionedSelector.h @@ -38,6 +38,10 @@ namespace candf = candidate_functions; +namespace vid { + class CutFlowResult; +} + template class VersionedSelector : public Selector { public: @@ -70,6 +74,7 @@ class VersionedSelector : public Selector { virtual bool operator()( const T& ref, pat::strbitset& ret ) CINT_GUARD(override final) { howfar_ = 0; bitmap_ = 0; + values_.clear(); bool failed = false; if( !initialized_ ) { throw cms::Exception("CutNotInitialized") @@ -78,6 +83,7 @@ class VersionedSelector : public Selector { for( unsigned i = 0; i < cuts_.size(); ++i ) { reco::CandidatePtr temp(ref); const bool result = (*cuts_[i])(temp); + values_.push_back(cuts_[i]->value(temp)); if( result || this->ignoreCut(cut_indices_[i]) ) { this->passCut(ret,cut_indices_[i]); bitmap_ |= 1< { //repeat the other operator() we left out here //in the base class here so they are exposed to ROOT + + /* VID BY VALUE */ + bool operator()( typename T::value_type const & t ) { + const T temp(&t,0); // assuming T is edm::Ptr + return this->operator()(temp); + } + + bool operator()( typename T::value_type const & t, edm::EventBase const & e) { + const T temp(&t,0); + return this->operator()(temp,e); + } virtual bool operator()( T const & t ) CINT_GUARD(override final) { this->retInternal_.set(false); @@ -134,6 +151,8 @@ class VersionedSelector : public Selector { const size_t cutFlowSize() const { return cuts_.size(); } + vid::CutFlowResult cutFlowResult() const; + void initialize(const edm::ParameterSet&); CINT_GUARD(void setConsumes(edm::ConsumesCollector)); @@ -144,6 +163,7 @@ class VersionedSelector : public Selector { std::vector needs_event_content_; std::vector::index_type> cut_indices_; unsigned howfar_, bitmap_; + std::vector values_; private: unsigned char id_md5_[MD5_DIGEST_LENGTH]; @@ -171,23 +191,24 @@ initialize( const edm::ParameterSet& conf ) { cend(cutflow.end()); std::vector::const_iterator icut = cbegin; std::map cut_counter; - for( ; icut != cend; ++icut ) { - std::stringstream realname; - const std::string& name = icut->getParameter("cutName"); - if( !cut_counter.count(name) ) cut_counter[name] = 0; - realname << name << "_" << cut_counter[name]; + for( ; icut != cend; ++icut ) { + const std::string& cname = icut->getParameter("cutName"); const bool needsContent = icut->getParameter("needsAdditionalProducts"); const bool ignored = icut->getParameter("isIgnored"); candf::CandidateCut* plugin = nullptr; - CINT_GUARD(plugin = CutApplicatorFactory::get()->create(name,*icut)); + CINT_GUARD(plugin = CutApplicatorFactory::get()->create(cname,*icut)); if( plugin != nullptr ) { cuts_.push_back(SHARED_PTR(candf::CandidateCut)(plugin)); } else { throw cms::Exception("BadPluginName") - << "The requested cut: " << name << " is not available!"; + << "The requested cut: " << cname << " is not available!"; } needs_event_content_.push_back(needsContent); + const std::string& name = plugin->name(); + std::stringstream realname; + if( !cut_counter.count(name) ) cut_counter[name] = 0; + realname << name << "_" << cut_counter[name]; const std::string therealname = realname.str(); this->push_back(therealname); this->set(therealname); @@ -200,7 +221,7 @@ initialize( const edm::ParameterSet& conf ) { cut_counter.clear(); for( ; icut != cend; ++icut ) { std::stringstream realname; - const std::string& name = icut->getParameter("cutName"); + const std::string& name = cuts_[std::distance(cbegin,icut)]->name(); if( !cut_counter.count(name) ) cut_counter[name] = 0; realname << name << "_" << cut_counter[name]; cut_indices_.push_back(typename Selector::index_type(&(this->bits_),realname.str())); @@ -210,7 +231,25 @@ initialize( const edm::ParameterSet& conf ) { initialized_ = true; } + + #ifdef REGULAR_CPLUSPLUS +#include "DataFormats/PatCandidates/interface/VIDCutFlowResult.h" +template +vid::CutFlowResult VersionedSelector::cutFlowResult() const { + std::map names_to_index; + std::map cut_counter; + for( unsigned idx = 0; idx < cuts_.size(); ++idx ) { + const std::string& name = cuts_[idx]->name(); + if( !cut_counter.count(name) ) cut_counter[name] = 0; + std::stringstream realname; + realname << name << "_" << cut_counter[name]; + names_to_index.emplace(realname.str(),idx); + cut_counter[name]++; + } + return vid::CutFlowResult(name_,md5_string_,names_to_index,values_,bitmap_); +} + #include "PhysicsTools/SelectorUtils/interface/CutApplicatorWithEventContentBase.h" template void VersionedSelector::setConsumes(edm::ConsumesCollector cc) { diff --git a/PhysicsTools/SelectorUtils/plugins/EtaMultiRangeCut.cc b/PhysicsTools/SelectorUtils/plugins/EtaMultiRangeCut.cc index 502811fefb4df..eb5f221f20ccf 100644 --- a/PhysicsTools/SelectorUtils/plugins/EtaMultiRangeCut.cc +++ b/PhysicsTools/SelectorUtils/plugins/EtaMultiRangeCut.cc @@ -14,6 +14,10 @@ class EtaMultiRangeCut : public CutApplicatorBase { } } + double value(const reco::CandidatePtr& cand) const override final { + return ( _absEta ? std::abs(cand->eta()) : cand->eta() ); + } + result_type asCandidate(const argument_type&) const override final; private: @@ -25,7 +29,7 @@ DEFINE_EDM_PLUGIN(CutApplicatorFactory,EtaMultiRangeCut,"EtaMultiRangeCut"); CutApplicatorBase::result_type EtaMultiRangeCut:: -asCandidate(const argument_type& cand) const{ +asCandidate(const argument_type& cand) const { const double the_eta = ( _absEta ? std::abs(cand->eta()) : cand->eta() ); bool result = false; for(const auto& range : _ranges ) { diff --git a/PhysicsTools/SelectorUtils/plugins/ExpressionEvaluatorCut.cc b/PhysicsTools/SelectorUtils/plugins/ExpressionEvaluatorCut.cc new file mode 100644 index 0000000000000..662203dc3a537 --- /dev/null +++ b/PhysicsTools/SelectorUtils/plugins/ExpressionEvaluatorCut.cc @@ -0,0 +1,57 @@ +#include "CommonTools/Utils/interface/ExpressionEvaluator.h" +#include "CommonTools/Utils/interface/ExpressionEvaluatorTemplates.h" + +#include "PhysicsTools/SelectorUtils/interface/CutApplicatorBase.h" + +class ExpressionEvaluatorCut : public CutApplicatorBase { +public: + ExpressionEvaluatorCut(const edm::ParameterSet& c); + virtual ~ExpressionEvaluatorCut(){}; + + result_type asCandidate(const argument_type& cand) const override final { + return (*cut_)(cand); + } + + double value(const reco::CandidatePtr& cand) const override final { + return cut_->value(cand); + } + + const std::string& name() const override final { return realname_; } + +private: + const std::string realname_; + CutApplicatorBase* cut_; +}; + +ExpressionEvaluatorCut:: +ExpressionEvaluatorCut(const edm::ParameterSet& c) : + CutApplicatorBase(c), + realname_(c.getParameter("realCutName")) +{ + const std::string newline("\n"); + const std::string close_function("; };"); + const std::string candTypePreamble("CandidateType candidateType() const override final { return "); + + //construct the overload of candidateType() + const std::string& candType = c.getParameter("candidateType"); + const std::string candTypeExpr = candTypePreamble + candType + close_function; + + // read in the overload of operator() + const std::string& oprExpr = c.getParameter("functionDef"); + + // read in the overload of value() + const std::string& valExpr = c.getParameter("valueDef"); + + // concatenate and evaluate the expression + const std::string total_expr = ( candTypeExpr + newline + + oprExpr + newline + + valExpr ); + reco::ExpressionEvaluator eval("PhysicsTools/SelectorUtils", + "CutApplicatorBase", + total_expr.c_str()); + cut_ = eval.expr(); +} + +DEFINE_EDM_PLUGIN(CutApplicatorFactory, + ExpressionEvaluatorCut, + "ExpressionEvaluatorCut"); diff --git a/PhysicsTools/SelectorUtils/plugins/ExpressionEvaluatorCutWithEventContent.cc b/PhysicsTools/SelectorUtils/plugins/ExpressionEvaluatorCutWithEventContent.cc new file mode 100644 index 0000000000000..995ece99d286e --- /dev/null +++ b/PhysicsTools/SelectorUtils/plugins/ExpressionEvaluatorCutWithEventContent.cc @@ -0,0 +1,78 @@ +#include "CommonTools/Utils/interface/ExpressionEvaluator.h" +#include "CommonTools/Utils/interface/ExpressionEvaluatorTemplates.h" + +#include "PhysicsTools/SelectorUtils/interface/CutApplicatorWithEventContentBase.h" + +class ExpressionEvaluatorCutWithEventContent : public CutApplicatorWithEventContentBase { +public: + ExpressionEvaluatorCutWithEventContent(const edm::ParameterSet& c); + virtual ~ExpressionEvaluatorCutWithEventContent() {}; + + result_type asCandidate(const argument_type& cand) const override final { + return (*cut_)(cand); + } + + void setConsumes(edm::ConsumesCollector& sumes) override final { + cut_->setConsumes(sumes); + } + + void getEventContent(const edm::EventBase& event) override final { + cut_->getEventContent(event); + } + + double value(const reco::CandidatePtr& cand) const override final { + return cut_->value(cand); + } + + const std::string& name() const override final { return realname_; } + +private: + const std::string realname_; + CutApplicatorWithEventContentBase* cut_; +}; + +ExpressionEvaluatorCutWithEventContent:: +ExpressionEvaluatorCutWithEventContent(const edm::ParameterSet& c) : + CutApplicatorWithEventContentBase(c), + realname_(c.getParameter("realCutName")) +{ + const std::string newline("\n"); + const std::string close_function("; };"); + const std::string candTypePreamble("CandidateType candidateType() const override final { return "); + + //construct the overload of candidateType() + const std::string& candType = c.getParameter("candidateType"); + const std::string candTypeExpr = candTypePreamble + candType + close_function; + + // read in the overload of operator() + const std::string& oprExpr = c.getParameter("functionDef"); + + // read in the overload of value() + const std::string& valExpr = c.getParameter("valueDef"); + + // read in the overload of setConsumes() + const std::string& setConsumesExpr = + c.getParameter("setConsumesDef"); + + // read in the overload of getEventContent() + const std::string& getEventContentExpr = + c.getParameter("getEventContentDef"); + + + // concatenate and evaluate the expression + const std::string total_expr = ( candTypeExpr + newline + + oprExpr + newline + + valExpr + newline + + setConsumesExpr + newline + + getEventContentExpr ); + reco::ExpressionEvaluator eval("PhysicsTools/SelectorUtils", + "CutApplicatorWithEventContentBase", + total_expr.c_str()); + cut_ = eval.expr(); + +} + + +DEFINE_EDM_PLUGIN(CutApplicatorFactory, + ExpressionEvaluatorCutWithEventContent, + "ExpressionEvaluatorCutWithEventContent"); diff --git a/PhysicsTools/SelectorUtils/plugins/MaxAbsEtaCut.cc b/PhysicsTools/SelectorUtils/plugins/MaxAbsEtaCut.cc index eda9218db40a5..2a7d97d3fcd64 100644 --- a/PhysicsTools/SelectorUtils/plugins/MaxAbsEtaCut.cc +++ b/PhysicsTools/SelectorUtils/plugins/MaxAbsEtaCut.cc @@ -6,6 +6,10 @@ class MaxAbsEtaCut : public CutApplicatorBase { CutApplicatorBase(c), _maxEta(c.getParameter("maxEta")) { } + double value(const reco::CandidatePtr& cand) const override final { + return std::abs(cand->eta()); + } + result_type asCandidate(const argument_type& cand) const override final { return std::abs(cand->eta()) < _maxEta; } diff --git a/PhysicsTools/SelectorUtils/plugins/MinPtCut.cc b/PhysicsTools/SelectorUtils/plugins/MinPtCut.cc index 071bea88ecbc9..36850bf8bb767 100644 --- a/PhysicsTools/SelectorUtils/plugins/MinPtCut.cc +++ b/PhysicsTools/SelectorUtils/plugins/MinPtCut.cc @@ -6,6 +6,10 @@ class MinPtCut : public CutApplicatorBase { CutApplicatorBase(c), _minPt(c.getParameter("minPt")) { } + double value(const reco::CandidatePtr& cand) const override final { + return cand->pt(); + } + result_type asCandidate(const argument_type& cand) const override final { return cand->pt() > _minPt; } diff --git a/PhysicsTools/SelectorUtils/plugins/MinPtCutInEtaRanges.cc b/PhysicsTools/SelectorUtils/plugins/MinPtCutInEtaRanges.cc index 627c3ad437717..9a31cede6a770 100644 --- a/PhysicsTools/SelectorUtils/plugins/MinPtCutInEtaRanges.cc +++ b/PhysicsTools/SelectorUtils/plugins/MinPtCutInEtaRanges.cc @@ -15,7 +15,11 @@ class MinPtCutInEtaRanges : public CutApplicatorBase { _minPt.push_back(minPt); } } - + + double value(const reco::CandidatePtr& cand) const override final { + return cand->pt(); + } + result_type asCandidate(const argument_type&) const override final; private: diff --git a/PhysicsTools/SelectorUtils/python/VIDCutFlowResult.py b/PhysicsTools/SelectorUtils/python/VIDCutFlowResult.py new file mode 100644 index 0000000000000..f1930ed9ed112 --- /dev/null +++ b/PhysicsTools/SelectorUtils/python/VIDCutFlowResult.py @@ -0,0 +1,64 @@ +import ROOT +import string +import random + +# load FWLite C++ libraries +ROOT.gSystem.Load("libFWCoreFWLite.so"); +ROOT.gSystem.Load("libDataFormatsFWLite.so"); +ROOT.FWLiteEnabler.enable() + +class VIDCutFlowResult: + def __init__(self, instance): + self.__instance = instance + + def cutFlowName(self): + return self.__instance.cutFlowName() + + def cutFlowPassed(self): + return self.__instance.cutFlowPassed() + + def cutFlowSize(self): + return self.__instance.cutFlowSize() + + def getNameAtIndex(self,idx): + return self.__instance.getNameAtIndex(idx) + + def getCutResultByIndex(self,idx): + return self.__instance.getCutResultByIndex(idx) + + def getCutResultByName(self,name): + return self.__instance.getCutResultByName(name) + + def isCutMasked(self,idx_or_name): + return self.__instance.isCutMasked(idx_or_name) + + def getValueCutUpon(self,idx_or_name): + return self.__instance.getValueCutUpon(idx_or_name) + + def getCutFlowResultMasking(self,things_to_mask): + if type(things_to_mask) == str or type(things_to_mask) == int: + return VIDCutFlowResult(self.__instance.getCutFlowResultMasking(things_to_mask)) + elif type(things_to_mask) != list: + raise Exception('InvalidType','getCutFlowResultMasking only accepts (lists of) strings or ints!') + + if type(things_to_mask) == list: + vect = None + if len(things_to_mask) <= 0: + raise Exception('NothingToMask') + if type(things_to_mask[0]) == str: + vect = ROOT.std.vector('std::string')() + elif type(things_to_mask[0]) == int: + vect = ROOT.std.vector('unsigned int')() + else: + raise Exception('InvalidType','getCutFlowResultMasking only accepts (lists of) strings or ints!') + + for item in things_to_mask: + vect.push_back(item) + + result = VIDCutFlowResult(self.__instance.getCutFlowResultMasking(vect)) + del vect + + return result + + + diff --git a/PhysicsTools/SelectorUtils/python/VIDSelectorBase.py b/PhysicsTools/SelectorUtils/python/VIDSelectorBase.py index 9041665947159..ba70e892c8433 100644 --- a/PhysicsTools/SelectorUtils/python/VIDSelectorBase.py +++ b/PhysicsTools/SelectorUtils/python/VIDSelectorBase.py @@ -1,11 +1,16 @@ import ROOT import string import random +import sys + +from PhysicsTools.SelectorUtils.centralIDRegistry import central_id_registry +from PhysicsTools.SelectorUtils.VIDCutFlowResult import VIDCutFlowResult +import DataFormats.FWLite # load FWLite C++ libraries ROOT.gSystem.Load("libFWCoreFWLite.so"); ROOT.gSystem.Load("libDataFormatsFWLite.so"); -ROOT.AutoLibraryLoader.enable() +ROOT.FWLiteEnabler.enable() config_template = """ import FWCore.ParameterSet.Config as cms @@ -37,38 +42,85 @@ def __init__(self, vidSelectorBuilder, ptrMaker, printer, pythonpset = None): self.__selectorBuilder = vidSelectorBuilder() self.__instance = None if pythonpset is not None: + if hasattr(pythonpset,'isPOGApproved'): + approved = pythonpset.isPOGApproved.value() + if not approved: + sys.stderr.write('This ID is not POG approved and likely under development!!!!\n') + sys.stderr.write('Please make sure to report your progress with this ID'\ + ' at the next relevant POG meeting.\n') + del pythonpset.isPOGApproved + else: + sys.stderr.write('This ID is not POG approved and likely under development!!!!\n') + sys.stderr.write('Please make sure to report your progress with this ID'\ + ' at the next relevant POG meeting.\n') self.__instance = process_pset( self.__selectorBuilder, pythonpset ) + expectedmd5 = central_id_registry.getMD5FromName(pythonpset.idName) + if expectedmd5 != self.md5String(): + sys.stderr.write("ID: %s\n"%self.name()) + sys.stderr.write("The expected md5: %s does not match the md5\n"%expectedmd5) + sys.stderr.write("calculated by the ID: %s please\n"%self.md5String()) + sys.stderr.write("update your python configuration or determine the source\n") + sys.stderr.write("of transcription error!\n") self.__initialized = True else: self.__instance = self.__selectorBuilder() def __call__(self,*args): - if( len(args) < 2 ): - print 'call takes the following args: (the collection, index, event)' - raise - temp = self.__ptrMaker(args[0],args[1]) - newargs = [temp] + if( len(args) == 1 ): + return self.__instance(*args) + if( len(args) == 2 and isinstance(args[1],DataFormats.FWLite.Events) ): + return self.__instance(args[0],args[1].object().event()) + elif( len(args) == 2 and type(args[1]) is int ): + temp = self.__ptrMaker(args[0],args[1]) + newargs = [temp] + return self.__instance(*newargs) if( len(args) == 3 ): + temp = self.__ptrMaker(args[0],args[1]) + newargs = [temp] newargs += [args[2].object().event()] - return self.__instance(*newargs) + return self.__instance(*newargs) def initialize(self,pythonpset): if( self.__initialized ): print 'VID Selector is already initialized, doing nothing!' return del process.__instance + if hasattr(pythonpset,'isPOGApproved'): + approved = pythonpset.isPOGApproved.value() + if not approved: + sys.stderr.write('This ID is not POG approved and likely under development!!!!\n') + sys.stderr.write('Please make sure to report your progress with this ID'\ + ' at the next relevant POG meeting.\n') + del pythonpset.isPOGApproved + else: + sys.stderr.write('This ID is not POG approved and likely under development!!!!\n') + sys.stderr.write('Please make sure to report your progress with this ID'\ + ' at the next relevant POG meeting.\n') self.__instance = process_pset( self.__selectorBuilder, pythonpset ) + expectedmd5 = central_id_registry.getMD5FromName(pythonpset.idName) + if expectedmd5 != self.md5String(): + sys.stderr.write("ID: %s\n"%self.name()) + sys.stderr.write("The expected md5: %s does not match the md5\n"%expectedmd5) + sys.stderr.write("calculated by the ID: %s please\n"%self.md5String()) + sys.stderr.write("update your python configuration or determine the source\n") + sys.stderr.write("of transcription error!\n") self.__initialized = True def cutFlowSize(self): return self.__instance.cutFlowSize() + def cutFlowResult(self): + return VIDCutFlowResult(self.__instance.cutFlowResult()) + def howFarInCutFlow(self): return self.__instance.howFarInCutFlow() def name(self): return self.__instance.name() + def bitMap(self): + return self.__instance.bitMap() + def md5String(self): return self.__instance.md5String() diff --git a/PhysicsTools/SelectorUtils/python/VIDSelectorValidator.py b/PhysicsTools/SelectorUtils/python/VIDSelectorValidator.py new file mode 100644 index 0000000000000..1c9104df1f9eb --- /dev/null +++ b/PhysicsTools/SelectorUtils/python/VIDSelectorValidator.py @@ -0,0 +1,119 @@ +import md5 +import ROOT + +# load FWLite C++ libraries +ROOT.gSystem.Load("libFWCoreFWLite.so") +ROOT.gSystem.Load("libDataFormatsFWLite.so") +ROOT.FWLiteEnabler.enable() + +#cms python data types +import FWCore.ParameterSet.Config as cms + +# load FWlite python libraries +from DataFormats.FWLite import Handle, Events + +#hasher= md5.new() +# +#hasher.update('hello world') +# +#print hasher.digest() +#print hasher.hexdigest() + +class VIDSelectorValidator: + def __init__(self, selector, collection_type, collection_name): + self.__hasher = md5.new() + self.__selector = selector + self.__colltype = collection_type + self.__collname = collection_name + self.__signalfiles = [] + self.__backgroundfiles = [] + self.__mixfiles = [] + + def setSignalFiles(self, files): + if not isinstance(files,list): + raise Exception('BadFileInput','You need to give "setSignalFiles" a list of strings') + self.__signalfiles = files[:] + + def setBackgroundFiles(self, files): + if not isinstance(files,list): + raise Exception('BadFileInput','You need to give "setBackgroundFiles" a list of strings') + self.__backgroundfiles = files[:] + + def setMixFiles(self, files): + if not isinstance(files,list): + raise Exception('BadFileInput','You need to give "setMixFiles" a list of strings') + self.__mixfiles = files[:] + + def runValidation(self): + samples = {} + samples['signal'] = self.__signalfiles + samples['background'] = self.__backgroundfiles + samples['mix'] = self.__mixfiles + + select = self.__selector + + print 'running validation for: %s'%(select.name()) + + # checksum of the input files + if not len(samples['signal'] + samples['background'] + samples['mix']): + raise Exception('NoInputFiles','There were no input files given, cannot validate!') + + for key in sorted(samples.keys()): + self.processInputList(samples[key],key) + + print 'input files checksum: %s'%(self.__hasher.hexdigest()) + + for key in sorted(samples.keys()): + if len(samples[key]): + local_hash = md5.new() + self.processEvents(samples[key],key,local_hash) + self.__hasher.update(local_hash.hexdigest()) + + print 'event processing checksum: %s'%(self.__hasher.hexdigest()) + + self.__hasher.update(select.md5String()) + + print 'total checksum: %s'%(self.__hasher.hexdigest()) + + def processInputList(self,the_list,name): + for item in the_list: + self.__hasher.update(item) + print 'Input %s file: %s'%(name,item) + + def processEvents(self,the_list,name,hasher): + #data products + handle, productLabel = Handle(self.__colltype), self.__collname + + #now loop over the events in each category + events = Events(the_list) + n_pass, n_fail = 0,0 + + sub_cutnames = [] + sub_hashes = [] + for idstring in repr(self.__selector).split('\n'): + if idstring == '': continue + sub_cutnames.append(idstring.split()[2]) # gets the cutname + sub_hashes.append(md5.new(idstring)) + + for event in events: + event.getByLabel(productLabel,handle) + for i,obj in enumerate(handle.product()): + if self.__selector(handle.product(),i,event): + n_pass += 1 + else: + n_fail += 1 + icut = 0 + for idstring in repr(self.__selector).split('\n'): + if idstring == '': continue + sub_hashes[icut].update(idstring) + icut += 1 + + for sub_hash in sub_hashes: + hasher.update(sub_hash.hexdigest()) + + hasher.update(str(n_pass)) + hasher.update(str(n_fail)) + print '%s sample pass : fail : hash -> %d : %d : %s'%(name,n_pass,n_fail,hasher.hexdigest()) + print '%s sample cut breakdown:'%(name) + for i,sub_hash in enumerate(sub_hashes): + print '\t%s hash -> %s'%(sub_cutnames[i],sub_hash.hexdigest()) diff --git a/PhysicsTools/SelectorUtils/python/tools/vid_id_tools.py b/PhysicsTools/SelectorUtils/python/tools/vid_id_tools.py index c2e5b2bb18c51..33a4e3d1b7a81 100644 --- a/PhysicsTools/SelectorUtils/python/tools/vid_id_tools.py +++ b/PhysicsTools/SelectorUtils/python/tools/vid_id_tools.py @@ -27,12 +27,23 @@ def setupVIDSelection(vidproducer,cutflow): def addVIDSelectionToPATProducer(patProducer,idProducer,idName): patProducerIDs = None + userDatas = None for key in patProducer.__dict__.keys(): if 'IDSources' in key: patProducerIDs = getattr(patProducer,key) + if 'userData' in key: + userDatas = getattr(patProducer,key) if patProducerIDs is None: raise Exception('StrangePatModule','%s does not have ID sources!'%patProducer.label()) - setattr(patProducerIDs,idName,cms.InputTag('%s:%s'%(idProducer,idName))) + if userDatas is None: + raise Exception('StrangePatModule','%s does not have UserData sources!'%patProducer.label()) + setattr(patProducerIDs,idName,cms.InputTag('%s:%s'%(idProducer,idName))) + if( len(userDatas.userClasses.src) == 1 and + type(userDatas.userClasses.src[0]) is str and + userDatas.userClasses.src[0] == '' ): + userDatas.userClasses.src = cms.VInputTag(cms.InputTag('%s:%s'%(idProducer,idName))) + else: + userDatas.userClasses.src.append(cms.InputTag('%s:%s'%(idProducer,idName))) sys.stderr.write('\t--- %s:%s added to %s\n'%(idProducer,idName,patProducer.label())) def setupAllVIDIdsInModule(process,id_module_name,setupFunction,patProducer=None): diff --git a/PhysicsTools/SelectorUtils/python/trivialCutFlow_cff.py b/PhysicsTools/SelectorUtils/python/trivialCutFlow_cff.py index addd0f5d2182a..3d816044da84a 100644 --- a/PhysicsTools/SelectorUtils/python/trivialCutFlow_cff.py +++ b/PhysicsTools/SelectorUtils/python/trivialCutFlow_cff.py @@ -2,6 +2,19 @@ from PhysicsTools.SelectorUtils.centralIDRegistry import central_id_registry +string_func = """ +result_type asCandidate(const argument_type& obj) const override final { + std::cout << "lol I was written in python!" << std::endl; + return obj->pt() < 5.0; +} +""" + +string_value = """ +double value(const reco::CandidatePtr& obj) const override final { + return obj->pt(); +} +""" + trivialCutFlow = cms.PSet( idName = cms.string("trivialCutFlow"), cutFlow = cms.VPSet( @@ -12,6 +25,13 @@ cms.PSet( cutName = cms.string("MaxAbsEtaCut"), maxEta = cms.double(2.5), needsAdditionalProducts = cms.bool(False), + isIgnored = cms.bool(False) ), + cms.PSet( cutName = cms.string("ExpressionEvaluatorCut"), + realCutName = cms.string("StringMinPtCut"), + candidateType = cms.string("NONE"), + functionDef = cms.string(string_func), + valueDef = cms.string(string_value), + needsAdditionalProducts = cms.bool(False), isIgnored = cms.bool(False) ) ) ) diff --git a/PhysicsTools/SelectorUtils/src/precompile.h b/PhysicsTools/SelectorUtils/src/precompile.h new file mode 100644 index 0000000000000..7f895149788c4 --- /dev/null +++ b/PhysicsTools/SelectorUtils/src/precompile.h @@ -0,0 +1,2 @@ +#include "PhysicsTools/SelectorUtils/interface/CutApplicatorBase.h" +#include "PhysicsTools/SelectorUtils/interface/CutApplicatorWithEventContentBase.h" diff --git a/PhysicsTools/SelectorUtils/test/pyfwlite_test.py b/PhysicsTools/SelectorUtils/test/pyfwlite_test.py index 619616f477527..ce409376d4e57 100755 --- a/PhysicsTools/SelectorUtils/test/pyfwlite_test.py +++ b/PhysicsTools/SelectorUtils/test/pyfwlite_test.py @@ -11,7 +11,7 @@ # load FWLite C++ libraries ROOT.gSystem.Load("libFWCoreFWLite.so"); ROOT.gSystem.Load("libDataFormatsFWLite.so"); -ROOT.AutoLibraryLoader.enable() +ROOT.FWLiteEnabler.enable() #cms python data types import FWCore.ParameterSet.Config as cms @@ -21,12 +21,24 @@ from RecoEgamma.ElectronIdentification.VIDElectronSelector import VIDElectronSelector -from RecoEgamma.ElectronIdentification.Identification.cutBasedElectronID_PHYS14_PU20bx25_V1_cff import cutBasedElectronID_PHYS14_PU20bx25_V1_standalone_tight +from RecoEgamma.ElectronIdentification.Identification.cutBasedElectronID_PHYS14_PU20bx25_V2_cff import cutBasedElectronID_PHYS14_PU20bx25_V2_standalone_tight -selectElectron = VIDElectronSelector(cutBasedElectronID_PHYS14_PU20bx25_V1_standalone_tight) +selectElectron = VIDElectronSelector(cutBasedElectronID_PHYS14_PU20bx25_V2_standalone_tight) print 'Initialized VID Selector for Electrons' print selectElectron +from PhysicsTools.SelectorUtils.trivialCutFlow_cff import trivialCutFlow +testExprEval = VIDElectronSelector(trivialCutFlow) +print 'test expression evaluator' +print testExprEval + +#photon MVA (only works on reMiniAOD) +print 'Initialized VID Photon MVA Selector' +from RecoEgamma.PhotonIdentification.VIDPhotonSelector import VIDPhotonSelector +from RecoEgamma.PhotonIdentification.Identification.mvaPhotonID_Spring15_50ns_nonTrig_V0_cff import mvaPhoID_Spring15_50ns_nonTrig_V0_wp90 +selectPhoton = VIDPhotonSelector(mvaPhoID_Spring15_50ns_nonTrig_V0_wp90) +print selectPhoton + # try muons! from RecoMuon.MuonIdentification.VIDMuonSelector import VIDMuonSelector from RecoMuon.MuonIdentification.Identification.globalMuonPromptTight_V0_cff import globalMuonPromptTight_V0 @@ -42,23 +54,23 @@ print selectMuon # open file (you can use 'edmFileUtil -d /store/whatever.root' to get the physical file name) -#events = Events("root://eoscms//eos/cms/store/cmst3/user/gpetrucc/miniAOD/74X/miniAOD-new_ZTT.root") events = Events("root://eoscms//eos/cms/store/relval/CMSSW_7_4_0_pre9_ROOT6/DoubleMu/MINIAOD/GR_R_74_V8A_RelVal_zMu2011A-v1/00000/06961B48-CFD1-E411-8B87-002618943971.root") -muons, muonLabel = Handle("std::vector"), "slimmedMuons" -electrons, electronLabel = Handle("std::vector"), "slimmedElectrons" +muons, muonLabel = Handle("std::vector"), "slimmedMuons::".split(":") +electrons, electronLabel = Handle("std::vector"), "slimmedElectrons::".split(":") +photons, photonLabel = Handle("std::vector"), "slimmedPhotons::".split(":") for iev,event in enumerate(events): if iev > 10: break - event.getByLabel(muonLabel, muons) - event.getByLabel(electronLabel, electrons) - + event.getByLabel(muonLabel[0],muonLabel[1],muonLabel[2], muons) + event.getByLabel(electronLabel[0],electronLabel[1],electronLabel[2], electrons) + event.getByLabel(photonLabel[0],photonLabel[1],photonLabel[2],photons) print "\nEvent %d: run %6d, lumi %4d, event %12d" % (iev,event.eventAuxiliary().run(), event.eventAuxiliary().luminosityBlock(), event.eventAuxiliary().event()) - + # Muons for i,mu in enumerate(muons.product()): if mu.pt() < 5 or not mu.isLooseMuon(): continue @@ -73,6 +85,54 @@ if el.pt() < 5: continue print "elec %2d: pt %4.1f, supercluster eta %+5.3f, sigmaIetaIeta %.3f (%.3f with full5x5 shower shapes), pass conv veto %d" % ( i, el.pt(), el.superCluster().eta(), el.sigmaIetaIeta(), el.full5x5_sigmaIetaIeta(), el.passConversionVeto()) - selectElectron(electrons.product(),i,event) + passfail_byvalue = selectElectron(el,event) + passfail = selectElectron(electrons.product(),i,event) print selectElectron + testExprEval(electrons.product(),i,event) + print testExprEval + + cf_result = selectElectron.cutFlowResult() + for i in range(cf_result.cutFlowSize()): + print '%d : %s : %d'%(i,cf_result.getNameAtIndex(i),cf_result.getCutResultByName(cf_result.getNameAtIndex(i))) + print passfail, passfail_byvalue + print cf_result.cutFlowPassed() + print "{0:b}".format(selectElectron.bitMap()) + masked_cf_ints = cf_result.getCutFlowResultMasking([2,3,4,9]) + masked_cf_strs = cf_result.getCutFlowResultMasking(['GsfEleDEtaInCut_0', + 'GsfEleDPhiInCut_0', + 'GsfEleFull5x5SigmaIEtaIEtaCut_0', + 'GsfEleEffAreaPFIsoCut_0']) + print masked_cf_ints.cutFlowPassed(), masked_cf_strs.cutFlowPassed() + + for i,ph in enumerate(photons.product()): + print "pho %2d: pt %4.1f, supercluster eta %+5.3f, sigmaIetaIeta %.3f (%.3f with full5x5 shower shapes)" % ( + i, ph.pt(), ph.superCluster().eta(), ph.sigmaIetaIeta(), ph.full5x5_sigmaIetaIeta()) + passfail_byvalue = selectPhoton(ph,event) + for uf in ph.userFloatNames(): + print uf + for ui in ph.userIntNames(): + print ui + print passfail_byvalue + print selectPhoton + +#test the validator framework + +print 'test validation framework' + +selectElectronValid = VIDElectronSelector(cutBasedElectronID_PHYS14_PU20bx25_V2_standalone_tight) +selectMuonValid = VIDMuonSelector(globalMuonPromptTight_V0) + +from PhysicsTools.SelectorUtils.VIDSelectorValidator import VIDSelectorValidator +electron_validator = VIDSelectorValidator(selectElectronValid,'std::vector','slimmedElectrons') +muon_validator = VIDSelectorValidator(selectMuonValid,'std::vector','slimmedMuons') + +signal_files = [] +background_files = [] +mix_files = ['root://eoscms//eos/cms/store/relval/CMSSW_7_4_0_pre9_ROOT6/DoubleMu/MINIAOD/GR_R_74_V8A_RelVal_zMu2011A-v1/00000/06961B48-CFD1-E411-8B87-002618943971.root'] + +electron_validator.setMixFiles(mix_files) +muon_validator.setMixFiles(mix_files) + +electron_validator.runValidation() +muon_validator.runValidation() diff --git a/RecoEgamma/EgammaTools/interface/AnyMVAEstimatorRun2Base.h b/RecoEgamma/EgammaTools/interface/AnyMVAEstimatorRun2Base.h new file mode 100644 index 0000000000000..7b06d42e9d585 --- /dev/null +++ b/RecoEgamma/EgammaTools/interface/AnyMVAEstimatorRun2Base.h @@ -0,0 +1,62 @@ +#ifndef RecoEgamma_EgammaTools_AnyMVAEstimatorRun2Base_H +#define RecoEgamma_EgammaTools_AnyMVAEstimatorRun2Base_H + +#include "FWCore/ParameterSet/interface/ParameterSet.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/Framework/interface/ConsumesCollector.h" + +#include "DataFormats/Candidate/interface/Candidate.h" + +class AnyMVAEstimatorRun2Base { + + public: + // Constructor, destructor + AnyMVAEstimatorRun2Base(const edm::ParameterSet& conf) : _conf(conf){}; + virtual ~AnyMVAEstimatorRun2Base(){}; + + // Functions that must be provided in derived classes + // These function should work on electrons or photons + // of the reco or pat type + + virtual float mvaValue( const edm::Ptr& particle) = 0; + + // A specific implementation of MVA is expected to have data members + // that will contain particle's quantities on which the MVA operates. + // This function fill their value for a given particle. + virtual void fillMVAVariables(const edm::Ptr& particle) = 0; + // A specific implementation of MVA is expected to have one or more categories + // defined with respect to eta, pt, etc. + // This function determines the category for a given particle. + virtual int findCategory( const edm::Ptr& particle) = 0; + virtual int getNCategories() = 0; + // The name is a unique name associated with a particular MVA implementation, + // it is found as a const data member in a derived class. + virtual const std::string getName() = 0; + + // + // Extra event content - if needed. + // + // Some MVA implementation may require direct access to event content. + // Implement these methods only if needed in the derived classes (use "override" + // for certainty). + // This method needs to be used only once after this MVA estimator is constructed + virtual void setConsumes(edm::ConsumesCollector &&cc){}; + // This method needs to be called for each event + virtual void getEventContent(const edm::Event& iEvent){}; + + // + // Data members + // + // Configuration + const edm::ParameterSet _conf; + +}; + +// define the factory for this base class +#include "FWCore/PluginManager/interface/PluginFactory.h" +typedef edmplugin::PluginFactory< AnyMVAEstimatorRun2Base* (const edm::ParameterSet&) > + AnyMVAEstimatorRun2Factory; + +#endif diff --git a/RecoEgamma/EgammaTools/interface/MVAValueMapProducer.h b/RecoEgamma/EgammaTools/interface/MVAValueMapProducer.h new file mode 100644 index 0000000000000..826fbb50e60bf --- /dev/null +++ b/RecoEgamma/EgammaTools/interface/MVAValueMapProducer.h @@ -0,0 +1,182 @@ +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/stream/EDProducer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" + +#include "DataFormats/Common/interface/ValueMap.h" +#include "DataFormats/Common/interface/View.h" + +#include "RecoEgamma/EgammaTools/interface/AnyMVAEstimatorRun2Base.h" + +#include +#include + +template +class MVAValueMapProducer : public edm::stream::EDProducer<> { + + public: + + explicit MVAValueMapProducer(const edm::ParameterSet&); + ~MVAValueMapProducer(); + + static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); + + private: + + virtual void produce(edm::Event&, const edm::EventSetup&) override; + + template + void writeValueMap(edm::Event &iEvent, + const edm::Handle > & handle, + const std::vector & values, + const std::string & label) const ; + + // for AOD case + edm::EDGetToken src_; + + // for miniAOD case + edm::EDGetToken srcMiniAOD_; + + // MVA estimator + std::vector> mvaEstimators_; + + // Value map names + std::vector mvaValueMapNames_; + std::vector mvaCategoriesMapNames_; + +}; + +template +MVAValueMapProducer::MVAValueMapProducer(const edm::ParameterSet& iConfig) +{ + + // + // Declare consummables, handle both AOD and miniAOD case + // + src_ = mayConsume >(iConfig.getParameter("src")); + srcMiniAOD_ = mayConsume >(iConfig.getParameter("srcMiniAOD")); + + // Loop over the list of MVA configurations passed here from python and + // construct all requested MVA esimtators. + const std::vector& mvaEstimatorConfigs + = iConfig.getParameterSetVector("mvaConfigurations"); + for( auto &imva : mvaEstimatorConfigs ){ + + std::unique_ptr thisEstimator; + thisEstimator.reset(NULL); + if( !imva.empty() ) { + const std::string& pName = imva.getParameter("mvaName"); + // The factory below constructs the MVA of the appropriate type based + // on the "mvaName" which is the name of the derived MVA class (plugin) + AnyMVAEstimatorRun2Base *estimator = AnyMVAEstimatorRun2Factory::get()->create(pName, imva); + // Declare all event content, such as ValueMaps produced upstream or other, + // original event data pieces, that is needed (if any is implemented in the specific + // MVA classes) + //edm::ConsumesCollector &cc = consumesCollector(); + estimator->setConsumes( consumesCollector() ); + + thisEstimator.reset(estimator); + + } else + throw cms::Exception(" MVA configuration not found: ") + << " failed to find proper configuration for one of the MVAs in the main python script " << std::endl; + + // The unique pointer control is passed to the vector in the line below. + // Don't use thisEstimator pointer beyond the next line. + mvaEstimators_.emplace_back( thisEstimator.release() ); + + // + // Compose and save the names of the value maps to be produced + // + const auto& currentEstimator = mvaEstimators_.back(); + std::string thisValueMapName = currentEstimator->getName() + "Values"; + std::string thisCategoriesMapName = currentEstimator->getName() + "Categories"; + mvaValueMapNames_.push_back( thisValueMapName ); + mvaCategoriesMapNames_.push_back( thisCategoriesMapName ); + + // Declare the maps to the framework + produces >(thisValueMapName); + produces >(thisCategoriesMapName); + + } + + +} + +template + MVAValueMapProducer::~MVAValueMapProducer() { +} + +template +void MVAValueMapProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { + + using namespace edm; + + edm::Handle > src; + + // Retrieve the collection of particles from the event. + // If we fail to retrieve the collection with the standard AOD + // name, we next look for the one with the stndard miniAOD name. + iEvent.getByToken(src_, src); + if( !src.isValid() ){ + iEvent.getByToken(srcMiniAOD_,src); + if( !src.isValid() ) + throw cms::Exception(" Collection not found: ") + << " failed to find a standard AOD or miniAOD particle collection " << std::endl; + } + + + // Loop over MVA estimators + for( unsigned iEstimator = 0; iEstimator < mvaEstimators_.size(); iEstimator++ ){ + + // Set up all event content, such as ValueMaps produced upstream or other, + // original event data pieces, that is needed (if any is implemented in the specific + // MVA classes) + mvaEstimators_[iEstimator]->getEventContent( iEvent ); + + std::vector mvaValues; + std::vector mvaCategories; + + // Loop over particles + for (size_t i = 0; i < src->size(); ++i){ + auto iCand = src->ptrAt(i); + + mvaValues.push_back( mvaEstimators_[iEstimator]->mvaValue( iCand ) ); + mvaCategories.push_back( mvaEstimators_[iEstimator]->findCategory( iCand ) ); + } // end loop over particles + + writeValueMap(iEvent, src, mvaValues, mvaValueMapNames_[iEstimator] ); + writeValueMap(iEvent, src, mvaCategories, mvaCategoriesMapNames_[iEstimator] ); + + } // end loop over estimators + + +} + +template template +void MVAValueMapProducer::writeValueMap(edm::Event &iEvent, + const edm::Handle > & handle, + const std::vector & values, + const std::string & label) const +{ + using namespace edm; + using namespace std; + auto_ptr > valMap(new ValueMap()); + typename edm::ValueMap::Filler filler(*valMap); + filler.insert(handle, values.begin(), values.end()); + filler.fill(); + iEvent.put(valMap, label); +} + +template + void MVAValueMapProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + //The following says we do not know what parameters are allowed so do no validation + // Please change this to state exactly what you do use, even if it is no parameters + edm::ParameterSetDescription desc; + desc.setUnknown(); + descriptions.addDefault(desc); +} + diff --git a/RecoEgamma/EgammaTools/plugins/BuildFile.xml b/RecoEgamma/EgammaTools/plugins/BuildFile.xml index 53a9355e6addc..0f2d1cf346ad3 100644 --- a/RecoEgamma/EgammaTools/plugins/BuildFile.xml +++ b/RecoEgamma/EgammaTools/plugins/BuildFile.xml @@ -3,6 +3,7 @@ + diff --git a/RecoEgamma/EgammaTools/plugins/EGExtraInfoModifierFromFloatValueMaps.cc b/RecoEgamma/EgammaTools/plugins/EGExtraInfoModifierFromFloatValueMaps.cc new file mode 100644 index 0000000000000..497f524259a69 --- /dev/null +++ b/RecoEgamma/EgammaTools/plugins/EGExtraInfoModifierFromFloatValueMaps.cc @@ -0,0 +1,222 @@ +#include "CommonTools/CandAlgos/interface/ModifyObjectValueBase.h" + +#include "FWCore/Utilities/interface/InputTag.h" +#include "FWCore/Utilities/interface/EDGetToken.h" +#include "DataFormats/Common/interface/ValueMap.h" + +#include "DataFormats/EgammaCandidates/interface/GsfElectron.h" +#include "DataFormats/EgammaCandidates/interface/Photon.h" + +namespace { + const edm::EDGetTokenT > empty_token; + const edm::InputTag empty_tag; +} + +#include + +class EGExtraInfoModifierFromFloatValueMaps : public ModifyObjectValueBase { +public: + typedef edm::EDGetTokenT > ValMapFloatToken; + typedef std::unordered_map ValueMaps; + typedef std::unordered_map ValueMapsTags; + struct electron_config { + edm::InputTag electron_src; + edm::EDGetTokenT > tok_electron_src; + ValueMapsTags valuemaps; + ValueMaps tok_valuemaps; + }; + + struct photon_config { + edm::InputTag photon_src; + edm::EDGetTokenT > tok_photon_src; + ValueMapsTags valuemaps; + ValueMaps tok_valuemaps; + }; + + EGExtraInfoModifierFromFloatValueMaps(const edm::ParameterSet& conf); + + void setEvent(const edm::Event&) override final; + void setEventContent(const edm::EventSetup&) override final; + void setConsumes(edm::ConsumesCollector&) override final; + + void modifyObject(pat::Electron&) const override final; + void modifyObject(pat::Photon&) const override final; + +private: + electron_config e_conf; + photon_config ph_conf; + std::unordered_map > eles_by_oop; // indexed by original object ptr + std::unordered_map > > ele_vmaps; + std::unordered_map > phos_by_oop; + std::unordered_map > > pho_vmaps; + mutable unsigned ele_idx,pho_idx; // hack here until we figure out why some slimmedPhotons don't have original object ptrs +}; + +DEFINE_EDM_PLUGIN(ModifyObjectValueFactory, + EGExtraInfoModifierFromFloatValueMaps, + "EGExtraInfoModifierFromFloatValueMaps"); + +EGExtraInfoModifierFromFloatValueMaps:: +EGExtraInfoModifierFromFloatValueMaps(const edm::ParameterSet& conf) : + ModifyObjectValueBase(conf) { + constexpr char electronSrc[] = "electronSrc"; + constexpr char photonSrc[] = "photonSrc"; + + if( conf.exists("electron_config") ) { + const edm::ParameterSet& electrons = conf.getParameter("electron_config"); + if( electrons.exists(electronSrc) ) e_conf.electron_src = electrons.getParameter(electronSrc); + const std::vector parameters = electrons.getParameterNames(); + for( const std::string& name : parameters ) { + if( std::string(electronSrc) == name ) continue; + if( electrons.existsAs(name) ) { + e_conf.valuemaps[name] = electrons.getParameter(name); + } + } + } + if( conf.exists("photon_config") ) { + const edm::ParameterSet& photons = conf.getParameter("photon_config"); + if( photons.exists(photonSrc) ) ph_conf.photon_src = photons.getParameter(photonSrc); + const std::vector parameters = photons.getParameterNames(); + for( const std::string& name : parameters ) { + if( std::string(photonSrc) == name ) continue; + if( photons.existsAs(name) ) { + ph_conf.valuemaps[name] = photons.getParameter(name); + } + } + } + ele_idx = pho_idx = 0; +} + +inline void get_product(const edm::Event& evt, + const edm::EDGetTokenT >& tok, + std::unordered_map > >& map) { + evt.getByToken(tok,map[tok.index()]); +} + +void EGExtraInfoModifierFromFloatValueMaps:: +setEvent(const edm::Event& evt) { + eles_by_oop.clear(); + phos_by_oop.clear(); + ele_vmaps.clear(); + pho_vmaps.clear(); + + ele_idx = pho_idx = 0; + + if( !e_conf.tok_electron_src.isUninitialized() ) { + edm::Handle > eles; + evt.getByToken(e_conf.tok_electron_src,eles); + + for( unsigned i = 0; i < eles->size(); ++i ) { + edm::Ptr ptr = eles->ptrAt(i); + eles_by_oop[i] = ptr; + } + } + + for( auto itr = e_conf.tok_valuemaps.begin(); itr != e_conf.tok_valuemaps.end(); ++itr ) { + get_product(evt,itr->second,ele_vmaps); + } + + if( !ph_conf.tok_photon_src.isUninitialized() ) { + edm::Handle > phos; + evt.getByToken(ph_conf.tok_photon_src,phos); + + for( unsigned i = 0; i < phos->size(); ++i ) { + edm::Ptr ptr = phos->ptrAt(i); + phos_by_oop[i] = ptr; + } + } + + for( auto itr = ph_conf.tok_valuemaps.begin(); itr != ph_conf.tok_valuemaps.end(); ++itr ) { + get_product(evt,itr->second,pho_vmaps); + } +} + +void EGExtraInfoModifierFromFloatValueMaps:: +setEventContent(const edm::EventSetup& evs) { +} + +template +inline void make_consumes(T& tag,U& tok,V& sume) { if( !(empty_tag == tag) ) tok = sume.template consumes >(tag); } + +void EGExtraInfoModifierFromFloatValueMaps:: +setConsumes(edm::ConsumesCollector& sumes) { + //setup electrons + if( !(empty_tag == e_conf.electron_src) ) e_conf.tok_electron_src = sumes.consumes >(e_conf.electron_src); + + for( auto itr = e_conf.valuemaps.begin(); itr != e_conf.valuemaps.end(); ++itr ) { + make_consumes(itr->second,e_conf.tok_valuemaps[itr->first],sumes); + } + + // setup photons + if( !(empty_tag == ph_conf.photon_src) ) ph_conf.tok_photon_src = sumes.consumes >(ph_conf.photon_src); + + for( auto itr = ph_conf.valuemaps.begin(); itr != ph_conf.valuemaps.end(); ++itr ) { + make_consumes(itr->second,ph_conf.tok_valuemaps[itr->first],sumes); + } +} + +template +inline void assignValue(const T& ptr, const U& tok, const V& map, float& value) { + if( !tok.isUninitialized() ) value = map.find(tok.index())->second->get(ptr.id(),ptr.key()); +} + +void EGExtraInfoModifierFromFloatValueMaps:: +modifyObject(pat::Electron& ele) const { + // we encounter two cases here, either we are running AOD -> MINIAOD + // and the value maps are to the reducedEG object, can use original object ptr + // or we are running MINIAOD->MINIAOD and we need to fetch the pat objects to reference + edm::Ptr ptr(ele.originalObjectRef()); + if( !e_conf.tok_electron_src.isUninitialized() ) { + auto key = eles_by_oop.find(ele_idx); + if( key != eles_by_oop.end() ) { + ptr = key->second; + } else { + throw cms::Exception("BadElectronKey") + << "Original object pointer with key = " << ele.originalObjectRef().key() + << " not found in cache!"; + } + } + //now we go through and modify the objects using the valuemaps we read in + for( auto itr = e_conf.tok_valuemaps.begin(); itr != e_conf.tok_valuemaps.end(); ++itr ) { + float value(0.0); + assignValue(ptr,itr->second,ele_vmaps,value); + if( !ele.hasUserFloat(itr->first) ) { + ele.addUserFloat(itr->first,value); + } else { + throw cms::Exception("ValueNameAlreadyExists") + << "Trying to add new UserFloat = " << itr->first + << " failed because it already exists!"; + } + } + ++ele_idx; +} + +void EGExtraInfoModifierFromFloatValueMaps:: +modifyObject(pat::Photon& pho) const { + // we encounter two cases here, either we are running AOD -> MINIAOD + // and the value maps are to the reducedEG object, can use original object ptr + // or we are running MINIAOD->MINIAOD and we need to fetch the pat objects to reference + edm::Ptr ptr(pho.originalObjectRef()); + if( !ph_conf.tok_photon_src.isUninitialized() ) { + auto key = phos_by_oop.find(pho_idx); + if( key != phos_by_oop.end() ) { + ptr = key->second; + } else { + throw cms::Exception("BadPhotonKey") + << "Original object pointer with key = " << pho.originalObjectRef().key() << " not found in cache!"; + } + } + //now we go through and modify the objects using the valuemaps we read in + for( auto itr = ph_conf.tok_valuemaps.begin(); itr != ph_conf.tok_valuemaps.end(); ++itr ) { + float value(0.0); + assignValue(ptr,itr->second,pho_vmaps,value); + if( !pho.hasUserFloat(itr->first) ) { + pho.addUserFloat(itr->first,value); + } else { + throw cms::Exception("ValueNameAlreadyExists") + << "Trying to add new UserFloat = " << itr->first + << " failed because it already exists!"; + } + } + ++pho_idx; +} diff --git a/RecoEgamma/EgammaTools/plugins/EGExtraInfoModifierFromIntValueMaps.cc b/RecoEgamma/EgammaTools/plugins/EGExtraInfoModifierFromIntValueMaps.cc new file mode 100644 index 0000000000000..33f0997162384 --- /dev/null +++ b/RecoEgamma/EgammaTools/plugins/EGExtraInfoModifierFromIntValueMaps.cc @@ -0,0 +1,222 @@ +#include "CommonTools/CandAlgos/interface/ModifyObjectValueBase.h" + +#include "FWCore/Utilities/interface/InputTag.h" +#include "FWCore/Utilities/interface/EDGetToken.h" +#include "DataFormats/Common/interface/ValueMap.h" + +#include "DataFormats/EgammaCandidates/interface/GsfElectron.h" +#include "DataFormats/EgammaCandidates/interface/Photon.h" + +namespace { + const edm::EDGetTokenT > empty_token; + const edm::InputTag empty_tag; +} + +#include + +class EGExtraInfoModifierFromIntValueMaps : public ModifyObjectValueBase { +public: + typedef edm::EDGetTokenT > ValMapIntToken; + typedef std::unordered_map ValueMaps; + typedef std::unordered_map ValueMapsTags; + struct electron_config { + edm::InputTag electron_src; + edm::EDGetTokenT > tok_electron_src; + ValueMapsTags valuemaps; + ValueMaps tok_valuemaps; + }; + + struct photon_config { + edm::InputTag photon_src; + edm::EDGetTokenT > tok_photon_src; + ValueMapsTags valuemaps; + ValueMaps tok_valuemaps; + }; + + EGExtraInfoModifierFromIntValueMaps(const edm::ParameterSet& conf); + + void setEvent(const edm::Event&) override final; + void setEventContent(const edm::EventSetup&) override final; + void setConsumes(edm::ConsumesCollector&) override final; + + void modifyObject(pat::Electron&) const override final; + void modifyObject(pat::Photon&) const override final; + +private: + electron_config e_conf; + photon_config ph_conf; + std::unordered_map > eles_by_oop; // indexed by original object ptr + std::unordered_map > > ele_vmaps; + std::unordered_map > phos_by_oop; + std::unordered_map > > pho_vmaps; + mutable unsigned ele_idx,pho_idx; // hack here until we figure out why some slimmedPhotons don't have original object ptrs +}; + +DEFINE_EDM_PLUGIN(ModifyObjectValueFactory, + EGExtraInfoModifierFromIntValueMaps, + "EGExtraInfoModifierFromIntValueMaps"); + +EGExtraInfoModifierFromIntValueMaps:: +EGExtraInfoModifierFromIntValueMaps(const edm::ParameterSet& conf) : + ModifyObjectValueBase(conf) { + constexpr char electronSrc[] = "electronSrc"; + constexpr char photonSrc[] = "photonSrc"; + + if( conf.exists("electron_config") ) { + const edm::ParameterSet& electrons = conf.getParameter("electron_config"); + if( electrons.exists(electronSrc) ) e_conf.electron_src = electrons.getParameter(electronSrc); + const std::vector parameters = electrons.getParameterNames(); + for( const std::string& name : parameters ) { + if( std::string(electronSrc) == name ) continue; + if( electrons.existsAs(name) ) { + e_conf.valuemaps[name] = electrons.getParameter(name); + } + } + } + if( conf.exists("photon_config") ) { + const edm::ParameterSet& photons = conf.getParameter("photon_config"); + if( photons.exists(photonSrc) ) ph_conf.photon_src = photons.getParameter(photonSrc); + const std::vector parameters = photons.getParameterNames(); + for( const std::string& name : parameters ) { + if( std::string(photonSrc) == name ) continue; + if( photons.existsAs(name) ) { + ph_conf.valuemaps[name] = photons.getParameter(name); + } + } + } + ele_idx = pho_idx = 0; +} + +inline void get_product(const edm::Event& evt, + const edm::EDGetTokenT >& tok, + std::unordered_map > >& map) { + evt.getByToken(tok,map[tok.index()]); +} + +void EGExtraInfoModifierFromIntValueMaps:: +setEvent(const edm::Event& evt) { + eles_by_oop.clear(); + phos_by_oop.clear(); + ele_vmaps.clear(); + pho_vmaps.clear(); + + ele_idx = pho_idx = 0; + + if( !e_conf.tok_electron_src.isUninitialized() ) { + edm::Handle > eles; + evt.getByToken(e_conf.tok_electron_src,eles); + + for( unsigned i = 0; i < eles->size(); ++i ) { + edm::Ptr ptr = eles->ptrAt(i); + eles_by_oop[i] = ptr; + } + } + + for( auto itr = e_conf.tok_valuemaps.begin(); itr != e_conf.tok_valuemaps.end(); ++itr ) { + get_product(evt,itr->second,ele_vmaps); + } + + if( !ph_conf.tok_photon_src.isUninitialized() ) { + edm::Handle > phos; + evt.getByToken(ph_conf.tok_photon_src,phos); + + for( unsigned i = 0; i < phos->size(); ++i ) { + edm::Ptr ptr = phos->ptrAt(i); + phos_by_oop[i] = ptr; + } + } + + for( auto itr = ph_conf.tok_valuemaps.begin(); itr != ph_conf.tok_valuemaps.end(); ++itr ) { + get_product(evt,itr->second,pho_vmaps); + } +} + +void EGExtraInfoModifierFromIntValueMaps:: +setEventContent(const edm::EventSetup& evs) { +} + +template +inline void make_consumes(T& tag,U& tok,V& sume) { if( !(empty_tag == tag) ) tok = sume.template consumes >(tag); } + +void EGExtraInfoModifierFromIntValueMaps:: +setConsumes(edm::ConsumesCollector& sumes) { + //setup electrons + if( !(empty_tag == e_conf.electron_src) ) e_conf.tok_electron_src = sumes.consumes >(e_conf.electron_src); + + for( auto itr = e_conf.valuemaps.begin(); itr != e_conf.valuemaps.end(); ++itr ) { + make_consumes(itr->second,e_conf.tok_valuemaps[itr->first],sumes); + } + + // setup photons + if( !(empty_tag == ph_conf.photon_src) ) ph_conf.tok_photon_src = sumes.consumes >(ph_conf.photon_src); + + for( auto itr = ph_conf.valuemaps.begin(); itr != ph_conf.valuemaps.end(); ++itr ) { + make_consumes(itr->second,ph_conf.tok_valuemaps[itr->first],sumes); + } +} + +template +inline void assignValue(const T& ptr, const U& tok, const V& map, int& value) { + if( !tok.isUninitialized() ) value = map.find(tok.index())->second->get(ptr.id(),ptr.key()); +} + +void EGExtraInfoModifierFromIntValueMaps:: +modifyObject(pat::Electron& ele) const { + // we encounter two cases here, either we are running AOD -> MINIAOD + // and the value maps are to the reducedEG object, can use original object ptr + // or we are running MINIAOD->MINIAOD and we need to fetch the pat objects to reference + edm::Ptr ptr(ele.originalObjectRef()); + if( !e_conf.tok_electron_src.isUninitialized() ) { + auto key = eles_by_oop.find(ele_idx); + if( key != eles_by_oop.end() ) { + ptr = key->second; + } else { + throw cms::Exception("BadElectronKey") + << "Original object pointer with key = " << ele.originalObjectRef().key() + << " not found in cache!"; + } + } + //now we go through and modify the objects using the valuemaps we read in + for( auto itr = e_conf.tok_valuemaps.begin(); itr != e_conf.tok_valuemaps.end(); ++itr ) { + int value(0); + assignValue(ptr,itr->second,ele_vmaps,value); + if( !ele.hasUserInt(itr->first) ) { + ele.addUserInt(itr->first,value); + } else { + throw cms::Exception("ValueNameAlreadyExists") + << "Trying to add new UserInt = " << itr->first + << " failed because it already exists!"; + } + } + ++ele_idx; +} + +void EGExtraInfoModifierFromIntValueMaps:: +modifyObject(pat::Photon& pho) const { + // we encounter two cases here, either we are running AOD -> MINIAOD + // and the value maps are to the reducedEG object, can use original object ptr + // or we are running MINIAOD->MINIAOD and we need to fetch the pat objects to reference + edm::Ptr ptr(pho.originalObjectRef()); + if( !ph_conf.tok_photon_src.isUninitialized() ) { + auto key = phos_by_oop.find(pho_idx); + if( key != phos_by_oop.end() ) { + ptr = key->second; + } else { + throw cms::Exception("BadPhotonKey") + << "Original object pointer with key = " << pho.originalObjectRef().key() << " not found in cache!"; + } + } + //now we go through and modify the objects using the valuemaps we read in + for( auto itr = ph_conf.tok_valuemaps.begin(); itr != ph_conf.tok_valuemaps.end(); ++itr ) { + int value(0); + assignValue(ptr,itr->second,pho_vmaps,value); + if( !pho.hasUserInt(itr->first) ) { + pho.addUserInt(itr->first,value); + } else { + throw cms::Exception("ValueNameAlreadyExists") + << "Trying to add new UserInt = " << itr->first + << " failed because it already exists!"; + } + } + ++pho_idx; +} diff --git a/RecoEgamma/EgammaTools/plugins/EGFull5x5ShowerShapeModifier.cc b/RecoEgamma/EgammaTools/plugins/EGFull5x5ShowerShapeModifier.cc new file mode 100644 index 0000000000000..9728a53977443 --- /dev/null +++ b/RecoEgamma/EgammaTools/plugins/EGFull5x5ShowerShapeModifier.cc @@ -0,0 +1,302 @@ +#include "CommonTools/CandAlgos/interface/ModifyObjectValueBase.h" + +#include "FWCore/Utilities/interface/InputTag.h" +#include "FWCore/Utilities/interface/EDGetToken.h" +#include "DataFormats/Common/interface/ValueMap.h" + +#include "DataFormats/EgammaCandidates/interface/GsfElectron.h" +#include "DataFormats/EgammaCandidates/interface/Photon.h" + +namespace { + const edm::EDGetTokenT > empty_token; + const static edm::InputTag empty_tag(""); +} + +#include + +class EGFull5x5ShowerShapeModifierFromValueMaps : public ModifyObjectValueBase { +public: + struct electron_config { + edm::InputTag electron_src; + edm::InputTag sigmaEtaEta ; + edm::InputTag sigmaIetaIeta ; + edm::InputTag sigmaIphiIphi ; + edm::InputTag e1x5 ; + edm::InputTag e2x5Max ; + edm::InputTag e5x5 ; + edm::InputTag r9 ; + edm::InputTag hcalDepth1OverEcal ; + edm::InputTag hcalDepth2OverEcal ; + edm::InputTag hcalDepth1OverEcalBc ; + edm::InputTag hcalDepth2OverEcalBc ; + edm::EDGetTokenT > tok_electron_src; + edm::EDGetTokenT > tok_sigmaEtaEta ; + edm::EDGetTokenT > tok_sigmaIetaIeta ; + edm::EDGetTokenT > tok_sigmaIphiIphi ; + edm::EDGetTokenT > tok_e1x5 ; + edm::EDGetTokenT > tok_e2x5Max ; + edm::EDGetTokenT > tok_e5x5 ; + edm::EDGetTokenT > tok_r9 ; + edm::EDGetTokenT > tok_hcalDepth1OverEcal ; + edm::EDGetTokenT > tok_hcalDepth2OverEcal ; + edm::EDGetTokenT > tok_hcalDepth1OverEcalBc ; + edm::EDGetTokenT > tok_hcalDepth2OverEcalBc ; + }; + + struct photon_config { + edm::InputTag photon_src ; + edm::InputTag sigmaEtaEta ; + edm::InputTag sigmaIetaIeta ; + edm::InputTag e1x5 ; + edm::InputTag e2x5 ; + edm::InputTag e3x3 ; + edm::InputTag e5x5 ; + edm::InputTag maxEnergyXtal ; + edm::InputTag hcalDepth1OverEcal ; + edm::InputTag hcalDepth2OverEcal ; + edm::InputTag hcalDepth1OverEcalBc; + edm::InputTag hcalDepth2OverEcalBc; + edm::EDGetTokenT > tok_photon_src; + edm::EDGetTokenT > tok_sigmaEtaEta ; + edm::EDGetTokenT > tok_sigmaIetaIeta ; + edm::EDGetTokenT > tok_e1x5 ; + edm::EDGetTokenT > tok_e2x5 ; + edm::EDGetTokenT > tok_e3x3 ; + edm::EDGetTokenT > tok_e5x5 ; + edm::EDGetTokenT > tok_maxEnergyXtal ; + edm::EDGetTokenT > tok_hcalDepth1OverEcal ; + edm::EDGetTokenT > tok_hcalDepth2OverEcal ; + edm::EDGetTokenT > tok_hcalDepth1OverEcalBc; + edm::EDGetTokenT > tok_hcalDepth2OverEcalBc; + }; + + EGFull5x5ShowerShapeModifierFromValueMaps(const edm::ParameterSet& conf); + + void setEvent(const edm::Event&) override final; + void setEventContent(const edm::EventSetup&) override final; + void setConsumes(edm::ConsumesCollector&) override final; + + void modifyObject(pat::Electron&) const override final; + void modifyObject(pat::Photon&) const override final; + +private: + electron_config e_conf; + photon_config ph_conf; + std::unordered_map > eles_by_oop; // indexed by original object ptr + std::unordered_map > > ele_vmaps; + std::unordered_map > phos_by_oop; + std::unordered_map > > pho_vmaps; + mutable unsigned ele_idx,pho_idx; // hack here until we figure out why some slimmedPhotons don't have original object ptrs +}; + +DEFINE_EDM_PLUGIN(ModifyObjectValueFactory, + EGFull5x5ShowerShapeModifierFromValueMaps, + "EGFull5x5ShowerShapeModifierFromValueMaps"); + +EGFull5x5ShowerShapeModifierFromValueMaps:: +EGFull5x5ShowerShapeModifierFromValueMaps(const edm::ParameterSet& conf) : + ModifyObjectValueBase(conf) { + if( conf.exists("electron_config") ) { + const edm::ParameterSet& electrons = conf.getParameter("electron_config"); + if( electrons.exists("electronSrc") ) e_conf.electron_src = electrons.getParameter("electronSrc"); + if( electrons.exists("sigmaEtaEta") ) e_conf.sigmaEtaEta = electrons.getParameter("sigmaEtaEta"); + if( electrons.exists("sigmaIetaIeta") ) e_conf.sigmaIetaIeta = electrons.getParameter("sigmaIetaIeta"); + if( electrons.exists("sigmaIphiIphi") ) e_conf.sigmaIphiIphi = electrons.getParameter("sigmaIphiIphi"); + if( electrons.exists("e1x5") ) e_conf.e1x5 = electrons.getParameter("e1x5"); + if( electrons.exists("e2x5Max") ) e_conf.e2x5Max = electrons.getParameter("e2x5Max"); + if( electrons.exists("e5x5") ) e_conf.e5x5 = electrons.getParameter("e5x5"); + if( electrons.exists("r9") ) e_conf.r9 = electrons.getParameter("r9"); + if( electrons.exists("hcalDepth1OverEcal") ) e_conf.hcalDepth1OverEcal = electrons.getParameter("hcalDepth1OverEcal"); + if( electrons.exists("hcalDepth2OverEcal") ) e_conf.hcalDepth2OverEcal = electrons.getParameter("hcalDepth2OverEcal"); + if( electrons.exists("hcalDepth1OverEcalBc") ) e_conf.hcalDepth1OverEcalBc = electrons.getParameter("hcalDepth1OverEcalBc"); + if( electrons.exists("hcalDepth2OverEcalBc") ) e_conf.hcalDepth2OverEcalBc = electrons.getParameter("hcalDepth2OverEcalBc"); + } + if( conf.exists("photon_config") ) { + const edm::ParameterSet& photons = conf.getParameter("photon_config"); + if( photons.exists("photonSrc") ) ph_conf.photon_src = photons.getParameter("photonSrc"); + if( photons.exists("sigmaEtaEta") ) ph_conf.sigmaEtaEta = photons.getParameter("sigmaEtaEta"); + if( photons.exists("sigmaIetaIeta") ) ph_conf.sigmaIetaIeta = photons.getParameter("sigmaIetaIeta"); + if( photons.exists("e1x5") ) ph_conf.e1x5 = photons.getParameter("e1x5"); + if( photons.exists("e2x5") ) ph_conf.e2x5 = photons.getParameter("e2x5"); + if( photons.exists("e3x3") ) ph_conf.e3x3 = photons.getParameter("e3x3"); + if( photons.exists("e5x5") ) ph_conf.e5x5 = photons.getParameter("e5x5"); + if( photons.exists("maxEnergyXtal") ) ph_conf.maxEnergyXtal = photons.getParameter("maxEnergyXtal"); + if( photons.exists("hcalDepth1OverEcal") ) ph_conf.hcalDepth1OverEcal = photons.getParameter("hcalDepth1OverEcal"); + if( photons.exists("hcalDepth2OverEcal") ) ph_conf.hcalDepth2OverEcal = photons.getParameter("hcalDepth2OverEcal"); + if( photons.exists("hcalDepth1OverEcalBc") ) ph_conf.hcalDepth1OverEcalBc = photons.getParameter("hcalDepth1OverEcalBc"); + if( photons.exists("hcalDepth2OverEcalBc") ) ph_conf.hcalDepth2OverEcalBc = photons.getParameter("hcalDepth2OverEcalBc"); + } + + ele_idx = pho_idx = 0; +} + +inline void get_product(const edm::Event& evt, + const edm::EDGetTokenT >& tok, + std::unordered_map > >& map) { + if( !tok.isUninitialized() ) evt.getByToken(tok,map[tok.index()]); +} + +void EGFull5x5ShowerShapeModifierFromValueMaps:: +setEvent(const edm::Event& evt) { + eles_by_oop.clear(); + phos_by_oop.clear(); + ele_vmaps.clear(); + pho_vmaps.clear(); + + ele_idx = pho_idx = 0; + + if( !e_conf.tok_electron_src.isUninitialized() ) { + edm::Handle > eles; + evt.getByToken(e_conf.tok_electron_src,eles); + + for( unsigned i = 0; i < eles->size(); ++i ) { + edm::Ptr ptr = eles->ptrAt(i); + eles_by_oop[i] = ptr; + } + } + + get_product(evt,e_conf.tok_sigmaEtaEta,ele_vmaps); + get_product(evt,e_conf.tok_sigmaIetaIeta,ele_vmaps); + get_product(evt,e_conf.tok_sigmaIphiIphi,ele_vmaps); + get_product(evt,e_conf.tok_e1x5,ele_vmaps); + get_product(evt,e_conf.tok_e2x5Max,ele_vmaps); + get_product(evt,e_conf.tok_e5x5,ele_vmaps); + get_product(evt,e_conf.tok_r9,ele_vmaps); + get_product(evt,e_conf.tok_hcalDepth1OverEcal,ele_vmaps); + get_product(evt,e_conf.tok_hcalDepth2OverEcal,ele_vmaps); + get_product(evt,e_conf.tok_hcalDepth1OverEcalBc,ele_vmaps); + get_product(evt,e_conf.tok_hcalDepth2OverEcalBc,ele_vmaps); + + if( !ph_conf.tok_photon_src.isUninitialized() ) { + edm::Handle > phos; + evt.getByToken(ph_conf.tok_photon_src,phos); + + for( unsigned i = 0; i < phos->size(); ++i ) { + edm::Ptr ptr = phos->ptrAt(i); + phos_by_oop[i] = ptr; + } + } + + get_product(evt,ph_conf.tok_sigmaEtaEta,pho_vmaps); + get_product(evt,ph_conf.tok_sigmaIetaIeta,pho_vmaps); + get_product(evt,ph_conf.tok_e1x5,pho_vmaps); + get_product(evt,ph_conf.tok_e2x5,pho_vmaps); + get_product(evt,ph_conf.tok_e3x3,pho_vmaps); + get_product(evt,ph_conf.tok_e5x5,pho_vmaps); + get_product(evt,ph_conf.tok_maxEnergyXtal,pho_vmaps); + get_product(evt,ph_conf.tok_hcalDepth1OverEcal,pho_vmaps); + get_product(evt,ph_conf.tok_hcalDepth2OverEcal,pho_vmaps); + get_product(evt,ph_conf.tok_hcalDepth1OverEcalBc,pho_vmaps); + get_product(evt,ph_conf.tok_hcalDepth2OverEcalBc,pho_vmaps); + +} + +void EGFull5x5ShowerShapeModifierFromValueMaps:: +setEventContent(const edm::EventSetup& evs) { +} + +template +inline void make_consumes(T& tag,U& tok,V& sume) { if( !(empty_tag == tag) ) tok = sume.template consumes >(tag); } + +void EGFull5x5ShowerShapeModifierFromValueMaps:: +setConsumes(edm::ConsumesCollector& sumes) { + //setup electrons + if( !(empty_tag == e_conf.electron_src) ) e_conf.tok_electron_src = sumes.consumes >(e_conf.electron_src); + make_consumes(e_conf.sigmaEtaEta,e_conf.tok_sigmaEtaEta,sumes); + make_consumes(e_conf.sigmaIetaIeta,e_conf.tok_sigmaIetaIeta,sumes); + make_consumes(e_conf.sigmaIphiIphi,e_conf.tok_sigmaIphiIphi,sumes); + make_consumes(e_conf.e1x5,e_conf.tok_e1x5,sumes); + make_consumes(e_conf.e2x5Max,e_conf.tok_e2x5Max,sumes); + make_consumes(e_conf.e5x5,e_conf.tok_e5x5,sumes); + make_consumes(e_conf.r9,e_conf.tok_r9,sumes); + make_consumes(e_conf.hcalDepth1OverEcal,e_conf.tok_hcalDepth1OverEcal,sumes); + make_consumes(e_conf.hcalDepth2OverEcal,e_conf.tok_hcalDepth2OverEcal,sumes); + make_consumes(e_conf.hcalDepth1OverEcalBc,e_conf.tok_hcalDepth1OverEcalBc,sumes); + make_consumes(e_conf.hcalDepth2OverEcalBc,e_conf.tok_hcalDepth2OverEcalBc,sumes); + + // setup photons + if( !(empty_tag == ph_conf.photon_src) ) ph_conf.tok_photon_src = sumes.consumes >(ph_conf.photon_src); + make_consumes(ph_conf.sigmaEtaEta,ph_conf.tok_sigmaEtaEta,sumes); + make_consumes(ph_conf.sigmaIetaIeta,ph_conf.tok_sigmaIetaIeta,sumes); + make_consumes(ph_conf.e1x5,ph_conf.tok_e1x5,sumes); + make_consumes(ph_conf.e2x5,ph_conf.tok_e2x5,sumes); + make_consumes(ph_conf.e3x3,ph_conf.tok_e3x3,sumes); + make_consumes(ph_conf.e5x5,ph_conf.tok_e5x5,sumes); + make_consumes(ph_conf.maxEnergyXtal,ph_conf.tok_maxEnergyXtal,sumes); + make_consumes(ph_conf.hcalDepth1OverEcal,ph_conf.tok_hcalDepth1OverEcal,sumes); + make_consumes(ph_conf.hcalDepth2OverEcal,ph_conf.tok_hcalDepth2OverEcal,sumes); + make_consumes(ph_conf.hcalDepth1OverEcalBc,ph_conf.tok_hcalDepth1OverEcalBc,sumes); + make_consumes(ph_conf.hcalDepth2OverEcalBc,ph_conf.tok_hcalDepth2OverEcalBc,sumes); +} + +template +inline void assignValue(const T& ptr, const U& tok, const V& map, float& value) { + if( !tok.isUninitialized() ) value = map.find(tok.index())->second->get(ptr.id(),ptr.key()); +} + +void EGFull5x5ShowerShapeModifierFromValueMaps:: +modifyObject(pat::Electron& ele) const { + // we encounter two cases here, either we are running AOD -> MINIAOD + // and the value maps are to the reducedEG object, can use original object ptr + // or we are running MINIAOD->MINIAOD and we need to fetch the pat objects to reference + edm::Ptr ptr(ele.originalObjectRef()); + if( !e_conf.tok_electron_src.isUninitialized() ) { + auto key = eles_by_oop.find(ele_idx); + if( key != eles_by_oop.end() ) { + ptr = key->second; + } else { + throw cms::Exception("BadElectronKey") + << "Original object pointer with key = " << ele.originalObjectRef().key() << " not found in cache!"; + } + } + //now we go through and modify the objects using the valuemaps we read in + auto full5x5 = ele.full5x5_showerShape(); + assignValue(ptr,e_conf.tok_sigmaEtaEta,ele_vmaps,full5x5.sigmaEtaEta); + assignValue(ptr,e_conf.tok_sigmaIetaIeta,ele_vmaps,full5x5.sigmaIetaIeta); + assignValue(ptr,e_conf.tok_sigmaIphiIphi,ele_vmaps,full5x5.sigmaIphiIphi); + assignValue(ptr,e_conf.tok_e1x5,ele_vmaps,full5x5.e1x5); + assignValue(ptr,e_conf.tok_e2x5Max,ele_vmaps,full5x5.e2x5Max); + assignValue(ptr,e_conf.tok_e5x5,ele_vmaps,full5x5.e5x5); + assignValue(ptr,e_conf.tok_r9,ele_vmaps,full5x5.r9); + assignValue(ptr,e_conf.tok_hcalDepth1OverEcal,ele_vmaps,full5x5.hcalDepth1OverEcal); + assignValue(ptr,e_conf.tok_hcalDepth2OverEcal,ele_vmaps,full5x5.hcalDepth2OverEcal); + assignValue(ptr,e_conf.tok_hcalDepth1OverEcalBc,ele_vmaps,full5x5.hcalDepth1OverEcalBc); + assignValue(ptr,e_conf.tok_hcalDepth2OverEcalBc,ele_vmaps,full5x5.hcalDepth2OverEcalBc); + + ele.full5x5_setShowerShape(full5x5); + ++ele_idx; +} + + +void EGFull5x5ShowerShapeModifierFromValueMaps:: +modifyObject(pat::Photon& pho) const { + // we encounter two cases here, either we are running AOD -> MINIAOD + // and the value maps are to the reducedEG object, can use original object ptr + // or we are running MINIAOD->MINIAOD and we need to fetch the pat objects to reference + edm::Ptr ptr(pho.originalObjectRef()); + if( !ph_conf.tok_photon_src.isUninitialized() ) { + auto key = phos_by_oop.find(pho_idx); + if( key != phos_by_oop.end() ) { + ptr = key->second; + } else { + throw cms::Exception("BadPhotonKey") + << "Original object pointer with key = " << pho.originalObjectRef().key() << " not found in cache!"; + } + } + //now we go through and modify the objects using the valuemaps we read in + auto full5x5 = pho.full5x5_showerShapeVariables(); + assignValue(ptr,ph_conf.tok_sigmaEtaEta,pho_vmaps,full5x5.sigmaEtaEta); + assignValue(ptr,ph_conf.tok_sigmaIetaIeta,pho_vmaps,full5x5.sigmaIetaIeta); + assignValue(ptr,ph_conf.tok_e1x5,pho_vmaps,full5x5.e1x5); + assignValue(ptr,ph_conf.tok_e2x5,pho_vmaps,full5x5.e2x5); + assignValue(ptr,ph_conf.tok_e3x3,pho_vmaps,full5x5.e3x3); + assignValue(ptr,ph_conf.tok_e5x5,pho_vmaps,full5x5.e5x5); + assignValue(ptr,ph_conf.tok_maxEnergyXtal,pho_vmaps,full5x5.maxEnergyXtal); + assignValue(ptr,ph_conf.tok_hcalDepth1OverEcal,pho_vmaps,full5x5.hcalDepth1OverEcal); + assignValue(ptr,ph_conf.tok_hcalDepth2OverEcal,pho_vmaps,full5x5.hcalDepth2OverEcal); + assignValue(ptr,ph_conf.tok_hcalDepth1OverEcalBc,pho_vmaps,full5x5.hcalDepth1OverEcalBc); + assignValue(ptr,ph_conf.tok_hcalDepth2OverEcalBc,pho_vmaps,full5x5.hcalDepth2OverEcalBc); + + pho.full5x5_setShowerShapeVariables(full5x5); + ++pho_idx; +} diff --git a/RecoEgamma/EgammaTools/python/egammaObjectModificationsInMiniAOD_cff.py b/RecoEgamma/EgammaTools/python/egammaObjectModificationsInMiniAOD_cff.py new file mode 100644 index 0000000000000..9f506b089fffb --- /dev/null +++ b/RecoEgamma/EgammaTools/python/egammaObjectModificationsInMiniAOD_cff.py @@ -0,0 +1,53 @@ +import FWCore.ParameterSet.Config as cms + +#electron mva ids +import RecoEgamma.ElectronIdentification.Identification.mvaElectronID_PHYS14_PU20bx25_nonTrig_V1_cff as ele_phys14_nt + +#photon mva ids +import RecoEgamma.PhotonIdentification.Identification.mvaPhotonID_PHYS14_PU20bx25_nonTrig_V1_cff as pho_phys14_nt +import RecoEgamma.PhotonIdentification.Identification.mvaPhotonID_Spring15_50ns_nonTrig_V0_cff as pho_spring15_nt + +ele_mva_prod_name = 'electronMVAValueMapProducer' +pho_mva_prod_name = 'photonMVAValueMapProducer' + +def setup_mva(val_pset,cat_pset,prod_name,mva_name): + value_name = '%s:%sValues'%(prod_name,mva_name) + cat_name = '%s:%sCategories'%(prod_name,mva_name) + setattr( val_pset, '%sValues'%mva_name, cms.InputTag(value_name) ) + setattr( cat_pset, '%sCategories'%mva_name, cms.InputTag(cat_name) ) + +egamma_modifications = cms.VPSet( + cms.PSet( modifierName = cms.string('EGExtraInfoModifierFromFloatValueMaps'), + electron_config = cms.PSet( ), + photon_config = cms.PSet( phoFull5x5SigmaIEtaIPhi = cms.InputTag('photonIDValueMapProducer:phoFull5x5SigmaIEtaIPhi'), + phoFull5x5E1x3 = cms.InputTag('photonIDValueMapProducer:phoFull5x5E1x3'), + phoFull5x5E2x2 = cms.InputTag('photonIDValueMapProducer:phoFull5x5E2x2'), + phoFull5x5E2x5Max = cms.InputTag('photonIDValueMapProducer:phoFull5x5E2x5Max'), + phoESEffSigmaRR = cms.InputTag('photonIDValueMapProducer:phoESEffSigmaRR'), + phoChargedIsolation = cms.InputTag('photonIDValueMapProducer:phoChargedIsolation'), + phoNeutralHadronIsolation = cms.InputTag('photonIDValueMapProducer:phoNeutralHadronIsolation'), + phoPhotonIsolation = cms.InputTag('photonIDValueMapProducer:phoPhotonIsolation'), + phoWorstChargedIsolation = cms.InputTag('photonIDValueMapProducer:phoWorstChargedIsolation') + ) + ), + cms.PSet( modifierName = cms.string('EGExtraInfoModifierFromIntValueMaps'), + electron_config = cms.PSet( ), + photon_config = cms.PSet( ) + ) +) + +#setup the mva value maps to embed +setup_mva(egamma_modifications[0].electron_config, + egamma_modifications[1].electron_config, + ele_mva_prod_name, + ele_phys14_nt.mvaPhys14NonTrigClassName) + +setup_mva(egamma_modifications[0].photon_config, + egamma_modifications[1].photon_config, + pho_mva_prod_name, + pho_phys14_nt.mvaPhys14NonTrigClassName) + +setup_mva(egamma_modifications[0].photon_config, + egamma_modifications[1].photon_config, + pho_mva_prod_name, + pho_spring15_nt.mvaSpring15NonTrigClassName) diff --git a/RecoEgamma/EgammaTools/python/egammaObjectModificationsPatches_cff.py b/RecoEgamma/EgammaTools/python/egammaObjectModificationsPatches_cff.py new file mode 100644 index 0000000000000..a52e73bf7cd76 --- /dev/null +++ b/RecoEgamma/EgammaTools/python/egammaObjectModificationsPatches_cff.py @@ -0,0 +1,3 @@ +import FWCore.ParameterSet.Config as cms + +egamma_modifications = cms.VPSet( ) diff --git a/RecoEgamma/EgammaTools/src/AnyMVAEstimatorRun2Base.cc b/RecoEgamma/EgammaTools/src/AnyMVAEstimatorRun2Base.cc new file mode 100644 index 0000000000000..de1d4ab8f8dbd --- /dev/null +++ b/RecoEgamma/EgammaTools/src/AnyMVAEstimatorRun2Base.cc @@ -0,0 +1,4 @@ +#include "RecoEgamma/EgammaTools/interface/AnyMVAEstimatorRun2Base.h" + +EDM_REGISTER_PLUGINFACTORY(AnyMVAEstimatorRun2Factory, + "AnyMVAEstimatorRun2Factory"); diff --git a/RecoEgamma/ElectronIdentification/interface/ElectronMVAEstimatorRun2Phys14NonTrig.h b/RecoEgamma/ElectronIdentification/interface/ElectronMVAEstimatorRun2Phys14NonTrig.h new file mode 100644 index 0000000000000..61e8001e43322 --- /dev/null +++ b/RecoEgamma/ElectronIdentification/interface/ElectronMVAEstimatorRun2Phys14NonTrig.h @@ -0,0 +1,106 @@ +#ifndef RecoEgamma_ElectronIdentification_ElectronMVAEstimatorRun2Phys14NonTrig_H +#define RecoEgamma_ElectronIdentification_ElectronMVAEstimatorRun2Phys14NonTrig_H + +#include "RecoEgamma/EgammaTools/interface/AnyMVAEstimatorRun2Base.h" + +#include "DataFormats/EgammaCandidates/interface/GsfElectron.h" + +#include +#include +#include +#include "TMVA/Factory.h" +#include "TMVA/Tools.h" +#include "TMVA/Reader.h" + +class ElectronMVAEstimatorRun2Phys14NonTrig : public AnyMVAEstimatorRun2Base{ + + public: + + // Define here the number and the meaning of the categories + // for this specific MVA + const int nCategories = 6; + enum mvaCategories { + UNDEFINED = -1, + CAT_EB1_PT5to10 = 0, + CAT_EB2_PT5to10 = 1, + CAT_EE_PT5to10 = 2, + CAT_EB1_PT10plus = 3, + CAT_EB2_PT10plus = 4, + CAT_EE_PT10plus = 5 + }; + + // Define the struct that contains all necessary for MVA variables + struct AllVariables { + float kfhits; + // Pure ECAL -> shower shapes + float see; + float spp; + float OneMinusE1x5E5x5; + float R9; + float etawidth; + float phiwidth; + float HoE; + // Endcap only variables + float PreShowerOverRaw; + //Pure tracking variables + float kfchi2; + float gsfchi2; + // Energy matching + float fbrem; + float EoP; + float eleEoPout; + float IoEmIoP; + // Geometrical matchings + float deta; + float dphi; + float detacalo; + // Spectator variables + float pt; + float isBarrel; + float isEndcap; + float SCeta; + }; + + // Constructor and destructor + ElectronMVAEstimatorRun2Phys14NonTrig(const edm::ParameterSet& conf); + ~ElectronMVAEstimatorRun2Phys14NonTrig(); + + // Calculation of the MVA value + float mvaValue( const edm::Ptr& particle); + + // Utility functions + TMVA::Reader *createSingleReader(const int iCategory, const edm::FileInPath &weightFile); + + inline int getNCategories(){return nCategories;}; + bool isEndcapCategory( int category ); + const inline std::string getName(){return name_;}; + + // Functions that should work on both pat and reco electrons + // (use the fact that pat::Electron inherits from reco::GsfElectron) + void fillMVAVariables(const edm::Ptr& particle); + int findCategory( const edm::Ptr& particle); + // The function below ensures that the variables passed to MVA are + // within reasonable bounds + void constrainMVAVariables(); + + private: + + // MVA name. This is a unique name for this MVA implementation. + // It will be used as part of ValueMap names. + // For simplicity, keep it set to the class name. + const std::string name_ = "ElectronMVAEstimatorRun2Phys14NonTrig"; + + // Data members + std::vector< std::unique_ptr > _tmvaReaders; + + // All variables needed by this MVA + std::string _MethodName; + AllVariables _allMVAVars; + +}; + +DEFINE_EDM_PLUGIN(AnyMVAEstimatorRun2Factory, + ElectronMVAEstimatorRun2Phys14NonTrig, + "ElectronMVAEstimatorRun2Phys14NonTrig"); + +#endif diff --git a/RecoEgamma/ElectronIdentification/plugins/ElectronMVAEstimatorRun2Phys14NonTrig.cc b/RecoEgamma/ElectronIdentification/plugins/ElectronMVAEstimatorRun2Phys14NonTrig.cc new file mode 100644 index 0000000000000..fee844edbf679 --- /dev/null +++ b/RecoEgamma/ElectronIdentification/plugins/ElectronMVAEstimatorRun2Phys14NonTrig.cc @@ -0,0 +1,297 @@ +#include "RecoEgamma/ElectronIdentification/interface/ElectronMVAEstimatorRun2Phys14NonTrig.h" + +#include "DataFormats/TrackReco/interface/Track.h" +#include "DataFormats/GsfTrackReco/interface/GsfTrack.h" + +#include "DataFormats/PatCandidates/interface/Electron.h" + +#include "FWCore/ParameterSet/interface/FileInPath.h" + +ElectronMVAEstimatorRun2Phys14NonTrig::ElectronMVAEstimatorRun2Phys14NonTrig(const edm::ParameterSet& conf): + AnyMVAEstimatorRun2Base(conf){ + + const std::vector weightFileNames + = conf.getParameter >("weightFileNames"); + + if( (int)(weightFileNames.size()) != nCategories ) + throw cms::Exception("MVA config failure: ") + << "wrong number of weightfiles" << std::endl; + + _tmvaReaders.clear(); + _MethodName = "BDTG method"; + // Create a TMVA reader object for each category + for(int i=0; i ( createSingleReader(i, weightFile ) ) ); + + } + +} + +ElectronMVAEstimatorRun2Phys14NonTrig:: +~ElectronMVAEstimatorRun2Phys14NonTrig(){ + + _tmvaReaders.clear(); +} + +float ElectronMVAEstimatorRun2Phys14NonTrig:: +mvaValue( const edm::Ptr& particle){ + + int iCategory = findCategory( particle ); + fillMVAVariables( particle ); + constrainMVAVariables(); + float result = _tmvaReaders.at(iCategory)->EvaluateMVA(_MethodName); + + bool debug = false; + if(debug) { + std::cout << " *** Inside the class _MethodName " << _MethodName << std::endl; + std::cout << " bin " << iCategory + << " fbrem " << _allMVAVars.fbrem + << " kfchi2 " << _allMVAVars.kfchi2 + << " mykfhits " << _allMVAVars.kfhits + << " gsfchi2 " << _allMVAVars.gsfchi2 + << " deta " << _allMVAVars.deta + << " dphi " << _allMVAVars.dphi + << " detacalo " << _allMVAVars.detacalo + << " see " << _allMVAVars.see + << " spp " << _allMVAVars.spp + << " etawidth " << _allMVAVars.etawidth + << " phiwidth " << _allMVAVars.phiwidth + << " OneMinusE1x5E5x5 " << _allMVAVars.OneMinusE1x5E5x5 + << " R9 " << _allMVAVars.R9 + << " HoE " << _allMVAVars.HoE + << " EoP " << _allMVAVars.EoP + << " IoEmIoP " << _allMVAVars.IoEmIoP + << " eleEoPout " << _allMVAVars.eleEoPout + //<< " d0 " << _allMVAVars.d0 + // << " ip3d " << _allMVAVars.ip3d + << " eta " << _allMVAVars.SCeta + << " pt " << _allMVAVars.pt << std::endl; + std::cout << " ### MVA " << result << std::endl; + } + + return result; +} + +int ElectronMVAEstimatorRun2Phys14NonTrig::findCategory( const edm::Ptr& particle){ + + // Try to cast the particle into a reco particle. + // This should work for both reco and pat. + const edm::Ptr eleRecoPtr = ( edm::Ptr )particle; + if( eleRecoPtr.get() == NULL ) + throw cms::Exception("MVA failure: ") + << " given particle is expected to be reco::GsfElectron or pat::Electron," << std::endl + << " but appears to be neither" << std::endl; + + float pt = eleRecoPtr->pt(); + float eta = eleRecoPtr->superCluster()->eta(); + + // + // Determine the category + // + int iCategory = UNDEFINED; + const float ptSplit = 10; // we have above and below 10 GeV categories + const float ebSplit = 0.800;// barrel is split into two regions + const float ebeeSplit = 1.479; // division between barrel and endcap + + if (pt < ptSplit && std::abs(eta) < ebSplit) + iCategory = CAT_EB1_PT5to10; + + if (pt < ptSplit && std::abs(eta) >= ebSplit && std::abs(eta) < ebeeSplit) + iCategory = CAT_EB2_PT5to10; + + if (pt < ptSplit && std::abs(eta) >= ebeeSplit) + iCategory = CAT_EE_PT5to10; + + if (pt >= ptSplit && std::abs(eta) < ebSplit) + iCategory = CAT_EB1_PT10plus; + + if (pt >= ptSplit && std::abs(eta) >= ebSplit && std::abs(eta) < ebeeSplit) + iCategory = CAT_EB2_PT10plus; + + if (pt >= ptSplit && std::abs(eta) >= ebeeSplit) + iCategory = CAT_EE_PT10plus; + + return iCategory; +} + +bool ElectronMVAEstimatorRun2Phys14NonTrig:: +isEndcapCategory(int category ){ + + bool isEndcap = false; + if( category == CAT_EE_PT5to10 || category == CAT_EE_PT10plus ) + isEndcap = true; + + return isEndcap; +} + + +TMVA::Reader *ElectronMVAEstimatorRun2Phys14NonTrig:: +createSingleReader(const int iCategory, const edm::FileInPath &weightFile){ + + // + // Create the reader + // + TMVA::Reader *tmpTMVAReader = new TMVA::Reader( "!Color:Silent:Error" ); + + // + // Configure all variables and spectators. Note: the order and names + // must match what is found in the xml weights file! + // + + tmpTMVAReader->AddVariable("ele_kfhits", &_allMVAVars.kfhits); + + // Pure ECAL -> shower shapes + tmpTMVAReader->AddVariable("ele_oldsigmaietaieta", &_allMVAVars.see); + tmpTMVAReader->AddVariable("ele_oldsigmaiphiiphi", &_allMVAVars.spp); + tmpTMVAReader->AddVariable("ele_oldcircularity", &_allMVAVars.OneMinusE1x5E5x5); + tmpTMVAReader->AddVariable("ele_oldr9", &_allMVAVars.R9); + tmpTMVAReader->AddVariable("ele_scletawidth", &_allMVAVars.etawidth); + tmpTMVAReader->AddVariable("ele_sclphiwidth", &_allMVAVars.phiwidth); + tmpTMVAReader->AddVariable("ele_he", &_allMVAVars.HoE); + // Endcap only variables + if( isEndcapCategory(iCategory) ) + tmpTMVAReader->AddVariable("ele_psEoverEraw", &_allMVAVars.PreShowerOverRaw); + + //Pure tracking variables + tmpTMVAReader->AddVariable("ele_kfchi2", &_allMVAVars.kfchi2); + tmpTMVAReader->AddVariable("ele_chi2_hits", &_allMVAVars.gsfchi2); + + // Energy matching + tmpTMVAReader->AddVariable("ele_fbrem", &_allMVAVars.fbrem); + tmpTMVAReader->AddVariable("ele_ep", &_allMVAVars.EoP); + tmpTMVAReader->AddVariable("ele_eelepout", &_allMVAVars.eleEoPout); + tmpTMVAReader->AddVariable("ele_IoEmIop", &_allMVAVars.IoEmIoP); + + // Geometrical matchings + tmpTMVAReader->AddVariable("ele_deltaetain", &_allMVAVars.deta); + tmpTMVAReader->AddVariable("ele_deltaphiin", &_allMVAVars.dphi); + tmpTMVAReader->AddVariable("ele_deltaetaseed", &_allMVAVars.detacalo); + + // Spectator variables + tmpTMVAReader->AddSpectator("ele_pT", &_allMVAVars.pt); + tmpTMVAReader->AddSpectator("ele_isbarrel", &_allMVAVars.isBarrel); + tmpTMVAReader->AddSpectator("ele_isendcap", &_allMVAVars.isEndcap); + tmpTMVAReader->AddSpectator("scl_eta", &_allMVAVars.SCeta); + + // + // Book the method and set up the weights file + // + tmpTMVAReader->BookMVA(_MethodName , weightFile.fullPath() ); + + return tmpTMVAReader; +} + +// A function that should work on both pat and reco objects +void ElectronMVAEstimatorRun2Phys14NonTrig::fillMVAVariables(const edm::Ptr& particle){ + + // Try to cast the particle into a reco particle. + // This should work for both reco and pat. + const edm::Ptr eleRecoPtr = ( edm::Ptr )particle; + if( eleRecoPtr.get() == NULL ) + throw cms::Exception("MVA failure: ") + << " given particle is expected to be reco::GsfElectron or pat::Electron," << std::endl + << " but appears to be neither" << std::endl; + + // Both pat and reco particles have exactly the same accessors, so we use a reco ptr + // throughout the code, with a single exception as of this writing, handled separately below. + auto superCluster = eleRecoPtr->superCluster(); + + // To get to CTF track information in pat::Electron, we have to have the pointer + // to pat::Electron, it is not accessible from the pointer to reco::GsfElectron. + // This behavior is reported and is expected to change in the future (post-7.4.5 some time). + bool validKF= false; + reco::TrackRef myTrackRef = eleRecoPtr->closestCtfTrackRef(); + const edm::Ptr elePatPtr(eleRecoPtr); + // Check if this is really a pat::Electron, and if yes, get the track ref from this new + // pointer instead + if( elePatPtr.get() != NULL ) + myTrackRef = elePatPtr->closestCtfTrackRef(); + validKF = (myTrackRef.isAvailable() && (myTrackRef.isNonnull()) ); + + _allMVAVars.kfhits = (validKF) ? myTrackRef->hitPattern().trackerLayersWithMeasurement() : -1. ; + // Pure ECAL -> shower shapes + _allMVAVars.see = eleRecoPtr->full5x5_sigmaIetaIeta(); + _allMVAVars.spp = eleRecoPtr->full5x5_sigmaIphiIphi(); + _allMVAVars.OneMinusE1x5E5x5 = 1. - eleRecoPtr->full5x5_e1x5() / eleRecoPtr->full5x5_e5x5(); + _allMVAVars.R9 = eleRecoPtr->full5x5_r9(); + _allMVAVars.etawidth = superCluster->etaWidth(); + _allMVAVars.phiwidth = superCluster->phiWidth(); + _allMVAVars.HoE = eleRecoPtr->hadronicOverEm(); + // Endcap only variables + _allMVAVars.PreShowerOverRaw = superCluster->preshowerEnergy() / superCluster->rawEnergy(); + //Pure tracking variables + _allMVAVars.kfchi2 = (validKF) ? myTrackRef->normalizedChi2() : 0; + _allMVAVars.gsfchi2 = eleRecoPtr->gsfTrack()->normalizedChi2(); + // Energy matching + _allMVAVars.fbrem = eleRecoPtr->fbrem(); + _allMVAVars.EoP = eleRecoPtr->eSuperClusterOverP(); + _allMVAVars.eleEoPout = eleRecoPtr->eEleClusterOverPout(); + _allMVAVars.IoEmIoP = (1.0/eleRecoPtr->ecalEnergy()) - (1.0 / eleRecoPtr->p()); + // Geometrical matchings + _allMVAVars.deta = eleRecoPtr->deltaEtaSuperClusterTrackAtVtx(); + _allMVAVars.dphi = eleRecoPtr->deltaPhiSuperClusterTrackAtVtx(); + _allMVAVars.detacalo = eleRecoPtr->deltaEtaSeedClusterTrackAtCalo(); + // Spectator variables + _allMVAVars.pt = eleRecoPtr->pt(); + float scEta = superCluster->eta(); + _allMVAVars.isBarrel = ( std::abs(scEta) < 1.479 ); + _allMVAVars.isEndcap = ( std::abs(scEta) >= 1.479); + _allMVAVars.SCeta = scEta; + + +} + +void ElectronMVAEstimatorRun2Phys14NonTrig::constrainMVAVariables(){ + + // Check that variables do not have crazy values + + if(_allMVAVars.fbrem < -1.) + _allMVAVars.fbrem = -1.; + + _allMVAVars.deta = fabs(_allMVAVars.deta); + if(_allMVAVars.deta > 0.06) + _allMVAVars.deta = 0.06; + + + _allMVAVars.dphi = fabs(_allMVAVars.dphi); + if(_allMVAVars.dphi > 0.6) + _allMVAVars.dphi = 0.6; + + + if(_allMVAVars.EoP > 20.) + _allMVAVars.EoP = 20.; + + if(_allMVAVars.eleEoPout > 20.) + _allMVAVars.eleEoPout = 20.; + + + _allMVAVars.detacalo = fabs(_allMVAVars.detacalo); + if(_allMVAVars.detacalo > 0.2) + _allMVAVars.detacalo = 0.2; + + if(_allMVAVars.OneMinusE1x5E5x5 < -1.) + _allMVAVars.OneMinusE1x5E5x5 = -1; + + if(_allMVAVars.OneMinusE1x5E5x5 > 2.) + _allMVAVars.OneMinusE1x5E5x5 = 2.; + + + + if(_allMVAVars.R9 > 5) + _allMVAVars.R9 = 5; + + if(_allMVAVars.gsfchi2 > 200.) + _allMVAVars.gsfchi2 = 200; + + + if(_allMVAVars.kfchi2 > 10.) + _allMVAVars.kfchi2 = 10.; + + +} + diff --git a/RecoEgamma/ElectronIdentification/plugins/ElectronMVAValueMapProducer.cc b/RecoEgamma/ElectronIdentification/plugins/ElectronMVAValueMapProducer.cc new file mode 100644 index 0000000000000..ccb7b5209cf21 --- /dev/null +++ b/RecoEgamma/ElectronIdentification/plugins/ElectronMVAValueMapProducer.cc @@ -0,0 +1,9 @@ +#include "RecoEgamma/EgammaTools/interface/MVAValueMapProducer.h" + +#include "DataFormats/EgammaCandidates/interface/GsfElectron.h" +#include "DataFormats/EgammaCandidates/interface/GsfElectronFwd.h" + +typedef MVAValueMapProducer ElectronMVAValueMapProducer; + +//define this as a plug-in +DEFINE_FWK_MODULE(ElectronMVAValueMapProducer); diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleConversionVetoCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleConversionVetoCut.cc index c4fdc36181726..fbaadfdd3d599 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleConversionVetoCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleConversionVetoCut.cc @@ -14,6 +14,8 @@ class GsfEleConversionVetoCut : public CutApplicatorWithEventContentBase { void setConsumes(edm::ConsumesCollector&) override final; void getEventContent(const edm::EventBase&) override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -71,3 +73,15 @@ operator()(const reco::GsfElectronPtr& cand) const{ } return true; } + +double GsfEleConversionVetoCut::value(const reco::CandidatePtr& cand) const { + reco::GsfElectronPtr ele(cand); + if( _thebs.isValid() && _convs.isValid() ) { + return !ConversionTools::hasMatchedConversion(*ele,_convs, + _thebs->position()); + } else { + edm::LogWarning("GsfEleConversionVetoCut") + << "Couldn't find a necessary collection, returning true!"; + return true; + } +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDEtaInCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDEtaInCut.cc index 01c1affafb725..f38671a18e3f3 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDEtaInCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDEtaInCut.cc @@ -12,6 +12,8 @@ class GsfEleDEtaInCut : public CutApplicatorBase { result_type operator()(const reco::GsfElectronPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -32,3 +34,8 @@ operator()(const reco::GsfElectronPtr& cand) const{ _dEtaInCutValueEB : _dEtaInCutValueEE ); return std::abs(cand->deltaEtaSuperClusterTrackAtVtx()) < dEtaInCutValue; } + +double GsfEleDEtaInCut::value(const reco::CandidatePtr& cand) const { + reco::GsfElectronPtr ele(cand); + return std::abs(ele->deltaEtaSuperClusterTrackAtVtx()); +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDEtaInLinearCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDEtaInLinearCut.cc index eddb5dcb054a6..6c42fa194a831 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDEtaInLinearCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDEtaInLinearCut.cc @@ -14,6 +14,8 @@ class GsfEleDEtaInLinearCut : public CutApplicatorBase { result_type operator()(const reco::GsfElectronPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -37,3 +39,8 @@ operator()(const reco::GsfElectronPtr& cand) const return std::abs(cand->deltaEtaSuperClusterTrackAtVtx())deltaEtaSuperClusterTrackAtVtx()); +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDEtaInSeedCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDEtaInSeedCut.cc index f81f69c11abb6..4896d37db090a 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDEtaInSeedCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDEtaInSeedCut.cc @@ -12,6 +12,8 @@ class GsfEleDEtaInSeedCut : public CutApplicatorBase { result_type operator()(const reco::GsfElectronPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -40,4 +42,7 @@ operator()(const reco::GsfElectronPtr& cand) const{ return std::abs(dEtaInSeed(cand))deltaPhiSuperClusterTrackAtVtx()) < dPhiInCutValue; } + +double GsfEleDPhiInCut::value(const reco::CandidatePtr& cand) const { + reco::GsfElectronPtr ele(cand); + return std::abs(ele->deltaPhiSuperClusterTrackAtVtx()); +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDeltaBetaIsoCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDeltaBetaIsoCut.cc index 6614012ab3a4a..3623bfb95cb3b 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDeltaBetaIsoCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDeltaBetaIsoCut.cc @@ -14,6 +14,8 @@ class GsfEleDeltaBetaIsoCut : public CutApplicatorWithEventContentBase { void setConsumes(edm::ConsumesCollector&) override final; void getEventContent(const edm::EventBase&) override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -80,11 +82,91 @@ operator()(const reco::GsfElectronPtr& cand) const{ _isoCutEBLowPt : _isoCutEELowPt ) : ( std::abs(cand->superCluster()->position().eta()) < _barrelCutOff ? _isoCutEBHighPt : _isoCutEEHighPt ) ); - const float chad = (*_chad_iso)[cand]; - const float nhad = (*_nhad_iso)[cand]; - const float pho = (*_ph_iso)[cand]; - const float puchad = (*_PUchad_iso)[cand]; + const reco::GsfElectron::PflowIsolationVariables& pfIso = + cand->pfIsolationVariables(); + + float chad_val = 0.0; + float nhad_val = 0.0; + float pho_val = 0.0; + float puchad_val = 0.0; + + if( _chad_iso.isValid() && _chad_iso->contains( cand.id() ) && + _nhad_iso.isValid() && _nhad_iso->contains( cand.id() ) && + _ph_iso.isValid() && _ph_iso->contains( cand.id() ) && + _PUchad_iso.isValid() && _PUchad_iso->contains( cand.id() ) ) { + chad_val = (*_chad_iso)[cand]; + nhad_val = (*_nhad_iso)[cand]; + pho_val = (*_ph_iso)[cand]; + puchad_val = (*_PUchad_iso)[cand]; + } else if ( _chad_iso.isValid() && _chad_iso->idSize() == 1 && + _nhad_iso.isValid() && _nhad_iso->idSize() == 1 && + _ph_iso.isValid() && _ph_iso->idSize() == 1 && + _PUchad_iso.isValid() && _PUchad_iso->idSize() == 1 && + cand.id() == edm::ProductID() ) { + // in case we have spoofed a ptr + //note this must be a 1:1 valuemap (only one product input) + chad_val = _chad_iso->begin()[cand.key()]; + nhad_val = _nhad_iso->begin()[cand.key()]; + pho_val = _ph_iso->begin()[cand.key()]; + puchad_val = _PUchad_iso->begin()[cand.key()]; + } else if ( _chad_iso.isValid() && _nhad_iso.isValid() && + _ph_iso.isValid() && _PUchad_iso.isValid() ){ // throw an exception + chad_val = (*_chad_iso)[cand]; + nhad_val = (*_nhad_iso)[cand]; + pho_val = (*_ph_iso)[cand]; + puchad_val = (*_PUchad_iso)[cand]; + } + + const float chad = _chad_iso.isValid() ? chad_val : pfIso.sumChargedHadronPt; + const float nhad = _nhad_iso.isValid() ? nhad_val : pfIso.sumNeutralHadronEt; + const float pho = _ph_iso.isValid() ? pho_val : pfIso.sumPhotonEt; + const float puchad = _PUchad_iso.isValid() ? puchad_val : pfIso.sumPUPt; float iso = chad + std::max(0.0f, nhad + pho - _deltaBetaConstant*puchad); if( _relativeIso ) iso /= cand->p4().pt(); return iso < isoCut; } + +double GsfEleDeltaBetaIsoCut::value(const reco::CandidatePtr& cand) const { + edm::Ptr ele(cand); + const reco::GsfElectron::PflowIsolationVariables& pfIso = + ele->pfIsolationVariables(); + float chad_val = 0.0; + float nhad_val = 0.0; + float pho_val = 0.0; + float puchad_val = 0.0; + + if( _chad_iso.isValid() && _chad_iso->contains( cand.id() ) && + _nhad_iso.isValid() && _nhad_iso->contains( cand.id() ) && + _ph_iso.isValid() && _ph_iso->contains( cand.id() ) && + _PUchad_iso.isValid() && _PUchad_iso->contains( cand.id() ) ) { + chad_val = (*_chad_iso)[cand]; + nhad_val = (*_nhad_iso)[cand]; + pho_val = (*_ph_iso)[cand]; + puchad_val = (*_PUchad_iso)[cand]; + } else if ( _chad_iso.isValid() && _chad_iso->idSize() == 1 && + _nhad_iso.isValid() && _nhad_iso->idSize() == 1 && + _ph_iso.isValid() && _ph_iso->idSize() == 1 && + _PUchad_iso.isValid() && _PUchad_iso->idSize() == 1 && + cand.id() == edm::ProductID() ) { + // in case we have spoofed a ptr + //note this must be a 1:1 valuemap (only one product input) + chad_val = _chad_iso->begin()[cand.key()]; + nhad_val = _nhad_iso->begin()[cand.key()]; + pho_val = _ph_iso->begin()[cand.key()]; + puchad_val = _PUchad_iso->begin()[cand.key()]; + } else if ( _chad_iso.isValid() && _nhad_iso.isValid() && + _ph_iso.isValid() && _PUchad_iso.isValid() ){ // throw an exception + chad_val = (*_chad_iso)[cand]; + nhad_val = (*_nhad_iso)[cand]; + pho_val = (*_ph_iso)[cand]; + puchad_val = (*_PUchad_iso)[cand]; + } + + const float chad = _chad_iso.isValid() ? chad_val : pfIso.sumChargedHadronPt; + const float nhad = _nhad_iso.isValid() ? nhad_val : pfIso.sumNeutralHadronEt; + const float pho = _ph_iso.isValid() ? pho_val : pfIso.sumPhotonEt; + const float puchad = _PUchad_iso.isValid() ? puchad_val : pfIso.sumPUPt; + float iso = chad + std::max(0.0f, nhad + pho - _deltaBetaConstant*puchad); + if( _relativeIso ) iso /= cand->p4().pt(); + return iso; +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDeltaBetaIsoCutStandalone.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDeltaBetaIsoCutStandalone.cc index 86f648518f36b..88748dd3a3b8a 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDeltaBetaIsoCutStandalone.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDeltaBetaIsoCutStandalone.cc @@ -11,6 +11,8 @@ class GsfEleDeltaBetaIsoCutStandalone : public CutApplicatorBase { result_type operator()(const reco::GsfElectronPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -57,3 +59,17 @@ operator()(const reco::GsfElectronPtr& cand) const{ if( _relativeIso ) iso /= cand->p4().pt(); return iso < isoCut; } + +double GsfEleDeltaBetaIsoCutStandalone:: +value(const reco::CandidatePtr& cand) const { + reco::GsfElectronPtr ele(cand); + const reco::GsfElectron::PflowIsolationVariables& pfIso = + ele->pfIsolationVariables(); + const float chad = pfIso.sumChargedHadronPt; + const float nhad = pfIso.sumNeutralHadronEt; + const float pho = pfIso.sumPhotonEt; + const float puchad = pfIso.sumPUPt; + float iso = chad + std::max(0.0f, nhad + pho - _deltaBetaConstant*puchad); + if( _relativeIso ) iso /= cand->p4().pt(); + return iso; +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDxyCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDxyCut.cc index 4b3aa66efa5bc..384ddb1817473 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDxyCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDxyCut.cc @@ -13,6 +13,8 @@ class GsfEleDxyCut : public CutApplicatorWithEventContentBase { void setConsumes(edm::ConsumesCollector&) override final; void getEventContent(const edm::EventBase&) override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -64,3 +66,12 @@ operator()(const reco::GsfElectronPtr& cand) const{ cand->gsfTrack()->dxy() ); return std::abs(dxy) < dxyCutValue; } + +double GsfEleDxyCut::value(const reco::CandidatePtr& cand) const { + reco::GsfElectronPtr ele(cand); + const reco::VertexCollection& vtxs = *_vtxs; + const double dxy = ( vtxs.size() ? + ele->gsfTrack()->dxy(vtxs[0].position()) : + ele->gsfTrack()->dxy() ); + return std::abs(dxy); +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDzCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDzCut.cc index 6570d05b78c6b..878ecb291437c 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDzCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleDzCut.cc @@ -13,6 +13,8 @@ class GsfEleDzCut : public CutApplicatorWithEventContentBase { void setConsumes(edm::ConsumesCollector&) override final; void getEventContent(const edm::EventBase&) override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -64,3 +66,12 @@ operator()(const reco::GsfElectronPtr& cand) const{ cand->gsfTrack()->dz() ); return std::abs(dz) < dzCutValue; } + +double GsfEleDzCut::value(const reco::CandidatePtr& cand) const { + reco::GsfElectronPtr ele(cand); + const reco::VertexCollection& vtxs = *_vtxs; + const double dz = ( vtxs.size() ? + ele->gsfTrack()->dz(vtxs[0].position()) : + ele->gsfTrack()->dz() ); + return std::abs(dz); +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleE2x5OverE5x5Cut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleE2x5OverE5x5Cut.cc index 4a3a94303c53d..0908a86409f5a 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleE2x5OverE5x5Cut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleE2x5OverE5x5Cut.cc @@ -11,6 +11,8 @@ class GsfEleE2x5OverE5x5Cut : public CutApplicatorBase { result_type operator()(const reco::GsfElectronPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -34,3 +36,10 @@ operator()(const reco::GsfElectronPtr& cand) const{ cand->e1x5() > minE1x5OverE5x5_(cand)*cand->e5x5(); } + +double GsfEleE2x5OverE5x5Cut::value(const reco::CandidatePtr& cand) const { + reco::GsfElectronPtr ele(cand); + // here return the ratio since it is a decent encoding of the value of + // both variables + return ele->e2x5Max()/ele->e1x5(); +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleEInverseMinusPInverseCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleEInverseMinusPInverseCut.cc index 281ffdc84807c..4038ab17c2d5e 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleEInverseMinusPInverseCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleEInverseMinusPInverseCut.cc @@ -12,6 +12,8 @@ class GsfEleEInverseMinusPInverseCut : public CutApplicatorBase { result_type operator()(const reco::GsfElectronPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -34,3 +36,11 @@ operator()(const reco::GsfElectronPtr& cand) const{ const float eSCoverP = cand->eSuperClusterOverP(); return std::abs(1.0 - eSCoverP)*ecal_energy_inverse < ooemoopCutValue; } + +double GsfEleEInverseMinusPInverseCut:: +value(const reco::CandidatePtr& cand) const { + reco::GsfElectronPtr ele(cand); + const float ecal_energy_inverse = 1.0/ele->ecalEnergy(); + const float eSCoverP = ele->eSuperClusterOverP(); + return std::abs(1.0 - eSCoverP)*ecal_energy_inverse; +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleEcalDrivenCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleEcalDrivenCut.cc index c6e7ea45a48ce..3d64726c43072 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleEcalDrivenCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleEcalDrivenCut.cc @@ -13,6 +13,8 @@ class GsfEleEcalDrivenCut : public CutApplicatorBase { result_type operator()(const reco::GsfElectronPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -35,3 +37,8 @@ operator()(const reco::GsfElectronPtr& cand) const{ else if(ecalDriven==0) return !cand->ecalDriven(); else return cand->ecalDriven(); } + +double GsfEleEcalDrivenCut::value(const reco::CandidatePtr& cand) const { + reco::GsfElectronPtr ele(cand); + return ele->ecalDriven(); +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleEffAreaPFIsoCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleEffAreaPFIsoCut.cc index 01b9bbc9b2ad3..34be64d4241a3 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleEffAreaPFIsoCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleEffAreaPFIsoCut.cc @@ -12,6 +12,8 @@ class GsfEleEffAreaPFIsoCut : public CutApplicatorWithEventContentBase { void setConsumes(edm::ConsumesCollector&) override final; void getEventContent(const edm::EventBase&) override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -91,3 +93,26 @@ operator()(const reco::GsfElectronPtr& cand) const{ // Scale by pT if the relative isolation is requested but avoid division by 0 return iso < isoCut*(_isRelativeIso ? cand->pt() : 1.); } + +double GsfEleEffAreaPFIsoCut::value(const reco::CandidatePtr& cand) const { + reco::GsfElectronPtr ele(cand); + // Establish the cut value + double absEta = std::abs(ele->superCluster()->eta()); + + // Compute the combined isolation with effective area correction + const reco::GsfElectron::PflowIsolationVariables& pfIso = + ele->pfIsolationVariables(); + const float chad = pfIso.sumChargedHadronPt; + const float nhad = pfIso.sumNeutralHadronEt; + const float pho = pfIso.sumPhotonEt; + float eA = _effectiveAreas.getEffectiveArea( absEta ); + float rho = (float)(*_rhoHandle); // std::max likes float arguments + float iso = chad + std::max(0.0f, nhad + pho - rho*eA); + + // Divide by pT if the relative isolation is requested + if( _isRelativeIso ) + iso /= ele->pt(); + + // Apply the cut and return the result + return iso; +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleEmHadD1IsoRhoCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleEmHadD1IsoRhoCut.cc index f9c9d2d8f5032..10662ac332552 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleEmHadD1IsoRhoCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleEmHadD1IsoRhoCut.cc @@ -15,6 +15,8 @@ class GsfEleEmHadD1IsoRhoCut : public CutApplicatorWithEventContentBase { void setConsumes(edm::ConsumesCollector&) override final; void getEventContent(const edm::EventBase&) override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -65,3 +67,8 @@ operator()(const reco::GsfElectronPtr& cand) const{ const float cutValue = et > slopeStart_(cand) ? slopeTerm_(cand)*(et-slopeStart_(cand)) + constTerm_(cand) : constTerm_(cand); return isolEmHadDepth1 < cutValue + rhoConstant_*rho; } + +double GsfEleEmHadD1IsoRhoCut::value(const reco::CandidatePtr& cand) const { + reco::GsfElectronPtr ele(cand); + return ele->dr03EcalRecHitSumEt() + ele->dr03HcalDepth1TowerSumEt(); +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleFull5x5E2x5OverE5x5Cut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleFull5x5E2x5OverE5x5Cut.cc index 73d209b1ebcb8..2fc0ab7231059 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleFull5x5E2x5OverE5x5Cut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleFull5x5E2x5OverE5x5Cut.cc @@ -9,6 +9,8 @@ class GsfEleFull5x5E2x5OverE5x5Cut : public CutApplicatorBase { result_type operator()(const reco::GsfElectronPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -43,3 +45,9 @@ operator()(const reco::GsfElectronPtr& cand) const{ return e1x5OverE5x5 > minE1x5OverE5x5Cut_(cand) || e2x5OverE5x5 > minE2x5OverE5x5Cut_(cand); } + +double GsfEleFull5x5E2x5OverE5x5Cut:: +value(const reco::CandidatePtr& cand) const { + reco::GsfElectronPtr ele(cand); + return ele->full5x5_e2x5Max()/ele->full5x5_e1x5(); +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleFull5x5SigmaIEtaIEtaCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleFull5x5SigmaIEtaIEtaCut.cc index 982c757704db6..c58de45353872 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleFull5x5SigmaIEtaIEtaCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleFull5x5SigmaIEtaIEtaCut.cc @@ -7,6 +7,8 @@ class GsfEleFull5x5SigmaIEtaIEtaCut : public CutApplicatorBase { result_type operator()(const reco::GsfElectronPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -42,3 +44,9 @@ operator()(const reco::GsfElectronPtr& cand) const{ // Apply the cut and return the result return cand->full5x5_sigmaIetaIeta() < full5x5SigmaIEtaIEtaCutValue; } + +double GsfEleFull5x5SigmaIEtaIEtaCut:: +value(const reco::CandidatePtr& cand) const { + reco::GsfElectronPtr ele(cand); + return ele->full5x5_sigmaIetaIeta(); +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleHadronicOverEMCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleHadronicOverEMCut.cc index bdae12ccdb5e2..5d8d765b749d2 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleHadronicOverEMCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleHadronicOverEMCut.cc @@ -12,6 +12,8 @@ class GsfEleHadronicOverEMCut : public CutApplicatorBase { result_type operator()(const reco::GsfElectronPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -32,3 +34,8 @@ operator()(const reco::GsfElectronPtr& cand) const { _hadronicOverEMCutValueEB : _hadronicOverEMCutValueEE ); return cand->hadronicOverEm() < hadronicOverEMCutValue; } + +double GsfEleHadronicOverEMCut::value(const reco::CandidatePtr& cand) const { + reco::GsfElectronPtr ele(cand); + return ele->hadronicOverEm(); +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleHadronicOverEMLinearCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleHadronicOverEMLinearCut.cc index 04f92d02e1135..62153634d0620 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleHadronicOverEMLinearCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleHadronicOverEMLinearCut.cc @@ -11,6 +11,8 @@ class GsfEleHadronicOverEMLinearCut : public CutApplicatorBase { result_type operator()(const reco::GsfElectronPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -35,3 +37,10 @@ operator()(const reco::GsfElectronPtr& cand) const { return cand->hadronicOverEm()*energy < cutValue; } + +double GsfEleHadronicOverEMLinearCut:: +value(const reco::CandidatePtr& cand) const { + reco::GsfElectronPtr ele(cand); + const float energy = ele->superCluster()->energy(); + return ele->hadronicOverEm()*energy; +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleMVACut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleMVACut.cc new file mode 100644 index 0000000000000..5d7dec9d13ac7 --- /dev/null +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleMVACut.cc @@ -0,0 +1,126 @@ +#include "PhysicsTools/SelectorUtils/interface/CutApplicatorWithEventContentBase.h" +#include "DataFormats/EgammaCandidates/interface/GsfElectron.h" + + +class GsfEleMVACut : public CutApplicatorWithEventContentBase { +public: + GsfEleMVACut(const edm::ParameterSet& c); + + result_type operator()(const reco::GsfElectronPtr&) const override final; + + void setConsumes(edm::ConsumesCollector&) override final; + void getEventContent(const edm::EventBase&) override final; + + double value(const reco::CandidatePtr& cand) const override final; + + CandidateType candidateType() const override final { + return ELECTRON; + } + +private: + + // Cut values + const std::vector _mvaCutValues; + + // Pre-computed MVA value map + edm::Handle > _mvaValueMap; + edm::Handle > _mvaCategoriesMap; + +}; + +DEFINE_EDM_PLUGIN(CutApplicatorFactory, + GsfEleMVACut, + "GsfEleMVACut"); + +GsfEleMVACut::GsfEleMVACut(const edm::ParameterSet& c) : + CutApplicatorWithEventContentBase(c), + _mvaCutValues(c.getParameter >("mvaCuts")) +{ + edm::InputTag mvaValTag = c.getParameter("mvaValueMapName"); + contentTags_.emplace("mvaVal",mvaValTag); + + edm::InputTag mvaCatTag = c.getParameter("mvaCategoriesMapName"); + contentTags_.emplace("mvaCat",mvaCatTag); + +} + +void GsfEleMVACut::setConsumes(edm::ConsumesCollector& cc) { + + auto mvaVal = + cc.consumes >(contentTags_["mvaVal"]); + contentTokens_.emplace("mvaVal",mvaVal); + + auto mvaCat = + cc.consumes >(contentTags_["mvaCat"]); + contentTokens_.emplace("mvaCat",mvaCat); +} + +void GsfEleMVACut::getEventContent(const edm::EventBase& ev) { + + ev.getByLabel(contentTags_["mvaVal"],_mvaValueMap); + ev.getByLabel(contentTags_["mvaCat"],_mvaCategoriesMap); +} + +CutApplicatorBase::result_type +GsfEleMVACut:: +operator()(const reco::GsfElectronPtr& cand) const{ + + // in case we are by-value + const std::string& val_name = contentTags_.find("mvaVal")->second.instance(); + const std::string& cat_name = contentTags_.find("mvaCat")->second.instance(); + edm::Ptr pat(cand); + float val = -1.0; + int cat = -1; + if( _mvaCategoriesMap.isValid() && _mvaCategoriesMap->contains( cand.id() ) && + _mvaValueMap.isValid() && _mvaValueMap->contains( cand.id() ) ) { + cat = (*_mvaCategoriesMap)[cand]; + val = (*_mvaValueMap)[cand]; + } else if ( _mvaCategoriesMap.isValid() && _mvaValueMap.isValid() && + _mvaCategoriesMap->idSize() == 1 && _mvaValueMap->idSize() == 1 && + cand.id() == edm::ProductID() ) { + // in case we have spoofed a ptr + //note this must be a 1:1 valuemap (only one product input) + cat = _mvaCategoriesMap->begin()[cand.key()]; + val = _mvaValueMap->begin()[cand.key()]; + } else if ( _mvaCategoriesMap.isValid() && _mvaValueMap.isValid() ){ // throw an exception + cat = (*_mvaCategoriesMap)[cand]; + val = (*_mvaValueMap)[cand]; + } + + + // Find the cut value + const int iCategory = _mvaCategoriesMap.isValid() ? cat : pat->userInt( cat_name ); + if( iCategory >= (int)(_mvaCutValues.size()) ) + throw cms::Exception(" Error in MVA categories: ") + << " found a particle with a category larger than max configured " << std::endl; + const float cutValue = _mvaCutValues[iCategory]; + + // Look up the MVA value for this particle + const float mvaValue = _mvaValueMap.isValid() ? val : pat->userFloat( val_name ); + + // Apply the cut and return the result + return mvaValue > cutValue; +} + +double GsfEleMVACut::value(const reco::CandidatePtr& cand) const { + + // in case we are by-value + const std::string& val_name =contentTags_.find("mvaVal")->second.instance(); + edm::Ptr pat(cand); + float val = 0.0; + if( _mvaCategoriesMap.isValid() && _mvaCategoriesMap->contains( cand.id() ) && + _mvaValueMap.isValid() && _mvaValueMap->contains( cand.id() ) ) { + val = (*_mvaValueMap)[cand]; + } else if ( _mvaCategoriesMap.isValid() && _mvaValueMap.isValid() && + _mvaCategoriesMap->idSize() == 1 && _mvaValueMap->idSize() == 1 && + cand.id() == edm::ProductID() ) { + // in case we have spoofed a ptr + //note this must be a 1:1 valuemap (only one product input) + val = _mvaValueMap->begin()[cand.key()]; + } else if ( _mvaCategoriesMap.isValid() && _mvaValueMap.isValid() ){ // throw an exception + val = (*_mvaValueMap)[cand]; + } + + const float mvaValue = _mvaValueMap.isValid() ? val : pat->userFloat( val_name ); + return mvaValue; +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleMissingHitsCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleMissingHitsCut.cc index c2a9693fb3829..eae4db2058b0e 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleMissingHitsCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleMissingHitsCut.cc @@ -13,6 +13,8 @@ class GsfEleMissingHitsCut : public CutApplicatorBase { result_type operator()(const reco::GsfElectronPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -38,3 +40,12 @@ operator()(const reco::GsfElectronPtr& cand) const{ cand->gsfTrack()->hitPattern().numberOfHits(missingHitType); return mHits <= maxMissingHits; } + +double GsfEleMissingHitsCut::value(const reco::CandidatePtr& cand) const { + constexpr reco::HitPattern::HitCategory missingHitType = + reco::HitPattern::MISSING_INNER_HITS; + reco::GsfElectronPtr ele(cand); + const unsigned mHits = + ele->gsfTrack()->hitPattern().numberOfHits(missingHitType); + return mHits; +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleSCEtaMultiRangeCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleSCEtaMultiRangeCut.cc index ea0906b299cb3..8d9c6b34407fb 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleSCEtaMultiRangeCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleSCEtaMultiRangeCut.cc @@ -17,6 +17,8 @@ class GsfEleSCEtaMultiRangeCut : public CutApplicatorBase { result_type operator()(const reco::GsfElectronPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -43,3 +45,9 @@ operator()(const reco::GsfElectronPtr& cand) const{ } return result; } + +double GsfEleSCEtaMultiRangeCut::value(const reco::CandidatePtr& cand) const { + reco::GsfElectronPtr ele(cand); + const reco::SuperClusterRef& scref = ele->superCluster(); + return ( _absEta ? std::abs(scref->eta()) : scref->eta() ); +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleSCMaxAbsEtaCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleSCMaxAbsEtaCut.cc index 72f49e6e10a52..9ce166f86c7ed 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleSCMaxAbsEtaCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleSCMaxAbsEtaCut.cc @@ -12,6 +12,12 @@ class GsfEleSCMaxAbsEtaCut : public CutApplicatorBase { return std::abs(scref->eta()) < _maxEta; } + double value(const reco::CandidatePtr& cand) const override final { + reco::GsfElectronPtr ele(cand); + const reco::SuperClusterRef& scref = ele->superCluster(); + return std::abs(scref->eta()); + } + CandidateType candidateType() const override final { return ELECTRON; } diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleSigmaIEtaIEtaCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleSigmaIEtaIEtaCut.cc index f80f85b5afa2c..89be69f952228 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleSigmaIEtaIEtaCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleSigmaIEtaIEtaCut.cc @@ -12,6 +12,8 @@ class GsfEleSigmaIEtaIEtaCut : public CutApplicatorBase { result_type operator()(const reco::GsfElectronPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -32,3 +34,9 @@ operator()(const reco::GsfElectronPtr& cand) const{ _sigmaIEtaIEtaCutValueEB : _sigmaIEtaIEtaCutValueEE ); return cand->sigmaIetaIeta() < sigmaIEtaIEtaCutValue; } + +double GsfEleSigmaIEtaIEtaCut:: +value(const reco::CandidatePtr& cand) const { + reco::GsfElectronPtr ele(cand); + return ele->sigmaIetaIeta(); +} diff --git a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleTrkPtIsoCut.cc b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleTrkPtIsoCut.cc index 5886fae82cd7f..7e850f2693deb 100644 --- a/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleTrkPtIsoCut.cc +++ b/RecoEgamma/ElectronIdentification/plugins/cuts/GsfEleTrkPtIsoCut.cc @@ -12,6 +12,8 @@ class GsfEleTrkPtIsoCut : public CutApplicatorBase { result_type operator()(const reco::GsfElectronPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return ELECTRON; } @@ -51,3 +53,9 @@ operator()(const reco::GsfElectronPtr& cand) const{ const float cutValue = et > slopeStart_(cand) ? slopeTerm_(cand)*(et-slopeStart_(cand)) + constTerm_(cand) : constTerm_(cand); return isolTrkPt < cutValue; } + +double GsfEleTrkPtIsoCut:: +value(const reco::CandidatePtr& cand) const { + reco::GsfElectronPtr ele(cand); + return ele->dr03TkSumPt(); +} diff --git a/RecoEgamma/ElectronIdentification/python/ElectronIDValueMapProducer_cfi.py b/RecoEgamma/ElectronIdentification/python/ElectronIDValueMapProducer_cfi.py index 8b6b32f82b50d..aff1439d4d704 100644 --- a/RecoEgamma/ElectronIdentification/python/ElectronIDValueMapProducer_cfi.py +++ b/RecoEgamma/ElectronIdentification/python/ElectronIDValueMapProducer_cfi.py @@ -15,5 +15,5 @@ ebReducedRecHitCollectionMiniAOD = cms.InputTag("reducedEgamma:reducedEBRecHits"), eeReducedRecHitCollectionMiniAOD = cms.InputTag("reducedEgamma:reducedEERecHits"), esReducedRecHitCollectionMiniAOD = cms.InputTag("reducedEgamma:reducedESRecHits"), - srcMiniAOD = cms.InputTag('slimmedElectrons'), + srcMiniAOD = cms.InputTag('slimmedElectrons',processName=cms.InputTag.skipCurrentProcess()), ) diff --git a/RecoEgamma/ElectronIdentification/python/ElectronMVAValueMapProducer_cfi.py b/RecoEgamma/ElectronIdentification/python/ElectronMVAValueMapProducer_cfi.py new file mode 100644 index 0000000000000..0d2b9ace07ee1 --- /dev/null +++ b/RecoEgamma/ElectronIdentification/python/ElectronMVAValueMapProducer_cfi.py @@ -0,0 +1,23 @@ +import FWCore.ParameterSet.Config as cms + +mvaConfigsForEleProducer = cms.VPSet( ) + +# Import and add all desired MVAs +from RecoEgamma.ElectronIdentification.Identification.mvaElectronID_PHYS14_PU20bx25_nonTrig_V1_cff import * +mvaConfigsForEleProducer.append( mvaEleID_PHYS14_PU20bx25_nonTrig_V1_producer_config ) + +electronMVAValueMapProducer = cms.EDProducer('ElectronMVAValueMapProducer', + # The module automatically detects AOD vs miniAOD, so we configure both + # + # AOD case + # + src = cms.InputTag('gedGsfElectrons'), + # + # miniAOD case + # + srcMiniAOD = cms.InputTag('slimmedElectrons',processName=cms.InputTag.skipCurrentProcess()), + # + # MVA configurations + # + mvaConfigurations = mvaConfigsForEleProducer + ) diff --git a/RecoEgamma/ElectronIdentification/python/Identification/heepElectronID_HEEPV60_cff.py b/RecoEgamma/ElectronIdentification/python/Identification/heepElectronID_HEEPV60_cff.py new file mode 100644 index 0000000000000..5e133865793da --- /dev/null +++ b/RecoEgamma/ElectronIdentification/python/Identification/heepElectronID_HEEPV60_cff.py @@ -0,0 +1,102 @@ +from PhysicsTools.SelectorUtils.centralIDRegistry import central_id_registry + +# Common functions and classes for ID definition are imported here: +from RecoEgamma.ElectronIdentification.Identification.heepElectronID_tools import * + +# +# The HEEP ID cuts V6.0 below are optimized IDs for PHYS14 Scenario PU 20, bx 25ns +# The cut values are taken from the twiki: +# https://twiki.cern.ch/twiki/bin/view/CMS/HEEPElectronIdentificationRun2#Selection_Cuts_HEEP_V5_1 +# (where they may not stay, if a newer version of cuts becomes available for these +# conditions) +# See also the presentation explaining these working points (this will not change): +# [ ... none available for this particular version ... ] + + +# The cut values for the Barrel and Endcap +idName = "heepElectronID-HEEPV60" +WP_HEEP60_EB = HEEP_WorkingPoint_V1( + idName=idName, + dEtaInSeedCut=0.004, + dPhiInCut=0.06, + full5x5SigmaIEtaIEtaCut=9999, + # Two constants for the GsfEleFull5x5E2x5OverE5x5Cut + minE1x5OverE5x5Cut=0.83, + minE2x5OverE5x5Cut=0.94, + # Three constants for the GsfEleHadronicOverEMLinearCut + # cut = constTerm if value < slopeStart + # cut = slopeTerm * (value - slopeStart) + constTerm if value >= slopeStart + hOverESlopeTerm=0.05, + hOverESlopeStart=0.00, + hOverEConstTerm=1.00, + # Three constants for the GsfEleTrkPtIsoCut: + # cut = constTerm if value < slopeStart + # cut = slopeTerm * (value - slopeStart) + constTerm if value >= slopeStart + trkIsoSlopeTerm=0.00, + trkIsoSlopeStart=0.00, + trkIsoConstTerm=5.00, + # Three constants for the GsfEleEmHadD1IsoRhoCut: + # cut = constTerm if value < slopeStart + # cut = slopeTerm * (value - slopeStart) + constTerm if value >= slopeStart + # Also for the same cut, the effective area for the rho correction of the isolation + ehIsoSlopeTerm=0.03, + ehIsoSlopeStart=0.00, + ehIsoConstTerm=2.00, + effAreaForEHIso=0.28, + # other cuts + dxyCut=0.02, + maxMissingHitsCut=1, + ecalDrivenCut=1 + ) + +WP_HEEP60_EE = HEEP_WorkingPoint_V1( + idName=idName, + dEtaInSeedCut=0.006, + dPhiInCut=0.06, + full5x5SigmaIEtaIEtaCut=0.03, + # Two constants for the GsfEleFull5x5E2x5OverE5x5Cut + minE1x5OverE5x5Cut=-1.0, + minE2x5OverE5x5Cut=-1.0, + # Three constants for the GsfEleHadronicOverEMLinearCut + # cut = constTerm if value < slopeStart + # cut = slopeTerm * (value - slopeStart) + constTerm if value >= slopeStart + hOverESlopeTerm=0.05, + hOverESlopeStart=0.00, + hOverEConstTerm=5, + # Three constants for the GsfEleTrkPtIsoCut: + # cut = constTerm if value < slopeStart + # cut = slopeTerm * (value - slopeStart) + constTerm if value >= slopeStart + trkIsoSlopeTerm=0.00, + trkIsoSlopeStart=0.00, + trkIsoConstTerm=5.00, + # Three constants for the GsfEleEmHadD1IsoRhoCut: + # cut = constTerm if value < slopeStart + # cut = slopeTerm * (value - slopeStart) + constTerm if value >= slopeStart + # Also for the same cut, the effective area for the rho correction of the isolation + ehIsoSlopeTerm=0.03, + ehIsoSlopeStart=50.0, + ehIsoConstTerm=2.50, + effAreaForEHIso=0.28, + # other cuts + dxyCut=0.05, + maxMissingHitsCut=1, + ecalDrivenCut=1 + + ) + +# +# Finally, set up VID configuration for all cuts +# +heepElectronID_HEEPV60 = configureHEEPElectronID_V60 ( WP_HEEP60_EB, WP_HEEP60_EE ) + +# +# The MD5 sum numbers below reflect the exact set of cut variables +# and values above. If anything changes, one has to +# 1) comment out the lines below about the registry, +# 2) run "calculateMD5 +# 3) update the MD5 sum strings below and uncomment the lines again. +# + +central_id_registry.register(heepElectronID_HEEPV60.idName,"df10ac7e3a9c22f63fa7936573beaafb") + +heepElectronID_HEEPV60.isPOGApproved = cms.untracked.bool(True) diff --git a/RecoEgamma/ElectronIdentification/python/Identification/heepElectronID_tools.py b/RecoEgamma/ElectronIdentification/python/Identification/heepElectronID_tools.py index 8aaf7c0f71975..afb49da39508b 100644 --- a/RecoEgamma/ElectronIdentification/python/Identification/heepElectronID_tools.py +++ b/RecoEgamma/ElectronIdentification/python/Identification/heepElectronID_tools.py @@ -255,3 +255,27 @@ def configureHEEPElectronID_V51(wpEB, wpEE): ) return parameterSet +def configureHEEPElectronID_V60(wpEB, wpEE): + """ + This function configures the full cms.PSet for a VID ID and returns it. + The inputs: two objects of the type HEEP_WorkingPoint_V1, one + containing the cuts for the Barrel (EB) and the other one for the Endcap (EE). + """ + parameterSet = cms.PSet( + idName = cms.string("heepElectronID-HEEPV60"), + cutFlow = cms.VPSet( + psetMinPtCut(), #0 + psetGsfEleSCEtaMultiRangeCut(), #1 + psetGsfEleDEtaInSeedCut(wpEB,wpEE), #2 + psetGsfEleDPhiInCut(wpEB,wpEE), #3 + psetGsfEleFull5x5SigmaIEtaIEtaCut(wpEB,wpEE), #4 + psetGsfEleFull5x5E2x5OverE5x5Cut(wpEB,wpEE), #5 + psetGsfEleHadronicOverEMLinearCut(wpEB,wpEE), #6 + psetGsfEleTrkPtIsoCut(wpEB,wpEE), #7 + psetGsfEleEmHadD1IsoRhoCut(wpEB,wpEE), #8 + psetGsfEleDxyCut(wpEB,wpEE), #9 + psetGsfEleMissingHitsCut(wpEB,wpEE), #10, + psetGsfEleEcalDrivenCut(wpEB,wpEE) #11 + ) + ) + return parameterSet diff --git a/RecoEgamma/ElectronIdentification/python/Identification/mvaElectronID_PHYS14_PU20bx25_nonTrig_V1_cff.py b/RecoEgamma/ElectronIdentification/python/Identification/mvaElectronID_PHYS14_PU20bx25_nonTrig_V1_cff.py new file mode 100644 index 0000000000000..e2ade1494784f --- /dev/null +++ b/RecoEgamma/ElectronIdentification/python/Identification/mvaElectronID_PHYS14_PU20bx25_nonTrig_V1_cff.py @@ -0,0 +1,104 @@ +from PhysicsTools.SelectorUtils.centralIDRegistry import central_id_registry + +import FWCore.ParameterSet.Config as cms + +# +# In this file we define the locations of the MVA weights, cuts on the MVA values +# for specific working points, and configure those cuts in VID +# + +# +# The following MVA is derived for PHYS14 MC samples for non-triggering electrons. +# See more documentation in this presentation: +# https://indico.cern.ch/event/367861/contribution/1/material/slides/0.pdf +# + +# This MVA implementation class name +mvaPhys14NonTrigClassName = "ElectronMVAEstimatorRun2Phys14NonTrig" + +# There are 6 categories in this MVA. They have to be configured in this strict order +# (cuts and weight files order): +# 0 EB1 (eta<0.8) pt 5-10 GeV +# 1 EB2 (eta>=0.8) pt 5-10 GeV +# 2 EE pt 5-10 GeV +# 3 EB1 (eta<0.8) pt 10-inf GeV +# 4 EB2 (eta>=0.8) pt 10-inf GeV +# 5 EE pt 10-inf GeV + +mvaPhys14NonTrigWeightFiles_V1 = cms.vstring( + "RecoEgamma/ElectronIdentification/data/PHYS14/EIDmva_EB1_5_oldscenario2phys14_BDT.weights.xml", + "RecoEgamma/ElectronIdentification/data/PHYS14/EIDmva_EB2_5_oldscenario2phys14_BDT.weights.xml", + "RecoEgamma/ElectronIdentification/data/PHYS14/EIDmva_EE_5_oldscenario2phys14_BDT.weights.xml", + "RecoEgamma/ElectronIdentification/data/PHYS14/EIDmva_EB1_10_oldscenario2phys14_BDT.weights.xml", + "RecoEgamma/ElectronIdentification/data/PHYS14/EIDmva_EB2_10_oldscenario2phys14_BDT.weights.xml", + "RecoEgamma/ElectronIdentification/data/PHYS14/EIDmva_EE_10_oldscenario2phys14_BDT.weights.xml" + ) + +# Load some common definitions for MVA machinery +from RecoEgamma.ElectronIdentification.Identification.mvaElectronID_tools import * + +# The locatoins of value maps with the actual MVA values and categories +# for all particles. +# The names for the maps are ":Values" +# and ":Categories" +mvaProducerModuleLabel = "electronMVAValueMapProducer" +mvaValueMapName = mvaProducerModuleLabel + ":" + mvaPhys14NonTrigClassName + "Values" +mvaCategoriesMapName = mvaProducerModuleLabel + ":" + mvaPhys14NonTrigClassName + "Categories" + +# The working point for this MVA that is expected to have about 80% signal +# efficiency on in each category +idName = "mvaEleID-PHYS14-PU20bx25-nonTrig-V1-wp80" +MVA_WP80 = EleMVA_6Categories_WP( + idName, + mvaValueMapName, # map with MVA values for all particles + mvaCategoriesMapName, # map with category index for all particles + cutCategory0 = -0.253, # EB1 low pt + cutCategory1 = 0.081, # EB2 low pt + cutCategory2 = -0.081, # EE low pt + cutCategory3 = 0.965, # EB1 + cutCategory4 = 0.917, # EB2 + cutCategory5 = 0.683 # EE + ) + +# The working point for this MVA that is expected to have about 90% signal +# efficiency in each category +idName = "mvaEleID-PHYS14-PU20bx25-nonTrig-V1-wp90" +MVA_WP90 = EleMVA_6Categories_WP( + idName = idName, + mvaValueMapName = mvaValueMapName, # map with MVA values for all particles + mvaCategoriesMapName = mvaCategoriesMapName, # map with category index for all particles + cutCategory0 = -0.483, # EB1 low pt + cutCategory1 = -0.267, # EB2 low pt + cutCategory2 = -0.323, # EE low pt + cutCategory3 = 0.933, # EB1 + cutCategory4 = 0.825, # EB2 + cutCategory5 = 0.337 # EE + ) + +# +# Finally, set up VID configuration for all cuts +# + +# Create the PSet that will be fed to the MVA value map producer +mvaEleID_PHYS14_PU20bx25_nonTrig_V1_producer_config = cms.PSet( + mvaName = cms.string(mvaPhys14NonTrigClassName), + weightFileNames = mvaPhys14NonTrigWeightFiles_V1 + ) +# Create the VPset's for VID cuts +mvaEleID_PHYS14_PU20bx25_nonTrig_V1_wp80 = configureVIDMVAEleID_V1( MVA_WP80 ) +mvaEleID_PHYS14_PU20bx25_nonTrig_V1_wp90 = configureVIDMVAEleID_V1( MVA_WP90 ) + +# The MD5 sum numbers below reflect the exact set of cut variables +# and values above. If anything changes, one has to +# 1) comment out the lines below about the registry, +# 2) run "calculateMD5 +# 3) update the MD5 sum strings below and uncomment the lines again. +# + +central_id_registry.register( mvaEleID_PHYS14_PU20bx25_nonTrig_V1_wp80.idName, + '8b587a6315d6808df7af9d3471d22a20') +central_id_registry.register( mvaEleID_PHYS14_PU20bx25_nonTrig_V1_wp90.idName, + 'a01428d36d3d0e6b1f89ab772aa606a1') + +mvaEleID_PHYS14_PU20bx25_nonTrig_V1_wp80.isPOGApproved = cms.untracked.bool(True) +mvaEleID_PHYS14_PU20bx25_nonTrig_V1_wp90.isPOGApproved = cms.untracked.bool(True) diff --git a/RecoEgamma/ElectronIdentification/python/Identification/mvaElectronID_tools.py b/RecoEgamma/ElectronIdentification/python/Identification/mvaElectronID_tools.py new file mode 100644 index 0000000000000..1fb4d555010eb --- /dev/null +++ b/RecoEgamma/ElectronIdentification/python/Identification/mvaElectronID_tools.py @@ -0,0 +1,62 @@ +import FWCore.ParameterSet.Config as cms + +# ======================================================= +# Define simple containers for MVA cut values and related +# ======================================================= + +class EleMVA_6Categories_WP: + """ + This is a container class to hold MVA cut values for a 6-category MVA + as well as the names of the value maps that contain the MVA values computed + for all particles in a producer upstream. + """ + def __init__(self, + idName, + mvaValueMapName, + mvaCategoriesMapName, + cutCategory0, + cutCategory1, + cutCategory2, + cutCategory3, + cutCategory4, + cutCategory5 + ): + self.idName = idName + self.mvaValueMapName = mvaValueMapName + self.mvaCategoriesMapName = mvaCategoriesMapName + self.cutCategory0 = cutCategory0 + self.cutCategory1 = cutCategory1 + self.cutCategory2 = cutCategory2 + self.cutCategory3 = cutCategory3 + self.cutCategory4 = cutCategory4 + self.cutCategory5 = cutCategory5 + + def getCutValues(self): + return [self.cutCategory0, self.cutCategory1, self.cutCategory2, + self.cutCategory3, self.cutCategory4, self.cutCategory5] + +# ============================================================== +# Define the complete MVA cut sets +# ============================================================== + +def configureVIDMVAEleID_V1( mvaWP ): + """ + This function configures the full cms.PSet for a VID ID and returns it. + The inputs: an object of the class EleMVA_6Categories_WP or similar + that contains all necessary parameters for this MVA. + """ + parameterSet = cms.PSet( + # + idName = cms.string( mvaWP.idName ), + cutFlow = cms.VPSet( + cms.PSet( cutName = cms.string("GsfEleMVACut"), + mvaCuts = cms.vdouble( mvaWP.getCutValues() ), + mvaValueMapName = cms.InputTag( mvaWP.mvaValueMapName ), + mvaCategoriesMapName =cms.InputTag( mvaWP.mvaCategoriesMapName ), + needsAdditionalProducts = cms.bool(True), + isIgnored = cms.bool(False) + ) + ) + ) + # + return parameterSet diff --git a/RecoEgamma/ElectronIdentification/python/egmGsfElectronIDs_cff.py b/RecoEgamma/ElectronIdentification/python/egmGsfElectronIDs_cff.py index 2a285c6554b24..c4333210ff431 100644 --- a/RecoEgamma/ElectronIdentification/python/egmGsfElectronIDs_cff.py +++ b/RecoEgamma/ElectronIdentification/python/egmGsfElectronIDs_cff.py @@ -12,4 +12,7 @@ # #from RecoEgamma.ElectronIdentification.ElectronIDValueMapProducer_cfi import * -egmGsfElectronIDSequence = cms.Sequence(egmGsfElectronIDs) +# Load the producer for MVA IDs. Make sure it is also added to the sequence! +from RecoEgamma.ElectronIdentification.ElectronMVAValueMapProducer_cfi import * + +egmGsfElectronIDSequence = cms.Sequence( electronMVAValueMapProducer * egmGsfElectronIDs) diff --git a/RecoEgamma/PhotonIdentification/interface/PhotonMVAEstimatorRun2Phys14NonTrig.h b/RecoEgamma/PhotonIdentification/interface/PhotonMVAEstimatorRun2Phys14NonTrig.h new file mode 100644 index 0000000000000..40db447e91910 --- /dev/null +++ b/RecoEgamma/PhotonIdentification/interface/PhotonMVAEstimatorRun2Phys14NonTrig.h @@ -0,0 +1,148 @@ +#ifndef RecoEgamma_PhotonIdentification_PhotonMVAEstimatorRun2Phys14NonTrig_H +#define RecoEgamma_PhotonIdentification_PhotonMVAEstimatorRun2Phys14NonTrig_H + +#include "FWCore/Framework/interface/ConsumesCollector.h" + +#include "DataFormats/Common/interface/ValueMap.h" + +#include "RecoEgamma/EgammaTools/interface/AnyMVAEstimatorRun2Base.h" + +#include "DataFormats/EgammaCandidates/interface/Photon.h" + +#include +#include +#include +#include "TMVA/Factory.h" +#include "TMVA/Tools.h" +#include "TMVA/Reader.h" + +class PhotonMVAEstimatorRun2Phys14NonTrig : public AnyMVAEstimatorRun2Base{ + + public: + + // Define here the number and the meaning of the categories + // for this specific MVA + const int nCategories = 2; + enum mvaCategories { + UNDEFINED = -1, + CAT_EB = 0, + CAT_EE = 1 + }; + + // Define the struct that contains all necessary for MVA variables + struct AllVariables { + + float varPhi; + float varR9; + float varSieie; + float varSieip; + float varE1x3overE5x5; + float varE2x2overE5x5; + float varE2x5overE5x5; + float varSCEta; + float varRawE; + float varSCEtaWidth; + float varSCPhiWidth; + float varESEnOverRawE; // for endcap MVA only + float varESEffSigmaRR; // for endcap MVA only + // Pile-up + float varRho; + // Isolations + float varPhoIsoRaw; + float varChIsoRaw; + float varWorstChRaw; + // Spectators + float varPt; + float varEta; + + }; + + // Constructor and destructor + PhotonMVAEstimatorRun2Phys14NonTrig(const edm::ParameterSet& conf); + ~PhotonMVAEstimatorRun2Phys14NonTrig(); + + // Calculation of the MVA value + float mvaValue( const edm::Ptr& particle); + + // Utility functions + TMVA::Reader *createSingleReader(const int iCategory, const edm::FileInPath &weightFile); + + inline int getNCategories(){return nCategories;}; + bool isEndcapCategory( int category ); + const inline std::string getName(){return name_;}; + + // Functions that should work on both pat and reco electrons + // (use the fact that pat::Electron inherits from reco::GsfElectron) + void fillMVAVariables(const edm::Ptr& particle); + int findCategory( const edm::Ptr& particle); + // The function below ensures that the variables passed to MVA are + // within reasonable bounds + void constrainMVAVariables(); + + // Call this function once after the constructor to declare + // the needed event content pieces to the framework + void setConsumes(edm::ConsumesCollector&&) override; + // Call this function once per event to retrieve all needed + // event content pices + void getEventContent(const edm::Event& iEvent) override; + + + private: + + // MVA name. This is a unique name for this MVA implementation. + // It will be used as part of ValueMap names. + // For simplicity, keep it set to the class name. + const std::string name_ = "PhotonMVAEstimatorRun2Phys14NonTrig"; + + // Data members + std::vector< std::unique_ptr > _tmvaReaders; + + // All variables needed by this MVA + std::string _MethodName; + AllVariables _allMVAVars; + + // This MVA implementation relies on several ValueMap objects + // produced upstream. + + // + // Declare all tokens that will be needed to retrieve misc + // data from the event content required by this MVA + // + edm::EDGetTokenT > _full5x5SigmaIEtaIEtaMapToken; + edm::EDGetTokenT > _full5x5SigmaIEtaIPhiMapToken; + edm::EDGetTokenT > _full5x5E1x3MapToken; + edm::EDGetTokenT > _full5x5E2x2MapToken; + edm::EDGetTokenT > _full5x5E2x5MaxMapToken; + edm::EDGetTokenT > _full5x5E5x5MapToken; + edm::EDGetTokenT > _esEffSigmaRRMapToken; + // + edm::EDGetTokenT > _phoChargedIsolationToken; + edm::EDGetTokenT > _phoPhotonIsolationToken; + edm::EDGetTokenT > _phoWorstChargedIsolationToken; + + // + // Declare all value maps corresponding to the above tokens + // + edm::Handle > _full5x5SigmaIEtaIEtaMap; + edm::Handle > _full5x5SigmaIEtaIPhiMap; + edm::Handle > _full5x5E1x3Map; + edm::Handle > _full5x5E2x2Map; + edm::Handle > _full5x5E2x5MaxMap; + edm::Handle > _full5x5E5x5Map; + edm::Handle > _esEffSigmaRRMap; + // + edm::Handle > _phoChargedIsolationMap; + edm::Handle > _phoPhotonIsolationMap; + edm::Handle > _phoWorstChargedIsolationMap; + + // Rho will be pulled from the event content + edm::EDGetTokenT _rhoToken; + edm::Handle _rho; + +}; + +DEFINE_EDM_PLUGIN(AnyMVAEstimatorRun2Factory, + PhotonMVAEstimatorRun2Phys14NonTrig, + "PhotonMVAEstimatorRun2Phys14NonTrig"); + +#endif diff --git a/RecoEgamma/PhotonIdentification/interface/PhotonMVAEstimatorRun2Spring15NonTrig.h b/RecoEgamma/PhotonIdentification/interface/PhotonMVAEstimatorRun2Spring15NonTrig.h new file mode 100644 index 0000000000000..9b175445a0d4f --- /dev/null +++ b/RecoEgamma/PhotonIdentification/interface/PhotonMVAEstimatorRun2Spring15NonTrig.h @@ -0,0 +1,148 @@ +#ifndef RecoEgamma_PhotonIdentification_PhotonMVAEstimatorRun2Spring15NonTrig_H +#define RecoEgamma_PhotonIdentification_PhotonMVAEstimatorRun2Spring15NonTrig_H + +#include "FWCore/Framework/interface/ConsumesCollector.h" + +#include "DataFormats/Common/interface/ValueMap.h" + +#include "RecoEgamma/EgammaTools/interface/AnyMVAEstimatorRun2Base.h" + +#include "DataFormats/EgammaCandidates/interface/Photon.h" + +#include +#include +#include +#include "TMVA/Factory.h" +#include "TMVA/Tools.h" +#include "TMVA/Reader.h" + +class PhotonMVAEstimatorRun2Spring15NonTrig : public AnyMVAEstimatorRun2Base{ + + public: + + // Define here the number and the meaning of the categories + // for this specific MVA + const int nCategories = 2; + enum mvaCategories { + UNDEFINED = -1, + CAT_EB = 0, + CAT_EE = 1 + }; + + // Define the struct that contains all necessary for MVA variables + struct AllVariables { + + float varPhi; + float varR9; + float varSieie; + float varSieip; + float varE1x3overE5x5; + float varE2x2overE5x5; + float varE2x5overE5x5; + float varSCEta; + float varRawE; + float varSCEtaWidth; + float varSCPhiWidth; + float varESEnOverRawE; // for endcap MVA only + float varESEffSigmaRR; // for endcap MVA only + // Pile-up + float varRho; + // Isolations + float varPhoIsoRaw; + float varChIsoRaw; + float varWorstChRaw; + // Spectators + float varPt; + float varEta; + + }; + + // Constructor and destructor + PhotonMVAEstimatorRun2Spring15NonTrig(const edm::ParameterSet& conf); + ~PhotonMVAEstimatorRun2Spring15NonTrig(); + + // Calculation of the MVA value + float mvaValue( const edm::Ptr& particle); + + // Utility functions + TMVA::Reader *createSingleReader(const int iCategory, const edm::FileInPath &weightFile); + + inline int getNCategories(){return nCategories;}; + bool isEndcapCategory( int category ); + const inline std::string getName(){return name_;}; + + // Functions that should work on both pat and reco electrons + // (use the fact that pat::Electron inherits from reco::GsfElectron) + void fillMVAVariables(const edm::Ptr& particle); + int findCategory( const edm::Ptr& particle); + // The function below ensures that the variables passed to MVA are + // within reasonable bounds + void constrainMVAVariables(); + + // Call this function once after the constructor to declare + // the needed event content pieces to the framework + void setConsumes(edm::ConsumesCollector&&) override; + // Call this function once per event to retrieve all needed + // event content pices + void getEventContent(const edm::Event& iEvent) override; + + + private: + + // MVA name. This is a unique name for this MVA implementation. + // It will be used as part of ValueMap names. + // For simplicity, keep it set to the class name. + const std::string name_ = "PhotonMVAEstimatorRun2Spring15NonTrig"; + + // Data members + std::vector< std::unique_ptr > _tmvaReaders; + + // All variables needed by this MVA + std::string _MethodName; + AllVariables _allMVAVars; + + // This MVA implementation relies on several ValueMap objects + // produced upstream. + + // + // Declare all tokens that will be needed to retrieve misc + // data from the event content required by this MVA + // + edm::EDGetTokenT > _full5x5SigmaIEtaIEtaMapToken; + edm::EDGetTokenT > _full5x5SigmaIEtaIPhiMapToken; + edm::EDGetTokenT > _full5x5E1x3MapToken; + edm::EDGetTokenT > _full5x5E2x2MapToken; + edm::EDGetTokenT > _full5x5E2x5MaxMapToken; + edm::EDGetTokenT > _full5x5E5x5MapToken; + edm::EDGetTokenT > _esEffSigmaRRMapToken; + // + edm::EDGetTokenT > _phoChargedIsolationToken; + edm::EDGetTokenT > _phoPhotonIsolationToken; + edm::EDGetTokenT > _phoWorstChargedIsolationToken; + + // + // Declare all value maps corresponding to the above tokens + // + edm::Handle > _full5x5SigmaIEtaIEtaMap; + edm::Handle > _full5x5SigmaIEtaIPhiMap; + edm::Handle > _full5x5E1x3Map; + edm::Handle > _full5x5E2x2Map; + edm::Handle > _full5x5E2x5MaxMap; + edm::Handle > _full5x5E5x5Map; + edm::Handle > _esEffSigmaRRMap; + // + edm::Handle > _phoChargedIsolationMap; + edm::Handle > _phoPhotonIsolationMap; + edm::Handle > _phoWorstChargedIsolationMap; + + // Rho will be pulled from the event content + edm::EDGetTokenT _rhoToken; + edm::Handle _rho; + +}; + +DEFINE_EDM_PLUGIN(AnyMVAEstimatorRun2Factory, + PhotonMVAEstimatorRun2Spring15NonTrig, + "PhotonMVAEstimatorRun2Spring15NonTrig"); + +#endif diff --git a/RecoEgamma/PhotonIdentification/plugins/PhotonMVAEstimatorRun2Phys14NonTrig.cc b/RecoEgamma/PhotonIdentification/plugins/PhotonMVAEstimatorRun2Phys14NonTrig.cc new file mode 100644 index 0000000000000..e3d7296d59e9f --- /dev/null +++ b/RecoEgamma/PhotonIdentification/plugins/PhotonMVAEstimatorRun2Phys14NonTrig.cc @@ -0,0 +1,304 @@ +#include "RecoEgamma/PhotonIdentification/interface/PhotonMVAEstimatorRun2Phys14NonTrig.h" + +#include "FWCore/ParameterSet/interface/FileInPath.h" + +PhotonMVAEstimatorRun2Phys14NonTrig::PhotonMVAEstimatorRun2Phys14NonTrig(const edm::ParameterSet& conf): + AnyMVAEstimatorRun2Base(conf) +{ + + // + // Construct the MVA estimators + // + const std::vector weightFileNames + = conf.getParameter >("weightFileNames"); + + if( (int)(weightFileNames.size()) != nCategories ) + throw cms::Exception("MVA config failure: ") + << "wrong number of weightfiles" << std::endl; + + _tmvaReaders.clear(); + // The method name is just a key to retrieve this method later, it is not + // a control parameter for a reader (the full definition of the MVA type and + // everything else comes from the xml weight files). + _MethodName = "BDTG method"; + // Create a TMVA reader object for each category + for(int i=0; i + ( createSingleReader(i, weightFile ) ) ); + + } + +} + +PhotonMVAEstimatorRun2Phys14NonTrig:: +~PhotonMVAEstimatorRun2Phys14NonTrig(){ + + _tmvaReaders.clear(); +} + +void PhotonMVAEstimatorRun2Phys14NonTrig::setConsumes(edm::ConsumesCollector&& cc){ + + // All tokens for event content needed by this MVA + // Cluster shapes + _full5x5SigmaIEtaIEtaMapToken = cc.consumes > + (_conf.getParameter("full5x5SigmaIEtaIEtaMap")); + + _full5x5SigmaIEtaIPhiMapToken = cc.consumes > + (_conf.getParameter("full5x5SigmaIEtaIPhiMap")); + + _full5x5E1x3MapToken = cc.consumes > + (_conf.getParameter("full5x5E1x3Map")); + + _full5x5E2x2MapToken = cc.consumes > + (_conf.getParameter("full5x5E2x2Map")); + + _full5x5E2x5MaxMapToken = cc.consumes > + (_conf.getParameter("full5x5E2x5MaxMap")); + + _full5x5E5x5MapToken = cc.consumes > + (_conf.getParameter("full5x5E5x5Map")); + + _esEffSigmaRRMapToken = cc.consumes > + (_conf.getParameter("esEffSigmaRRMap")); + + // Isolations + _phoChargedIsolationToken = cc.consumes > + (_conf.getParameter("phoChargedIsolation")); + + _phoPhotonIsolationToken = cc.consumes > + (_conf.getParameter("phoPhotonIsolation")); + + _phoWorstChargedIsolationToken = cc.consumes > + (_conf.getParameter("phoWorstChargedIsolation")); + + // Pileup + _rhoToken = cc.consumes (_conf.getParameter("rho")); + +} + +void PhotonMVAEstimatorRun2Phys14NonTrig::getEventContent(const edm::Event& iEvent){ + + // Get the full5x5 and ES maps + iEvent.getByToken(_full5x5SigmaIEtaIEtaMapToken, _full5x5SigmaIEtaIEtaMap); + iEvent.getByToken(_full5x5SigmaIEtaIPhiMapToken, _full5x5SigmaIEtaIPhiMap); + iEvent.getByToken(_full5x5E1x3MapToken, _full5x5E1x3Map); + iEvent.getByToken(_full5x5E2x2MapToken, _full5x5E2x2Map); + iEvent.getByToken(_full5x5E2x5MaxMapToken, _full5x5E2x5MaxMap); + iEvent.getByToken(_full5x5E5x5MapToken, _full5x5E5x5Map); + iEvent.getByToken(_esEffSigmaRRMapToken, _esEffSigmaRRMap); + + // Get the isolation maps + iEvent.getByToken(_phoChargedIsolationToken, _phoChargedIsolationMap); + iEvent.getByToken(_phoPhotonIsolationToken, _phoPhotonIsolationMap); + iEvent.getByToken(_phoWorstChargedIsolationToken, _phoWorstChargedIsolationMap); + + // Get rho + iEvent.getByToken(_rhoToken,_rho); + + // Make sure everything is retrieved successfully + if(! (_full5x5SigmaIEtaIEtaMap.isValid() + && _full5x5SigmaIEtaIPhiMap.isValid() + && _full5x5E1x3Map.isValid() + && _full5x5E2x2Map.isValid() + && _full5x5E2x5MaxMap.isValid() + && _full5x5E5x5Map.isValid() + && _esEffSigmaRRMap.isValid() + && _phoChargedIsolationMap.isValid() + && _phoPhotonIsolationMap.isValid() + && _phoWorstChargedIsolationMap.isValid() + && _rho.isValid() ) ) + throw cms::Exception("MVA failure: ") + << "Failed to retrieve event content needed for this MVA" + << std::endl + << "Check python MVA configuration file and make sure all needed" + << std::endl + << "producers are running upstream" << std::endl; +} + + +float PhotonMVAEstimatorRun2Phys14NonTrig:: +mvaValue( const edm::Ptr& particle){ + + int iCategory = findCategory( particle ); + fillMVAVariables( particle ); + constrainMVAVariables(); + float result = _tmvaReaders.at(iCategory)->EvaluateMVA(_MethodName); + + // DEBUG + const bool debug = false; + if( debug ){ + printf("Printout of the photon variable inputs for MVA:\n"); + printf(" varPhi_ %f\n", _allMVAVars.varPhi ); + printf(" varR9_ %f\n", _allMVAVars.varR9 ); + printf(" varSieie_ %f\n", _allMVAVars.varSieie ); + printf(" varSieip_ %f\n", _allMVAVars.varSieip ); + printf(" varE1x3overE5x5_ %f\n", _allMVAVars.varE1x3overE5x5); + printf(" varE2x2overE5x5_ %f\n", _allMVAVars.varE2x2overE5x5); + printf(" varE2x5overE5x5_ %f\n", _allMVAVars.varE2x5overE5x5); + printf(" varSCEta_ %f\n", _allMVAVars.varSCEta ); + printf(" varRawE_ %f\n", _allMVAVars.varRawE ); + printf(" varSCEtaWidth_ %f\n", _allMVAVars.varSCEtaWidth ); + printf(" varSCPhiWidth_ %f\n", _allMVAVars.varSCPhiWidth ); + printf(" varRho_ %f\n", _allMVAVars.varRho ); + printf(" varPhoIsoRaw_ %f\n", _allMVAVars.varPhoIsoRaw ); + printf(" varChIsoRaw_ %f\n", _allMVAVars.varChIsoRaw ); + printf(" varWorstChRaw_ %f\n", _allMVAVars.varWorstChRaw ); + printf(" varESEnOverRawE_ %f\n", _allMVAVars.varESEnOverRawE); // for endcap MVA only + printf(" varESEffSigmaRR_ %f\n", _allMVAVars.varESEffSigmaRR); // for endcap MVA only + // The spectators + printf(" varPt_ %f\n", _allMVAVars.varPt ); + printf(" varEta_ %f\n", _allMVAVars.varEta ); + } + + return result; +} + +int PhotonMVAEstimatorRun2Phys14NonTrig::findCategory( const edm::Ptr& particle){ + + // Try to cast the particle into a reco particle. + // This should work for both reco and pat. + const edm::Ptr phoRecoPtr = ( edm::Ptr )particle; + if( phoRecoPtr.isNull() ) + throw cms::Exception("MVA failure: ") + << " given particle is expected to be reco::Photon or pat::Photon," << std::endl + << " but appears to be neither" << std::endl; + + float eta = phoRecoPtr->superCluster()->eta(); + + // + // Determine the category + // + int iCategory = UNDEFINED; + const float ebeeSplit = 1.479; // division between barrel and endcap + + if ( std::abs(eta) < ebeeSplit) + iCategory = CAT_EB; + + if (std::abs(eta) >= ebeeSplit) + iCategory = CAT_EE; + + return iCategory; +} + +bool PhotonMVAEstimatorRun2Phys14NonTrig:: +isEndcapCategory(int category ){ + + // For this specific MVA the function is trivial, but kept for possible + // future evolution to an MVA with more categories in eta + bool isEndcap = false; + if( category == CAT_EE ) + isEndcap = true; + + return isEndcap; +} + + +TMVA::Reader *PhotonMVAEstimatorRun2Phys14NonTrig:: +createSingleReader(const int iCategory, const edm::FileInPath &weightFile){ + + // + // Create the reader + // + TMVA::Reader *tmpTMVAReader = new TMVA::Reader( "!Color:Silent:Error" ); + + // + // Configure all variables and spectators. Note: the order and names + // must match what is found in the xml weights file! + // + + tmpTMVAReader->AddVariable("recoPhi" , &_allMVAVars.varPhi); + tmpTMVAReader->AddVariable("r9" , &_allMVAVars.varR9); + tmpTMVAReader->AddVariable("sieie_2012", &_allMVAVars.varSieie); + tmpTMVAReader->AddVariable("sieip_2012", &_allMVAVars.varSieip); + tmpTMVAReader->AddVariable("e1x3_2012/e5x5_2012" , &_allMVAVars.varE1x3overE5x5); + tmpTMVAReader->AddVariable("e2x2_2012/e5x5_2012" , &_allMVAVars.varE2x2overE5x5); + tmpTMVAReader->AddVariable("e2x5_2012/e5x5_2012" , &_allMVAVars.varE2x5overE5x5); + tmpTMVAReader->AddVariable("recoSCEta" , &_allMVAVars.varSCEta); + tmpTMVAReader->AddVariable("rawE" , &_allMVAVars.varRawE); + tmpTMVAReader->AddVariable("scEtaWidth", &_allMVAVars.varSCEtaWidth); + tmpTMVAReader->AddVariable("scPhiWidth", &_allMVAVars.varSCPhiWidth); + + // Endcap only variables + if( isEndcapCategory(iCategory) ){ + tmpTMVAReader->AddVariable("esEn/rawE" , &_allMVAVars.varESEnOverRawE); + tmpTMVAReader->AddVariable("esRR" , &_allMVAVars.varESEffSigmaRR); + } + + // Pileup + tmpTMVAReader->AddVariable("rho" , &_allMVAVars.varRho); + + // Isolations + tmpTMVAReader->AddVariable("phoIsoRaw" , &_allMVAVars.varPhoIsoRaw); + tmpTMVAReader->AddVariable("chIsoRaw" , &_allMVAVars.varChIsoRaw); + tmpTMVAReader->AddVariable("chWorstRaw", &_allMVAVars.varWorstChRaw); + + // Spectators + tmpTMVAReader->AddSpectator("recoPt" , &_allMVAVars.varPt); + tmpTMVAReader->AddSpectator("recoEta", &_allMVAVars.varEta); + + // + // Book the method and set up the weights file + // + tmpTMVAReader->BookMVA(_MethodName , weightFile.fullPath() ); + + return tmpTMVAReader; +} + +// A function that should work on both pat and reco objects +void PhotonMVAEstimatorRun2Phys14NonTrig::fillMVAVariables(const edm::Ptr& particle){ + + // Try to cast the particle into a reco particle. + // This should work for both reco and pat. + const edm::Ptr phoRecoPtr = ( edm::Ptr )particle; + if( phoRecoPtr.isNull() ) + throw cms::Exception("MVA failure: ") + << " given particle is expected to be reco::Photon or pat::Photon," << std::endl + << " but appears to be neither" << std::endl; + + // Both pat and reco particles have exactly the same accessors. + auto superCluster = phoRecoPtr->superCluster(); + // Full 5x5 cluster shapes. We could take some of this directly from + // the photon object, but some of these are not available. + float e1x3 = (*_full5x5E1x3Map )[ phoRecoPtr ]; + float e2x2 = (*_full5x5E2x2Map )[ phoRecoPtr ]; + float e2x5 = (*_full5x5E2x5MaxMap)[ phoRecoPtr ]; + float e5x5 = (*_full5x5E5x5Map )[ phoRecoPtr ]; + + _allMVAVars.varPhi = phoRecoPtr->phi(); + _allMVAVars.varR9 = phoRecoPtr->r9() ; + _allMVAVars.varSieie = (*_full5x5SigmaIEtaIEtaMap)[ phoRecoPtr ]; // in principle, in the photon object as well + _allMVAVars.varSieip = (*_full5x5SigmaIEtaIPhiMap)[ phoRecoPtr ]; // not in the photon object + _allMVAVars.varE1x3overE5x5 = e1x3/e5x5; + _allMVAVars.varE2x2overE5x5 = e2x2/e5x5; + _allMVAVars.varE2x5overE5x5 = e2x5/e5x5; + _allMVAVars.varSCEta = superCluster->eta(); + _allMVAVars.varRawE = superCluster->rawEnergy(); + _allMVAVars.varSCEtaWidth = superCluster->etaWidth(); + _allMVAVars.varSCPhiWidth = superCluster->phiWidth(); + _allMVAVars.varESEnOverRawE = superCluster->preshowerEnergy() / superCluster->rawEnergy(); + _allMVAVars.varESEffSigmaRR = (*_esEffSigmaRRMap)[ phoRecoPtr ]; + _allMVAVars.varRho = *_rho; + _allMVAVars.varPhoIsoRaw = (*_phoPhotonIsolationMap)[phoRecoPtr]; + _allMVAVars.varChIsoRaw = (*_phoChargedIsolationMap)[phoRecoPtr]; + _allMVAVars.varWorstChRaw = (*_phoWorstChargedIsolationMap)[phoRecoPtr]; + // Declare spectator vars + _allMVAVars.varPt = phoRecoPtr->pt(); + _allMVAVars.varEta = phoRecoPtr->eta(); + +} + +void PhotonMVAEstimatorRun2Phys14NonTrig::constrainMVAVariables(){ + + // Check that variables do not have crazy values + + // This function is currently empty as this specific MVA was not + // developed with restricting variables to specific physical ranges. + return; + +} + diff --git a/RecoEgamma/PhotonIdentification/plugins/PhotonMVAEstimatorRun2Spring15NonTrig.cc b/RecoEgamma/PhotonIdentification/plugins/PhotonMVAEstimatorRun2Spring15NonTrig.cc new file mode 100644 index 0000000000000..278a770c756ba --- /dev/null +++ b/RecoEgamma/PhotonIdentification/plugins/PhotonMVAEstimatorRun2Spring15NonTrig.cc @@ -0,0 +1,304 @@ +#include "RecoEgamma/PhotonIdentification/interface/PhotonMVAEstimatorRun2Spring15NonTrig.h" + +#include "FWCore/ParameterSet/interface/FileInPath.h" + +PhotonMVAEstimatorRun2Spring15NonTrig::PhotonMVAEstimatorRun2Spring15NonTrig(const edm::ParameterSet& conf): + AnyMVAEstimatorRun2Base(conf) +{ + + // + // Construct the MVA estimators + // + const std::vector weightFileNames + = conf.getParameter >("weightFileNames"); + + if( (int)(weightFileNames.size()) != nCategories ) + throw cms::Exception("MVA config failure: ") + << "wrong number of weightfiles" << std::endl; + + _tmvaReaders.clear(); + // The method name is just a key to retrieve this method later, it is not + // a control parameter for a reader (the full definition of the MVA type and + // everything else comes from the xml weight files). + _MethodName = "BDTG method"; + // Create a TMVA reader object for each category + for(int i=0; i + ( createSingleReader(i, weightFile ) ) ); + + } + +} + +PhotonMVAEstimatorRun2Spring15NonTrig:: +~PhotonMVAEstimatorRun2Spring15NonTrig(){ + + _tmvaReaders.clear(); +} + +void PhotonMVAEstimatorRun2Spring15NonTrig::setConsumes(edm::ConsumesCollector&& cc){ + + // All tokens for event content needed by this MVA + // Cluster shapes + _full5x5SigmaIEtaIEtaMapToken = cc.consumes > + (_conf.getParameter("full5x5SigmaIEtaIEtaMap")); + + _full5x5SigmaIEtaIPhiMapToken = cc.consumes > + (_conf.getParameter("full5x5SigmaIEtaIPhiMap")); + + _full5x5E1x3MapToken = cc.consumes > + (_conf.getParameter("full5x5E1x3Map")); + + _full5x5E2x2MapToken = cc.consumes > + (_conf.getParameter("full5x5E2x2Map")); + + _full5x5E2x5MaxMapToken = cc.consumes > + (_conf.getParameter("full5x5E2x5MaxMap")); + + _full5x5E5x5MapToken = cc.consumes > + (_conf.getParameter("full5x5E5x5Map")); + + _esEffSigmaRRMapToken = cc.consumes > + (_conf.getParameter("esEffSigmaRRMap")); + + // Isolations + _phoChargedIsolationToken = cc.consumes > + (_conf.getParameter("phoChargedIsolation")); + + _phoPhotonIsolationToken = cc.consumes > + (_conf.getParameter("phoPhotonIsolation")); + + _phoWorstChargedIsolationToken = cc.consumes > + (_conf.getParameter("phoWorstChargedIsolation")); + + // Pileup + _rhoToken = cc.consumes (_conf.getParameter("rho")); + +} + +void PhotonMVAEstimatorRun2Spring15NonTrig::getEventContent(const edm::Event& iEvent){ + + // Get the full5x5 and ES maps + iEvent.getByToken(_full5x5SigmaIEtaIEtaMapToken, _full5x5SigmaIEtaIEtaMap); + iEvent.getByToken(_full5x5SigmaIEtaIPhiMapToken, _full5x5SigmaIEtaIPhiMap); + iEvent.getByToken(_full5x5E1x3MapToken, _full5x5E1x3Map); + iEvent.getByToken(_full5x5E2x2MapToken, _full5x5E2x2Map); + iEvent.getByToken(_full5x5E2x5MaxMapToken, _full5x5E2x5MaxMap); + iEvent.getByToken(_full5x5E5x5MapToken, _full5x5E5x5Map); + iEvent.getByToken(_esEffSigmaRRMapToken, _esEffSigmaRRMap); + + // Get the isolation maps + iEvent.getByToken(_phoChargedIsolationToken, _phoChargedIsolationMap); + iEvent.getByToken(_phoPhotonIsolationToken, _phoPhotonIsolationMap); + iEvent.getByToken(_phoWorstChargedIsolationToken, _phoWorstChargedIsolationMap); + + // Get rho + iEvent.getByToken(_rhoToken,_rho); + + // Make sure everything is retrieved successfully + if(! (_full5x5SigmaIEtaIEtaMap.isValid() + && _full5x5SigmaIEtaIPhiMap.isValid() + && _full5x5E1x3Map.isValid() + && _full5x5E2x2Map.isValid() + && _full5x5E2x5MaxMap.isValid() + && _full5x5E5x5Map.isValid() + && _esEffSigmaRRMap.isValid() + && _phoChargedIsolationMap.isValid() + && _phoPhotonIsolationMap.isValid() + && _phoWorstChargedIsolationMap.isValid() + && _rho.isValid() ) ) + throw cms::Exception("MVA failure: ") + << "Failed to retrieve event content needed for this MVA" + << std::endl + << "Check python MVA configuration file and make sure all needed" + << std::endl + << "producers are running upstream" << std::endl; +} + + +float PhotonMVAEstimatorRun2Spring15NonTrig:: +mvaValue( const edm::Ptr& particle){ + + int iCategory = findCategory( particle ); + fillMVAVariables( particle ); + constrainMVAVariables(); + float result = _tmvaReaders.at(iCategory)->EvaluateMVA(_MethodName); + + // DEBUG + const bool debug = false; + if( debug ){ + printf("Printout of the photon variable inputs for MVA:\n"); + printf(" varPhi_ %f\n", _allMVAVars.varPhi ); + printf(" varR9_ %f\n", _allMVAVars.varR9 ); + printf(" varSieie_ %f\n", _allMVAVars.varSieie ); + printf(" varSieip_ %f\n", _allMVAVars.varSieip ); + printf(" varE1x3overE5x5_ %f\n", _allMVAVars.varE1x3overE5x5); + printf(" varE2x2overE5x5_ %f\n", _allMVAVars.varE2x2overE5x5); + printf(" varE2x5overE5x5_ %f\n", _allMVAVars.varE2x5overE5x5); + printf(" varSCEta_ %f\n", _allMVAVars.varSCEta ); + printf(" varRawE_ %f\n", _allMVAVars.varRawE ); + printf(" varSCEtaWidth_ %f\n", _allMVAVars.varSCEtaWidth ); + printf(" varSCPhiWidth_ %f\n", _allMVAVars.varSCPhiWidth ); + printf(" varRho_ %f\n", _allMVAVars.varRho ); + printf(" varPhoIsoRaw_ %f\n", _allMVAVars.varPhoIsoRaw ); + printf(" varChIsoRaw_ %f\n", _allMVAVars.varChIsoRaw ); + printf(" varWorstChRaw_ %f\n", _allMVAVars.varWorstChRaw ); + printf(" varESEnOverRawE_ %f\n", _allMVAVars.varESEnOverRawE); // for endcap MVA only + printf(" varESEffSigmaRR_ %f\n", _allMVAVars.varESEffSigmaRR); // for endcap MVA only + // The spectators + printf(" varPt_ %f\n", _allMVAVars.varPt ); + printf(" varEta_ %f\n", _allMVAVars.varEta ); + } + + return result; +} + +int PhotonMVAEstimatorRun2Spring15NonTrig::findCategory( const edm::Ptr& particle){ + + // Try to cast the particle into a reco particle. + // This should work for both reco and pat. + const edm::Ptr phoRecoPtr = ( edm::Ptr )particle; + if( phoRecoPtr.isNull() ) + throw cms::Exception("MVA failure: ") + << " given particle is expected to be reco::Photon or pat::Photon," << std::endl + << " but appears to be neither" << std::endl; + + float eta = phoRecoPtr->superCluster()->eta(); + + // + // Determine the category + // + int iCategory = UNDEFINED; + const float ebeeSplit = 1.479; // division between barrel and endcap + + if ( std::abs(eta) < ebeeSplit) + iCategory = CAT_EB; + + if (std::abs(eta) >= ebeeSplit) + iCategory = CAT_EE; + + return iCategory; +} + +bool PhotonMVAEstimatorRun2Spring15NonTrig:: +isEndcapCategory(int category ){ + + // For this specific MVA the function is trivial, but kept for possible + // future evolution to an MVA with more categories in eta + bool isEndcap = false; + if( category == CAT_EE ) + isEndcap = true; + + return isEndcap; +} + + +TMVA::Reader *PhotonMVAEstimatorRun2Spring15NonTrig:: +createSingleReader(const int iCategory, const edm::FileInPath &weightFile){ + + // + // Create the reader + // + TMVA::Reader *tmpTMVAReader = new TMVA::Reader( "!Color:Silent:Error" ); + + // + // Configure all variables and spectators. Note: the order and names + // must match what is found in the xml weights file! + // + + tmpTMVAReader->AddVariable("recoPhi" , &_allMVAVars.varPhi); + tmpTMVAReader->AddVariable("r9" , &_allMVAVars.varR9); + tmpTMVAReader->AddVariable("sieieFull5x5", &_allMVAVars.varSieie); + tmpTMVAReader->AddVariable("sieipFull5x5", &_allMVAVars.varSieip); + tmpTMVAReader->AddVariable("e1x3Full5x5/e5x5Full5x5" , &_allMVAVars.varE1x3overE5x5); + tmpTMVAReader->AddVariable("e2x2Full5x5/e5x5Full5x5" , &_allMVAVars.varE2x2overE5x5); + tmpTMVAReader->AddVariable("e2x5Full5x5/e5x5Full5x5" , &_allMVAVars.varE2x5overE5x5); + tmpTMVAReader->AddVariable("recoSCEta" , &_allMVAVars.varSCEta); + tmpTMVAReader->AddVariable("rawE" , &_allMVAVars.varRawE); + tmpTMVAReader->AddVariable("scEtaWidth", &_allMVAVars.varSCEtaWidth); + tmpTMVAReader->AddVariable("scPhiWidth", &_allMVAVars.varSCPhiWidth); + + // Endcap only variables + if( isEndcapCategory(iCategory) ){ + tmpTMVAReader->AddVariable("esEn/rawE" , &_allMVAVars.varESEnOverRawE); + tmpTMVAReader->AddVariable("esRR" , &_allMVAVars.varESEffSigmaRR); + } + + // Pileup + tmpTMVAReader->AddVariable("rho" , &_allMVAVars.varRho); + + // Isolations + tmpTMVAReader->AddVariable("phoIsoRaw" , &_allMVAVars.varPhoIsoRaw); + tmpTMVAReader->AddVariable("chIsoRaw" , &_allMVAVars.varChIsoRaw); + tmpTMVAReader->AddVariable("chWorstRaw", &_allMVAVars.varWorstChRaw); + + // Spectators + tmpTMVAReader->AddSpectator("recoPt" , &_allMVAVars.varPt); + tmpTMVAReader->AddSpectator("recoEta", &_allMVAVars.varEta); + + // + // Book the method and set up the weights file + // + tmpTMVAReader->BookMVA(_MethodName , weightFile.fullPath() ); + + return tmpTMVAReader; +} + +// A function that should work on both pat and reco objects +void PhotonMVAEstimatorRun2Spring15NonTrig::fillMVAVariables(const edm::Ptr& particle){ + + // Try to cast the particle into a reco particle. + // This should work for both reco and pat. + const edm::Ptr phoRecoPtr = ( edm::Ptr )particle; + if( phoRecoPtr.isNull() ) + throw cms::Exception("MVA failure: ") + << " given particle is expected to be reco::Photon or pat::Photon," << std::endl + << " but appears to be neither" << std::endl; + + // Both pat and reco particles have exactly the same accessors. + auto superCluster = phoRecoPtr->superCluster(); + // Full 5x5 cluster shapes. We could take some of this directly from + // the photon object, but some of these are not available. + float e1x3 = (*_full5x5E1x3Map )[ phoRecoPtr ]; + float e2x2 = (*_full5x5E2x2Map )[ phoRecoPtr ]; + float e2x5 = (*_full5x5E2x5MaxMap)[ phoRecoPtr ]; + float e5x5 = (*_full5x5E5x5Map )[ phoRecoPtr ]; + + _allMVAVars.varPhi = phoRecoPtr->phi(); + _allMVAVars.varR9 = phoRecoPtr->r9() ; + _allMVAVars.varSieie = (*_full5x5SigmaIEtaIEtaMap)[ phoRecoPtr ]; // in principle, in the photon object as well + _allMVAVars.varSieip = (*_full5x5SigmaIEtaIPhiMap)[ phoRecoPtr ]; // not in the photon object + _allMVAVars.varE1x3overE5x5 = e1x3/e5x5; + _allMVAVars.varE2x2overE5x5 = e2x2/e5x5; + _allMVAVars.varE2x5overE5x5 = e2x5/e5x5; + _allMVAVars.varSCEta = superCluster->eta(); + _allMVAVars.varRawE = superCluster->rawEnergy(); + _allMVAVars.varSCEtaWidth = superCluster->etaWidth(); + _allMVAVars.varSCPhiWidth = superCluster->phiWidth(); + _allMVAVars.varESEnOverRawE = superCluster->preshowerEnergy() / superCluster->rawEnergy(); + _allMVAVars.varESEffSigmaRR = (*_esEffSigmaRRMap)[ phoRecoPtr ]; + _allMVAVars.varRho = *_rho; + _allMVAVars.varPhoIsoRaw = (*_phoPhotonIsolationMap)[phoRecoPtr]; + _allMVAVars.varChIsoRaw = (*_phoChargedIsolationMap)[phoRecoPtr]; + _allMVAVars.varWorstChRaw = (*_phoWorstChargedIsolationMap)[phoRecoPtr]; + // Declare spectator vars + _allMVAVars.varPt = phoRecoPtr->pt(); + _allMVAVars.varEta = phoRecoPtr->eta(); + +} + +void PhotonMVAEstimatorRun2Spring15NonTrig::constrainMVAVariables(){ + + // Check that variables do not have crazy values + + // This function is currently empty as this specific MVA was not + // developed with restricting variables to specific physical ranges. + return; + +} + diff --git a/RecoEgamma/PhotonIdentification/plugins/PhotonMVAValueMapProducer.cc b/RecoEgamma/PhotonIdentification/plugins/PhotonMVAValueMapProducer.cc new file mode 100644 index 0000000000000..c99ccbc5d3dc4 --- /dev/null +++ b/RecoEgamma/PhotonIdentification/plugins/PhotonMVAValueMapProducer.cc @@ -0,0 +1,8 @@ +#include "RecoEgamma/EgammaTools/interface/MVAValueMapProducer.h" + +#include "DataFormats/EgammaCandidates/interface/Photon.h" + +typedef MVAValueMapProducer PhotonMVAValueMapProducer; + +//define this as a plug-in +DEFINE_FWK_MODULE(PhotonMVAValueMapProducer); diff --git a/RecoEgamma/PhotonIdentification/plugins/cuts/PhoAnyPFIsoWithEAAndExpoScalingEBCut.cc b/RecoEgamma/PhotonIdentification/plugins/cuts/PhoAnyPFIsoWithEAAndExpoScalingEBCut.cc index 16fe4dc5c5c0c..322b0de3323a0 100644 --- a/RecoEgamma/PhotonIdentification/plugins/cuts/PhoAnyPFIsoWithEAAndExpoScalingEBCut.cc +++ b/RecoEgamma/PhotonIdentification/plugins/cuts/PhoAnyPFIsoWithEAAndExpoScalingEBCut.cc @@ -12,6 +12,8 @@ class PhoAnyPFIsoWithEAAndExpoScalingEBCut : public CutApplicatorWithEventConten void setConsumes(edm::ConsumesCollector&) override final; void getEventContent(const edm::EventBase&) override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return PHOTON; } @@ -82,6 +84,21 @@ CutApplicatorBase::result_type PhoAnyPFIsoWithEAAndExpoScalingEBCut:: operator()(const reco::PhotonPtr& cand) const{ + // in case we are by-value + const std::string& inst_name = contentTags_.find(anyPFIsoWithEA_)->second.instance(); + edm::Ptr pat(cand); + float anyisoval = -1.0; + if( _anyPFIsoMap.isValid() && _anyPFIsoMap->contains( cand.id() ) ) { + anyisoval = (*_anyPFIsoMap)[cand]; + } else if ( _anyPFIsoMap.isValid() && _anyPFIsoMap->idSize() == 1 && + cand.id() == edm::ProductID() ) { + // in case we have spoofed a ptr + //note this must be a 1:1 valuemap (only one product input) + anyisoval = _anyPFIsoMap->begin()[cand.key()]; + } else if ( _anyPFIsoMap.isValid() ){ // throw an exception + anyisoval = (*_anyPFIsoMap)[cand]; + } + // Figure out the cut value // The value is generally pt-dependent: C1 + pt * C2 const float pt = cand->pt(); @@ -96,7 +113,7 @@ operator()(const reco::PhotonPtr& cand) const{ : _C1_EE + pt * _C2_EE); // Retrieve the variable value for this particle - float anyPFIso = (*_anyPFIsoMap)[cand]; + float anyPFIso = _anyPFIsoMap.isValid() ? anyisoval : pat->userFloat(inst_name); // Apply pile-up correction double eA = _effectiveAreas.getEffectiveArea( absEta ); @@ -110,3 +127,47 @@ operator()(const reco::PhotonPtr& cand) const{ // Apply the cut and return the result return anyPFIsoWithEA < isolationCutValue; } + +double PhoAnyPFIsoWithEAAndExpoScalingEBCut:: +value(const reco::CandidatePtr& cand) const { + reco::PhotonPtr pho(cand); + + // in case we are by-value + const std::string& inst_name = contentTags_.find(anyPFIsoWithEA_)->second.instance(); + edm::Ptr pat(cand); + float anyisoval = -1.0; + if( _anyPFIsoMap.isValid() && _anyPFIsoMap->contains( cand.id() ) ) { + anyisoval = (*_anyPFIsoMap)[cand]; + } else if ( _anyPFIsoMap.isValid() && _anyPFIsoMap->idSize() == 1 && + cand.id() == edm::ProductID() ) { + // in case we have spoofed a ptr + //note this must be a 1:1 valuemap (only one product input) + anyisoval = _anyPFIsoMap->begin()[cand.key()]; + } else if ( _anyPFIsoMap.isValid() ){ // throw an exception + anyisoval = (*_anyPFIsoMap)[cand]; + } + + // Figure out the cut value + // The value is generally pt-dependent: C1 + pt * C2 + const float pt = pho->pt(); + + // In this version of the isolation cut we apply + // exponential pt scaling to the barrel isolation cut, + // and linear pt scaling to the endcap isolation cut. + double absEta = std::abs(pho->superCluster()->eta()); + + // Retrieve the variable value for this particle + float anyPFIso = _anyPFIsoMap.isValid() ? anyisoval : pat->userFloat(inst_name); + + // Apply pile-up correction + double eA = _effectiveAreas.getEffectiveArea( absEta ); + double rho = *_rhoHandle; + float anyPFIsoWithEA = std::max(0.0, anyPFIso - rho * eA); + + // Divide by pT if the relative isolation is requested + if( _useRelativeIso ) + anyPFIsoWithEA /= pt; + + // Apply the cut and return the result + return anyPFIsoWithEA; +} diff --git a/RecoEgamma/PhotonIdentification/plugins/cuts/PhoAnyPFIsoWithEACut.cc b/RecoEgamma/PhotonIdentification/plugins/cuts/PhoAnyPFIsoWithEACut.cc index 37b61578c768f..29b31b775fc75 100644 --- a/RecoEgamma/PhotonIdentification/plugins/cuts/PhoAnyPFIsoWithEACut.cc +++ b/RecoEgamma/PhotonIdentification/plugins/cuts/PhoAnyPFIsoWithEACut.cc @@ -12,6 +12,8 @@ class PhoAnyPFIsoWithEACut : public CutApplicatorWithEventContentBase { void setConsumes(edm::ConsumesCollector&) override final; void getEventContent(const edm::EventBase&) override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return PHOTON; } @@ -80,6 +82,21 @@ CutApplicatorBase::result_type PhoAnyPFIsoWithEACut:: operator()(const reco::PhotonPtr& cand) const{ + // in case we are by-value + const std::string& inst_name = contentTags_.find(anyPFIsoWithEA_)->second.instance(); + edm::Ptr pat(cand); + float anyisoval = -1.0; + if( _anyPFIsoMap.isValid() && _anyPFIsoMap->contains( cand.id() ) ) { + anyisoval = (*_anyPFIsoMap)[cand]; + } else if ( _anyPFIsoMap.isValid() && _anyPFIsoMap->idSize() == 1 && + cand.id() == edm::ProductID() ) { + // in case we have spoofed a ptr + //note this must be a 1:1 valuemap (only one product input) + anyisoval = _anyPFIsoMap->begin()[cand.key()]; + } else if ( _anyPFIsoMap.isValid() ){ // throw an exception + anyisoval = (*_anyPFIsoMap)[cand]; + } + // Figure out the cut value // The value is generally pt-dependent: C1 + pt * C2 const double absEta = std::abs(cand->superCluster()->eta()); @@ -91,7 +108,7 @@ operator()(const reco::PhotonPtr& cand) const{ ); // Retrieve the variable value for this particle - float anyPFIso = _anyPFIsoMap.isValid() ? (*_anyPFIsoMap)[cand] : 0; + float anyPFIso = _anyPFIsoMap.isValid() ? anyisoval : pat->userFloat(inst_name); // Apply pile-up correction const double eA = _effectiveAreas.getEffectiveArea( absEta ); @@ -102,3 +119,42 @@ operator()(const reco::PhotonPtr& cand) const{ // Scale by pT if the relative isolation is requested but avoid division by 0 return anyPFIsoWithEA < anyPFIsoWithEACutValue*(_useRelativeIso ? cand->pt() : 1.); } + +double PhoAnyPFIsoWithEACut:: +value(const reco::CandidatePtr& cand) const { + reco::PhotonPtr pho(cand); + + // in case we are by-value + const std::string& inst_name = contentTags_.find(anyPFIsoWithEA_)->second.instance(); + edm::Ptr pat(cand); + float anyisoval = -1.0; + if( _anyPFIsoMap.isValid() && _anyPFIsoMap->contains( cand.id() ) ) { + anyisoval = (*_anyPFIsoMap)[cand]; + } else if ( _anyPFIsoMap.isValid() && _anyPFIsoMap->idSize() == 1 && + cand.id() == edm::ProductID() ) { + // in case we have spoofed a ptr + //note this must be a 1:1 valuemap (only one product input) + anyisoval = _anyPFIsoMap->begin()[cand.key()]; + } else if ( _anyPFIsoMap.isValid() ){ // throw an exception + anyisoval = (*_anyPFIsoMap)[cand]; + } + + // Figure out the cut value + // The value is generally pt-dependent: C1 + pt * C2 + double absEta = std::abs(pho->superCluster()->eta()); + + // Retrieve the variable value for this particle + float anyPFIso = _anyPFIsoMap.isValid() ? anyisoval : pat->userFloat(inst_name); + + // Apply pile-up correction + double eA = _effectiveAreas.getEffectiveArea( absEta ); + double rho = *_rhoHandle; + float anyPFIsoWithEA = std::max(0.0, anyPFIso - rho * eA); + + // Divide by pT if the relative isolation is requested + if( _useRelativeIso ) + anyPFIsoWithEA /= pho->pt(); + + // Apply the cut and return the result + return anyPFIsoWithEA; +} diff --git a/RecoEgamma/PhotonIdentification/plugins/cuts/PhoFull5x5SigmaIEtaIEtaCut.cc b/RecoEgamma/PhotonIdentification/plugins/cuts/PhoFull5x5SigmaIEtaIEtaCut.cc index f62a55c2aafc7..6322c0176f796 100644 --- a/RecoEgamma/PhotonIdentification/plugins/cuts/PhoFull5x5SigmaIEtaIEtaCut.cc +++ b/RecoEgamma/PhotonIdentification/plugins/cuts/PhoFull5x5SigmaIEtaIEtaCut.cc @@ -7,6 +7,8 @@ class PhoFull5x5SigmaIEtaIEtaCut : public CutApplicatorBase { result_type operator()(const reco::PhotonPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return PHOTON; } @@ -40,3 +42,9 @@ operator()(const reco::PhotonPtr& cand) const{ // Apply the cut and return the result return cand->full5x5_sigmaIetaIeta() < full5x5SigmaIEtaIEtaCutValue; } + +double PhoFull5x5SigmaIEtaIEtaCut:: +value(const reco::CandidatePtr& cand) const { + reco::PhotonPtr pho(cand); + return pho->full5x5_sigmaIetaIeta(); +} diff --git a/RecoEgamma/PhotonIdentification/plugins/cuts/PhoFull5x5SigmaIEtaIEtaValueMapCut.cc b/RecoEgamma/PhotonIdentification/plugins/cuts/PhoFull5x5SigmaIEtaIEtaValueMapCut.cc index 7db4b89bc4782..635b5052b9e9c 100644 --- a/RecoEgamma/PhotonIdentification/plugins/cuts/PhoFull5x5SigmaIEtaIEtaValueMapCut.cc +++ b/RecoEgamma/PhotonIdentification/plugins/cuts/PhoFull5x5SigmaIEtaIEtaValueMapCut.cc @@ -10,6 +10,8 @@ class PhoFull5x5SigmaIEtaIEtaValueMapCut : public CutApplicatorWithEventContentB void setConsumes(edm::ConsumesCollector&) override final; void getEventContent(const edm::EventBase&) override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return PHOTON; } @@ -57,10 +59,39 @@ operator()(const reco::PhotonPtr& cand) const{ const float cutValue = ( std::abs(cand->superCluster()->eta()) < _barrelCutOff ? _cutValueEB : _cutValueEE ); + float sihihval = -1.0; + if( _full5x5SigmaIEtaIEtaMap.isValid() && _full5x5SigmaIEtaIEtaMap->contains( cand.id() ) ) { + sihihval = (*_full5x5SigmaIEtaIEtaMap)[cand]; + } else if ( _full5x5SigmaIEtaIEtaMap.isValid() && _full5x5SigmaIEtaIEtaMap->idSize() == 1 && + cand.id() == edm::ProductID() ) { + // in case we have spoofed a ptr + //note this must be a 1:1 valuemap (only one product input) + sihihval = _full5x5SigmaIEtaIEtaMap->begin()[cand.key()]; + } else if ( _full5x5SigmaIEtaIEtaMap.isValid() ){ // throw an exception + sihihval = (*_full5x5SigmaIEtaIEtaMap)[cand]; + } // Retrieve the variable value for this particle - const float full5x5SigmaIEtaIEta = _full5x5SigmaIEtaIEtaMap.isValid() ? (*_full5x5SigmaIEtaIEtaMap)[cand] : 0; + const float full5x5SigmaIEtaIEta = _full5x5SigmaIEtaIEtaMap.isValid() ? sihihval : cand->full5x5_sigmaIetaIeta(); // Apply the cut and return the result return full5x5SigmaIEtaIEta < cutValue; } + +double PhoFull5x5SigmaIEtaIEtaValueMapCut:: +value(const reco::CandidatePtr& cand) const { + reco::PhotonPtr pho(cand); + float sihihval = -1.0; + if( _full5x5SigmaIEtaIEtaMap.isValid() && _full5x5SigmaIEtaIEtaMap->contains( cand.id() ) ) { + sihihval = (*_full5x5SigmaIEtaIEtaMap)[cand]; + } else if ( _full5x5SigmaIEtaIEtaMap.isValid() && _full5x5SigmaIEtaIEtaMap->idSize() == 1 && + cand.id() == edm::ProductID() ) { + // in case we have spoofed a ptr + //note this must be a 1:1 valuemap (only one product input) + sihihval = _full5x5SigmaIEtaIEtaMap->begin()[cand.key()]; + } else if ( _full5x5SigmaIEtaIEtaMap.isValid() ){ // throw an exception + sihihval = (*_full5x5SigmaIEtaIEtaMap)[cand]; + } + + return _full5x5SigmaIEtaIEtaMap.isValid() ? sihihval : pho->full5x5_sigmaIetaIeta(); +} diff --git a/RecoEgamma/PhotonIdentification/plugins/cuts/PhoHadronicOverEMCut.cc b/RecoEgamma/PhotonIdentification/plugins/cuts/PhoHadronicOverEMCut.cc index 05af1e2b88940..390fb389ee595 100644 --- a/RecoEgamma/PhotonIdentification/plugins/cuts/PhoHadronicOverEMCut.cc +++ b/RecoEgamma/PhotonIdentification/plugins/cuts/PhoHadronicOverEMCut.cc @@ -12,6 +12,8 @@ class PhoHadronicOverEMCut : public CutApplicatorBase { result_type operator()(const reco::PhotonPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return PHOTON; } @@ -33,3 +35,9 @@ operator()(const reco::PhotonPtr& cand) const { return cand->hadronicOverEm() < hadronicOverEMCutValue; } + +double PhoHadronicOverEMCut:: +value(const reco::CandidatePtr& cand) const { + reco::PhotonPtr pho(cand); + return pho->hadronicOverEm(); +} diff --git a/RecoEgamma/PhotonIdentification/plugins/cuts/PhoMVACut.cc b/RecoEgamma/PhotonIdentification/plugins/cuts/PhoMVACut.cc new file mode 100644 index 0000000000000..ec400b36cb2f9 --- /dev/null +++ b/RecoEgamma/PhotonIdentification/plugins/cuts/PhoMVACut.cc @@ -0,0 +1,124 @@ +#include "PhysicsTools/SelectorUtils/interface/CutApplicatorWithEventContentBase.h" +#include "DataFormats/EgammaCandidates/interface/Photon.h" + + +class PhoMVACut : public CutApplicatorWithEventContentBase { +public: + PhoMVACut(const edm::ParameterSet& c); + + result_type operator()(const reco::PhotonPtr&) const override final; + + void setConsumes(edm::ConsumesCollector&) override final; + void getEventContent(const edm::EventBase&) override final; + + double value(const reco::CandidatePtr& cand) const override final; + + CandidateType candidateType() const override final { + return PHOTON; + } + +private: + + // Cut values + const std::vector _mvaCutValues; + + // Pre-computed MVA value map + edm::Handle > _mvaValueMap; + edm::Handle > _mvaCategoriesMap; + +}; + +DEFINE_EDM_PLUGIN(CutApplicatorFactory, + PhoMVACut, + "PhoMVACut"); + +PhoMVACut::PhoMVACut(const edm::ParameterSet& c) : + CutApplicatorWithEventContentBase(c), + _mvaCutValues(c.getParameter >("mvaCuts")) +{ + edm::InputTag mvaValTag = c.getParameter("mvaValueMapName"); + contentTags_.emplace("mvaVal",mvaValTag); + + edm::InputTag mvaCatTag = c.getParameter("mvaCategoriesMapName"); + contentTags_.emplace("mvaCat",mvaCatTag); + +} + +void PhoMVACut::setConsumes(edm::ConsumesCollector& cc) { + + auto mvaVal = + cc.consumes >(contentTags_["mvaVal"]); + contentTokens_.emplace("mvaVal",mvaVal); + + auto mvaCat = + cc.consumes >(contentTags_["mvaCat"]); + contentTokens_.emplace("mvaCat",mvaCat); +} + +void PhoMVACut::getEventContent(const edm::EventBase& ev) { + + ev.getByLabel(contentTags_["mvaVal"],_mvaValueMap); + ev.getByLabel(contentTags_["mvaCat"],_mvaCategoriesMap); +} + +CutApplicatorBase::result_type +PhoMVACut:: +operator()(const reco::PhotonPtr& cand) const{ + + // in case we are by-value + const std::string& val_name = contentTags_.find("mvaVal")->second.instance(); + const std::string& cat_name = contentTags_.find("mvaCat")->second.instance(); + edm::Ptr pat(cand); + float val = -1.0; + int cat = -1; + if( _mvaCategoriesMap.isValid() && _mvaCategoriesMap->contains( cand.id() ) && + _mvaValueMap.isValid() && _mvaValueMap->contains( cand.id() ) ) { + cat = (*_mvaCategoriesMap)[cand]; + val = (*_mvaValueMap)[cand]; + } else if ( _mvaCategoriesMap.isValid() && _mvaValueMap.isValid() && + _mvaCategoriesMap->idSize() == 1 && _mvaValueMap->idSize() == 1 && + cand.id() == edm::ProductID() ) { + // in case we have spoofed a ptr + //note this must be a 1:1 valuemap (only one product input) + cat = _mvaCategoriesMap->begin()[cand.key()]; + val = _mvaValueMap->begin()[cand.key()]; + } else if ( _mvaCategoriesMap.isValid() && _mvaValueMap.isValid() ){ // throw an exception + cat = (*_mvaCategoriesMap)[cand]; + val = (*_mvaValueMap)[cand]; + } + + // Find the cut value + const int iCategory = _mvaCategoriesMap.isValid() ? cat : pat->userInt( cat_name ); + if( iCategory >= (int)(_mvaCutValues.size()) ) + throw cms::Exception(" Error in MVA categories: ") + << " found a particle with a category larger than max configured " << std::endl; + const float cutValue = _mvaCutValues[iCategory]; + + // Look up the MVA value for this particle + const float mvaValue = _mvaValueMap.isValid() ? val : pat->userFloat( val_name ); + + // Apply the cut and return the result + return mvaValue > cutValue; +} + +double PhoMVACut::value(const reco::CandidatePtr& cand) const { + + // in case we are by-value + const std::string& val_name =contentTags_.find("mvaVal")->second.instance(); + edm::Ptr pat(cand); + float val = 0.0; + if( _mvaCategoriesMap.isValid() && _mvaCategoriesMap->contains( cand.id() ) && + _mvaValueMap.isValid() && _mvaValueMap->contains( cand.id() ) ) { + val = (*_mvaValueMap)[cand]; + } else if ( _mvaCategoriesMap.isValid() && _mvaValueMap.isValid() && + _mvaCategoriesMap->idSize() == 1 && _mvaValueMap->idSize() == 1 && + cand.id() == edm::ProductID() ) { + // in case we have spoofed a ptr + //note this must be a 1:1 valuemap (only one product input) + val = _mvaValueMap->begin()[cand.key()]; + } else if ( _mvaCategoriesMap.isValid() && _mvaValueMap.isValid() ) { + val = (*_mvaValueMap)[cand]; + } + const float mvaValue = _mvaValueMap.isValid() ? val : pat->userFloat( val_name ); + return mvaValue; +} diff --git a/RecoEgamma/PhotonIdentification/plugins/cuts/PhoSCEtaMultiRangeCut.cc b/RecoEgamma/PhotonIdentification/plugins/cuts/PhoSCEtaMultiRangeCut.cc index 15afd65cc55df..2e5f8d2da93e7 100644 --- a/RecoEgamma/PhotonIdentification/plugins/cuts/PhoSCEtaMultiRangeCut.cc +++ b/RecoEgamma/PhotonIdentification/plugins/cuts/PhoSCEtaMultiRangeCut.cc @@ -17,6 +17,8 @@ class PhoSCEtaMultiRangeCut : public CutApplicatorBase { result_type operator()(const reco::PhotonPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return PHOTON; } @@ -43,3 +45,10 @@ operator()(const reco::PhotonPtr& cand) const{ } return result; } + +double PhoSCEtaMultiRangeCut:: +value(const reco::CandidatePtr& cand) const { + reco::PhotonPtr pho(cand); + const reco::SuperClusterRef& scref = pho->superCluster(); + return ( _absEta ? std::abs(scref->eta()) : scref->eta() ); +} diff --git a/RecoEgamma/PhotonIdentification/plugins/cuts/PhoSingleTowerHadOverEmCut.cc b/RecoEgamma/PhotonIdentification/plugins/cuts/PhoSingleTowerHadOverEmCut.cc index 981083d6e4587..f0c551fe75806 100644 --- a/RecoEgamma/PhotonIdentification/plugins/cuts/PhoSingleTowerHadOverEmCut.cc +++ b/RecoEgamma/PhotonIdentification/plugins/cuts/PhoSingleTowerHadOverEmCut.cc @@ -12,6 +12,8 @@ class PhoSingleTowerHadOverEmCut : public CutApplicatorBase { result_type operator()(const reco::PhotonPtr&) const override final; + double value(const reco::CandidatePtr& cand) const override final; + CandidateType candidateType() const override final { return PHOTON; } @@ -33,3 +35,9 @@ operator()(const reco::PhotonPtr& cand) const { return cand->hadTowOverEm() < hadronicOverEMCutValue; } + +double PhoSingleTowerHadOverEmCut:: +value(const reco::CandidatePtr& cand) const { + reco::PhotonPtr pho(cand); + return pho->hadTowOverEm(); +} diff --git a/RecoEgamma/PhotonIdentification/python/Identification/mvaPhotonID_PHYS14_PU20bx25_nonTrig_V1_cff.py b/RecoEgamma/PhotonIdentification/python/Identification/mvaPhotonID_PHYS14_PU20bx25_nonTrig_V1_cff.py new file mode 100644 index 0000000000000..5b5b858f288bc --- /dev/null +++ b/RecoEgamma/PhotonIdentification/python/Identification/mvaPhotonID_PHYS14_PU20bx25_nonTrig_V1_cff.py @@ -0,0 +1,94 @@ +from PhysicsTools.SelectorUtils.centralIDRegistry import central_id_registry + +import FWCore.ParameterSet.Config as cms + +# +# In this file we define the locations of the MVA weights, cuts on the MVA values +# for specific working points, and configure those cuts in VID +# + +# +# The following MVA is derived for PHYS14 MC samples for non-triggering photons. +# See more documentation in this presentation: +# https://indico.cern.ch/event/369217/contribution/2/material/slides/0.pdf +# + +# This MVA implementation class name +mvaPhys14NonTrigClassName = "PhotonMVAEstimatorRun2Phys14NonTrig" + +# There are 2 categories in this MVA. They have to be configured in this strict order +# (cuts and weight files order): +# 0 barrel photons +# 1 endcap photons + +mvaPhys14NonTrigWeightFiles_V1 = cms.vstring( + "RecoEgamma/PhotonIdentification/data/PHYS14/photon_general_MVA_phys14_pu20bx25_EB_V1.weights.xml", + "RecoEgamma/PhotonIdentification/data/PHYS14/photon_general_MVA_phys14_pu20bx25_EE_V1.weights.xml" + ) + +# Load some common definitions for MVA machinery +from RecoEgamma.PhotonIdentification.Identification.mvaPhotonID_tools import * + +# The locatoins of value maps with the actual MVA values and categories +# for all particles. +# The names for the maps are ":Values" +# and ":Categories" +mvaProducerModuleLabel = "photonMVAValueMapProducer" +mvaValueMapName = mvaProducerModuleLabel + ":" + mvaPhys14NonTrigClassName + "Values" +mvaCategoriesMapName = mvaProducerModuleLabel + ":" + mvaPhys14NonTrigClassName + "Categories" + +# The working point for this MVA that is expected to have about 90% signal +# efficiency in each category for photons with pt>30 GeV (somewhat lower +# for lower pt photons). +idName = "mvaPhoID-PHYS14-PU20bx25-nonTrig-V1-wp90" +MVA_WP90 = PhoMVA_2Categories_WP( + idName = idName, + mvaValueMapName = mvaValueMapName, # map with MVA values for all particles + mvaCategoriesMapName = mvaCategoriesMapName, # map with category index for all particles + cutCategory0 = 0.593, # EB + cutCategory1 = 0.679 # EE + ) + +# +# Finally, set up VID configuration for all cuts +# + +# Create the PSet that will be fed to the MVA value map producer +mvaPhoID_PHYS14_PU20bx25_nonTrig_V1_producer_config = cms.PSet( + mvaName = cms.string(mvaPhys14NonTrigClassName), + weightFileNames = mvaPhys14NonTrigWeightFiles_V1, + # + # All the event content needed for this MVA implementation follows + # + # All the value maps: these are expected to be produced by the + # PhotonIDValueMapProducer running upstream + # + full5x5SigmaIEtaIEtaMap = cms.InputTag("photonIDValueMapProducer:phoFull5x5SigmaIEtaIEta"), + full5x5SigmaIEtaIPhiMap = cms.InputTag("photonIDValueMapProducer:phoFull5x5SigmaIEtaIPhi"), + full5x5E1x3Map = cms.InputTag("photonIDValueMapProducer:phoFull5x5E1x3"), + full5x5E2x2Map = cms.InputTag("photonIDValueMapProducer:phoFull5x5E2x2"), + full5x5E2x5MaxMap = cms.InputTag("photonIDValueMapProducer:phoFull5x5E2x5Max"), + full5x5E5x5Map = cms.InputTag("photonIDValueMapProducer:phoFull5x5E5x5"), + esEffSigmaRRMap = cms.InputTag("photonIDValueMapProducer:phoESEffSigmaRR"), + phoChargedIsolation = cms.InputTag("photonIDValueMapProducer:phoChargedIsolation"), + phoPhotonIsolation = cms.InputTag("photonIDValueMapProducer:phoPhotonIsolation"), + phoWorstChargedIsolation = cms.InputTag("photonIDValueMapProducer:phoWorstChargedIsolation"), + # + # Original event content: pileup in this case + # + rho = cms.InputTag("fixedGridRhoFastjetAll") + ) +# Create the VPset's for VID cuts +mvaPhoID_PHYS14_PU20bx25_nonTrig_V1_wp90 = configureVIDMVAPhoID_V1( MVA_WP90 ) + +# The MD5 sum numbers below reflect the exact set of cut variables +# and values above. If anything changes, one has to +# 1) comment out the lines below about the registry, +# 2) run "calculateMD5 +# 3) update the MD5 sum strings below and uncomment the lines again. +# + +central_id_registry.register( mvaPhoID_PHYS14_PU20bx25_nonTrig_V1_wp90.idName, + '6919edf9f82a78f675d9dec796fd5fab') + +mvaPhoID_PHYS14_PU20bx25_nonTrig_V1_wp90.isPOGApproved = cms.untracked.bool(True) diff --git a/RecoEgamma/PhotonIdentification/python/Identification/mvaPhotonID_Spring15_50ns_nonTrig_V0_cff.py b/RecoEgamma/PhotonIdentification/python/Identification/mvaPhotonID_Spring15_50ns_nonTrig_V0_cff.py new file mode 100644 index 0000000000000..0875c6f89ee6b --- /dev/null +++ b/RecoEgamma/PhotonIdentification/python/Identification/mvaPhotonID_Spring15_50ns_nonTrig_V0_cff.py @@ -0,0 +1,94 @@ +from PhysicsTools.SelectorUtils.centralIDRegistry import central_id_registry + +import FWCore.ParameterSet.Config as cms + +# +# In this file we define the locations of the MVA weights, cuts on the MVA values +# for specific working points, and configure those cuts in VID +# + +# +# The following MVA is derived for Spring15 MC samples for non-triggering photons. +# See more documentation in this presentation: +# https://indico.cern.ch/event/369233/contribution/3/material/slides/0.pdf +# + +# This MVA implementation class name +mvaSpring15NonTrigClassName = "PhotonMVAEstimatorRun2Spring15NonTrig" + +# There are 2 categories in this MVA. They have to be configured in this strict order +# (cuts and weight files order): +# 0 barrel photons +# 1 endcap photons + +mvaSpring15NonTrigWeightFiles_V0 = cms.vstring( + "RecoEgamma/PhotonIdentification/data/Spring15/photon_general_MVA_Spring15_50ns_EB_V0.weights.xml", + "RecoEgamma/PhotonIdentification/data/Spring15/photon_general_MVA_Spring15_50ns_EE_V0.weights.xml" + ) + +# Load some common definitions for MVA machinery +from RecoEgamma.PhotonIdentification.Identification.mvaPhotonID_tools import * + +# The locatoins of value maps with the actual MVA values and categories +# for all particles. +# The names for the maps are ":Values" +# and ":Categories" +mvaProducerModuleLabel = "photonMVAValueMapProducer" +mvaValueMapName = mvaProducerModuleLabel + ":" + mvaSpring15NonTrigClassName + "Values" +mvaCategoriesMapName = mvaProducerModuleLabel + ":" + mvaSpring15NonTrigClassName + "Categories" + +# The working point for this MVA that is expected to have about 90% signal +# efficiency in each category for photons with pt>30 GeV (somewhat lower +# for lower pt photons). +idName = "mvaPhoID-Spring15-50ns-nonTrig-V0-wp90" +MVA_WP90 = PhoMVA_2Categories_WP( + idName = idName, + mvaValueMapName = mvaValueMapName, # map with MVA values for all particles + mvaCategoriesMapName = mvaCategoriesMapName, # map with category index for all particles + cutCategory0 = 0.224, # EB + cutCategory1 = 0.355 # EE + ) + +# +# Finally, set up VID configuration for all cuts +# + +# Create the PSet that will be fed to the MVA value map producer +mvaPhoID_Spring15_50ns_nonTrig_V0_producer_config = cms.PSet( + mvaName = cms.string(mvaSpring15NonTrigClassName), + weightFileNames = mvaSpring15NonTrigWeightFiles_V0, + # + # All the event content needed for this MVA implementation follows + # + # All the value maps: these are expected to be produced by the + # PhotonIDValueMapProducer running upstream + # + full5x5SigmaIEtaIEtaMap = cms.InputTag("photonIDValueMapProducer:phoFull5x5SigmaIEtaIEta"), + full5x5SigmaIEtaIPhiMap = cms.InputTag("photonIDValueMapProducer:phoFull5x5SigmaIEtaIPhi"), + full5x5E1x3Map = cms.InputTag("photonIDValueMapProducer:phoFull5x5E1x3"), + full5x5E2x2Map = cms.InputTag("photonIDValueMapProducer:phoFull5x5E2x2"), + full5x5E2x5MaxMap = cms.InputTag("photonIDValueMapProducer:phoFull5x5E2x5Max"), + full5x5E5x5Map = cms.InputTag("photonIDValueMapProducer:phoFull5x5E5x5"), + esEffSigmaRRMap = cms.InputTag("photonIDValueMapProducer:phoESEffSigmaRR"), + phoChargedIsolation = cms.InputTag("photonIDValueMapProducer:phoChargedIsolation"), + phoPhotonIsolation = cms.InputTag("photonIDValueMapProducer:phoPhotonIsolation"), + phoWorstChargedIsolation = cms.InputTag("photonIDValueMapProducer:phoWorstChargedIsolation"), + # + # Original event content: pileup in this case + # + rho = cms.InputTag("fixedGridRhoFastjetAll") + ) +# Create the VPset's for VID cuts +mvaPhoID_Spring15_50ns_nonTrig_V0_wp90 = configureVIDMVAPhoID_V1( MVA_WP90 ) + +# The MD5 sum numbers below reflect the exact set of cut variables +# and values above. If anything changes, one has to +# 1) comment out the lines below about the registry, +# 2) run "calculateMD5 +# 3) update the MD5 sum strings below and uncomment the lines again. +# + +central_id_registry.register( mvaPhoID_Spring15_50ns_nonTrig_V0_wp90.idName, + '70d691efd445926bdccda729bb3f8542') + +mvaPhoID_Spring15_50ns_nonTrig_V0_wp90.isPOGApproved = cms.untracked.bool(True) diff --git a/RecoEgamma/PhotonIdentification/python/Identification/mvaPhotonID_tools.py b/RecoEgamma/PhotonIdentification/python/Identification/mvaPhotonID_tools.py new file mode 100644 index 0000000000000..585ea921388e4 --- /dev/null +++ b/RecoEgamma/PhotonIdentification/python/Identification/mvaPhotonID_tools.py @@ -0,0 +1,53 @@ +import FWCore.ParameterSet.Config as cms + +# ======================================================= +# Define simple containers for MVA cut values and related +# ======================================================= + +class PhoMVA_2Categories_WP: + """ + This is a container class to hold MVA cut values for a 2-category MVA + as well as the names of the value maps that contain the MVA values computed + for all particles in a producer upstream. + """ + def __init__(self, + idName, + mvaValueMapName, + mvaCategoriesMapName, + cutCategory0, + cutCategory1 + ): + self.idName = idName + self.mvaValueMapName = mvaValueMapName + self.mvaCategoriesMapName = mvaCategoriesMapName + self.cutCategory0 = cutCategory0 + self.cutCategory1 = cutCategory1 + + def getCutValues(self): + return [self.cutCategory0, self.cutCategory1] + +# ============================================================== +# Define the complete MVA cut sets +# ============================================================== + +def configureVIDMVAPhoID_V1( mvaWP ): + """ + This function configures the full cms.PSet for a VID ID and returns it. + The inputs: an object of the class PhoMVA_2Categories_WP or similar + that contains all necessary parameters for this MVA. + """ + parameterSet = cms.PSet( + # + idName = cms.string( mvaWP.idName ), + cutFlow = cms.VPSet( + cms.PSet( cutName = cms.string("PhoMVACut"), + mvaCuts = cms.vdouble( mvaWP.getCutValues() ), + mvaValueMapName = cms.InputTag( mvaWP.mvaValueMapName ), + mvaCategoriesMapName =cms.InputTag( mvaWP.mvaCategoriesMapName ), + needsAdditionalProducts = cms.bool(True), + isIgnored = cms.bool(False) + ) + ) + ) + # + return parameterSet diff --git a/RecoEgamma/PhotonIdentification/python/PhotonIDValueMapProducer_cfi.py b/RecoEgamma/PhotonIdentification/python/PhotonIDValueMapProducer_cfi.py index 86969ed923202..2833b65e5447b 100644 --- a/RecoEgamma/PhotonIdentification/python/PhotonIDValueMapProducer_cfi.py +++ b/RecoEgamma/PhotonIdentification/python/PhotonIDValueMapProducer_cfi.py @@ -21,5 +21,5 @@ verticesMiniAOD = cms.InputTag("offlineSlimmedPrimaryVertices"), pfCandidatesMiniAOD = cms.InputTag("packedPFCandidates"), # there is no need for the isolation map here, for miniAOD it is inside packedPFCandidates - srcMiniAOD = cms.InputTag('slimmedPhotons'), + srcMiniAOD = cms.InputTag('slimmedPhotons',processName=cms.InputTag.skipCurrentProcess()), ) diff --git a/RecoEgamma/PhotonIdentification/python/PhotonMVAValueMapProducer_cfi.py b/RecoEgamma/PhotonIdentification/python/PhotonMVAValueMapProducer_cfi.py new file mode 100644 index 0000000000000..6c6113ab35134 --- /dev/null +++ b/RecoEgamma/PhotonIdentification/python/PhotonMVAValueMapProducer_cfi.py @@ -0,0 +1,27 @@ +import FWCore.ParameterSet.Config as cms + +mvaConfigsForPhoProducer = cms.VPSet( ) + +# Import and add all desired MVAs + +from RecoEgamma.PhotonIdentification.Identification.mvaPhotonID_PHYS14_PU20bx25_nonTrig_V1_cff import * +mvaConfigsForPhoProducer.append( mvaPhoID_PHYS14_PU20bx25_nonTrig_V1_producer_config ) + +from RecoEgamma.PhotonIdentification.Identification.mvaPhotonID_Spring15_50ns_nonTrig_V0_cff import * +mvaConfigsForPhoProducer.append( mvaPhoID_Spring15_50ns_nonTrig_V0_producer_config ) + +photonMVAValueMapProducer = cms.EDProducer('PhotonMVAValueMapProducer', + # The module automatically detects AOD vs miniAOD, so we configure both + # + # AOD case + # + src = cms.InputTag('gedPhotons'), + # + # miniAOD case + # + srcMiniAOD = cms.InputTag('slimmedPhotons',processName=cms.InputTag.skipCurrentProcess()), + # + # MVA configurations + # + mvaConfigurations = mvaConfigsForPhoProducer + ) diff --git a/RecoEgamma/PhotonIdentification/python/egmPhotonIDs_cff.py b/RecoEgamma/PhotonIdentification/python/egmPhotonIDs_cff.py index db38e30874dd6..1cf2c845411ba 100644 --- a/RecoEgamma/PhotonIdentification/python/egmPhotonIDs_cff.py +++ b/RecoEgamma/PhotonIdentification/python/egmPhotonIDs_cff.py @@ -6,4 +6,10 @@ # else is needed for IDs from RecoEgamma.PhotonIdentification.PhotonIDValueMapProducer_cfi import * -egmPhotonIDSequence = cms.Sequence(photonIDValueMapProducer * egmPhotonIDs) +# Load the producer for MVA IDs. Make sure it is also added to the sequence! +from RecoEgamma.PhotonIdentification.PhotonMVAValueMapProducer_cfi import * + +# The sequence below is important. The MVA ValueMapProducer +# needs to be downstream from the ID ValueMapProducer because it relies +# on some of its products +egmPhotonIDSequence = cms.Sequence(photonIDValueMapProducer * photonMVAValueMapProducer * egmPhotonIDs) diff --git a/RecoMuon/MuonIdentification/plugins/cuts/MuonPOGStandardCut.cc b/RecoMuon/MuonIdentification/plugins/cuts/MuonPOGStandardCut.cc index 0ff8633be7f18..d564bb3d4e5cd 100644 --- a/RecoMuon/MuonIdentification/plugins/cuts/MuonPOGStandardCut.cc +++ b/RecoMuon/MuonIdentification/plugins/cuts/MuonPOGStandardCut.cc @@ -14,6 +14,8 @@ class MuonPOGStandardCut : public CutApplicatorWithEventContentBase void setConsumes(edm::ConsumesCollector&) override final; void getEventContent(const edm::EventBase&) override final; + double value(const reco::CandidatePtr& cand) const override final; + private: enum CutType { LOOSE, MEDIUM, TIGHT, SOFT, HIGHPT, @@ -57,13 +59,51 @@ void MuonPOGStandardCut::getEventContent(const edm::EventBase& ev) // Functors for evaluation CutApplicatorBase::result_type MuonPOGStandardCut::operator()(const reco::MuonPtr& cand) const { - if ( cutType_ == LOOSE ) return muon::isLooseMuon(*cand); - else if ( cutType_ == TIGHT ) return muon::isTightMuon(*cand, vtxs_->at(0)); - else if ( cutType_ == MEDIUM ) return muon::isMediumMuon(*cand); - else if ( cutType_ == SOFT ) return muon::isSoftMuon(*cand, vtxs_->at(0)); - else if ( cutType_ == HIGHPT ) return muon::isHighPtMuon(*cand, vtxs_->at(0)); - + switch( cutType_ ){ + case LOOSE: + return muon::isLooseMuon(*cand); + break; + case TIGHT: + return muon::isTightMuon(*cand, vtxs_->at(0)); + break; + case MEDIUM: + return muon::isMediumMuon(*cand); + break; + case SOFT: + return muon::isSoftMuon(*cand, vtxs_->at(0)); + break; + case HIGHPT: + return muon::isHighPtMuon(*cand, vtxs_->at(0)); + break; + case NONE: + return false; + break; + } + return true; } - +double MuonPOGStandardCut::value(const reco::CandidatePtr& cand) const { + edm::Ptr mu(cand); + switch( cutType_ ){ + case LOOSE: + return muon::isLooseMuon(*mu); + break; + case TIGHT: + return muon::isTightMuon(*mu, vtxs_->at(0)); + break; + case MEDIUM: + return muon::isMediumMuon(*mu); + break; + case SOFT: + return muon::isSoftMuon(*mu, vtxs_->at(0)); + break; + case HIGHPT: + return muon::isHighPtMuon(*mu, vtxs_->at(0)); + break; + case NONE: + return false; + break; + } + return 1.0; + } diff --git a/RecoMuon/MuonIdentification/plugins/cuts/MuonSelectorVIDWrapper.h b/RecoMuon/MuonIdentification/plugins/cuts/MuonSelectorVIDWrapper.h index 363062a2bfcd6..11f3f24d24ef7 100644 --- a/RecoMuon/MuonIdentification/plugins/cuts/MuonSelectorVIDWrapper.h +++ b/RecoMuon/MuonIdentification/plugins/cuts/MuonSelectorVIDWrapper.h @@ -12,6 +12,11 @@ template mu(cand); + return muon::isGoodMuon(*mu,selectionType,arbitrationType); + } + result_type operator()(const edm::Ptr & muon) const override final { return muon::isGoodMuon(*muon,selectionType,arbitrationType); }