diff --git a/NanoCORE/ElectronSelections.cc b/NanoCORE/ElectronSelections.cc index 8e1f436..63c3e31 100644 --- a/NanoCORE/ElectronSelections.cc +++ b/NanoCORE/ElectronSelections.cc @@ -4,6 +4,10 @@ using namespace tas; +namespace WWZ { + std::shared_ptr electron_mvareader_map; +} + bool SS::electronID(int idx, SS::IDLevel id_level, int year) { // Common (across years and ID levels) checks if (Electron_pt().at(idx) < 7.) { return false; } @@ -349,6 +353,109 @@ bool ttH::isTriggerSafeNoIso(int idx) { return true; } +void WWZ::electronLoadMVA(int year, bool isAPV) +{ + + if (electron_mvareader_map) + { + std::cout << "WARNING: XGBoost already loaded, but is trying to load again!" << std::endl; + return; + } + + std::string file_path = __FILE__; + std::string dir_path = file_path.substr(0, file_path.rfind("/")); + std::string fname = "el_TOP"; + if (year == 2018) + fname += "UL18"; + else if (year == 2017) + fname += "UL17"; + else if (year == 2016) + { + fname += "UL16"; + // Need to add option for APV as well.... + if (isAPV) + { + fname += "APV"; + } + } + fname += "_XGB.weights.bin"; + fname = dir_path + "/data/TopLeptonMVA/" + fname; + + std::cout << "electronLoadMVA(): Loading XGBoost binary file = " << fname << std::endl; + + std::vector varnames; + varnames = std::vector{ + "pt", + "eta", + "jetNDauCharged", + "miniPFRelIso_chg", + "miniPFRelIso_diff_all_chg", // = miniPFRelIso_all - miniPFRelIso_chg + "jetPtRelv2", + "jetPtRatio", // = 1/(jetRelIso+1) + "pfRelIso03_all", + "ak4jet:btagDeepFlavB", // B tagging discriminant score + "sip3d", + "log_abs_dxy", + "log_abs_dz", + }; + varnames.push_back("mvaFall17V2noIso"); + float missing_entry_val = std::numeric_limits::quiet_NaN(); + electron_mvareader_map = std::make_shared(); + electron_mvareader_map->build(fname, varnames, missing_entry_val); +} + +float WWZ::computeElectronTopMVAScore(unsigned int idx) +{ + + float res = -999; + std::unordered_map input_vars; + + auto const &vnames = electron_mvareader_map->getVariableNames(); + for (auto const &vname : vnames) + { + if (vname == "pt") + input_vars[vname] = static_cast(tas::Electron_pt().at(idx)); + else if (vname == "eta") + input_vars[vname] = static_cast(tas::Electron_eta().at(idx)); + else if (vname == "miniPFRelIso_diff_all_chg") + input_vars[vname] = static_cast(tas::Electron_miniPFRelIso_all().at(idx) - tas::Electron_miniPFRelIso_chg().at(idx)); + else if (vname == "jetPtRatio") + input_vars[vname] = static_cast(1. / (tas::Electron_jetRelIso().at(idx) + 1.)); + else if (vname == "log_abs_dxy") + input_vars[vname] = static_cast(std::log(std::abs(tas::Electron_dxy().at(idx)))); + else if (vname == "log_abs_dz") + input_vars[vname] = static_cast(std::log(std::abs(tas::Electron_dz().at(idx)))); + else if (vname == "sip3d") + input_vars[vname] = static_cast(tas::Electron_sip3d().at(idx)); + else if (vname == "miniPFRelIso_chg") + input_vars[vname] = static_cast(tas::Electron_miniPFRelIso_chg().at(idx)); + else if (vname == "jetPtRelv2") + input_vars[vname] = static_cast(tas::Electron_jetPtRelv2().at(idx)); + else if (vname == "jetNDauCharged") + input_vars[vname] = static_cast(tas::Electron_jetNDauCharged().at(idx)); + else if (vname == "pfRelIso03_all") + input_vars[vname] = static_cast(tas::Electron_pfRelIso03_all().at(idx)); + else if (vname == "mvaFall17V2noIso") + input_vars[vname] = static_cast(tas::Electron_mvaFall17V2noIso().at(idx)); + else if (vname == "ak4jet:btagDeepFlavB") + { + input_vars[vname] = float(0); + if (tas::Electron_jetIdx().at(idx) == -1) input_vars[vname] = static_cast(0.); + if (tas::Electron_jetIdx().at(idx) != -1) input_vars[vname] = static_cast(tas::Jet_btagDeepFlavB().at(tas::Electron_jetIdx().at(idx))); + } + else + { + std::cerr << "WWZ::computeElectronTopMVAScore: Input variable name " << vname << " does not match to a corresponding variable" << endl; + std::cerr << "Have you loaded the XGBoost binary? i.e. did you call muonLoadMVA()?" << std::endl; + assert(0); + } + } + + electron_mvareader_map->eval(input_vars, res); + + return res; +} + bool WWZ::electronID(int idx, WWZ::IDLevel id_level, int year) { // Year-specific checks switch (year) { diff --git a/NanoCORE/ElectronSelections.h b/NanoCORE/ElectronSelections.h index cb92149..460c45d 100644 --- a/NanoCORE/ElectronSelections.h +++ b/NanoCORE/ElectronSelections.h @@ -2,6 +2,7 @@ #define ELECTRONSELECTIONS_H #include "Base.h" #include "Nano.h" +#include "Tools/xgboost/XGBoostInterface.h" namespace SS { enum ElectronMVAIDLevel { @@ -31,6 +32,9 @@ namespace ttH { } namespace WWZ { + extern std::shared_ptr electron_mvareader_map; + void electronLoadMVA(int year, bool isAPV); + float computeElectronTopMVAScore(unsigned int idx); bool electronID(int idx, WWZ::IDLevel id_level, int year); bool electron2016ID(int idx, WWZ::IDLevel id_level); bool electron2017ID(int idx, WWZ::IDLevel id_level); diff --git a/NanoCORE/Makefile b/NanoCORE/Makefile index bd7465c..cdb161c 100755 --- a/NanoCORE/Makefile +++ b/NanoCORE/Makefile @@ -4,12 +4,19 @@ SOURCES=$(wildcard *.cc) $(wildcard Tools/*.cc) $(wildcard Tools/btagsf/*.cc) $( OBJECTS=$(SOURCES:.cc=.o) LIB=NANO_CORE.so +# XGBOOST essentials +XGBOOSTLIBDIR = ${XGBOOST_PATH}/lib/ +XGBOOSTINCDIR = ${XGBOOSTLIBDIR}../include/ +RABITINCDIR = ${XGBOOSTLIBDIR}../rabit/include/ +XGBOOSTCXXFLAGS = -I$(XGBOOSTINCDIR) -I$(RABITINCDIR) -L$(XGBOOSTLIBDIR) +XGBOOSTLIBS = -lxgboost -L$(XGBOOSTLIBDIR) + $(LIB): $(OBJECTS) - $(LD) $(LDFLAGS) $(SOFLAGS) $(OBJECTS) $(ROOTLIBS) -lTMVA -lEG -lGenVector -lXMLIO -lMLP -lTreePlayer -o $@ + $(LD) $(LDFLAGS) $(SOFLAGS) $(OBJECTS) $(XGBOOSTLIBS) $(ROOTLIBS) -lTMVA -lEG -lGenVector -lXMLIO -lMLP -lTreePlayer -o $@ ln -sf $(LIB) lib$(LIB) %.o: %.cc - $(CXX) $(CXXFLAGS) -I${CMSSW_BASE}/../../../external/boost/1.67.0/include -I${CMSSW_BASE}/src -c $< -o $@ -fno-var-tracking + $(CXX) $(CXXFLAGS) $(XGBOOSTCXXFLAGS) -I${CMSSW_BASE}/../../../external/boost/1.67.0/include -I${CMSSW_BASE}/src -c $< -o $@ -fno-var-tracking test: all python Tools/unit_tests/tests.py diff --git a/NanoCORE/MuonSelections.cc b/NanoCORE/MuonSelections.cc index 6e0efb8..7497b54 100644 --- a/NanoCORE/MuonSelections.cc +++ b/NanoCORE/MuonSelections.cc @@ -4,6 +4,10 @@ using namespace tas; +namespace WWZ { + std::shared_ptr muon_mvareader_map; +} + bool SS::muonID(unsigned int idx, SS::IDLevel id_level, int year) { // Common (across years and ID levels) checks if (Muon_pt().at(idx) < 5.) { return false; } @@ -131,6 +135,108 @@ bool ttH::muonID(unsigned int idx, ttH::IDLevel id_level, int year) { return true; } +void WWZ::muonLoadMVA(int year, bool isAPV) +{ + + if (muon_mvareader_map) + { + std::cout << "WARNING: XGBoost already loaded, but is trying to load again!" << std::endl; + return; + } + + std::string file_path = __FILE__; + std::string dir_path = file_path.substr(0, file_path.rfind("/")); + std::string fname = "mu_TOP"; + if (year == 2018) + fname += "UL18"; + else if (year == 2017) + fname += "UL17"; + else if (year == 2016) + { + fname += "UL16"; + // Need to add option for APV as well.... + if (isAPV) + { + fname += "APV"; + } + } + fname += "_XGB.weights.bin"; + fname = dir_path + "/data/TopLeptonMVA/" + fname; + + std::cout << "muonLoadMVA(): Loading XGBoost binary file = " << fname << std::endl; + + std::vector varnames; + varnames = std::vector{ + "pt", + "eta", + "jetNDauCharged", + "miniPFRelIso_chg", + "miniPFRelIso_diff_all_chg", // = miniPFRelIso_all - miniPFRelIso_chg + "jetPtRelv2", + "jetPtRatio", // = 1/(jetRelIso+1) + "pfRelIso03_all", + "ak4jet:btagDeepFlavB", // B tagging discriminant score + "sip3d", + "log_abs_dxy", + "log_abs_dz", + "segmentComp", + }; + float missing_entry_val = std::numeric_limits::quiet_NaN(); + muon_mvareader_map = std::make_shared(); + muon_mvareader_map->build(fname, varnames, missing_entry_val); +} + +float WWZ::computeMuonTopMVAScore(unsigned int idx) +{ + + float res = -999; + std::unordered_map input_vars; + + auto const &vnames = muon_mvareader_map->getVariableNames(); + for (auto const &vname : vnames) + { + if (vname == "pt") + input_vars[vname] = static_cast(tas::Muon_pt().at(idx)); + else if (vname == "eta") + input_vars[vname] = static_cast(tas::Muon_eta().at(idx)); + else if (vname == "miniPFRelIso_diff_all_chg") + input_vars[vname] = static_cast(tas::Muon_miniPFRelIso_all().at(idx) - tas::Muon_miniPFRelIso_chg().at(idx)); + else if (vname == "jetPtRatio") + input_vars[vname] = static_cast(1. / (tas::Muon_jetRelIso().at(idx) + 1.)); + else if (vname == "log_abs_dxy") + input_vars[vname] = static_cast(std::log(std::abs(tas::Muon_dxy().at(idx)))); + else if (vname == "log_abs_dz") + input_vars[vname] = static_cast(std::log(std::abs(tas::Muon_dz().at(idx)))); + else if (vname == "sip3d") + input_vars[vname] = static_cast(tas::Muon_sip3d().at(idx)); + else if (vname == "segmentComp") + input_vars[vname] = static_cast(tas::Muon_segmentComp().at(idx)); + else if (vname == "miniPFRelIso_chg") + input_vars[vname] = static_cast(tas::Muon_miniPFRelIso_chg().at(idx)); + else if (vname == "jetPtRelv2") + input_vars[vname] = static_cast(tas::Muon_jetPtRelv2().at(idx)); + else if (vname == "jetNDauCharged") + input_vars[vname] = static_cast(tas::Muon_jetNDauCharged().at(idx)); + else if (vname == "pfRelIso03_all") + input_vars[vname] = static_cast(tas::Muon_pfRelIso03_all().at(idx)); + else if (vname == "ak4jet:btagDeepFlavB") + { + if (tas::Muon_jetIdx().at(idx) == -1) input_vars[vname] = static_cast(0.); + if (tas::Muon_jetIdx().at(idx) != -1) input_vars[vname] = static_cast(tas::Jet_btagDeepFlavB().at(tas::Muon_jetIdx().at(idx))); + } + else + { + std::cerr << "WWZ::computeMuonTopMVAScore: Input variable name " << vname << " does not match to a corresponding variable" << endl; + std::cerr << "Have you loaded the XGBoost binary? i.e. did you call muonLoadMVA()?" << std::endl; + assert(0); + } + } + + muon_mvareader_map->eval(input_vars, res); + + return res; +} + bool WWZ::muonID(int idx, WWZ::IDLevel id_level, int year) { // Year-specific checks switch (year) { diff --git a/NanoCORE/MuonSelections.h b/NanoCORE/MuonSelections.h index 871d994..bfeed36 100644 --- a/NanoCORE/MuonSelections.h +++ b/NanoCORE/MuonSelections.h @@ -2,6 +2,7 @@ #define MUONSELECTIONS_H #include "Nano.h" #include "Base.h" +#include "Tools/xgboost/XGBoostInterface.h" namespace SS { bool muonID(unsigned int idx, SS::IDLevel id_level, int year); @@ -15,6 +16,9 @@ namespace ttH { } namespace WWZ { + extern std::shared_ptr muon_mvareader_map; + void muonLoadMVA(int year, bool isAPV); + float computeMuonTopMVAScore(unsigned int idx); bool muonID(int idx, WWZ::IDLevel id_level, int year); bool muon2016ID(unsigned int idx, WWZ::IDLevel id_level); bool muon2017ID(unsigned int idx, WWZ::IDLevel id_level); diff --git a/NanoCORE/Tools/xgboost/MLWrapper.h b/NanoCORE/Tools/xgboost/MLWrapper.h new file mode 100644 index 0000000..57ff319 --- /dev/null +++ b/NanoCORE/Tools/xgboost/MLWrapper.h @@ -0,0 +1,17 @@ +#ifndef MLWRAPPER_H +#define MLWRAPPER_H + +#include +#include + +class MLWrapper{ +public: + + MLWrapper(){}; + virtual ~MLWrapper(){}; + + virtual bool build(std::string fname, std::vector const& varnames, float missing_entry_val) = 0; + +}; + +#endif diff --git a/NanoCORE/Tools/xgboost/XGBoostInterface.cc b/NanoCORE/Tools/xgboost/XGBoostInterface.cc new file mode 100644 index 0000000..f2a1e12 --- /dev/null +++ b/NanoCORE/Tools/xgboost/XGBoostInterface.cc @@ -0,0 +1,41 @@ +#include +#include +#include +//#include +//#include "/cvmfs/cms.cern.ch/slc7_amd64_gcc900/external/py3-xgboost/0.90-ghbfee2/lib/python3.8/site-packages/xgboost/include/xgboost/c_api.h" +#include "XGBoostInterface.hpp" + +XGBoostInterface::XGBoostInterface() : MLWrapper(), booster(nullptr), defval(0) {} + +XGBoostInterface::~XGBoostInterface() +{ + SAFE_XGBOOST(XGBoosterFree(*booster)); + delete booster; +} + +bool XGBoostInterface::build(std::string fname, std::vector const &varnames, float missing_entry_val) +{ + + if (booster) + { + std::cerr << "XGBoostInterface::build: The booster is already built." << endl; + return false; + } + if (fname == "") + { + std::cerr << "XGBoostInterface::build: The file name is an empty string. This function should be called to load models from a file." << endl; + assert(0); + } + + defval = missing_entry_val; + variable_names = varnames; + + booster = new BoosterHandle; + SAFE_XGBOOST(XGBoosterCreate(nullptr, 0, booster)); + + // std::cout << "XGBoostInterface::build: A new xgboost is created. Loading the model in " << fname << "..." << endl; + + SAFE_XGBOOST(XGBoosterLoadModel(*booster, fname.data())); + + return true; +} diff --git a/NanoCORE/Tools/xgboost/XGBoostInterface.h b/NanoCORE/Tools/xgboost/XGBoostInterface.h new file mode 100644 index 0000000..8000627 --- /dev/null +++ b/NanoCORE/Tools/xgboost/XGBoostInterface.h @@ -0,0 +1,31 @@ +#ifndef XGBOOSTINTERFACE_H +#define XGBOOSTINTERFACE_H + +#include +//#include "${XGBOOST_PATH}/include/xgboost/c_api.h" +//#include "/cvmfs/cms.cern.ch/slc7_amd64_gcc900/external/py3-xgboost/0.90-ghbfee2/lib/python3.8/site-packages/xgboost/include/xgboost/c_api.h" +#include "MLWrapper.h" + +class XGBoostInterface : public MLWrapper +{ + protected: + BoosterHandle *booster; + float defval; + std::vector variable_names; + + public: + XGBoostInterface(); + virtual ~XGBoostInterface(); + + bool build(std::string fname, std::vector const &varnames, float missing_entry_val); + + std::vector const &getVariableNames() const { return variable_names; } + + BoosterHandle *const &getBooster() const { return booster; } + + template bool eval(std::unordered_map const &vars, std::vector &res); + template bool eval(std::unordered_map const &vars, T &res); +}; + +#endif + diff --git a/NanoCORE/Tools/xgboost/XGBoostInterface.hpp b/NanoCORE/Tools/xgboost/XGBoostInterface.hpp new file mode 100644 index 0000000..682bf70 --- /dev/null +++ b/NanoCORE/Tools/xgboost/XGBoostInterface.hpp @@ -0,0 +1,59 @@ +#ifndef XGBOOSTINTERFACE_HPP +#define XGBOOSTINTERFACE_HPP + +#include +//#include "/cvmfs/cms.cern.ch/slc7_amd64_gcc900/external/py3-xgboost/0.90-ghbfee2/lib/python3.8/site-packages/xgboost/include/xgboost/c_api.h" +#include "XGBoostInterface.h" + +using namespace std; + +#define SAFE_XGBOOST(CALL) \ +{ int err_call = (CALL); if (err_call!=0){ std::cout << "Call '" << #CALL << "' returned error code " << err_call << ". XGBoost last error: " << XGBGetLastError() << std::endl; } } + +template bool XGBoostInterface::eval(std::unordered_map const& vars, std::vector& res){ + + res.clear(); + + constexpr unsigned long long nSample = 1; + const unsigned long long nFeatures = variable_names.size(); + float* data_arr = new float[nFeatures]; // array containing the data values input into XGBoost + float* data_arr_ptr = &(data_arr[0]); + for (auto& vv:variable_names){ + auto it_vars = vars.find(vv); + if (it_vars==vars.end()) *data_arr_ptr = defval; + else *data_arr_ptr = it_vars->second; + data_arr_ptr++; + }; + + bst_ulong nout = 0; + const float* score; + DMatrixHandle dvalues; + SAFE_XGBOOST(XGDMatrixCreateFromMat(data_arr, nSample, nFeatures, defval, &dvalues)); + SAFE_XGBOOST(XGBoosterPredict(*booster, dvalues, 0, 0, &nout, &score)); + SAFE_XGBOOST(XGDMatrixFree(dvalues)); + + res.clear(); + res.reserve(nout); + for (bst_ulong rr=0; rr(score[rr])); + + delete[] data_arr; + return true; +} + +template bool XGBoostInterface::eval(std::unordered_map const& vars, T& res){ + std::vector vres; + bool success = this->eval(vars, vres); + if (vres.empty() || vres.size()!=1){ + std::cout << "XGBoostInterface::eval: The vector of results has size = " << vres.size() << " != 1." << std::endl; + assert(0); + success = false; + } + + res = vres.front(); + return success; +} + +template bool XGBoostInterface::eval(std::unordered_map const& vars, float& res); +template bool XGBoostInterface::eval(std::unordered_map const& vars, double& res); + +#endif diff --git a/NanoCORE/data/TopLeptonMVA/el_TOPUL16APV_XGB.weights.bin b/NanoCORE/data/TopLeptonMVA/el_TOPUL16APV_XGB.weights.bin new file mode 100644 index 0000000..de9dfeb Binary files /dev/null and b/NanoCORE/data/TopLeptonMVA/el_TOPUL16APV_XGB.weights.bin differ diff --git a/NanoCORE/data/TopLeptonMVA/el_TOPUL16_XGB.weights.bin b/NanoCORE/data/TopLeptonMVA/el_TOPUL16_XGB.weights.bin new file mode 100644 index 0000000..a11a747 Binary files /dev/null and b/NanoCORE/data/TopLeptonMVA/el_TOPUL16_XGB.weights.bin differ diff --git a/NanoCORE/data/TopLeptonMVA/el_TOPUL17_XGB.weights.bin b/NanoCORE/data/TopLeptonMVA/el_TOPUL17_XGB.weights.bin new file mode 100644 index 0000000..5be35b6 Binary files /dev/null and b/NanoCORE/data/TopLeptonMVA/el_TOPUL17_XGB.weights.bin differ diff --git a/NanoCORE/data/TopLeptonMVA/el_TOPUL18_XGB.weights.bin b/NanoCORE/data/TopLeptonMVA/el_TOPUL18_XGB.weights.bin new file mode 100644 index 0000000..125444d Binary files /dev/null and b/NanoCORE/data/TopLeptonMVA/el_TOPUL18_XGB.weights.bin differ diff --git a/NanoCORE/data/TopLeptonMVA/el_TOPv2UL16APV_XGB.weights.bin b/NanoCORE/data/TopLeptonMVA/el_TOPv2UL16APV_XGB.weights.bin new file mode 100644 index 0000000..90efca3 Binary files /dev/null and b/NanoCORE/data/TopLeptonMVA/el_TOPv2UL16APV_XGB.weights.bin differ diff --git a/NanoCORE/data/TopLeptonMVA/el_TOPv2UL16_XGB.weights.bin b/NanoCORE/data/TopLeptonMVA/el_TOPv2UL16_XGB.weights.bin new file mode 100644 index 0000000..bf28234 Binary files /dev/null and b/NanoCORE/data/TopLeptonMVA/el_TOPv2UL16_XGB.weights.bin differ diff --git a/NanoCORE/data/TopLeptonMVA/el_TOPv2UL17_XGB.weights.bin b/NanoCORE/data/TopLeptonMVA/el_TOPv2UL17_XGB.weights.bin new file mode 100644 index 0000000..85df15f Binary files /dev/null and b/NanoCORE/data/TopLeptonMVA/el_TOPv2UL17_XGB.weights.bin differ diff --git a/NanoCORE/data/TopLeptonMVA/el_TOPv2UL18_XGB.weights.bin b/NanoCORE/data/TopLeptonMVA/el_TOPv2UL18_XGB.weights.bin new file mode 100644 index 0000000..43547dd Binary files /dev/null and b/NanoCORE/data/TopLeptonMVA/el_TOPv2UL18_XGB.weights.bin differ diff --git a/NanoCORE/data/TopLeptonMVA/mu_TOPUL16APV_XGB.weights.bin b/NanoCORE/data/TopLeptonMVA/mu_TOPUL16APV_XGB.weights.bin new file mode 100644 index 0000000..75c8762 Binary files /dev/null and b/NanoCORE/data/TopLeptonMVA/mu_TOPUL16APV_XGB.weights.bin differ diff --git a/NanoCORE/data/TopLeptonMVA/mu_TOPUL16_XGB.weights.bin b/NanoCORE/data/TopLeptonMVA/mu_TOPUL16_XGB.weights.bin new file mode 100644 index 0000000..62ab32c Binary files /dev/null and b/NanoCORE/data/TopLeptonMVA/mu_TOPUL16_XGB.weights.bin differ diff --git a/NanoCORE/data/TopLeptonMVA/mu_TOPUL17_XGB.weights.bin b/NanoCORE/data/TopLeptonMVA/mu_TOPUL17_XGB.weights.bin new file mode 100644 index 0000000..8dbfff3 Binary files /dev/null and b/NanoCORE/data/TopLeptonMVA/mu_TOPUL17_XGB.weights.bin differ diff --git a/NanoCORE/data/TopLeptonMVA/mu_TOPUL18_XGB.weights.bin b/NanoCORE/data/TopLeptonMVA/mu_TOPUL18_XGB.weights.bin new file mode 100644 index 0000000..4f16087 Binary files /dev/null and b/NanoCORE/data/TopLeptonMVA/mu_TOPUL18_XGB.weights.bin differ diff --git a/NanoCORE/data/TopLeptonMVA/mu_TOPv2UL16APV_XGB.weights.bin b/NanoCORE/data/TopLeptonMVA/mu_TOPv2UL16APV_XGB.weights.bin new file mode 100644 index 0000000..358a2c0 Binary files /dev/null and b/NanoCORE/data/TopLeptonMVA/mu_TOPv2UL16APV_XGB.weights.bin differ diff --git a/NanoCORE/data/TopLeptonMVA/mu_TOPv2UL16_XGB.weights.bin b/NanoCORE/data/TopLeptonMVA/mu_TOPv2UL16_XGB.weights.bin new file mode 100644 index 0000000..511c411 Binary files /dev/null and b/NanoCORE/data/TopLeptonMVA/mu_TOPv2UL16_XGB.weights.bin differ diff --git a/NanoCORE/data/TopLeptonMVA/mu_TOPv2UL17_XGB.weights.bin b/NanoCORE/data/TopLeptonMVA/mu_TOPv2UL17_XGB.weights.bin new file mode 100644 index 0000000..391a250 Binary files /dev/null and b/NanoCORE/data/TopLeptonMVA/mu_TOPv2UL17_XGB.weights.bin differ diff --git a/NanoCORE/data/TopLeptonMVA/mu_TOPv2UL18_XGB.weights.bin b/NanoCORE/data/TopLeptonMVA/mu_TOPv2UL18_XGB.weights.bin new file mode 100644 index 0000000..db25401 Binary files /dev/null and b/NanoCORE/data/TopLeptonMVA/mu_TOPv2UL18_XGB.weights.bin differ