diff --git a/PhysicsAnalysis/Interfaces/TriggerAnalysisInterfaces/TriggerAnalysisInterfaces/ITrigGlobalEfficiencyCorrectionTool.h b/PhysicsAnalysis/Interfaces/TriggerAnalysisInterfaces/TriggerAnalysisInterfaces/ITrigGlobalEfficiencyCorrectionTool.h index d01f664e7771735812a4d4140619f5e6f2186c71..f454d5a836311c6f8f164632b580533d041902fb 100644 --- a/PhysicsAnalysis/Interfaces/TriggerAnalysisInterfaces/TriggerAnalysisInterfaces/ITrigGlobalEfficiencyCorrectionTool.h +++ b/PhysicsAnalysis/Interfaces/TriggerAnalysisInterfaces/TriggerAnalysisInterfaces/ITrigGlobalEfficiencyCorrectionTool.h @@ -9,38 +9,104 @@ #include "PATInterfaces/ISystematicsTool.h" #include "PATInterfaces/CorrectionCode.h" -#include "xAODEgamma/ElectronFwd.h" +#include "xAODEgamma/Electron.h" #include "xAODMuon/Muon.h" -#include "xAODEgamma/PhotonFwd.h" +#include "xAODEgamma/Photon.h" #include <vector> -#include <map> +#include <type_traits> class ITrigGlobalEfficiencyCorrectionTool : public virtual CP::ISystematicsTool { public: ASG_TOOL_INTERFACE(ITrigGlobalEfficiencyCorrectionTool) + + template<typename Arg> static constexpr bool validArgs(unsigned nTrailingDoubles); + template<typename Arg1, typename Arg2, typename... OtherArgs> static constexpr bool validArgs(unsigned nTrailingDoubles); virtual CP::CorrectionCode getEfficiencyScaleFactor(const std::vector<const xAOD::IParticle*>& particles, double& efficiencyScaleFactor) = 0; - virtual CP::CorrectionCode getEfficiencyScaleFactor(unsigned runNumber, const std::vector<const xAOD::IParticle*>& particles, double& efficiencyScaleFactor) = 0; virtual CP::CorrectionCode getEfficiency(const std::vector<const xAOD::IParticle*>& particles, double& efficiencyData, double& efficiencyMc) = 0; - virtual CP::CorrectionCode getEfficiency(unsigned runNumber, const std::vector<const xAOD::IParticle*>& particles, double& efficiencyData, double& efficiencyMc) = 0; + virtual CP::CorrectionCode checkTriggerMatching(bool& matched, const std::vector<const xAOD::IParticle*>& particles) = 0; - virtual CP::CorrectionCode getEfficiencyScaleFactor(const std::vector<const xAOD::Electron*>& electrons, - const std::vector<const xAOD::Muon*>& muons, double& efficiencyScaleFactor) = 0; - virtual CP::CorrectionCode getEfficiencyScaleFactor(unsigned runNumber, const std::vector<const xAOD::Electron*>& electrons, - const std::vector<const xAOD::Muon*>& muons, double& efficiencyScaleFactor) = 0; - virtual CP::CorrectionCode getEfficiency(const std::vector<const xAOD::Electron*>& electrons, - const std::vector<const xAOD::Muon*>& muons, double& efficiencyData, double& efficiencyMc) = 0; - virtual CP::CorrectionCode getEfficiency(unsigned runNumber, const std::vector<const xAOD::Electron*>& electrons, - const std::vector<const xAOD::Muon*>& muons, double& efficiencyData, double& efficiencyMc) = 0; - - virtual CP::CorrectionCode getEfficiencyScaleFactor(const std::vector<const xAOD::Photon*>& photons, double& efficiencyScaleFactor) = 0; - virtual CP::CorrectionCode getEfficiency(const std::vector<const xAOD::Photon*>& photons, double& efficiencyData, double& efficiencyMc) = 0; + /// Alternatively, the list of particles can be supplied via one or several vectors of xAOD::Electron*/Muon*/Photon* + /// The generic signature is getEfficiencyScaleFactor((const) vector<(const)Type1*>&, ..., (const) vector<(const)TypeN*>&, double& efficiencyScaleFactor) + /// e.g. getEfficiencyScaleFactor(electrons, muons, sf); + /// getEfficiencyScaleFactor(photons, sf); + /// getEfficiencyScaleFactor(muons, electrons, photons, sf); + /// don't forget the last argument(s)! (scale factor for getEfficiencyScaleFactor(), data and MC efficiencies for getEfficiency()) + template<typename... Args> + auto getEfficiencyScaleFactor(Args&... args) -> std::enable_if_t<validArgs<Args...>(1), CP::CorrectionCode>; + template<typename... Args> + auto getEfficiency(Args&... args) -> std::enable_if_t<validArgs<Args...>(2), CP::CorrectionCode>; + template<typename... Args> + auto checkTriggerMatching(bool& matched, Args&... args) -> std::enable_if_t<validArgs<Args...>(0), CP::CorrectionCode>; - virtual CP::CorrectionCode checkTriggerMatching(bool& matched, const std::vector<const xAOD::IParticle*>& particles) = 0; - virtual CP::CorrectionCode checkTriggerMatching(bool& matched, const std::vector<const xAOD::Electron*>& electrons, const std::vector<const xAOD::Muon*>& muons) = 0; - virtual CP::CorrectionCode checkTriggerMatching(bool& matched, const std::vector<const xAOD::Photon*>& photons) = 0; + /// This will fill the 'triggers' argument with the names of the triggers relevant for the current run number, among those specified in the tool configuration + virtual CP::CorrectionCode getRelevantTriggers(std::vector<std::string>& triggers) = 0; + + /// These should in principle not be used (except by unit tests), as the CP tools require the EventInfo decoration "RandomRunNumber" to be present + virtual CP::CorrectionCode getEfficiencyScaleFactor(unsigned runNumber, const std::vector<const xAOD::IParticle*>& particles, double& efficiencyScaleFactor) = 0; + virtual CP::CorrectionCode getEfficiency(unsigned runNumber, const std::vector<const xAOD::IParticle*>& particles, double& efficiencyData, double& efficiencyMc) = 0; + +protected: + double* handleArg(double& arg, std::vector<const xAOD::IParticle*>&) { return &arg; } + template<typename P> double* handleArg(const std::vector<P>& arg, std::vector<const xAOD::IParticle*>& particles) + { + for(auto ptr : arg) particles.push_back(static_cast<const xAOD::IParticle*>(ptr)); + return nullptr; + } }; +template<typename Arg> +constexpr bool ITrigGlobalEfficiencyCorrectionTool::validArgs(unsigned nTrailingDoubles) +{ + if(std::is_same<double, Arg>::value) return (nTrailingDoubles==1); + using P = std::remove_cv_t<Arg>; + return std::is_same<P, std::vector<xAOD::Electron*>>::value + || std::is_same<P, std::vector<const xAOD::Electron*>>::value + || std::is_same<P, std::vector<xAOD::Muon*>>::value + || std::is_same<P, std::vector<const xAOD::Muon*>>::value + || std::is_same<P, std::vector<xAOD::Photon*>>::value + || std::is_same<P, std::vector<const xAOD::Photon*>>::value; +} + +template<typename Arg1, typename Arg2, typename... OtherArgs> +constexpr bool ITrigGlobalEfficiencyCorrectionTool::validArgs(unsigned nTrailingDoubles) +{ + bool xs [] = { std::is_same<OtherArgs, double>::value..., true }; + for(bool x : xs) if(!x) return validArgs<Arg1>(0) && validArgs<Arg2, OtherArgs...>(nTrailingDoubles); + unsigned nTD = sizeof...(OtherArgs); + if(nTD == nTrailingDoubles) return validArgs<Arg1>(0) && validArgs<Arg2>(0); + if(nTD == nTrailingDoubles-1) return validArgs<Arg1>(0) && std::is_same<Arg2, double>::value; + if(nTD == nTrailingDoubles-2) return std::is_same<Arg1, double>::value && std::is_same<Arg2, double>::value; + return false; +} + +template<typename... Args> +auto ITrigGlobalEfficiencyCorrectionTool::getEfficiencyScaleFactor(Args&... args) + -> std::enable_if_t<validArgs<Args...>(1), CP::CorrectionCode> +{ + std::vector<const xAOD::IParticle*> particles; + double* sf[] = { nullptr, handleArg(args, particles)... }; + return getEfficiencyScaleFactor(particles, *sf[sizeof...(Args)]); +} + +template<typename... Args> +auto ITrigGlobalEfficiencyCorrectionTool::getEfficiency(Args&... args) + -> std::enable_if_t<validArgs<Args...>(2), CP::CorrectionCode> +{ + std::vector<const xAOD::IParticle*> particles; + double* eff[] = { nullptr, handleArg(args, particles)... }; + return getEfficiency(particles, *eff[sizeof...(Args)-1], *eff[sizeof...(Args)]); +} + +template<typename... Args> +auto ITrigGlobalEfficiencyCorrectionTool::checkTriggerMatching(bool& matched, Args&... args) + -> std::enable_if_t<validArgs<Args...>(0), CP::CorrectionCode> +{ + std::vector<const xAOD::IParticle*> particles; + double* eff[] __attribute__((unused)) = { nullptr, handleArg(args, particles)... }; + return checkTriggerMatching(matched, particles); +} + #endif //> !TRIGGERANALYSISINTERFACES_ITRIGGLOBALEFFICIENCYCORRECTIONTOOL_H diff --git a/PhysicsAnalysis/SUSYPhys/SUSYTools/Root/Trigger.cxx b/PhysicsAnalysis/SUSYPhys/SUSYTools/Root/Trigger.cxx index 51e4eaa4041941c7f8645c61280e6883878b2ac3..a1842674fc8b86d09d14cbe79d9910f2dc43dda4 100644 --- a/PhysicsAnalysis/SUSYPhys/SUSYTools/Root/Trigger.cxx +++ b/PhysicsAnalysis/SUSYPhys/SUSYTools/Root/Trigger.cxx @@ -374,8 +374,6 @@ double SUSYObjDef_xAOD::GetTriggerGlobalEfficiencySF(const xAOD::ElectronContain return trig_sf; } - unsigned runNumber = (unsigned) this->GetRandomRunNumber(); - std::vector<const xAOD::Electron*> elec_trig; elec_trig.clear(); for (const auto& electron : electrons) { @@ -405,10 +403,10 @@ double SUSYObjDef_xAOD::GetTriggerGlobalEfficiencySF(const xAOD::ElectronContain CP::CorrectionCode result; if ((elec_trig.size()+muon_trig.size())>1 && trigExpr=="diLepton" && matched) { - result = m_trigGlobalEffCorrTool_diLep->getEfficiencyScaleFactor( runNumber, elec_trig, muon_trig, trig_sf); + result = m_trigGlobalEffCorrTool_diLep->getEfficiencyScaleFactor( elec_trig, muon_trig, trig_sf); } else if ((elec_trig.size()+muon_trig.size())>2 && trigExpr=="multiLepton" && matched) { - result = m_trigGlobalEffCorrTool_multiLep->getEfficiencyScaleFactor( runNumber, elec_trig, muon_trig, trig_sf); + result = m_trigGlobalEffCorrTool_multiLep->getEfficiencyScaleFactor( elec_trig, muon_trig, trig_sf); } switch (result) { @@ -436,8 +434,6 @@ double SUSYObjDef_xAOD::GetTriggerGlobalEfficiency(const xAOD::ElectronContainer return trig_eff; } - unsigned runNumber = (unsigned) this->GetRandomRunNumber(); - std::vector<const xAOD::Electron*> elec_trig; elec_trig.clear(); for (const auto& electron : electrons) { @@ -467,10 +463,10 @@ double SUSYObjDef_xAOD::GetTriggerGlobalEfficiency(const xAOD::ElectronContainer CP::CorrectionCode result; if ((elec_trig.size()+muon_trig.size())>1 && trigExpr=="diLepton" && matched) { - result = m_trigGlobalEffCorrTool_diLep->getEfficiency( runNumber, elec_trig, muon_trig, trig_eff_data, trig_eff); + result = m_trigGlobalEffCorrTool_diLep->getEfficiency( elec_trig, muon_trig, trig_eff_data, trig_eff); } else if ((elec_trig.size()+muon_trig.size())>2 && trigExpr=="multiLepton" && matched) { - result = m_trigGlobalEffCorrTool_multiLep->getEfficiency( runNumber, elec_trig, muon_trig, trig_eff_data, trig_eff); + result = m_trigGlobalEffCorrTool_multiLep->getEfficiency( elec_trig, muon_trig, trig_eff_data, trig_eff); } switch (result) { diff --git a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/Root/Calculator.cxx b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/Root/Calculator.cxx index aac286df55d08a94ee817d6c7c5e8c3e20ea081e..f7feade5f1fa4035f03e277935db03c5505391a1 100644 --- a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/Root/Calculator.cxx +++ b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/Root/Calculator.cxx @@ -11,6 +11,7 @@ #include "AsgTools/AsgMessaging.h" #include <random> +#include <iterator> using namespace TrigGlobEffCorr; using std::placeholders::_1; @@ -18,223 +19,6 @@ using std::placeholders::_2; using std::placeholders::_3; using std::placeholders::_4; -Calculator::Helper::Helper(const std::vector<TrigDef>& defs) : - m_n1L(std::count_if(defs.cbegin(), defs.cend(), [](const TrigDef& td)->bool{ return td.type&TT_SINGLELEPTON_FLAG;})), - m_n2L(std::count_if(defs.cbegin(), defs.cend(), [](const TrigDef& td)->bool{ return td.type&TT_DILEPTON_FLAG;})), - m_n3L(std::count_if(defs.cbegin(), defs.cend(), [](const TrigDef& td)->bool{ return td.type&TT_TRILEPTON_FLAG;})), - m_nPhotonTriggers(std::count_if(defs.cbegin(), defs.cend(), [](const TrigDef& td)->bool{ return td.type&TT_PHOTON_FLAG;})), - m_func(nullptr), m_defs(defs) -{ -} - -namespace TrigGlobEffCorr -{ - -template<typename Trig1L> -bool Calculator::Helper::bind_1x1L() -{ - auto n1 = count<Trig1L>(); - if(!n1 || n1!=m_defs.size()) return false; - if(n1>1) - { - using fnptr = bool(Calculator::*)(const LeptonList&, unsigned, const flat_set<Trig1L>&, Efficiencies&); - m_func = std::bind<fnptr>(&Calculator::globalEfficiency_Several1L, ::_1, ::_2, ::_3, get_all<Trig1L>(), ::_4); - } - else - { - using fnptr = bool(Calculator::*)(const LeptonList&, unsigned, const Trig1L, Efficiencies&); - m_func = std::bind<fnptr>(&Calculator::globalEfficiency_One1L, ::_1, ::_2, ::_3, get<Trig1L>(0), ::_4); - } - return true; -} - -template<> -bool Calculator::Helper::bind_1x1L<void>() -{ - auto nE = count<Trig1E>(), nM = count<Trig1MU>(), n1 = nE+nM; - if(!n1 || n1!=m_defs.size()) return false; - if(nE>1 || nM>1) - { - using fnptr = bool(Calculator::*)(const LeptonList&, unsigned, const flat_set<Trig1E>&, const flat_set<Trig1MU>&, Efficiencies&); - m_func = std::bind<fnptr>(&Calculator::globalEfficiency_Several1L, ::_1, ::_2, ::_3, get_all<Trig1E>(), get_all<Trig1MU>(), ::_4); - } - else if(nE>0 && nM>0) - { - m_func = std::bind(&Calculator::globalEfficiency_Two1L, ::_1, ::_2, ::_3, get<Trig1E>(0), get<Trig1MU>(0), ::_4); - } - else if(!nE) return bind_1x1L<Trig1MU>(); - else return bind_1x1L<Trig1E>(); - return true; -} - -template<typename Trig2L> -bool Calculator::Helper::bind_1x2L_singleFlavour() -{ - using Trig1L = typename Trig2L::companionTrig1LType; - auto n2 = count<Trig2L>(), n1 = count<Trig1L>(); - if(n2!=1 || n2+n1!=m_defs.size()) return false; - if(n1 > 0) - { - using fnptr = bool(Calculator::*)(const LeptonList&, unsigned, const Trig2L, const flat_set<Trig1L>&, Efficiencies&); - m_func = std::bind<fnptr>(&Calculator::globalEfficiency_One2LSeveral1L, ::_1, ::_2, ::_3, get<Trig2L>(0), get_all<Trig1L>(), ::_4); - } - else - { - using fnptr = bool(Calculator::*)(const LeptonList&, unsigned, const Trig2L, Efficiencies&); - m_func = std::bind<fnptr>(&Calculator::globalEfficiency_One2L, ::_1, ::_2, ::_3, get<Trig2L>(0), ::_4); - } - return true; -} - -template<typename Trig2L> -bool Calculator::Helper::bind_1x2L() -{ - using Trig1L = typename Trig2L::companionTrig1LType; - std::size_t n2 = count<Trig2L>(), n1 = count<Trig1E>()+count<Trig1MU>(), n1sf = count<Trig1L>(); - if(n2!=1 || n2+n1!=m_defs.size()) return false; - if(n1 > n1sf) - { - using fnptr = bool(Calculator::*)(const LeptonList&, unsigned, const Trig2L, const flat_set<Trig1E>&, const flat_set<Trig1MU>&, Efficiencies&); - m_func = std::bind<fnptr>(&Calculator::globalEfficiency_One2LSeveral1L, ::_1, ::_2, ::_3, get<Trig2L>(0), get_all<Trig1E>(), get_all<Trig1MU>(), ::_4); - return true; - } - return bind_1x2L_singleFlavour<Trig2L>(); -} - -template<> -bool Calculator::Helper::bind_1x2L<TrigEMU>() -{ - auto n2 = count<TrigEMU>(), n1 = count<Trig1E>()+count<Trig1MU>(); - if(n2!=1 || n2+n1!=m_defs.size()) return false; - if(n1 > 0) - { - using fnptr = bool(Calculator::*)(const LeptonList&, unsigned, const TrigEMU, const flat_set<Trig1E>&, const flat_set<Trig1MU>&, Efficiencies&); - m_func = std::bind<fnptr>(&Calculator::globalEfficiency_One2LSeveral1L, ::_1, ::_2, ::_3, get<TrigEMU>(0), get_all<Trig1E>(), get_all<Trig1MU>(), ::_4); - } - else - { - using fnptr = bool(Calculator::*)(const LeptonList&, unsigned, const TrigEMU, Efficiencies&); - m_func = std::bind<fnptr>(&Calculator::globalEfficiency_One2L, ::_1, ::_2, ::_3, get<TrigEMU>(0), ::_4); - } - return true; -} - -template<typename Trig2L1, typename Trig2L2> -bool Calculator::Helper::bind_2x2L_singleFlavour() -{ - static_assert((Trig2L1::object()==Trig2L2::object()) && !Trig2L1::mixed() && !Trig2L2::mixed(), ""); - using Trig1L = typename Trig2L1::companionTrig1LType; - constexpr bool sameType = (Trig2L1::type()==Trig2L2::type()); - auto n2 = count<Trig2L1>()+(sameType?0:count<Trig2L2>()), n1 = count<Trig1L>(); - if(n2!=2 || n2+n1!=m_defs.size()) return false; - using Trig2Lsym = typename std::conditional<Trig2L1::is2Lasym(), Trig2L2, Trig2L1>::type; - using Trig2L = typename std::conditional<Trig2L1::is2Lasym(), Trig2L1, Trig2L2>::type; - using fnptr = bool(Calculator::*)(const LeptonList& leptons, unsigned runNumber, const Trig2L, const Trig2Lsym, const flat_set<Trig1L>&, Efficiencies&); - m_func = std::bind<fnptr>(&Calculator::globalEfficiency_Two2LSeveral1L, ::_1, ::_2, ::_3, get<Trig2L>(0), get<Trig2Lsym>(sameType*1), get_all<Trig1L>(), ::_4); - return true; -} - -template<typename Trig2E, typename Trig2MU> -bool Calculator::Helper::bind_3x2L() -{ - static_assert(Trig2E::object()==xAOD::Type::Electron && Trig2MU::object()==xAOD::Type::Muon, ""); - std::size_t n2E = count<Trig2E>(), n2M = count<Trig2MU>(), nEM = count<TrigEMU>(), n1 = count<Trig1E>()+count<Trig1MU>(); - if(n2E>1 || n2M>1 || nEM>1 || n2E+n2M+nEM+n1!=m_defs.size()) return false; - if(n1 > 0) - { - using fnptr = bool(Calculator::*)(const LeptonList&, unsigned, const Trig2E, const Trig2MU, - const TrigEMU, const flat_set<Trig1E>&, const flat_set<Trig1MU>&, Efficiencies&); - m_func = std::bind<fnptr>(&Calculator::globalEfficiency_Three2LSeveral1L, ::_1, ::_2, ::_3, get<Trig2E>(0), get<Trig2MU>(0), - get<TrigEMU>(0), get_all<Trig1E>(), get_all<Trig1MU>(), ::_4); - } - else - { - using fnptr = bool(Calculator::*)(const LeptonList&, unsigned, const Trig2E, const Trig2MU, const TrigEMU, Efficiencies&); - m_func = std::bind<fnptr>(&Calculator::globalEfficiency_Three2L, ::_1, ::_2, ::_3, get<Trig2E>(0), get<Trig2MU>(0), get<TrigEMU>(0), ::_4); - } - return true; -} - -template<typename Trig2E, typename Trig2MU> -bool Calculator::Helper::bind_6x2L() -{ - static_assert(Trig2E::object()==xAOD::Type::Electron && Trig2MU::object()==xAOD::Type::Muon, ""); - constexpr bool two2Esym = std::is_same<Trig2E, Trig2Esym>::value, two2MUsym = std::is_same<Trig2MU, Trig2MUsym>::value; - auto n2E = count<Trig2Esym>() + (two2Esym? 0 : count<Trig2E>()); - auto n2M = count<Trig2MUsym>() + (two2MUsym? 0 : count<Trig2MU>()); - auto nEM = count<TrigEMU>(), n1 = count<Trig1E>()+count<Trig1MU>(); - if(n2E>2 || n2M>2 || count<Trig2Easym>()>1 || count<Trig2MUasym>()>1 || nEM>2 || n2E+n2M+nEM+n1!=m_defs.size()) return false; - Trig2Esym trig2Esym = get<Trig2Esym>(two2Esym? 1 : 0); - Trig2MUsym trig2MUsym = get<Trig2MUsym>(two2MUsym? 1 : 0); - using fnptr = bool(Calculator::*)(const LeptonList&, unsigned, const Trig2E, const Trig2Esym, const Trig2MU, const Trig2MUsym, - const TrigEMU, const TrigEMU, const flat_set<Trig1E>&, const flat_set<Trig1MU>&, Efficiencies&); - m_func = std::bind<fnptr>(&Calculator::globalEfficiency_Six2LSeveral1L, ::_1, ::_2, ::_3, get<Trig2E>(0), trig2Esym, get<Trig2MU>(0), trig2MUsym, - get<TrigEMU>(0), get<TrigEMU>(1), get_all<Trig1E>(), get_all<Trig1MU>(), ::_4); - return true; -} - -template<typename Trig3L> -bool Calculator::Helper::bind_1x3L() -{ - std::size_t n3 = count<Trig3L>(); - if(n3!=1 || n3!=m_defs.size()) return false; - using fnptr = bool(Calculator::*)(const LeptonList&, unsigned, const Trig3L, Efficiencies&); - m_func = std::bind<fnptr>(&Calculator::globalEfficiency_One3L, ::_1, ::_2, ::_3, get<Trig3L>(0), ::_4); - return true; -} - -template<typename Trig3L1, typename Trig3L2> -bool Calculator::Helper::bind_2x3L() -{ - static_assert((Trig3L1::type()!=Trig3L2::type()) && Trig3L1::is3Lmix() && Trig3L2::is3Lmix(), ""); - std::size_t n31 = count<Trig3L1>(), n32 = count<Trig3L2>(); - if(n31!=1 || n32!=1 || n31+n32!=m_defs.size()) return false; - using fnptr = bool(Calculator::*)(const LeptonList&, unsigned, const Trig3L1, const Trig3L2, Efficiencies&); - m_func = std::bind<fnptr>(&Calculator::globalEfficiency_Two3L, ::_1, ::_2, ::_3, get<Trig3L1>(0), get<Trig3L2>(0), ::_4); - return true; -} - -template<typename Trig> -Trig Calculator::Helper::get(unsigned index) const -{ - unsigned discarded = 0; - for(auto& def : m_defs) - { - if(def.type != Trig::type()) continue; - if(index < ++discarded) - { - Trig t; - t.set_definition(def); - return t; - } - } - return Trig(); -} - -template<typename Trig> -auto Calculator::Helper::get_all() const -> flat_set<Trig> -{ - flat_set<Trig> trigs; - for(auto& def : m_defs) - { - if(def.type != Trig::type()) continue; - Trig t; - t.set_definition(def); - trigs.emplace(t); - } - return trigs; -} - -bool Calculator::Helper::duplicates() const -{ - for(auto itr1=m_defs.cbegin(); itr1!=m_defs.cend(); ++itr1) - for(auto itr2=itr1+1; itr2!=m_defs.cend(); ++itr2) - if(itr1->type==itr2->type && itr1->leg==itr2->leg) return true; - return false; -} - -} - Calculator::Calculator(TrigGlobalEfficiencyCorrectionTool& parent, unsigned nPeriodsToReserve) : asg::AsgMessaging(&parent), m_parent(&parent) @@ -244,56 +28,23 @@ Calculator::Calculator(TrigGlobalEfficiencyCorrectionTool& parent, unsigned nPer } bool Calculator::addPeriod(ImportData& data, const std::pair<unsigned,unsigned>& boundaries, const std::string& combination, - bool useToys, bool useDefaultElectronTools, std::size_t& uniqueElectronLeg, bool useDefaultPhotonTools, std::size_t& uniquePhotonLeg) + bool useToys, std::size_t& uniqueElectronLeg, std::size_t& uniquePhotonLeg) { bool success = true; m_parent = data.getParent(); - auto triggers = data.parseTriggerString(combination,success); + auto triggers = data.parseTriggerString(combination, success); if(!success) return false; - - uniqueElectronLeg = uniquePhotonLeg = 0; - bool severalElectronLegs = false, severalPhotonLegs = false; - for(auto& trig : triggers) - { - switch(trig.type) - { - case TT_SINGLE_MU: case TT_2MU_ASYM: case TT_2MU_SYM: case TT_3MU_ASYM: case TT_3MU_SYM: - break; - case TT_SINGLE_E: case TT_2E_SYM: case TT_EMU: case TT_3E_SYM: case TT_E_2MU_ASYM: case TT_E_2MU_SYM: - if(!severalElectronLegs) - { - if(uniqueElectronLeg && uniqueElectronLeg!=trig.leg[0]) severalElectronLegs = true; - uniqueElectronLeg = trig.leg[0]; - } - break; - case TT_SINGLE_PH: case TT_2PH_SYM: case TT_3PH_SYM: - if(!severalPhotonLegs) - { - if(uniquePhotonLeg && uniquePhotonLeg!=trig.leg[0]) severalPhotonLegs = true; - uniquePhotonLeg = trig.leg[0]; - } - break; - case TT_2PH_ASYM: case TT_3PH_HALFSYM: case TT_3PH_ASYM: - severalPhotonLegs = true; - break; - default: // other defined triggers have >= 2 distinct electron legs - severalElectronLegs = true; - } - } - if(useDefaultElectronTools && severalElectronLegs) + if(!triggers.size()) { - ATH_MSG_ERROR("The property 'ListOfLegsPerTool' needs to be filled as the specified trigger combination involves several electron trigger legs"); - return false; - } - if(useDefaultPhotonTools && severalPhotonLegs) - { - ATH_MSG_ERROR("The property 'ListOfLegsPerTool' needs to be filled as the specified trigger combination involves several photon trigger legs"); + ATH_MSG_ERROR("The trigger combination is empty!"); return false; } - /// Choose the appropriate function to compute efficiencies for this particular trigger combination + if(!findUniqueLeg(xAOD::Type::Electron, uniqueElectronLeg, triggers)) return false; + if(!findUniqueLeg(xAOD::Type::Photon, uniquePhotonLeg, triggers)) return false; + /// Choose the appropriate function to compute efficiencies for this particular trigger combination Helper helper(triggers); if(helper.duplicates()) { @@ -302,60 +53,8 @@ bool Calculator::addPeriod(ImportData& data, const std::pair<unsigned,unsigned>& } if(!useToys) { - const unsigned n1L = helper.m_n1L, n2L = helper.m_n2L, n3L = helper.m_n3L; - if(!(n1L+n2L+n3L)) - { - ATH_MSG_ERROR("The trigger combination is empty!"); - return false; - } - else if(n1L && !(n2L+n3L)) // only single-lepton triggers - { - success = helper.bind_1x1L(); - } - else if(!helper.m_nPhotonTriggers) - { - - if(n2L==1 && !n3L) // one dilepton trigger (+ single-lepton triggers) - { - success = helper.bind_1x2L<TrigEMU>() || helper.bind_1x2L<Trig2Esym>() || helper.bind_1x2L<Trig2Easym>() - || helper.bind_1x2L<Trig2MUsym>() || helper.bind_1x2L<Trig2MUasym>(); - } - else if(n2L>=2 && n2L<=6 && !n3L) // several dilepton triggers (+ single-lepton triggers) - { - success = helper.bind_3x2L<Trig2Esym,Trig2MUsym>() || helper.bind_3x2L<Trig2Easym,Trig2MUsym>() - || helper.bind_3x2L<Trig2Esym,Trig2MUasym>() || helper.bind_3x2L<Trig2Easym,Trig2MUasym>() - || helper.bind_6x2L<Trig2Esym,Trig2MUsym>() || helper.bind_6x2L<Trig2Easym,Trig2MUsym>() - || helper.bind_6x2L<Trig2Esym,Trig2MUasym>() || helper.bind_6x2L<Trig2Easym,Trig2MUasym>(); - } - else if(n3L==1 && !n2L && !n1L) - { - success = helper.bind_1x3L<Trig3Esym>() || helper.bind_1x3L<Trig3Ehalfsym>() - || helper.bind_1x3L<Trig3MUsym>() || helper.bind_1x3L<Trig3MUhalfsym>() - || helper.bind_1x3L<Trig2EMUsym>() || helper.bind_1x3L<Trig2EMUasym>() - || helper.bind_1x3L<TrigE2MUsym>() || helper.bind_1x3L<TrigE2MUasym>(); - } - else if(n3L==2 && !n2L && !n1L) - { - success = helper.bind_2x3L<Trig2EMUsym,TrigE2MUsym>() || helper.bind_2x3L<Trig2EMUsym,TrigE2MUasym>() - || helper.bind_2x3L<Trig2EMUasym,TrigE2MUsym>() || helper.bind_2x3L<Trig2EMUasym,TrigE2MUasym>(); - } - } - else if(helper.m_nPhotonTriggers == triggers.size()) - { - if(n2L==1 && !n3L) // one diphoton trigger (+ single-photon triggers) - { - success = helper.bind_1x2L_singleFlavour<Trig2PHsym>() || helper.bind_1x2L_singleFlavour<Trig2PHasym>(); - } - else if(n2L==2 && !n3L) // two diphoton triggers (+ single-photon triggers) - { - success = helper.bind_2x2L_singleFlavour<Trig2PHasym,Trig2PHsym>() || helper.bind_2x2L_singleFlavour<Trig2PHsym,Trig2PHsym>(); - } - else if(n3L==1 && !n2L && !n1L) - { - success = helper.bind_1x3L<Trig3PHsym>() || helper.bind_1x3L<Trig3PHhalfsym>(); - } - } - if(!helper.m_func) + success = helper.findAndBindFunction(); + if(!helper.m_formula) { ATH_MSG_ERROR("This trigger combination is currently not supported with an explicit formula (you may use toys instead, slower): " << combination); return false; @@ -363,24 +62,19 @@ bool Calculator::addPeriod(ImportData& data, const std::pair<unsigned,unsigned>& } else { - if(!helper.m_nPhotonTriggers || helper.m_nPhotonTriggers==triggers.size()) - { - helper.m_func = std::bind(&Calculator::globalEfficiency_Toys, ::_1, ::_2, ::_3, triggers, ::_4); - } - else - { - ATH_MSG_ERROR("Currently it is not possible to combine electron/muon and photon triggers: " << combination); - return false; - } + helper.m_formula = std::bind(&Calculator::globalEfficiency_Toys, ::_1, ::_2, ::_3, triggers, ::_4); } if(success) { - if(m_parent->m_validTrigMatchTool) + if(data.adaptTriggerListForTriggerMatching(triggers)) { - if(!data.adaptTriggerListForTriggerMatching(triggers)) return false; - m_periods.emplace_back(boundaries, std::move(helper.m_func), std::move(triggers)); + m_periods.emplace_back(boundaries, std::move(helper.m_formula), std::move(triggers)); + } + else + { + if(m_parent->m_validTrigMatchTool) return false; + m_periods.emplace_back(boundaries, std::move(helper.m_formula)); } - else m_periods.emplace_back(boundaries, std::move(helper.m_func)); } else { @@ -389,6 +83,25 @@ bool Calculator::addPeriod(ImportData& data, const std::pair<unsigned,unsigned>& return success; } +bool Calculator::findUniqueLeg(xAOD::Type::ObjectType obj, std::size_t& uniqueLeg, const std::vector<TrigDef>& defs) +{ + if(uniqueLeg) return true; /// initial non-zero value means that ListOfLegsPerTool is filled + for(auto& def : defs) + { + TriggerProperties tp(def); + for(auto itr=tp.cbegin(obj);itr!=tp.cend(obj);++itr) + { + if(uniqueLeg && uniqueLeg!=*itr) + { + ATH_MSG_ERROR("The property 'ListOfLegsPerTool' needs to be filled as the specified trigger combination involves several electron (or photon) trigger legs"); + return false; + } + uniqueLeg = *itr; + } + } + return true; +} + const Calculator::Period* Calculator::getPeriod(unsigned runNumber) const { auto period = std::find_if(m_periods.cbegin(), m_periods.cend(), @@ -491,9 +204,36 @@ bool Calculator::checkTriggerMatching(TrigGlobalEfficiencyCorrectionTool& parent return true; } +bool Calculator::getRelevantTriggersForUser(TrigGlobalEfficiencyCorrectionTool& parent, std::vector<std::string>& triggers, unsigned runNumber) +{ + triggers.clear(); + m_parent = &parent; + auto period = getPeriod(runNumber); + if(!period) return false; + if(!period->m_triggers.size()) + { + ATH_MSG_ERROR("Empty list of triggers for run number " << runNumber << " (was there a configuration issue? please check for warnings during initialization)"); + return false; + } + bool success = true; + auto notfound = parent.m_dictionary.end(); + for(auto& trig : period->m_triggers) + { + auto itr = parent.m_dictionary.find(trig.name); + if(itr == notfound) + { + ATH_MSG_ERROR("can't retrieve name of trigger with hash " << trig.name << " (shouldn't happen; contact tool developers!)"); + success = false; + } + else triggers.push_back(itr->second); + } + if(!success) triggers.clear(); + return success; +} + Efficiencies Calculator::getCachedTriggerLegEfficiencies(const Lepton& lepton, unsigned runNumber, std::size_t leg, bool& success) { - auto insertion = m_cachedEfficiencies.emplace(std::make_pair(&lepton,leg),Efficiencies()); + auto insertion = m_cachedEfficiencies.emplace(std::make_pair(&lepton, leg), Efficiencies()); Efficiencies& efficiencies = insertion.first->second; if(insertion.second) { @@ -522,10 +262,12 @@ Efficiencies Calculator::getCachedTriggerLegEfficiencies(const Lepton& lepton, u return efficiencies; } - +/// +/// One single-lepton trigger +/// template<typename Trig1L> -auto Calculator::globalEfficiency_One1L(const LeptonList& leptons, unsigned runNumber, const Trig1L trig, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig1L::is1L(), bool>::type +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, const Trig1L trig, Efficiencies& globalEfficiencies) + -> std::enable_if_t<Trig1L::is1L(), bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_One1L() at line " << __LINE__); if(!trig) @@ -546,16 +288,27 @@ auto Calculator::globalEfficiency_One1L(const LeptonList& leptons, unsigned runN return success; } -bool Calculator::globalEfficiency_Two1L(const LeptonList& leptons, unsigned runNumber, const Trig1E trig1E, const Trig1MU trig1MU, Efficiencies& globalEfficiencies) +/// +/// Two single-lepton triggers, two object types +/// +template<typename Trig1L_obj1, typename Trig1L_obj2> +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, const Trig1L_obj1 trig1, const Trig1L_obj2 trig2, Efficiencies& globalEfficiencies) + -> std::enable_if_t<Trig1L_obj1::is1L() + && Trig1L_obj2::is1L() + && Trig1L_obj1::object() != Trig1L_obj2::object(), + bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_Two1L() at line " << __LINE__); - if(!trig1E) return globalEfficiency_One1L(leptons, runNumber, trig1MU, globalEfficiencies); - if(!trig1MU) return globalEfficiency_One1L(leptons, runNumber, trig1E, globalEfficiencies); + if(!trig1) return globalEfficiency(leptons, runNumber, trig2, globalEfficiencies); + if(!trig2) return globalEfficiency(leptons, runNumber, trig1, globalEfficiencies); globalEfficiencies = {1.}; bool success = true; for(auto& lepton : leptons) { - std::size_t leg = Trig1E::relevantFor(lepton)? trig1E() : trig1MU(); + std::size_t leg; + if(trig1.relevantFor(lepton)) leg = trig1(); + else if(trig2.relevantFor(lepton)) leg = trig2(); + else continue; if(!aboveThreshold(lepton, leg)) continue; auto efficiencies = getCachedTriggerLegEfficiencies(lepton, runNumber, leg, success); globalEfficiencies *= ~efficiencies; @@ -564,12 +317,15 @@ bool Calculator::globalEfficiency_Two1L(const LeptonList& leptons, unsigned runN return success; } +/// +/// Several single-lepton triggers, one object type +/// template<typename Trig1L> -auto Calculator::globalEfficiency_Several1L(const LeptonList& leptons, unsigned runNumber, const flat_set<Trig1L>& trigs, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig1L::is1L(), bool>::type +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, const flat_set<Trig1L>& trigs, Efficiencies& globalEfficiencies) + -> std::enable_if_t<Trig1L::is1L(), bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_Several1L() at line " << __LINE__); - if(trigs.size() == 1) return globalEfficiency_One1L(leptons, runNumber, *trigs.cbegin(), globalEfficiencies); + if(trigs.size() == 1) return globalEfficiency(leptons, runNumber, *trigs.cbegin(), globalEfficiencies); if(!trigs.size()) { globalEfficiencies = {0.}; @@ -591,23 +347,32 @@ auto Calculator::globalEfficiency_Several1L(const LeptonList& leptons, unsigned return success; } -bool Calculator::globalEfficiency_Several1L(const LeptonList& leptons, unsigned runNumber, - const flat_set<Trig1E>& trigs1E, const flat_set<Trig1MU>& trigs1MU, Efficiencies& globalEfficiencies) +/// +/// Several single-lepton triggers, two object types +/// +template<typename Trig1L_obj1, typename Trig1L_obj2> +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, + const flat_set<Trig1L_obj1>& trigs1, const flat_set<Trig1L_obj2>& trigs2, Efficiencies& globalEfficiencies) + -> std::enable_if_t<Trig1L_obj1::is1L() + && Trig1L_obj2::is1L() + && Trig1L_obj1::object() != Trig1L_obj2::object(), + bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_Several1L() at line " << __LINE__); - if(trigs1E.size()==1 && trigs1MU.size()==1) + if(trigs1.size()==1 && trigs2.size()==1) { - return globalEfficiency_Two1L(leptons, runNumber, *trigs1E.cbegin(), *trigs1MU.cbegin(), globalEfficiencies); + return globalEfficiency(leptons, runNumber, *trigs1.cbegin(), *trigs2.cbegin(), globalEfficiencies); } - if(!trigs1E.size()) return globalEfficiency_Several1L(leptons, runNumber, trigs1MU, globalEfficiencies); - if(!trigs1MU.size()) return globalEfficiency_Several1L(leptons, runNumber, trigs1E, globalEfficiencies); + if(!trigs1.size()) return globalEfficiency(leptons, runNumber, trigs2, globalEfficiencies); + if(!trigs2.size()) return globalEfficiency(leptons, runNumber, trigs1, globalEfficiencies); globalEfficiencies = {1.}; bool success = true; for(auto& lepton : leptons) { - std::size_t loosestLeg = (Trig1E::relevantFor(lepton))? - getLoosestLegAboveThreshold(lepton, trigs1E, success): - getLoosestLegAboveThreshold(lepton, trigs1MU, success); + std::size_t loosestLeg; + if(Trig1L_obj1::relevantFor(lepton)) loosestLeg = getLoosestLegAboveThreshold(lepton, trigs2, success); + else if(Trig1L_obj2::relevantFor(lepton)) loosestLeg = getLoosestLegAboveThreshold(lepton, trigs2, success); + else continue; if(loosestLeg && success) { auto efficiencies = getCachedTriggerLegEfficiencies(lepton, runNumber, loosestLeg, success); @@ -618,20 +383,28 @@ bool Calculator::globalEfficiency_Several1L(const LeptonList& leptons, unsigned return success; } -bool Calculator::globalEfficiency_One2L(const LeptonList& leptons, unsigned runNumber, const TrigEMU trig, Efficiencies& globalEfficiencies) +/// +/// One mixed-flavour dilepton trigger +/// +template<typename Trig2Lmix> +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, const Trig2Lmix trig, Efficiencies& globalEfficiencies) + -> std::enable_if_t<Trig2Lmix::is2Lmix(), bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_One2L() at line " << __LINE__); - Efficiencies electronEfficiencies, muonEfficiencies; - bool success = globalEfficiency_One1L(leptons, runNumber, trig.side<xAOD::Type::Electron>(), electronEfficiencies) - && globalEfficiency_One1L(leptons, runNumber, trig.side<xAOD::Type::Muon>(), muonEfficiencies); - if(success) globalEfficiencies = electronEfficiencies * muonEfficiencies; + Efficiencies efficiencies[2]; + bool success = globalEfficiency(leptons, runNumber, trig.side1(), efficiencies[0]) + && globalEfficiency(leptons, runNumber, trig.side2(), efficiencies[1]); + if(success) globalEfficiencies = efficiencies[0] * efficiencies[1]; else globalEfficiencies = {0.}; return success; } +/// +/// One symmetric dilepton trigger +/// template<typename Trig2Lsym> -auto Calculator::globalEfficiency_One2L(const LeptonList& leptons, unsigned runNumber, const Trig2Lsym trig , Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2Lsym::is2Lsym(), bool>::type +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, const Trig2Lsym trig , Efficiencies& globalEfficiencies) + -> std::enable_if_t<Trig2Lsym::is2Lsym(), bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_One2L() at line " << __LINE__); globalEfficiencies = {0.}; @@ -650,12 +423,15 @@ auto Calculator::globalEfficiency_One2L(const LeptonList& leptons, unsigned runN return success; } +/// +/// One asymmetric dilepton trigger +/// template<typename Trig2Lasym> -auto Calculator::globalEfficiency_One2L(const LeptonList& leptons, unsigned runNumber, const Trig2Lasym trig, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2Lasym::is2Lasym(), bool>::type +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, const Trig2Lasym trig, Efficiencies& globalEfficiencies) + -> std::enable_if_t<Trig2Lasym::is2Lasym(), bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_One2L() at line " << __LINE__); - if(trig.symmetric()) return globalEfficiency_One2L(leptons, runNumber, trig.to_symmetric(), globalEfficiencies); + if(trig.symmetric()) return globalEfficiency(leptons, runNumber, trig.to_symmetric(), globalEfficiencies); globalEfficiencies = {0.}; if(!trig) return true; Efficiencies singleInefficiencies[2] = {{1.},{1.}}, twoSingleInefficiencies = {1.}; @@ -690,19 +466,27 @@ auto Calculator::globalEfficiency_One2L(const LeptonList& leptons, unsigned runN return success; } -bool Calculator::globalEfficiency_One2LSeveral1L(const LeptonList& leptons, unsigned runNumber, - const TrigEMU trigEMU, const flat_set<Trig1E>& trigs1E, const flat_set<Trig1MU>& trigs1MU, Efficiencies& globalEfficiencies) +/// +/// One mixed-flavour dilepton trigger + single-lepton triggers +/// +template<typename Trig2Lmix, typename Trig1L_obj1, typename Trig1L_obj2> +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, + const Trig2Lmix trig2Lmix, const flat_set<Trig1L_obj1>& trigs1L1, const flat_set<Trig1L_obj2>& trigs1L2, Efficiencies& globalEfficiencies) + -> std::enable_if_t<Trig2Lmix::is2Lmix() + && Trig1L_obj1::is1L() && Trig2Lmix::object1()==Trig1L_obj1::object() + && Trig1L_obj2::is1L() && Trig2Lmix::object2()==Trig1L_obj2::object(), + bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_One2LSeveral1L() at line " << __LINE__); - if(!(trigs1E.size() + trigs1MU.size())) - return globalEfficiency_One2L(leptons, runNumber, trigEMU, globalEfficiencies); - if(trigEMU.hiddenBy(trigs1E) || trigEMU.hiddenBy(trigs1MU)) - return globalEfficiency_Several1L(leptons, runNumber, trigs1E, trigs1MU, globalEfficiencies); + if(!(trigs1L1.size() + trigs1L2.size())) + return globalEfficiency(leptons, runNumber, trig2Lmix, globalEfficiencies); + if(trig2Lmix.hiddenBy(trigs1L1) || trig2Lmix.hiddenBy(trigs1L2)) + return globalEfficiency(leptons, runNumber, trigs1L1, trigs1L2, globalEfficiencies); Efficiencies efficiencies[4]; - bool success = globalEfficiency_Several1L(leptons, runNumber, trigs1E, efficiencies[0]) - && globalEfficiency_Several1L(leptons, runNumber, trigs1MU, efficiencies[1]) - && globalEfficiency_Several1L(leptons, runNumber, trigEMU.addTo(trigs1E), efficiencies[2]) - && globalEfficiency_Several1L(leptons, runNumber, trigEMU.addTo(trigs1MU), efficiencies[3]); + bool success = globalEfficiency(leptons, runNumber, trigs1L1, efficiencies[0]) + && globalEfficiency(leptons, runNumber, trigs1L2, efficiencies[1]) + && globalEfficiency(leptons, runNumber, trig2Lmix.addTo(trigs1L1), efficiencies[2]) + && globalEfficiency(leptons, runNumber, trig2Lmix.addTo(trigs1L2), efficiencies[3]); if(success) { globalEfficiencies = Efficiencies(1.) - ~efficiencies[0]*~efficiencies[1] @@ -712,23 +496,35 @@ bool Calculator::globalEfficiency_One2LSeveral1L(const LeptonList& leptons, unsi return success; } +/// +/// One dilepton trigger + one single-lepton trigger +/// template<typename Trig2L, typename Trig1L> -inline auto Calculator::globalEfficiency_One2LSeveral1L(const LeptonList& leptons, unsigned runNumber, +inline auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, const Trig2L trig2L, const Trig1L trig1L, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2L::is2L(Trig1L::object()) && Trig1L::is1L(), bool>::type + -> std::enable_if_t<Trig2L::is2Lnomix() + && Trig1L::is1L() + && Trig2L::object()==Trig1L::object(), + bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_One2LSeveral1L() at line " << __LINE__); - return globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2L, flat_set<Trig1L>{trig1L}, globalEfficiencies); + return globalEfficiency(leptons, runNumber, trig2L, flat_set<Trig1L>{trig1L}, globalEfficiencies); } +/// +/// One symmetric dilepton trigger + several single-lepton triggers +/// template<typename Trig2Lsym, typename Trig1L> -auto Calculator::globalEfficiency_One2LSeveral1L(const LeptonList& leptons, unsigned runNumber, +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, const Trig2Lsym trig2L, const flat_set<Trig1L>& trigs1L, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2Lsym::is2Lsym(Trig1L::object()) && Trig1L::is1L(), bool>::type + -> std::enable_if_t<Trig2Lsym::is2Lsym() + && Trig1L::is1L() + && Trig1L::object() == Trig2Lsym::object(), + bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_One2LSeveral1L() at line " << __LINE__); - if(!trigs1L.size()) return globalEfficiency_One2L(leptons, runNumber, trig2L, globalEfficiencies); - if(!trig2L || trig2L.hiddenBy(trigs1L)) return globalEfficiency_Several1L(leptons, runNumber, trigs1L, globalEfficiencies); + if(!trigs1L.size()) return globalEfficiency(leptons, runNumber, trig2L, globalEfficiencies); + if(!trig2L || trig2L.hiddenBy(trigs1L)) return globalEfficiency(leptons, runNumber, trigs1L, globalEfficiencies); globalEfficiencies = {0.}; Efficiencies twoSingleInefficiencies = {1.}; bool success = true; @@ -761,15 +557,21 @@ auto Calculator::globalEfficiency_One2LSeveral1L(const LeptonList& leptons, unsi return success; } +/// +/// One asymmetric dilepton trigger + several single-lepton triggers +/// template<typename Trig2Lasym, typename Trig1L> -auto Calculator::globalEfficiency_One2LSeveral1L(const LeptonList& leptons, unsigned runNumber, +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, const Trig2Lasym trig2L, const flat_set<Trig1L>& trigs1L, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2Lasym::is2Lasym(Trig1L::object()) && Trig1L::is1L(), bool>::type + -> std::enable_if_t<Trig2Lasym::is2Lasym() + && Trig1L::is1L() + && Trig1L::object() == Trig2Lasym::object(), + bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_One2LSeveral1L() at line " << __LINE__); - if(trig2L.symmetric()) return globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2L.to_symmetric(), trigs1L, globalEfficiencies); - if(!trigs1L.size()) return globalEfficiency_One2L(leptons, runNumber, trig2L, globalEfficiencies); - if(!trig2L || trig2L.hiddenBy(trigs1L)) return globalEfficiency_Several1L(leptons, runNumber, trigs1L, globalEfficiencies); + if(trig2L.symmetric()) return globalEfficiency(leptons, runNumber, trig2L.to_symmetric(), trigs1L, globalEfficiencies); + if(!trigs1L.size()) return globalEfficiency(leptons, runNumber, trig2L, globalEfficiencies); + if(!trig2L || trig2L.hiddenBy(trigs1L)) return globalEfficiency(leptons, runNumber, trigs1L, globalEfficiencies); globalEfficiencies = {0.}; Efficiencies twoSingleInefficiencies[2] = {{1.}, {1.}}, threeSingleInefficiencies = {1.}; bool success = true; @@ -798,46 +600,26 @@ auto Calculator::globalEfficiency_One2LSeveral1L(const LeptonList& leptons, unsi if(loosest1lepLeg!=looseLegs.second) globalEfficiencies += (efficienciesMedium-efficiencies1L)*~threeSingleInefficiencies; } threeSingleInefficiencies *= ~efficienciesLoose; - twoSingleInefficiencies[0] *= (looseLegs.first!=trig2L.legs[1])?~efficienciesLoose:~efficienciesMedium; // S1 v S3 - twoSingleInefficiencies[1] *= (looseLegs.first!=trig2L.legs[0])?~efficienciesLoose:~efficienciesMedium; // S2 v S3 + twoSingleInefficiencies[0] *= (looseLegs.first!=trig2L.legs[1])?~efficienciesLoose:~efficienciesMedium; /// S1 v S3 + twoSingleInefficiencies[1] *= (looseLegs.first!=trig2L.legs[0])?~efficienciesLoose:~efficienciesMedium; /// S2 v S3 } return success; } -template<typename Trig2E> -auto Calculator::globalEfficiency_One2LSeveral1L(const LeptonList& leptons, unsigned runNumber, - const Trig2E trig2E, const flat_set<Trig1E>& trigs1E, const flat_set<Trig1MU>& trigs1MU, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2E::is2L(xAOD::Type::Electron), bool>::type -{ - ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_One2LSeveral1L() at line " << __LINE__); - Efficiencies effs[2] = {{0.}, {0.}}; - bool success = globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2E, trigs1E, effs[0]) - && globalEfficiency_Several1L(leptons, runNumber, trigs1MU, effs[1]); - globalEfficiencies = ~(~effs[0] * ~effs[1]); - return success; -} - -template<typename Trig2MU> -auto Calculator::globalEfficiency_One2LSeveral1L(const LeptonList& leptons, unsigned runNumber, - const Trig2MU trig2MU, const flat_set<Trig1E>& trigs1E, const flat_set<Trig1MU>& trigs1MU, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2MU::is2L(xAOD::Type::Muon), bool>::type -{ - ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_One2LSeveral1L() at line " << __LINE__); - Efficiencies effs[2] = {{0.}, {0.}}; - bool success = globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2MU, trigs1MU, effs[0]) - && globalEfficiency_Several1L(leptons, runNumber, trigs1E, effs[1]); - globalEfficiencies = ~(~effs[0] * ~effs[1]); - return success; -} - +/// +/// Two symmetric dilepton triggers + several single-lepton triggers +/// template<typename Trig2Lsym, typename Trig1L> -auto Calculator::globalEfficiency_Two2LSeveral1L(const LeptonList& leptons, unsigned runNumber, +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, const Trig2Lsym trig2L1, const Trig2Lsym trig2L2, const flat_set<Trig1L>& trigs1L, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2Lsym::is2Lsym(Trig1L::object()) && Trig1L::is1L(), bool>::type + -> std::enable_if_t<Trig2Lsym::is2Lsym() + && Trig1L::is1L() + && Trig1L::object() == Trig2Lsym::object(), + bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_Two2LSeveral1L() at line " << __LINE__); - if(!trig2L1 || trig2L1==trig2L2 || trig2L1.hiddenBy(trigs1L)) return globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2L2, trigs1L, globalEfficiencies); - if(!trig2L2 || trig2L2.hiddenBy(trigs1L)) return globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2L1, trigs1L, globalEfficiencies); + if(!trig2L1 || trig2L1==trig2L2 || trig2L1.hiddenBy(trigs1L)) return globalEfficiency(leptons, runNumber, trig2L2, trigs1L, globalEfficiencies); + if(!trig2L2 || trig2L2.hiddenBy(trigs1L)) return globalEfficiency(leptons, runNumber, trig2L1, trigs1L, globalEfficiencies); globalEfficiencies = {0.}; Efficiencies singleInefficiencies{1.}; Efficiencies efficiencies2Lsym[2] = {{0.},{0.}}; @@ -875,20 +657,26 @@ auto Calculator::globalEfficiency_Two2LSeveral1L(const LeptonList& leptons, unsi return success; } +/// +/// Two dilepton triggers (one asym., one sym.) + several single-lepton triggers +/// template<typename Trig2Lasym, typename Trig2Lsym, typename Trig1L> -auto Calculator::globalEfficiency_Two2LSeveral1L(const LeptonList& leptons, unsigned runNumber, +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, const Trig2Lasym trig2Lasym, const Trig2Lsym trig2Lsym, const flat_set<Trig1L>& trigs1L, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2Lasym::is2Lasym(Trig1L::object()) && Trig2Lsym::is2Lsym(Trig1L::object()) && Trig1L::is1L(), bool>::type + -> std::enable_if_t<Trig2Lasym::is2Lasym() + && Trig2Lsym::is2Lsym() && Trig2Lsym::object()==Trig2Lasym::object() + && Trig1L::is1L() && Trig1L::object()==Trig2Lasym::object(), + bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_Two2LSeveral1L() at line " << __LINE__); - if(!trig2Lasym || trig2Lasym.hiddenBy(trigs1L)) return globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2Lsym, trigs1L, globalEfficiencies); - if(!trig2Lsym || trig2Lsym.hiddenBy(trigs1L)) return globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2Lasym, trigs1L, globalEfficiencies); + if(!trig2Lasym || trig2Lasym.hiddenBy(trigs1L)) return globalEfficiency(leptons, runNumber, trig2Lsym, trigs1L, globalEfficiencies); + if(!trig2Lsym || trig2Lsym.hiddenBy(trigs1L)) return globalEfficiency(leptons, runNumber, trig2Lasym, trigs1L, globalEfficiencies); if(trig2Lasym(0)==trig2Lsym() || trig2Lasym(1)==trig2Lsym()) { ATH_MSG_ERROR("implementation -- does this function work properly when the two 2L triggers have one leg in common? Must be checked"); return false; } - if(trig2Lasym.symmetric()) return globalEfficiency_Two2LSeveral1L(leptons, runNumber, trig2Lasym.to_symmetric(), trig2Lsym, trigs1L, globalEfficiencies); + if(trig2Lasym.symmetric()) return globalEfficiency(leptons, runNumber, trig2Lasym.to_symmetric(), trig2Lsym, trigs1L, globalEfficiencies); globalEfficiencies = {0.}; Efficiencies singleInefficiencies[3] = {{1.}, {1.}, {1.}}; Efficiencies efficiencies2Lasym {0.}, efficiencies2Lsym[3] = {{0.},{0.},{0.}}; @@ -937,7 +725,7 @@ auto Calculator::globalEfficiency_Two2LSeveral1L(const LeptonList& leptons, unsi else if(secondTightestLeg==trig2Lasym(0) || secondTightestLeg==trig2Lasym(1)) tau23 = (secondTightestLeg==trig2Lasym(0))? trig2Lasym(1) : trig2Lasym(0); else if(tightestLeg==trig2Lasym(0) || tightestLeg==trig2Lasym(1)) tau23 = (tightestLeg==trig2Lasym(0))? trig2Lasym(1) : trig2Lasym(0); - // can't use tightestLeg==trig2Lsym because it might also be 0 + /// can't use tightestLeg==trig2Lsym because it might also be 0 globalEfficiencies = globalEfficiencies*~efficiencies[loosestLeg] + efficiencies[loosest1lepLeg] + (efficiencies[tau13] - efficiencies[secondTightestLeg])*~singleInefficiencies[0] + (efficiencies[tau12] - efficiencies[secondTightestLeg])*~singleInefficiencies[1] @@ -945,13 +733,13 @@ auto Calculator::globalEfficiency_Two2LSeveral1L(const LeptonList& leptons, unsi if(loosestLeg==trig2Lsym()) globalEfficiencies += (efficiencies[trig2Lsym()]-efficiencies[secondLoosestLeg])*efficiencies2Lasym; else if(loosestLeg==trig2Lasym(1)) globalEfficiencies += (efficiencies[trig2Lasym(1)]-efficiencies[secondLoosestLeg])*efficiencies2Lsym[0]; else if(loosestLeg==trig2Lasym(0)) globalEfficiencies += (efficiencies[trig2Lasym(0)]-efficiencies[secondLoosestLeg])*efficiencies2Lsym[1]; - if(secondTightestLeg && tightestLeg==loosest1lepLeg) // this works because loosest1lepLeg is 0 if not on plateau... + if(secondTightestLeg && tightestLeg==loosest1lepLeg) /// this works because loosest1lepLeg is 0 if not on plateau... globalEfficiencies += (efficiencies[secondTightestLeg]-efficiencies[tightestLeg])*~singleInefficiencies[2]; efficiencies2Lasym = ~efficiencies[loosestLeg]*efficiencies2Lasym + efficiencies[lambda14]; if(loosestLeg==trig2Lasym(0) || loosestLeg==trig2Lasym(1)) { - // note: secondLoosestLeg is valid because the loosest leg is either trig2Lasym(0) or trig2Lasym(1) + /// note: secondLoosestLeg is valid because the loosest leg is either trig2Lasym(0) or trig2Lasym(1) efficiencies2Lasym += (efficiencies[loosestLeg]-efficiencies[secondLoosestLeg])*~singleInefficiencies[loosestLeg==trig2Lasym(0)] + (efficiencies[secondLoosestLeg]-efficiencies[lambda14])*~singleInefficiencies[2]; } @@ -968,9 +756,12 @@ auto Calculator::globalEfficiency_Two2LSeveral1L(const LeptonList& leptons, unsi return success; } +/// +/// One symmetric trilepton trigger +/// template<typename Trig3Lsym> -auto Calculator::globalEfficiency_One3L(const LeptonList& leptons, unsigned runNumber, const Trig3Lsym trig, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig3Lsym::is3Lsym(), bool>::type +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, const Trig3Lsym trig, Efficiencies& globalEfficiencies) + -> std::enable_if_t<Trig3Lsym::is3Lsym(), bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_One3L() at line " << __LINE__); globalEfficiencies = {0.}; @@ -987,12 +778,15 @@ auto Calculator::globalEfficiency_One3L(const LeptonList& leptons, unsigned runN return success; } +/// +/// One half-symmetric trilepton trigger +/// template<typename Trig3Lhalfsym> -auto Calculator::globalEfficiency_One3L(const LeptonList& leptons, unsigned runNumber, const Trig3Lhalfsym trig, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig3Lhalfsym::is3Lhalfsym(), bool>::type +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, const Trig3Lhalfsym trig, Efficiencies& globalEfficiencies) + -> std::enable_if_t<Trig3Lhalfsym::is3Lhalfsym(), bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_One3L() at line " << __LINE__); - if(trig.symmetric()) return globalEfficiency_One3L(leptons, runNumber, trig.to_symmetric(), globalEfficiencies); + if(trig.symmetric()) return globalEfficiency(leptons, runNumber, trig.to_symmetric(), globalEfficiencies); globalEfficiencies = {0.}; Efficiencies singleInefficiencies[2] = {{1.}, {1.}}, twoSingleInefficiencies{1.}; Efficiencies efficiencies2Lsym{0.}, efficiencies2Lasym{0.}, efficiencies2L2L{0.}; @@ -1024,243 +818,247 @@ auto Calculator::globalEfficiency_One3L(const LeptonList& leptons, unsigned runN { globalEfficiencies = ~efficiencies[asym]*globalEfficiencies + efficiencies[sym]*efficiencies2L2L + delta*efficiencies2Lsym; efficiencies2L2L = ~efficiencies[asym]*efficiencies2L2L + efficiencies[sym]*~twoSingleInefficiencies + delta*~singleInefficiencies[sym]; - efficiencies2Lasym = ~efficiencies[asym]*efficiencies2Lasym + efficiencies[sym]*~twoSingleInefficiencies + delta*~singleInefficiencies[0]; + efficiencies2Lasym = ~efficiencies[asym]*efficiencies2Lasym + efficiencies[sym]*~twoSingleInefficiencies + delta*~singleInefficiencies[sym]; } else { globalEfficiencies = ~efficiencies[sym]*globalEfficiencies + efficiencies[asym]*efficiencies2L2L - delta*efficiencies2Lasym; efficiencies2L2L = ~efficiencies[sym]*efficiencies2L2L + efficiencies[sym]*~twoSingleInefficiencies; - efficiencies2Lasym = ~efficiencies[sym]*efficiencies2Lasym + efficiencies[asym]*~twoSingleInefficiencies - delta*~singleInefficiencies[1]; + efficiencies2Lasym = ~efficiencies[sym]*efficiencies2Lasym + efficiencies[asym]*~twoSingleInefficiencies - delta*~singleInefficiencies[asym]; } - efficiencies2Lsym = ~efficiencies[sym]*efficiencies2Lsym + efficiencies[sym]*~singleInefficiencies[0]; + efficiencies2Lsym = ~efficiencies[sym]*efficiencies2Lsym + efficiencies[sym]*~singleInefficiencies[sym]; twoSingleInefficiencies *= ~efficiencies[loosestLeg]; - singleInefficiencies[0] *= ~efficiencies[sym]; - singleInefficiencies[1] *= ~efficiencies[asym]; + singleInefficiencies[sym] *= ~efficiencies[sym]; + singleInefficiencies[asym] *= ~efficiencies[asym]; } return success; } -template<typename Trig2L> -auto Calculator::globalEfficiency_Two2L(const LeptonList& leptons, unsigned runNumber, const Trig2L trig2L, const TrigEMU trigEMU, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2L::is2L(), bool>::type +/// +/// One dilepton trigger + one mixed-flavour dilepton trigger +/// +template<typename Trig2L, typename Trig2Lmix> +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, const Trig2L trig2L, const Trig2Lmix trig2Lmix, Efficiencies& globalEfficiencies) + -> std::enable_if_t<Trig2L::is2Lnomix() + && Trig2Lmix::is2Lmix() + && (Trig2Lmix::object1()==Trig2L::object() || Trig2Lmix::object2()==Trig2L::object()), + bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_Two2L() at line " << __LINE__); Efficiencies efficiencies1L, efficiencies2L, efficiencies2Lor1L; - bool success = globalEfficiency_One1L(leptons, runNumber, trigEMU.antiside<Trig2L>(), efficiencies1L); - success = success && globalEfficiency_One2L(leptons, runNumber, trig2L, efficiencies2L); - success = success && globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2L, trigEMU.side<Trig2L>(), efficiencies2Lor1L); + bool success = globalEfficiency(leptons, runNumber, trig2Lmix.template antiside<Trig2L>(), efficiencies1L); + success = success && globalEfficiency(leptons, runNumber, trig2L, efficiencies2L); + success = success && globalEfficiency(leptons, runNumber, trig2L, trig2Lmix.template side<Trig2L>(), efficiencies2Lor1L); globalEfficiencies = efficiencies2L*~efficiencies1L + efficiencies1L*efficiencies2Lor1L; return success; } -template<typename Trig2E, typename Trig2MU> -auto Calculator::globalEfficiency_Three2L(const LeptonList& leptons, unsigned runNumber, - const Trig2E trig2E, const Trig2MU trig2MU, const TrigEMU trigEMU, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2E::is2L(xAOD::Type::Electron) && Trig2MU::is2L(xAOD::Type::Muon), bool>::type +/// +/// Combinaisons with 3 dilepton triggers including one mixed-flavour, and one sym./asym. dilepton for each flavour +/// +template<typename Trig2L_obj1, typename Trig2L_obj2, typename Trig2Lmix> +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, + const Trig2L_obj1 trig2L_obj1, const Trig2L_obj2 trig2L_obj2, const Trig2Lmix trig2Lmix, Efficiencies& globalEfficiencies) + -> std::enable_if_t<Trig2Lmix::is2Lmix() + && Trig2L_obj1::is2Lnomix() && Trig2L_obj1::object() == Trig2Lmix::object1() + && Trig2L_obj2::is2Lnomix() && Trig2L_obj2::object() == Trig2Lmix::object2(), + + bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_Three2L() at line " << __LINE__); Efficiencies efficiencies2L[2] = {{0.}, {0.}}, efficiencies2Lor1L[2] = {{0.}, {0.}}; bool success = true; - if(trig2E) + if(trig2L_obj1) { - success = success && globalEfficiency_One2L(leptons, runNumber, trig2E, efficiencies2L[0]); - if(trigEMU) success = success && globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2E, trigEMU.side<Trig2E>(), efficiencies2Lor1L[0]); + success = success && globalEfficiency(leptons, runNumber, trig2L_obj1, efficiencies2L[0]); + if(trig2Lmix) success = success && globalEfficiency(leptons, runNumber, trig2L_obj1, trig2Lmix.template side<Trig2L_obj1>(), efficiencies2Lor1L[0]); else efficiencies2Lor1L[0] = efficiencies2L[0]; } - else if(trigEMU) success = success && globalEfficiency_One1L(leptons, runNumber, trigEMU.side<Trig2E>(), efficiencies2Lor1L[0]); - if(trig2MU) + else if(trig2Lmix) success = success && globalEfficiency(leptons, runNumber, trig2Lmix.template side<Trig2L_obj1>(), efficiencies2Lor1L[0]); + if(trig2L_obj2) { - success = success && globalEfficiency_One2L(leptons, runNumber, trig2MU, efficiencies2L[1]); - if(trigEMU) success = success && globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2MU, trigEMU.side<Trig2MU>(), efficiencies2Lor1L[1]); + success = success && globalEfficiency(leptons, runNumber, trig2L_obj2, efficiencies2L[1]); + if(trig2Lmix) success = success && globalEfficiency(leptons, runNumber, trig2L_obj2, trig2Lmix.template side<Trig2L_obj2>(), efficiencies2Lor1L[1]); else efficiencies2Lor1L[1] = efficiencies2L[1]; } - else if(trigEMU) success = success && globalEfficiency_One1L(leptons, runNumber, trigEMU.side<Trig2MU>(), efficiencies2Lor1L[1]); + else if(trig2Lmix) success = success && globalEfficiency(leptons, runNumber, trig2Lmix.template side<Trig2L_obj2>(), efficiencies2Lor1L[1]); globalEfficiencies = efficiencies2L[0]*~efficiencies2Lor1L[1] + efficiencies2L[1]*~efficiencies2Lor1L[0] + efficiencies2Lor1L[0]*efficiencies2Lor1L[1]; return success; } -template<typename Trig2E, typename Trig2MU> -auto Calculator::globalEfficiency_Three2LSeveral1L(const LeptonList& leptons, unsigned runNumber, const Trig2E trig2E, const Trig2MU trig2MU, - const TrigEMU trigEMU, const flat_set<Trig1E>& trigs1E, const flat_set<Trig1MU>& trigs1MU, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2E::is2L(xAOD::Type::Electron) && Trig2MU::is2L(xAOD::Type::Muon), bool>::type +/// +/// Same combinaisons with 3 dilepton triggers, + single-lepton triggers +/// +template<typename Trig2L_obj1, typename Trig2L_obj2, typename Trig2Lmix, typename Trig1L_obj1, typename Trig1L_obj2> +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, const Trig2L_obj1 trig2L_obj1, const Trig2L_obj2 trig2L_obj2, + const Trig2Lmix trig2Lmix, const flat_set<Trig1L_obj1>& trigs1L_obj1, const flat_set<Trig1L_obj2>& trigs1L_obj2, Efficiencies& globalEfficiencies) + -> std::enable_if_t<Trig2Lmix::is2Lmix() + && Trig2L_obj1::is2Lnomix() && Trig2L_obj1::object()==Trig2Lmix::object1() + && Trig2L_obj2::is2Lnomix() && Trig2L_obj2::object()==Trig2Lmix::object2() + && Trig1L_obj1::is1L() && Trig1L_obj1::object()==Trig2Lmix::object1() + && Trig1L_obj2::is1L() && Trig1L_obj2::object()==Trig2Lmix::object2(), + + bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_Three2LSeveral1L() at line " << __LINE__); Efficiencies efficiencies[4]; bool success = true; - if(trig2E) success = success && globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2E, trigs1E, efficiencies[0]); - else success = success && globalEfficiency_Several1L(leptons, runNumber, trigs1E, efficiencies[0]); - if(trig2MU) success = success && globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2MU, trigs1MU, efficiencies[1]); - else success = success && globalEfficiency_Several1L(leptons, runNumber, trigs1MU, efficiencies[1]); - if(trigEMU && !trigEMU.hiddenBy(trigs1E)) + if(trig2L_obj1) success = success && globalEfficiency(leptons, runNumber, trig2L_obj1, trigs1L_obj1, efficiencies[0]); + else success = success && globalEfficiency(leptons, runNumber, trigs1L_obj1, efficiencies[0]); + if(trig2L_obj2) success = success && globalEfficiency(leptons, runNumber, trig2L_obj2, trigs1L_obj2, efficiencies[1]); + else success = success && globalEfficiency(leptons, runNumber, trigs1L_obj2, efficiencies[1]); + if(trig2Lmix && !trig2Lmix.hiddenBy(trigs1L_obj1)) { - auto trigs1E_plusEMU = trigEMU.addTo(trigs1E); - if(trig2E) success = success && globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2E, trigs1E_plusEMU, efficiencies[2]); - else success = success && globalEfficiency_Several1L(leptons, runNumber, trigs1E_plusEMU, efficiencies[2]); + auto t = trig2Lmix.addTo(trigs1L_obj1); + if(trig2L_obj1) success = success && globalEfficiency(leptons, runNumber, trig2L_obj1, t, efficiencies[2]); + else success = success && globalEfficiency(leptons, runNumber, t, efficiencies[2]); } else efficiencies[2] = efficiencies[0]; - if(trigEMU && !trigEMU.hiddenBy(trigs1MU)) + if(trig2Lmix && !trig2Lmix.hiddenBy(trigs1L_obj2)) { - auto trigs1MU_plusEMU = trigEMU.addTo(trigs1MU); - if(trig2MU) success = success && globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2MU, trigs1MU_plusEMU, efficiencies[3]); - else success = success && globalEfficiency_Several1L(leptons, runNumber, trigs1MU_plusEMU, efficiencies[3]); + auto t = trig2Lmix.addTo(trigs1L_obj2); + if(trig2L_obj2) success = success && globalEfficiency(leptons, runNumber, trig2L_obj2, t, efficiencies[3]); + else success = success && globalEfficiency(leptons, runNumber, t, efficiencies[3]); } else efficiencies[3] = efficiencies[1]; globalEfficiencies = Efficiencies(1.) - ~efficiencies[0]*~efficiencies[1] + (efficiencies[2]-efficiencies[0])*(efficiencies[3]-efficiencies[1]); return success; } -template<typename Trig2L, typename Trig2Lsym, typename Trig1L> -auto Calculator::globalEfficiency_Six2LSeveral1L_singleObjectFactor(const LeptonList& leptons, unsigned runNumber, - const Trig2L trig2L, const Trig2Lsym trig2Lsym, const TrigEMU trigEMU1, const TrigEMU trigEMU2, const flat_set<Trig1L>& trigs1L, Efficiencies (&efficiencies)[4]) - -> typename std::enable_if<Trig2L::is2L() && Trig2Lsym::is2Lsym(Trig2L::object()) && Trig1L::is1L(Trig2L::object()), bool>::type +/// +/// Six dilepton triggers (two mixed-flavour, two sym., two asym./sym.) for two object types +/// +template<typename Trig2L_obj1, typename Trig2Lsym_obj1, typename Trig2L_obj2, typename Trig2Lsym_obj2, + typename Trig2Lmix, typename Trig1L_obj1, typename Trig1L_obj2> +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, + const Trig2L_obj1 trig2L_obj1, const Trig2Lsym_obj1 trig2Lsym_obj1, const Trig2L_obj2 trig2L_obj2, const Trig2Lsym_obj2 trig2Lsym_obj2, + const Trig2Lmix trig2Lmix1, const Trig2Lmix trig2Lmix2, + const flat_set<Trig1L_obj1>& trigs1L_obj1, const flat_set<Trig1L_obj2>& trigs1L_obj2, Efficiencies& globalEfficiencies) + -> std::enable_if_t<Trig2Lmix::is2Lmix() + && Trig2L_obj1::is2Lnomix() && Trig2L_obj1::object()==Trig2Lmix::object1() + && Trig2L_obj2::is2Lnomix() && Trig2L_obj2::object()==Trig2Lmix::object2() + && Trig2Lsym_obj1::is2Lsym() && Trig2Lsym_obj1::object()==Trig2Lmix::object1() + && Trig2Lsym_obj2::is2Lsym() && Trig2Lsym_obj2::object()==Trig2Lmix::object2() + && Trig1L_obj1::is1L() && Trig1L_obj1::object()==Trig2Lmix::object1() + && Trig1L_obj2::is1L() && Trig1L_obj2::object()==Trig2Lmix::object2(), + bool> { - ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_Six2LSeveral1L_singleObjectFactor() at line " << __LINE__); - auto eval_for = [=](const flat_set<Trig1L>& trigs1L_extended, Efficiencies& eff) -> bool + ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_Six2LSeveral1L() at line " << __LINE__); + + auto singleObjectFactor = [=](auto trig2L, auto trig2Lsym, auto& trigs1L, Efficiencies (&efficiencies)[4]) -> bool { - if(trig2L && trig2Lsym) return globalEfficiency_Two2LSeveral1L(leptons, runNumber, trig2L, trig2Lsym, trigs1L_extended, eff); - else if(trig2L) return globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2L, trigs1L_extended, eff); - else if(trig2Lsym) return globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2Lsym, trigs1L_extended, eff); - else return globalEfficiency_Several1L(leptons, runNumber, trigs1L_extended, eff); + auto eval_for = [=](const auto& trigs1L_extended, Efficiencies& eff) -> bool + { + if(trig2L && trig2Lsym) return this->globalEfficiency(leptons, runNumber, trig2L, trig2Lsym, trigs1L_extended, eff); + else if(trig2L) return this->globalEfficiency(leptons, runNumber, trig2L, trigs1L_extended, eff); + else if(trig2Lsym) return this->globalEfficiency(leptons, runNumber, trig2Lsym, trigs1L_extended, eff); + else return this->globalEfficiency(leptons, runNumber, trigs1L_extended, eff); + }; + + bool success = eval_for(trigs1L, efficiencies[0]); + if(trig2Lmix1) success = success && eval_for(trig2Lmix1.addTo(trigs1L), efficiencies[1]); + else efficiencies[1] = efficiencies[0]; + if(trig2Lmix2) + { + auto t = trig2Lmix2.addTo(trigs1L); + success = success && eval_for(t, efficiencies[2]); + if(trig2Lmix1) success && eval_for(trig2Lmix1.addTo(t), efficiencies[3]); + else efficiencies[3] = efficiencies[2]; + } + else + { + efficiencies[2] = efficiencies[0]; + efficiencies[3] = efficiencies[1]; + } + return success; }; - bool success = eval_for(trigs1L, efficiencies[0]); - if(trigEMU1) success = success && eval_for(trigEMU1.addTo(trigs1L), efficiencies[1]); - else efficiencies[1] = efficiencies[0]; - if(trigEMU2) - { - auto trigs1L_withEMU2 = trigEMU2.addTo(trigs1L); - success = success && eval_for(trigs1L_withEMU2, efficiencies[2]); - if(trigEMU1) success && eval_for(trigEMU1.addTo(trigs1L_withEMU2), efficiencies[3]); - else efficiencies[3] = efficiencies[2]; - } - else - { - efficiencies[2] = efficiencies[0]; - efficiencies[3] = efficiencies[1]; - } - return success; -} - -template<typename Trig2E, typename Trig2MU> -auto Calculator::globalEfficiency_Six2LSeveral1L(const LeptonList& leptons, unsigned runNumber, - const Trig2E trig2E, const Trig2Esym trig2Esym, const Trig2MU trig2MU, const Trig2MUsym trig2MUsym, - const TrigEMU trigEMU1, const TrigEMU trigEMU2, const flat_set<Trig1E>& trigs1E, const flat_set<Trig1MU>& trigs1MU, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2E::is2L(xAOD::Type::Electron) && Trig2MU::is2L(xAOD::Type::Muon), bool>::type -{ - ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_Six2LSeveral1L() at line " << __LINE__); - Efficiencies efficienciesE[4], efficienciesM[4]; - bool success = globalEfficiency_Six2LSeveral1L_singleObjectFactor(leptons, runNumber, trig2E, trig2Esym, trigEMU1, trigEMU2, trigs1E, efficienciesE) - && globalEfficiency_Six2LSeveral1L_singleObjectFactor(leptons, runNumber, trig2MU, trig2MUsym, trigEMU1, trigEMU2, trigs1MU, efficienciesM); - globalEfficiencies = Efficiencies(1.) - ~efficienciesE[0]*~efficienciesM[0] + (efficienciesE[1]-efficienciesE[0])*(efficienciesM[1]-efficienciesM[0]) - + (efficienciesE[2]-efficienciesE[0])*(efficienciesM[2]-efficienciesM[0]) - - (efficienciesE[0]-efficienciesE[1]-efficienciesE[2]+efficienciesE[3])*(efficienciesM[0]-efficienciesM[1]-efficienciesM[2]+efficienciesM[3]); + + Efficiencies efficiencies1[4], efficiencies2[4]; + bool success = singleObjectFactor(trig2L_obj1, trig2Lsym_obj1, trigs1L_obj1, efficiencies1) + && singleObjectFactor(trig2L_obj2, trig2Lsym_obj2, trigs1L_obj2, efficiencies2); + globalEfficiencies = Efficiencies(1.) - ~efficiencies1[0]*~efficiencies2[0] + (efficiencies1[1]-efficiencies1[0])*(efficiencies2[1]-efficiencies2[0]) + + (efficiencies1[2]-efficiencies1[0])*(efficiencies2[2]-efficiencies2[0]) + - (efficiencies1[0]-efficiencies1[1]-efficiencies1[2]+efficiencies1[3])*(efficiencies2[0]-efficiencies2[1]-efficiencies2[2]+efficiencies2[3]); return success; } +/// +/// One mixed-flavour trilepton trigger +/// template<typename Trig3Lmix> -auto Calculator::globalEfficiency_One3L(const LeptonList& leptons, unsigned runNumber, const Trig3Lmix trig, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig3Lmix::is3Lmix(), bool>::type +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, const Trig3Lmix trig, Efficiencies& globalEfficiencies) + -> std::enable_if_t<Trig3Lmix::is3Lmix(), bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_One3L() at line " << __LINE__); Efficiencies efficiencies[2] = {{0.}, {0.}}; - bool success = globalEfficiency_One2L(leptons, runNumber, trig.template side<Trig3Lmix::major_object()>(), efficiencies[0]) - && globalEfficiency_One1L(leptons, runNumber, trig.template side<Trig3Lmix::minor_object()>(), efficiencies[1]); + bool success = globalEfficiency(leptons, runNumber, trig.template side<Trig3Lmix::object1()>(), efficiencies[0]) + && globalEfficiency(leptons, runNumber, trig.template side<Trig3Lmix::object2()>(), efficiencies[1]); globalEfficiencies = efficiencies[0]*efficiencies[1]; return success; } +/// +/// Two complementary mixed-flavour trilepton triggers +/// template<typename Trig3Lmix1, typename Trig3Lmix2> -auto Calculator::globalEfficiency_Two3L(const LeptonList& leptons, unsigned runNumber, const Trig3Lmix1 trig1, const Trig3Lmix2 trig2, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig3Lmix1::is3Lmix() && Trig3Lmix2::is3Lmix() && (Trig3Lmix1::major_object()!=Trig3Lmix2::major_object()), bool>::type +auto Calculator::globalEfficiency(const LeptonList& leptons, unsigned runNumber, const Trig3Lmix1 trig1, const Trig3Lmix2 trig2, Efficiencies& globalEfficiencies) + -> std::enable_if_t<Trig3Lmix1::is3Lmix() + && Trig3Lmix2::is3Lmix() + && Trig3Lmix1::object1() == Trig3Lmix2::object2() + && Trig3Lmix1::object2() == Trig3Lmix2::object1(), + bool> { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_Two3L() at line " << __LINE__); Efficiencies efficiencies[6] = {{0.}, {0.}, {0.}, {0.}, {0.}, {0.}}; - auto trig2La = trig1.template side<Trig3Lmix1::major_object()>(); - auto trig1La = trig2.template side<Trig3Lmix2::minor_object()>(); - bool success = globalEfficiency_One1L(leptons, runNumber, trig1La, efficiencies[0]) - && globalEfficiency_One2L(leptons, runNumber, trig2La, efficiencies[1]); - if(!trig2La.hiddenBy(trig1La)) success = success && globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2La, trig1La, efficiencies[2]); + auto trig2La = trig1.template side<Trig3Lmix1::object1()>(); + auto trig1La = trig2.template side<Trig3Lmix2::object2()>(); + bool success = globalEfficiency(leptons, runNumber, trig1La, efficiencies[0]) + && globalEfficiency(leptons, runNumber, trig2La, efficiencies[1]); + if(!trig2La.hiddenBy(trig1La)) success = success && globalEfficiency(leptons, runNumber, trig2La, trig1La, efficiencies[2]); else efficiencies[2] = efficiencies[0]; - auto trig2Lb = trig2.template side<Trig3Lmix2::major_object()>(); - auto trig1Lb = trig1.template side<Trig3Lmix1::minor_object()>(); - success = success && globalEfficiency_One1L(leptons, runNumber, trig1Lb, efficiencies[3]) - && globalEfficiency_One2L(leptons, runNumber, trig2Lb, efficiencies[4]); - if(!trig2Lb.hiddenBy(trig1Lb)) success = success && globalEfficiency_One2LSeveral1L(leptons, runNumber, trig2Lb, trig1Lb, efficiencies[5]); + auto trig2Lb = trig2.template side<Trig3Lmix2::object1()>(); + auto trig1Lb = trig1.template side<Trig3Lmix1::object2()>(); + success = success && globalEfficiency(leptons, runNumber, trig1Lb, efficiencies[3]) + && globalEfficiency(leptons, runNumber, trig2Lb, efficiencies[4]); + if(!trig2Lb.hiddenBy(trig1Lb)) success = success && globalEfficiency(leptons, runNumber, trig2Lb, trig1Lb, efficiencies[5]); else efficiencies[5] = efficiencies[3]; globalEfficiencies = efficiencies[0]*efficiencies[4] + efficiencies[3]*efficiencies[1] + (efficiencies[2]-efficiencies[0]-efficiencies[1])*(efficiencies[3]+efficiencies[4]-efficiencies[5]); return success; } +bool Calculator::globalEfficiency_Factorized2(const LeptonList& leptons, unsigned runNumber, GlobEffFunc func1, GlobEffFunc func2, Efficiencies& globalEfficiencies) +{ + Efficiencies efficiencies[2]; + if(!func1(this, leptons, runNumber, efficiencies[0])) return false; + if(!func2(this, leptons, runNumber, efficiencies[1])) return false; + globalEfficiencies = ~(~efficiencies[0] * ~efficiencies[1]); + return true; +} + +bool Calculator::globalEfficiency_Factorized3(const LeptonList& leptons, unsigned runNumber, GlobEffFunc func1, GlobEffFunc func2, GlobEffFunc func3, Efficiencies& globalEfficiencies) +{ + Efficiencies efficiencies[3]; + if(!func1(this, leptons, runNumber, efficiencies[0])) return false; + if(!func2(this, leptons, runNumber, efficiencies[1])) return false; + if(!func3(this, leptons, runNumber, efficiencies[2])) return false; + globalEfficiencies = ~(~efficiencies[0] * ~efficiencies[1]* ~efficiencies[2]); + return true; +} + bool Calculator::fillListOfLegsFor(const Lepton& lepton, const std::vector<TrigDef>& triggers, flat_set<std::size_t>& validLegs) const { validLegs.clear(); for(auto& trig : triggers) { - bool success = true; - if(lepton.type() == xAOD::Type::Electron) - { - switch(trig.type) - { - case TT_3E_ASYM: - if(aboveThreshold(lepton, trig.leg[2])) validLegs.emplace(trig.leg[2]); // no break - case TT_2E_ASYM: case TT_2E_MU_ASYM: case TT_3E_HALFSYM: - if(aboveThreshold(lepton, trig.leg[1])) validLegs.emplace(trig.leg[1]); // no break - case TT_SINGLE_E: case TT_2E_SYM: case TT_EMU: case TT_3E_SYM: - case TT_2E_MU_SYM: case TT_E_2MU_SYM: case TT_E_2MU_ASYM: - if(aboveThreshold(lepton, trig.leg[0])) validLegs.emplace(trig.leg[0]); - break; - default: - if(trig.type&TT_ELECTRON_FLAG) success = false; - } - } - else if(lepton.type() == xAOD::Type::Muon) - { - switch(trig.type) - { - case TT_3MU_ASYM: - if(aboveThreshold(lepton, trig.leg[2])) validLegs.emplace(trig.leg[2]); // no break - case TT_2MU_ASYM: case TT_3MU_HALFSYM: - if(aboveThreshold(lepton, trig.leg[1])) validLegs.emplace(trig.leg[1]); // no break - case TT_SINGLE_MU: case TT_2MU_SYM: case TT_3MU_SYM: - if(aboveThreshold(lepton, trig.leg[0])) validLegs.emplace(trig.leg[0]); - break; - case TT_E_2MU_ASYM: - if(aboveThreshold(lepton, trig.leg[2])) validLegs.emplace(trig.leg[2]); // no break - case TT_EMU: case TT_E_2MU_SYM: - if(aboveThreshold(lepton, trig.leg[1])) validLegs.emplace(trig.leg[1]); - break; - case TT_2E_MU_SYM: case TT_2E_MU_ASYM: - if(aboveThreshold(lepton, trig.leg[2])) validLegs.emplace(trig.leg[2]); - break; - default: - if(trig.type&TT_MUON_FLAG) success = false; - } - } - else if(lepton.type() == xAOD::Type::Photon) - { - switch(trig.type) - { - case TT_3PH_ASYM: - if(aboveThreshold(lepton, trig.leg[2])) validLegs.emplace(trig.leg[2]); // no break - case TT_2PH_ASYM: case TT_2E_MU_ASYM: case TT_3E_HALFSYM: - if(aboveThreshold(lepton, trig.leg[1])) validLegs.emplace(trig.leg[1]); // no break - case TT_SINGLE_PH: case TT_2PH_SYM: case TT_3PH_SYM: - if(aboveThreshold(lepton, trig.leg[0])) validLegs.emplace(trig.leg[0]); - break; - default: - if(trig.type&TT_PHOTON_FLAG) success = false; - } - } - else - { - ATH_MSG_ERROR("Unknown lepton type"); - return false; - } - if(!success) + TriggerProperties tp(trig); + if(!tp.valid()) { ATH_MSG_ERROR("Unrecognized trigger type " << trig.type); return false; } + auto end = tp.cend(lepton.type()); + for(auto itr=tp.cbegin(lepton.type()); itr!=end; ++itr)if(aboveThreshold(lepton, *itr)) validLegs.emplace(*itr); } return true; } @@ -1312,7 +1110,7 @@ bool Calculator::canTriggerBeFired(const TrigDef& trig, const std::vector<flat_s return false; } -bool Calculator::globalEfficiency_Toys(const LeptonList& leptons, unsigned runNumber, +bool Calculator::globalEfficiency_Toys(const LeptonList& leptons, unsigned runNumber, const std::vector<TrigDef>& triggers, Efficiencies& globalEfficiencies) { ATH_MSG_DEBUG("Entered Calculator::globalEfficiency_Toys() at line " << __LINE__); @@ -1380,3 +1178,229 @@ bool Calculator::globalEfficiency_Toys(const LeptonList& leptons, unsigned runNu globalEfficiencies.mc() = double(nPassed[1]) / double(m_parent->m_numberOfToys); return true; } + +Calculator::Helper::Helper(const std::vector<TrigDef>& defs) : + m_formula(nullptr), m_defs(defs) +{ +} + +bool Calculator::Helper::duplicates() const +{ + for(auto itr1=m_defs.cbegin(); itr1!=m_defs.cend(); ++itr1) + for(auto itr2=itr1+1; itr2!=m_defs.cend(); ++itr2) + if(itr1->type==itr2->type && itr1->leg==itr2->leg) return true; + return false; +} + +namespace TrigGlobEffCorr /// the template specializations below must be enclosed in this namespace +{ + template<typename T> + struct TrigGlobEffCorr::Calculator::Helper::BindPackedParam + { + using TrigType = T; + using ArgType = std::add_const_t<T>; + static constexpr bool multiple() { return false; } + static constexpr bool optional() { return false; } + static void add(T& arg, ImportData::TrigDef& def) { arg.setDefinition(def); } + static constexpr bool valid(const T& arg) { return bool(arg); } + }; + + template<typename T> + struct TrigGlobEffCorr::Calculator::Helper::BindPackedParam<flat_set<T>> + { + using TrigType = T; + using ArgType = const flat_set<T>&; + static constexpr bool multiple() { return true; } + static constexpr bool optional() { return false; } + static void add(flat_set<T>& arg, ImportData::TrigDef& def) { arg.emplace().first->setDefinition(def); } + static constexpr bool valid(const flat_set<T>& arg) { return arg.size(); } + }; + + template<typename T> + struct TrigGlobEffCorr::Calculator::Helper::BindPackedParam<Calculator::Helper::Optional<T>> + { + using TrigType = typename BindPackedParam<T>::TrigType; + using ArgType = typename BindPackedParam<T>::ArgType; + static constexpr bool multiple() { return BindPackedParam<T>::multiple(); } + static constexpr bool optional() { return true; } + static void add(std::remove_cv_t<std::remove_reference_t<ArgType>>& arg, ImportData::TrigDef def) { BindPackedParam<T>::add(arg, def); } + static constexpr bool valid(ArgType& arg) { return BindPackedParam<T>::valid(arg); } + }; +} + +template<typename Param> +auto Calculator::Helper::extract() +{ + std::remove_cv_t<std::remove_reference_t<typename Param::ArgType>> trigs; + for(auto& def : m_defs) + { + if(def.used || def.type!=Param::TrigType::type()) continue; + def.used = true; + Param::add(trigs, def); + if(!Param::multiple()) break; + } + if(!Param::optional() && !Param::valid(trigs)) throw NoSuchTrigger(); + return trigs; +} + +template<typename... Trigs> +bool Calculator::Helper::bindFunction() +{ + for(auto& def : m_defs) def.used = false; + using fnptr = bool(Calculator::*)(const LeptonList&, unsigned, typename BindPackedParam<Trigs>::ArgType..., Efficiencies&); + try + { + m_formula = std::bind<fnptr>(&Calculator::globalEfficiency, ::_1, ::_2, ::_3, extract<BindPackedParam<Trigs>>()..., ::_4); + if(std::all_of(m_defs.cbegin(), m_defs.cend(), [](auto& def){return def.used;})) return true; + } + catch(NoSuchTrigger){} + m_formula = nullptr; + return false; +} + +template<TriggerType object_flag> +bool Calculator::Helper::findAndBindFunction() /// for combinations with a single flavour present +{ + using A = TriggerClass<object_flag>; + using A1L = flat_set<typename A::T_1>; + using A_2sym = typename A::T_2sym; + using A_2asym = typename A::T_2asym; + if(!m_n2L && !m_n3L) + { + return bindFunction<typename A::T_1>() || bindFunction<A1L>(); + } + else if(m_n2L==1 && !m_n3L) + { + return bindFunction<A_2sym>() || bindFunction<A_2asym>() + || bindFunction<A_2sym, A1L>() || bindFunction<A_2asym, A1L>(); + } + else if(m_n2L==2 && !m_n3L) + { + return bindFunction<A_2sym, A_2sym, Optional<A1L>>() || bindFunction<A_2asym, A_2sym, Optional<A1L>>(); + } + else if(m_n3L==1 && !m_n1L && !m_n2L) + { + return bindFunction<typename A::T_3sym>() || bindFunction<typename A::T_3halfsym>(); + } + return false; +} + +template<TriggerType object_flag1, TriggerType object_flag2> +bool Calculator::Helper::findAndBindFunction() /// for combinations with two flavours present +{ + /// this only deals with the presence of mixed triggers + using A = TriggerClass<object_flag1>; + using B = TriggerClass<object_flag2>; + using AB = TriggerClass<object_flag1, object_flag2>; + using A_1 = typename A::T_1; + using B_1 = typename B::T_1; + using OA1L = Optional<flat_set<A_1>>; + using OB1L = Optional<flat_set<B_1>>; + using A_2sym = typename A::T_2sym; + using B_2sym = typename B::T_2sym; + using A_2asym = typename A::T_2asym; + using B_2asym = typename B::T_2asym; + using AB_1_1 = typename AB::T_1_1; + + /// checked if triggers can be factorized = no mixed trigger in the combination. + if(m_n1L>0 && !m_n2L && !m_n3L) + { + return bindFunction<A_1, B_1>() || bindFunction<flat_set<A_1>, flat_set<B_1>>(); + } + else if(m_n2L==1 && !m_n3L) /// one dilepton trigger (+ single-lepton triggers) + { + return bindFunction<AB_1_1>() || bindFunction<AB_1_1, flat_set<A_1>, flat_set<B_1>>(); + } + else if(m_n2L>=2 && m_n2L<=6 && !m_n3L) /// several dilepton triggers (+ single-lepton triggers) + { + return + /// 2 dilepton triggers + bindFunction<A_2sym, AB_1_1>() || bindFunction<A_2asym, AB_1_1>() + || bindFunction<B_2sym, AB_1_1>() || bindFunction<B_2asym, AB_1_1>() + /// 3 dilepton triggers + || bindFunction<Optional<A_2sym>, Optional<B_2sym>, Optional<AB_1_1>, OA1L, OB1L>() + || bindFunction<Optional<A_2asym>, Optional<B_2sym>, Optional<AB_1_1>, OA1L, OB1L>() + || bindFunction<Optional<A_2sym>, Optional<B_2asym>, Optional<AB_1_1>, OA1L, OB1L>() + || bindFunction<Optional<A_2asym>, Optional<B_2asym>, Optional<AB_1_1>, OA1L, OB1L>() + /// 6 dilepton triggers + || bindFunction<Optional<A_2sym>, Optional<A_2sym>, Optional<B_2sym>, Optional<B_2sym>, Optional<AB_1_1>, Optional<AB_1_1>, OA1L, OB1L>() + || bindFunction<Optional<A_2asym>, Optional<A_2sym>, Optional<B_2sym>, Optional<B_2sym>, Optional<AB_1_1>, Optional<AB_1_1>, OA1L, OB1L>() + || bindFunction<Optional<A_2sym>, Optional<A_2sym>, Optional<B_2asym>, Optional<B_2sym>, Optional<AB_1_1>, Optional<AB_1_1>, OA1L, OB1L>() + || bindFunction<Optional<A_2asym>, Optional<A_2sym>, Optional<B_2asym>, Optional<B_2sym>, Optional<AB_1_1>, Optional<AB_1_1>, OA1L, OB1L>(); + } + else if(m_n3L==1 && !m_n2L && !m_n1L) /// one mixed trilepton trigger + { + return bindFunction<typename AB::T_2sym_1>() || bindFunction<typename AB::T_1_2sym>() + || bindFunction<typename AB::T_2asym_1>() || bindFunction<typename AB::T_1_2asym>(); + } + else if(m_n3L==2 && !m_n2L && !m_n1L) /// two mixed trilepton triggers + { + return bindFunction<typename AB::T_2sym_1, typename AB::T_1_2sym>() + || bindFunction<typename AB::T_2asym_1, typename AB::T_1_2sym>() + || bindFunction<typename AB::T_2sym_1, typename AB::T_1_2asym>() + || bindFunction<typename AB::T_2asym_1, typename AB::T_1_2asym>(); + } + return false; +} + +bool Calculator::Helper::findAndBindFunction() /// top-level function +{ + auto countTriggers = [&](auto nlep_flag) { return std::count_if(m_defs.cbegin(), m_defs.cend(), [=](auto& def){return def.type&nlep_flag;}); }; + m_n1L = countTriggers(TT_SINGLELEPTON_FLAG); + m_n2L = countTriggers(TT_DILEPTON_FLAG); + m_n3L = countTriggers(TT_TRILEPTON_FLAG); + auto exclusively = [&](auto obj_flags) { return std::none_of(m_defs.cbegin(), m_defs.cend(), [=](auto& def){return def.type&TT_MASK_FLAVOUR&~obj_flags;}); }; + + /// First check if the trigger combination refers to a single object type + if(exclusively(TT_ELECTRON_FLAG)) return findAndBindFunction<TT_ELECTRON_FLAG>(); + if(exclusively(TT_MUON_FLAG)) return findAndBindFunction<TT_MUON_FLAG>(); + if(exclusively(TT_PHOTON_FLAG)) return findAndBindFunction<TT_PHOTON_FLAG>(); + + /// Then try to rely on available formulas for combinations with two object types + bool success = false; + if(exclusively(TT_ELECTRON_FLAG|TT_MUON_FLAG)) success = findAndBindFunction<TT_ELECTRON_FLAG,TT_MUON_FLAG>(); + else if(exclusively(TT_ELECTRON_FLAG|TT_PHOTON_FLAG)) success = findAndBindFunction<TT_ELECTRON_FLAG,TT_PHOTON_FLAG>(); + else if(exclusively(TT_MUON_FLAG|TT_PHOTON_FLAG)) success = findAndBindFunction<TT_MUON_FLAG,TT_PHOTON_FLAG>(); + if(success) return true; + + /// As a last resort, maybe factorizing helps + std::vector<Helper> helpers; + for(auto obj_flag : {TT_ELECTRON_FLAG, TT_MUON_FLAG, TT_PHOTON_FLAG}) + { + if(std::any_of(m_defs.cbegin(), m_defs.cend(), /// check there's no mixed-flavour trigger involving 'obj_flag' + [&](auto& def){ return (def.type&obj_flag) && TriggerProperties(def.type).mixed();})) continue; + std::vector<ImportData::TrigDef> trigs1, trigs2; + std::partition_copy(m_defs.begin(), m_defs.end(), std::back_inserter(trigs1), std::back_inserter(trigs2), [&](auto& def){ return (def.type&obj_flag); }); + m_defs.swap(trigs2); + if(!trigs1.size()) continue; + helpers.emplace_back(trigs1); + if(!helpers.back().findAndBindFunction()) return false; + } + if(helpers.size()) + { + if(m_defs.size()) + { + if(!findAndBindFunction()) return false; + if(helpers.size() == 1) m_formula = std::bind(&Calculator::globalEfficiency_Factorized2, ::_1, ::_2, ::_3, + std::move(m_formula), std::move(helpers[0].m_formula), ::_4); + else if(helpers.size()==2) m_formula = std::bind(&Calculator::globalEfficiency_Factorized3, ::_1, ::_2, ::_3, + std::move(m_formula), std::move(helpers[0].m_formula), std::move(helpers[1].m_formula), ::_4); + else + { + m_formula = nullptr; + return false; + } + } + else + { + if(helpers.size() == 2) m_formula = std::bind(&Calculator::globalEfficiency_Factorized2, ::_1, ::_2, ::_3, + std::move(helpers[0].m_formula), std::move(helpers[1].m_formula), ::_4); + else if(helpers.size() == 3) m_formula = std::bind(&Calculator::globalEfficiency_Factorized3, ::_1, ::_2, ::_3, + std::move(helpers[0].m_formula), std::move(helpers[1].m_formula), std::move(helpers[2].m_formula), ::_4); + else return false; + } + return true; + } + + return false; +} \ No newline at end of file diff --git a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/Root/CheckConfig.cxx b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/Root/CheckConfig.cxx index d320656c86130d15031342649326b2bb5a2e06c2..64750ee19ea87d41a13008719589252df513647a 100644 --- a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/Root/CheckConfig.cxx +++ b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/Root/CheckConfig.cxx @@ -8,6 +8,9 @@ #include "TrigGlobalEfficiencyCorrection/ImportData.h" #include "TrigGlobalEfficiencyCorrection/Calculator.h" #include <boost/container/flat_set.hpp> +template<typename Key> using flat_set = boost::container::flat_set<Key>; + +#include <cctype> using CheckConfig = TrigGlobEffCorr::CheckConfig; using ImportData = TrigGlobEffCorr::ImportData; @@ -49,7 +52,7 @@ bool CheckConfig::basicConfigChecks() return false; } - /// All tools mentioned in 'ListOfLegsPerTool' must be in 'ElectronEfficiencyTools' or 'ElectronScaleFactorTools' + /// All tools mentioned in 'ListOfLegsPerTool' must be in 'ElectronEfficiencyTools' or 'ElectronScaleFactorTools' (or equivalent photon tools) for(auto& kv : m_parent.m_legsPerTool) { auto& name = kv.first; @@ -75,23 +78,28 @@ bool CheckConfig::basicConfigChecks() } if(!success) return false; - /// All electron tools must be associated to trigger legs (except when there's only one tool) - if(m_parent.m_suppliedElectronEfficiencyTools.size() > 1) + /// All electron/photon tools must be associated to trigger legs (except when there's only one tool) + auto toolsHaveLegInfo = [this](auto& effTools, auto& sfTools, const char* type) { + if(effTools.size() < 2) return true; + bool success = true; for(int i=0;i<2;++i) { - for(auto& tool : (i? m_parent.m_suppliedElectronEfficiencyTools : m_parent.m_suppliedElectronScaleFactorTools)) + for(auto& tool : (i? effTools: sfTools)) { const std::string& name = tool.name(); if(m_parent.m_legsPerTool.find(name) == m_parent.m_legsPerTool.end()) { - success = false; - ATH_MSG_ERROR("Electron tool " << name << " associated trigger legs are not indicated in 'ListOfLegsPerTool', " + ATH_MSG_ERROR(type << " tool " << name << " associated trigger legs are not indicated in 'ListOfLegsPerTool', " "doing so is mandatory when several tools are used"); + success = false; } } } - } + return success; + }; + success &= toolsHaveLegInfo(m_parent.m_suppliedElectronEfficiencyTools, m_parent.m_suppliedElectronScaleFactorTools, "Electron"); + success &= toolsHaveLegInfo(m_parent.m_suppliedPhotonEfficiencyTools, m_parent.m_suppliedPhotonScaleFactorTools, "Photon"); if(!success) return false; /// @@ -110,20 +118,24 @@ bool CheckConfig::basicConfigChecks() return true; } - /// All tools mentioned in 'ListOfTagsPerTool' must be in 'ElectronEfficiencyTools', 'ElectronScaleFactorTools' or 'MuonTools' - unsigned nElectronToolsWithTags = 0, nMuonToolsWithTags = 0; + /// All tools mentioned in 'ListOfTagsPerTool' must be known + unsigned nElectronToolsWithTags = 0, nMuonToolsWithTags = 0, nPhotonToolsWithTags = 0; for(auto& kv : m_parent.m_tagsPerTool) { auto& name = kv.first; - if(findToolByName(m_parent.m_suppliedElectronEfficiencyTools,name) - || findToolByName(m_parent.m_suppliedElectronScaleFactorTools,name)) ++nElectronToolsWithTags; - else if(findToolByName(m_parent.m_suppliedMuonTools,name)) ++nMuonToolsWithTags; + if(findToolByName(m_parent.m_suppliedElectronEfficiencyTools, name) + || findToolByName(m_parent.m_suppliedElectronScaleFactorTools, name)) ++nElectronToolsWithTags; + else if(findToolByName(m_parent.m_suppliedMuonTools, name)) ++nMuonToolsWithTags; + else if(findToolByName(m_parent.m_suppliedPhotonEfficiencyTools, name) + || findToolByName(m_parent.m_suppliedPhotonScaleFactorTools, name)) ++nPhotonToolsWithTags; else { success = false; std::string all_tools = "; the known tools are"; for(auto& tool : m_parent.m_suppliedElectronEfficiencyTools) all_tools += " " + tool.name(); for(auto& tool : m_parent.m_suppliedElectronScaleFactorTools) all_tools += " " + tool.name(); + for(auto& tool : m_parent.m_suppliedPhotonEfficiencyTools) all_tools += " " + tool.name(); + for(auto& tool : m_parent.m_suppliedPhotonScaleFactorTools) all_tools += " " + tool.name(); ATH_MSG_ERROR("Unknown tool " << name << " mentioned in property 'ListOfTagsPerTool'"); } } @@ -141,26 +153,32 @@ bool CheckConfig::basicConfigChecks() success = false; } if(!success) return false; + /// Either all photon tools are associated to tags, either none + nSupplied = m_parent.m_suppliedPhotonEfficiencyTools.size() + m_parent.m_suppliedPhotonScaleFactorTools.size(); + if(nPhotonToolsWithTags && (nPhotonToolsWithTags!=nSupplied)) + { + ATH_MSG_ERROR("Not all photon tools have been associated with tags in the 'ListOfTagsPerTool' property"); + success = false; + } + if(!success) return false; /* * More checks that are done in other places (or still need to be implemented!): * * - [advancedConfigChecks()] for each entry in ListOfLegsPerTag there must be a suitable tool for that tag and leg(s) - * - [enumerateTools()] no two electron tools share the same {leg,tag} combination + * - [enumerateTools()] no two electron/photon tools share the same {leg,tag} combination * - [enumerateTools()] no two muon tools share the same tag - * - [matchingEfficiencyAndScaleFactorTools()] electron efficiency and scale factors have identical configurations: for each eff. tool leg/tag we must find a SF tool, and the other leg/tag pairs associated to those tools must be identical. - * - [UNCHECKED] if tags are used with electron (resp. muon) tools, then all electron (muon) tools must have an entry in ListOfTagsPerTool. Done partially in this function, but the case where no tools are tagged (yet tags are used, according to ListOfLegsPerTag or LeptonTagDecorations) escapes detection. + * - [advancedConfigChecks()] electron efficiency and scale factors have identical configurations: for each eff. tool leg/tag we must find a SF tool, and the other leg/tag pairs associated to those tools must be identical. + * - [UNCHECKED] if tags are used with electron (resp. muon, photon) tools, then all electron (muon, photon) tools must have an entry in ListOfTagsPerTool. Done partially in this function, but the case where no tools are tagged (yet tags are used, according to ListOfLegsPerTag or LeptonTagDecorations) escapes detection. * - [loadTagsConfiguration()] each entry of ListOfLegsPerTag can be matched to a suitable tool * - [UNCHECKED] suffixed tag read from a lepton must correspond to a know tag * - [enumerateTools()] list of legs associated to each tool contains only known legs * - [UNCHECKED TrigGlobEffCorrImportData import* functions] various consistency checks of the configuration files - * - [UNCHECKED] some unfinished functions in advancedConfigChecks * - [advancedConfigChecks()] user-specified periods are orthogonal * - [ImportData::parseTriggerString()] no duplicated triggers in the combination - * - [UNCHECKED] for each configured electron tool there is at least one associated tag^leg pair in 'ListOfLegsPerTag' (unless no electron tags used) + * - [UNCHECKED] for each configured electron/photon tool there is at least one associated tag^leg pair in 'ListOfLegsPerTag' (unless no electron/photon tags used) * - [UNCHECKED] for each configured muon tool there is at least one associated tag in 'MuonLegsPerTag' (unless empty) - * - [UNCHECKED] electron tools can't be associated to photon legs - * - [UNCHECKED] all checks also for photon tools + * - [enumerateTools()] electron tools can't be associated to photon legs; and reciprocally */ return success; @@ -171,51 +189,40 @@ bool CheckConfig::advancedConfigChecks() /// This method requires all (most) of TrigGlobalEfficiencyCorrectionTool internal variables to have been properly initialized already /// -> to be called as the last step of TrigGlobalEfficiencyCorrectionTool::initialize() bool success = true; - - const auto& electronEffToolIndex = m_parent.m_electronEffToolIndex; - const auto& electronSfToolIndex = m_parent.m_electronSfToolIndex; - const auto& muonToolIndex = m_parent.m_muonToolIndex; + using ToolKey = TrigGlobalEfficiencyCorrectionTool::ToolKey; - /// Check that for each electron efficiency tool there is an associated scale factor tool + /// Check that for each electron/photon efficiency tool there is an associated scale factor tool /// with the same associated legs and tags. And vice versa. - bool mismatch = (electronEffToolIndex.size() != electronSfToolIndex.size()); - if(!mismatch) + auto checkConsistency = [this](auto& effToolIndex, auto& sfToolIndex, const char* type) { - for(auto& kv : electronSfToolIndex) + bool mismatch = (effToolIndex.size() != sfToolIndex.size()); + if(!mismatch) { - auto itr = electronEffToolIndex.find(kv.first); - if(itr != electronEffToolIndex.end()) + for(auto& kv : sfToolIndex) { - std::size_t index1 = kv.second, index2 = itr->second; - flat_set<ToolKey> pairs1, pairs2; - for(auto& kv : electronSfToolIndex) - { - if(kv.second==index1) pairs1.insert(kv.first); - } - for(auto& kv : electronEffToolIndex) - { - if(kv.second==index2) pairs2.insert(kv.first); - } - if(pairs1 != pairs2) + auto itr = effToolIndex.find(kv.first); + if(itr != effToolIndex.end()) { - mismatch = true; - break; + std::size_t index1 = kv.second, index2 = itr->second; + flat_set<ToolKey> pairs1, pairs2; + for(auto& kv : sfToolIndex) if(kv.second==index1) pairs1.insert(kv.first); + for(auto& kv : effToolIndex) if(kv.second==index2) pairs2.insert(kv.first); + if(pairs1 != pairs2) mismatch = true; } - } - else - { - mismatch = true; - break; + else mismatch = true; } } - } - if(mismatch) - { - ATH_MSG_ERROR("There must be a one-to-one correspondence between the electron efficiency and scale factor tools " - "(including their associated trigger legs and selection tags)"); - return false; - } + if(mismatch) + { + ATH_MSG_ERROR("There must be a one-to-one correspondence between the " << type << " efficiency and scale factor tools " + "(including their associated trigger legs and selection tags)"); + return false; + } + return true; + }; + if(!checkConsistency(m_parent.m_electronEffToolIndex, m_parent.m_electronSfToolIndex, "electron")) return false; + if(!checkConsistency(m_parent.m_photonEffToolIndex, m_parent.m_photonSfToolIndex, "photon")) return false; /// A suitable CP tool must be available for each entry of 'ListOfLegsPerTag' for(auto& kv : m_parent.m_legsPerTag) @@ -226,7 +233,7 @@ bool CheckConfig::advancedConfigChecks() auto type = ImportData::associatedLeptonFlavour(m_parent.m_dictionary[leg],success); if(type == xAOD::Type::Electron) { - if(electronEffToolIndex.find(ToolKey(leg, tag)) == electronEffToolIndex.end()) + if(m_parent.m_electronEffToolIndex.find(ToolKey(leg, tag)) == m_parent.m_electronEffToolIndex.end()) { ATH_MSG_ERROR("No electron tool provided for the combination of trigger leg '" << m_parent.m_dictionary[leg] << "' and selection tag '" << kv.first << "' mentioned in the property 'ListOfLegsPerTag'"); @@ -235,13 +242,22 @@ bool CheckConfig::advancedConfigChecks() } else if(type == xAOD::Type::Muon) { - if(muonToolIndex.find(ToolKey(0, tag)) == muonToolIndex.end()) + if(m_parent.m_muonToolIndex.find(ToolKey(0, tag)) == m_parent.m_muonToolIndex.end()) { ATH_MSG_ERROR("No muon tool provided for the combination of trigger leg '" << m_parent.m_dictionary[leg] << "' and selection tag '" << kv.first << "' mentioned in the property 'ListOfLegsPerTag'"); success = false; } } + else if(type == xAOD::Type::Photon) + { + if(m_parent.m_photonEffToolIndex.find(ToolKey(leg, tag)) == m_parent.m_photonEffToolIndex.end()) + { + ATH_MSG_ERROR("No photon tool provided for the combination of trigger leg '" << m_parent.m_dictionary[leg] + << "' and selection tag '" << kv.first << "' mentioned in the property 'ListOfLegsPerTag'"); + success = false; + } + } else { ATH_MSG_ERROR("Unable to determine which lepton flavour is associated to the trigger leg '" << m_parent.m_dictionary[leg] << "' in the property 'ListOfLegsPerTag'"); diff --git a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/Root/ImportData.cxx b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/Root/ImportData.cxx index 56873cede4f2b95cb014d0d61c9c82f954a83c5b..ed6d3f00032fe48f11741103de680ec897cbf476 100644 --- a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/Root/ImportData.cxx +++ b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/Root/ImportData.cxx @@ -94,7 +94,7 @@ void ImportData::setNonMixed3LType(TrigDef& def, TriggerType flavourFlag) { if(def.leg[0]==def.leg[1] && def.leg[1]==def.leg[2]) def.type = static_cast<TriggerType>(TT_TRILEPTON_SYM | flavourFlag); else if(def.leg[0]!=def.leg[1] && def.leg[1]!=def.leg[2] && def.leg[0]!=def.leg[2]) def.type = static_cast<TriggerType>(TT_TRILEPTON_ASYM | flavourFlag); - else // swap legs so that the last two are identical, for later convenience + else /// swap legs so that the last two are identical, for later convenience { if(def.leg[1]!=def.leg[0] && def.leg[1]!=def.leg[2]) std::swap(def.leg[0],def.leg[1]); else if(def.leg[2]!=def.leg[0] && def.leg[2]!=def.leg[1]) std::swap(def.leg[0],def.leg[2]); @@ -145,62 +145,67 @@ bool ImportData::importTriggers() } if(!success) continue; - /// Classify trigger and re-arrange legs (if needed) so that all electron legs come before muon legs - def.type = TT_UNKNOWN; + /// Classify trigger and re-arrange legs (if needed) so that all electron legs come before muon legs, and muon legs before photon legs + def.type = TT_UNKNOWN; auto flavour0 = associatedLeptonFlavour(def.leg[0], success); - if(flavour0 == xAOD::Type::Electron || flavour0 == xAOD::Type::Muon) + int ne = (flavour0 == xAOD::Type::Electron)*1; + int nm = (flavour0 == xAOD::Type::Muon)*1; + if(def.leg[1]) { - int ne = (flavour0 == xAOD::Type::Electron)? 1: 0; - if(def.leg[1]) + auto flavour1 = associatedLeptonFlavour(def.leg[1], success); + if(flavour1 == xAOD::Type::Electron) { - if(associatedLeptonFlavour(def.leg[1], success) == xAOD::Type::Electron) + if(!ne) std::swap(def.leg[0],def.leg[1]); + ++ne; + } + else if(flavour1 == xAOD::Type::Muon) + { + if(!(ne+nm)) std::swap(def.leg[0],def.leg[1]); + ++nm; + } + else if(flavour1 != xAOD::Type::Photon) success = false; + if(def.leg[2]) + { + auto flavour2 = associatedLeptonFlavour(def.leg[2], success); + if(flavour2 == xAOD::Type::Electron) { - if(!ne) std::swap(def.leg[0],def.leg[1]); + if(!ne) std::swap(def.leg[0], def.leg[2]); + else if(ne==1) std::swap(def.leg[1], def.leg[2]); ++ne; } - if(def.leg[2]) + else if(flavour2 == xAOD::Type::Muon) { - if(associatedLeptonFlavour(def.leg[2], success)==xAOD::Type::Electron) - { - if(!ne) std::swap(def.leg[0], def.leg[2]); - else if(ne==1) std::swap(def.leg[1], def.leg[2]); - ++ne; - } - if(ne==0 || ne==3) // 3e, 3mu - { - setNonMixed3LType(def, (ne? TT_ELECTRON_FLAG : TT_MUON_FLAG)); - } - else // µµe, eeµ - { - if(def.leg[0]==def.leg[1] || def.leg[1]==def.leg[2]) def.type = ((ne>=2) ? TT_2E_MU_SYM : TT_E_2MU_SYM); - else def.type = ((ne>=2)? TT_2E_MU_ASYM : TT_E_2MU_ASYM); - } + if(!(ne+nm)) std::swap(def.leg[0], def.leg[2]); + else if((ne+nm)==1) std::swap(def.leg[1], def.leg[2]); + ++nm; + } + else if(flavour2 != xAOD::Type::Photon) success = false; + if(ne+nm==0 || ne==3 || nm==3) /// single-flavour trilepton triggers + { + setNonMixed3LType(def, (ne? TT_ELECTRON_FLAG : nm? TT_MUON_FLAG : TT_PHOTON_FLAG)); } - else + else /// mixed-flavour trilepton triggers { - if(ne==0) def.type = (def.leg[0]==def.leg[1])? TT_2MU_SYM : TT_2MU_ASYM; - else if(ne==1) def.type = TT_EMU; - else def.type = (def.leg[0]==def.leg[1])? TT_2E_SYM : TT_2E_ASYM; + bool sym = (def.leg[0]==def.leg[1] || def.leg[1]==def.leg[2]); + if(ne==2) def.type = nm? (sym? TT_2E_MU_SYM : TT_2E_MU_ASYM) : (sym? TT_2E_G_SYM : TT_2E_G_ASYM); + else if(nm==2) def.type = ne? (sym? TT_E_2MU_SYM : TT_E_2MU_ASYM) : (sym? TT_2MU_G_SYM : TT_2MU_G_ASYM); + else if(ne+nm==1) def.type = ne? (sym? TT_E_2G_SYM : TT_E_2G_ASYM) : (sym? TT_MU_2G_SYM : TT_MU_2G_ASYM); + else success = false; } } - else + else /// dilepton triggers { - def.type = ne? TT_SINGLE_E : TT_SINGLE_MU; + if(ne==2) def.type = (def.leg[0]==def.leg[1])? TT_2E_SYM : TT_2E_ASYM; + else if(nm==2) def.type = (def.leg[0]==def.leg[1])? TT_2MU_SYM : TT_2MU_ASYM; + else if(ne+nm==0) def.type = (def.leg[0]==def.leg[1])? TT_2G_SYM : TT_2G_ASYM; + else if(ne==1 && nm==1) def.type = TT_E_MU; + else if(ne==1) def.type = TT_E_G; + else if(nm==1) def.type = TT_MU_G; } } - else if(flavour0 == xAOD::Type::Photon) + else /// single lepton triggers { - if(def.leg[1]) - { - if(associatedLeptonFlavour(def.leg[1], success) != xAOD::Type::Photon) success = false; - if(def.leg[2]) - { - if(associatedLeptonFlavour(def.leg[2], success) != xAOD::Type::Photon) success = false; - setNonMixed3LType(def, TT_PHOTON_FLAG); - } - else def.type = (def.leg[0]==def.leg[1])? TT_2PH_SYM : TT_2PH_ASYM; - } - else def.type = TT_SINGLE_PH; + def.type = ne? TT_SINGLE_E : nm? TT_SINGLE_MU : TT_SINGLE_G; } if(!success || def.type==TT_UNKNOWN) { diff --git a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/Root/TrigGlobalEfficiencyCorrectionTool.cxx b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/Root/TrigGlobalEfficiencyCorrectionTool.cxx index 2c71f48864b71e6426db239f1c010d94cf1332f8..513c3dc528f27c0b6afa1f2273dc23bf785cd806 100644 --- a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/Root/TrigGlobalEfficiencyCorrectionTool.cxx +++ b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/Root/TrigGlobalEfficiencyCorrectionTool.cxx @@ -206,8 +206,8 @@ bool TrigGlobalEfficiencyCorrectionTool::enumerateTools(ImportData& data, ToolHa continue; } } - else if(!std::is_same<CPTool,CP::IMuonTriggerScaleFactors>::value - && !std::is_same<CPTool,IAsgPhotonEfficiencyCorrectionTool>::value) + else if(std::is_same<CPTool,IAsgElectronEfficiencyCorrectionTool>::value + || std::is_same<CPTool,IAsgPhotonEfficiencyCorrectionTool>::value) { ATH_MSG_ERROR("Property 'ListOfLegsPerTool' empty for tool '" << name << "'"); success = false; @@ -235,6 +235,16 @@ bool TrigGlobalEfficiencyCorrectionTool::enumerateTools(ImportData& data, ToolHa for(auto& key : listOfLegs) { std::size_t leg = key.hash; + if(leg) + { + auto flavour = data.associatedLeptonFlavour(leg, success); + if(!(flavour==xAOD::Type::Electron && std::is_same<CPTool,IAsgElectronEfficiencyCorrectionTool>::value) + && !(flavour==xAOD::Type::Photon && std::is_same<CPTool,IAsgPhotonEfficiencyCorrectionTool>::value)) + { + ATH_MSG_ERROR("Unexpected association of trigger leg '" << m_dictionary[leg] << "' to tool '" << name << "'"); + success = false; + } + } for(std::size_t tag : tags) { if(!toolIndex.emplace(ToolKey(leg, tag, key.boundaries), index).second) @@ -324,17 +334,14 @@ bool TrigGlobalEfficiencyCorrectionTool::loadTriggerCombination(ImportData& data success = false; continue; } - std::size_t uniqueElectronLeg = 0, uniquePhotonLeg = 0; - if(!m_calculator->addPeriod(data, boundaries, kv.second, m_numberOfToys, useDefaultElectronTools, uniqueElectronLeg, useDefaultPhotonTools, uniquePhotonLeg)) + std::size_t uniqueElectronLeg = !useDefaultElectronTools, uniquePhotonLeg = !useDefaultPhotonTools; + if(!m_calculator->addPeriod(data, boundaries, kv.second, m_numberOfToys, uniqueElectronLeg, uniquePhotonLeg)) { success = false; continue; } - else - { - if(uniqueElectronLeg) allUniqueElectronLegs.insert(uniqueElectronLeg); - if(uniquePhotonLeg) allUniquePhotonLegs.insert(uniquePhotonLeg); - } + if(uniqueElectronLeg && useDefaultElectronTools) allUniqueElectronLegs.insert(uniqueElectronLeg); + if(uniquePhotonLeg && useDefaultPhotonTools) allUniquePhotonLegs.insert(uniquePhotonLeg); } if(!success) return false; @@ -578,7 +585,7 @@ bool TrigGlobalEfficiencyCorrectionTool::getEgammaTriggerLegEfficiencies(const P { /// Common implementation for electrons and photons auto ptype = []() { return std::is_same<ParticleType, xAOD::Electron>::value? "electron" : std::is_same<ParticleType, xAOD::Photon>::value? "photon" : "<unknown type>"; }; - auto pp = reinterpret_cast<const xAOD::IParticle*>(p); + auto pp = static_cast<const xAOD::IParticle*>(p); ATH_MSG_DEBUG("Retrieving efficiencies for " << ptype() << ' ' << p << " (pt=" << pp->pt() << ", eta=" << pp->eta() << ", tag='" << m_dictionary[tag] << "') for trigger leg " << m_dictionary[leg]); auto itrSf = GetScaleFactorToolIndex(p).find(ToolKey(leg, tag, runNumber)); @@ -640,14 +647,23 @@ bool TrigGlobalEfficiencyCorrectionTool::getTriggerLegEfficiencies(const xAOD::M bool TrigGlobalEfficiencyCorrectionTool::retrieveRunNumber(unsigned& runNumber) { + runNumber = 0; auto eventInfo = evtStore()->retrieve<const xAOD::EventInfo>("EventInfo"); - if(!eventInfo || !m_runNumberDecorator.isAvailable(*eventInfo)) + if(!eventInfo) { - ATH_MSG_ERROR("Can't retrieve run number from evtStore()"); - runNumber = 0; + ATH_MSG_ERROR("Can't retrieve 'EventInfo' from evtStore()"); return false; } - runNumber = m_runNumberDecorator(*eventInfo); + if(eventInfo->eventType(xAOD::EventInfo::IS_SIMULATION)) + { + if(!m_runNumberDecorator.isAvailable(*eventInfo)) + { + ATH_MSG_ERROR("Can't retrieve 'RandomRunNumber' from EventInfo"); + return false; + } + runNumber = m_runNumberDecorator(*eventInfo); + } + else runNumber = eventInfo->runNumber(); return true; } @@ -692,54 +708,6 @@ bool TrigGlobalEfficiencyCorrectionTool::updateLeptonList(LeptonList& leptons, c return true; } -CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiencyScaleFactor(const std::vector<const xAOD::Electron*>& electrons, const std::vector<const xAOD::Muon*>& muons, double& efficiencyScaleFactor) -{ - unsigned runNumber; - if(!retrieveRunNumber(runNumber)) return CP::CorrectionCode::Error; - return getEfficiencyScaleFactor(runNumber, electrons, muons, efficiencyScaleFactor); -} - -CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiencyScaleFactor(unsigned runNumber, const std::vector<const xAOD::Electron*>& electrons, const std::vector<const xAOD::Muon*>& muons, double& efficiencyScaleFactor) -{ - LeptonList leptons; - updateLeptonList(leptons, electrons); - updateLeptonList(leptons, muons); - return getEfficiencyScaleFactor(runNumber, leptons, efficiencyScaleFactor); -} - -CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiency(const std::vector<const xAOD::Electron*>& electrons, const std::vector<const xAOD::Muon*>& muons, double& efficiencyData, double& efficiencyMc) -{ - unsigned runNumber; - if(!retrieveRunNumber(runNumber)) return CP::CorrectionCode::Error; - return getEfficiency(runNumber, electrons, muons, efficiencyData, efficiencyMc); -} - -CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiency(unsigned runNumber, const std::vector<const xAOD::Electron*>& electrons, const std::vector<const xAOD::Muon*>& muons, double& efficiencyData, double& efficiencyMc) -{ - LeptonList leptons; - updateLeptonList(leptons, electrons); - updateLeptonList(leptons, muons); - return getEfficiency(runNumber, leptons, efficiencyData, efficiencyMc); -} - -CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiencyScaleFactor(const std::vector<const xAOD::Photon*>& photons, double& efficiencyScaleFactor) -{ - unsigned runNumber; - if(!retrieveRunNumber(runNumber)) return CP::CorrectionCode::Error; - LeptonList leptons; - updateLeptonList(leptons, photons); - return getEfficiencyScaleFactor(runNumber, leptons, efficiencyScaleFactor); -} - -CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiency(const std::vector<const xAOD::Photon*>& photons, double& efficiencyData, double& efficiencyMc) -{ - unsigned runNumber; - if(!retrieveRunNumber(runNumber)) return CP::CorrectionCode::Error; - LeptonList leptons; - updateLeptonList(leptons, photons); - return getEfficiency(runNumber, leptons, efficiencyData, efficiencyMc); -} - CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiencyScaleFactor(const std::vector<const xAOD::IParticle*>& leptons, double& efficiencyScaleFactor) { unsigned runNumber; @@ -747,13 +715,6 @@ CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiencyScaleFactor( return getEfficiencyScaleFactor(runNumber, leptons, efficiencyScaleFactor); } -CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiencyScaleFactor(unsigned runNumber, const std::vector<const xAOD::IParticle*>& particles, double& efficiencyScaleFactor) -{ - LeptonList leptons; - updateLeptonList(leptons, particles); - return getEfficiencyScaleFactor(runNumber, leptons, efficiencyScaleFactor); -} - CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiency(const std::vector<const xAOD::IParticle*>& leptons, double& efficiencyData, double& efficiencyMc) { unsigned runNumber; @@ -761,20 +722,13 @@ CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiency(const std:: return getEfficiency(runNumber, leptons, efficiencyData, efficiencyMc); } -CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiency(unsigned runNumber, const std::vector<const xAOD::IParticle*>& particles, double& efficiencyData, double& efficiencyMc) -{ - LeptonList leptons; - updateLeptonList(leptons, particles); - return getEfficiency(runNumber, leptons, efficiencyData, efficiencyMc); -} - -CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiencyScaleFactor(unsigned runNumber, const LeptonList& leptons, double& efficiencyScaleFactor) +CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiencyScaleFactor(unsigned runNumber, const std::vector<const xAOD::IParticle*>& particles, double& efficiencyScaleFactor) { - m_cpCode = CP::CorrectionCode::Ok; // ignores silently previous state + clears "checked" flag + m_cpCode = CP::CorrectionCode::Ok; /// ignores silently previous state + clears "checked" flag efficiencyScaleFactor = 1.; Efficiencies efficiencies; - auto cc = getEfficiency(runNumber, leptons, efficiencies.data(), efficiencies.mc()); + auto cc = getEfficiency(runNumber, particles, efficiencies.data(), efficiencies.mc()); if(cc == CP::CorrectionCode::Ok) { if(efficiencies.data()>0. && efficiencies.mc()>0.) @@ -793,13 +747,13 @@ CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiencyScaleFactor( return cc; } -CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiency(unsigned runNumber, const LeptonList& leptons, double& efficiencyData, double& efficiencyMc) +CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiency(unsigned runNumber, const std::vector<const xAOD::IParticle*>& particles, double& efficiencyData, double& efficiencyMc) { - m_cpCode = CP::CorrectionCode::Ok; // ignores silently previous state + clears "checked" flag + m_cpCode = CP::CorrectionCode::Ok; /// ignores silently previous state + clears "checked" flag efficiencyData = 0.; efficiencyMc = 0.; - ATH_MSG_DEBUG("Computing global trigger efficiency for this event with " << leptons.size() << " lepton(s) as input; run number = " << runNumber); + ATH_MSG_DEBUG("Computing global trigger efficiency for this event with " << particles.size() << " lepton(s) as input; run number = " << runNumber); if(runNumber<266904 || runNumber>341649) { @@ -819,6 +773,9 @@ CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiency(unsigned ru } #endif + LeptonList leptons; + updateLeptonList(leptons, particles); + Efficiencies efficiencies; if(m_calculator->compute(*this, leptons, runNumber, efficiencies)) { @@ -840,29 +797,6 @@ CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getEfficiency(unsigned ru } CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::checkTriggerMatching(bool& matched, const std::vector<const xAOD::IParticle*>& particles) -{ - LeptonList leptons; - updateLeptonList(leptons, particles); - return checkTriggerMatching(matched, leptons); -} - -CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::checkTriggerMatching(bool& matched, const std::vector<const xAOD::Electron*>& electrons, - const std::vector<const xAOD::Muon*>& muons) -{ - LeptonList leptons; - updateLeptonList(leptons, electrons); - updateLeptonList(leptons, muons); - return checkTriggerMatching(matched, leptons); -} - -CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::checkTriggerMatching(bool& matched, const std::vector<const xAOD::Photon*>& photons) -{ - LeptonList leptons; - updateLeptonList(leptons, photons); - return checkTriggerMatching(matched, leptons); -} - -CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::checkTriggerMatching(bool& matched, const LeptonList& leptons) { unsigned runNumber; if(!retrieveRunNumber(runNumber)) @@ -875,10 +809,23 @@ CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::checkTriggerMatching(bool ATH_MSG_ERROR("A valid IMatchingTool instance should be provided via the property 'TriggerMatchingTool'"); return CP::CorrectionCode::Error; } + LeptonList leptons; + updateLeptonList(leptons, particles); return m_calculator->checkTriggerMatching(*this, matched, leptons, runNumber)? CP::CorrectionCode::Ok : CP::CorrectionCode::Error; } -bool TrigGlobalEfficiencyCorrectionTool::aboveThreshold(const Lepton& lepton,std::size_t leg) const +CP::CorrectionCode TrigGlobalEfficiencyCorrectionTool::getRelevantTriggers(std::vector<std::string>& triggers) +{ + unsigned runNumber; + if(!retrieveRunNumber(runNumber)) + { + ATH_MSG_ERROR("Unable to retrieve run number, aborting getRelevantTriggers()"); + return CP::CorrectionCode::Error; + } + return m_calculator->getRelevantTriggersForUser(*this, triggers, runNumber)? CP::CorrectionCode::Ok : CP::CorrectionCode::Error; +} + +bool TrigGlobalEfficiencyCorrectionTool::aboveThreshold(const Lepton& lepton, std::size_t leg) const { bool decision = (lepton.pt() >= m_thresholds.at(leg)); if(m_validLegTagPairs.size()) @@ -905,7 +852,7 @@ std::size_t TrigGlobalEfficiencyCorrectionTool::getCombinedHash(const flat_set<s std::size_t TrigGlobalEfficiencyCorrectionTool::getCombinedHash(std::size_t leg1, std::size_t leg2) { - return leg1 ^ leg2; // returns 0 if leg1 == leg2, which is the correct behaviour + return leg1 ^ leg2; /// returns 0 if leg1 == leg2, which is the correct behaviour } inline constexpr auto TrigGlobalEfficiencyCorrectionTool::forwardLegs(const flat_set<std::size_t>& legs) -> const flat_set<std::size_t>& @@ -952,8 +899,8 @@ auto TrigGlobalEfficiencyCorrectionTool::rankTriggerLegs(float pt, const Contain } std::vector<uint8_t> counts(nLegs); - // need not only to sort, but also to verify consistency for all pairs of legs (in case of configuration issue) - // for that, use a O(n^2) algorithm and count for each leg the number of legs tighter than itself + /// need not only to sort, but also to verify consistency for all pairs of legs (in case of configuration issue) + /// for that, use a O(n^2) algorithm and count for each leg the number of legs tighter than itself auto legI = legs.begin(); for(unsigned i=0;i<nLegs;++i) { diff --git a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/Calculator.h b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/Calculator.h index c69625f2146ee96f2bd80c1516b977545567e8e4..df75a5562711721ca93728dfb7bf74214f7f886a 100644 --- a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/Calculator.h +++ b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/Calculator.h @@ -14,35 +14,32 @@ #include <map> #include <algorithm> #include <functional> -#include <boost/container/container_fwd.hpp> +#include <boost/container/flat_set.hpp> +template<typename Key> using flat_set = boost::container::flat_set<Key>; namespace TrigGlobEffCorr { class Lepton; -class Trig1E; -class Trig1MU; -class Trig2Esym; -class Trig2MUsym; -class TrigEMU; class Calculator : public asg::AsgMessaging { using LeptonList = TrigGlobalEfficiencyCorrectionTool::LeptonList; using TrigDef = TrigGlobEffCorr::ImportData::TrigDef; - template<typename Key> using flat_set = boost::container::flat_set<Key>; + using GlobEffFunc = std::function<bool(Calculator*,const LeptonList&,unsigned,Efficiencies&)>; public: Calculator(TrigGlobalEfficiencyCorrectionTool& parent, unsigned nPeriodsToReserve); bool addPeriod(ImportData& data, const std::pair<unsigned,unsigned>& boundaries, const std::string& combination, - bool useToys, bool useDefaultElectronTools, std::size_t& uniqueElectronLeg, bool useDefaultPhotonTools, std::size_t& uniquePhotonLeg); + bool useToys, std::size_t& uniqueElectronLeg, std::size_t& uniquePhotonLeg); bool compute(TrigGlobalEfficiencyCorrectionTool& parent, const LeptonList& leptons, unsigned runNumber, Efficiencies& efficiencies); bool checkTriggerMatching(TrigGlobalEfficiencyCorrectionTool& parent, bool& matched, const LeptonList& leptons, unsigned runNumber); + bool getRelevantTriggersForUser(TrigGlobalEfficiencyCorrectionTool& parent, std::vector<std::string>& triggers, unsigned runNumber); struct Period { const std::pair<unsigned,unsigned> m_boundaries; - std::function<bool(Calculator*,const LeptonList&,unsigned,Efficiencies&)> m_formula; + GlobEffFunc m_formula; std::vector<TrigDef> m_triggers; /// only used for trigger matching; not filled otherwise. Also, single-lepton _OR_ triggers are split! Period(const decltype(m_boundaries)& b, decltype(m_formula)&& f, decltype(m_triggers)&& t = {}) : m_boundaries(b), m_formula(f), m_triggers(t) {} }; @@ -51,106 +48,157 @@ private: TrigGlobalEfficiencyCorrectionTool* m_parent; /// pointer updated at each call to compute() because the parent tool might have been moved in-between std::vector<Period> m_periods; - std::map<std::pair<const Lepton*,std::size_t>, Efficiencies> m_cachedEfficiencies; + std::map<std::pair<const Lepton*, std::size_t>, Efficiencies> m_cachedEfficiencies; bool aboveThreshold(const Lepton& p,std::size_t leg) const { return m_parent->aboveThreshold(p, leg); } template<typename Trig1L> auto getLoosestLegAboveThreshold(const Lepton& lepton, const flat_set<Trig1L>& trigs, bool& success) - -> typename std::enable_if<Trig1L::is1L(), std::size_t>::type + -> std::enable_if_t<Trig1L::is1L(), std::size_t> { return m_parent->getLoosestLegAboveThreshold(lepton, Trig1L::anonymize(trigs), success); } Efficiencies getCachedTriggerLegEfficiencies(const Lepton& lepton, unsigned runNumber, std::size_t leg, bool& success); bool fillListOfLegsFor(const Lepton& lepton, const std::vector<TrigDef>& triggers, flat_set<std::size_t>& validLegs) const; bool canTriggerBeFired(const TrigDef& trig, const std::vector<flat_set<std::size_t> >& firedLegs) const; const Period* getPeriod(unsigned runNumber) const; + bool findUniqueLeg(xAOD::Type::ObjectType obj, std::size_t& uniqueLeg, const std::vector<TrigDef>& defs); + /// One single-lepton trigger template<typename Trig1L> - auto globalEfficiency_One1L(const LeptonList& leptons, unsigned runNumber, const Trig1L trig, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig1L::is1L(), bool>::type; - bool globalEfficiency_Two1L(const LeptonList& leptons, unsigned runNumber, const Trig1E trig1E, const Trig1MU trig1MU, Efficiencies& globalEfficiencies); + auto globalEfficiency(const LeptonList&, unsigned, const Trig1L, Efficiencies&) + -> std::enable_if_t<Trig1L::is1L(), bool>; + /// Two single-lepton triggers, two object types + template<typename Trig1L_obj1, typename Trig1L_obj2> + auto globalEfficiency(const LeptonList&, unsigned, const Trig1L_obj1 trig1, const Trig1L_obj2 trig2, Efficiencies&) + -> std::enable_if_t<Trig1L_obj1::is1L() + && Trig1L_obj2::is1L() + && Trig1L_obj1::object() != Trig1L_obj2::object(), + bool>; + /// Several single-lepton triggers, one object type template<typename Trig1L> - auto globalEfficiency_Several1L(const LeptonList& leptons, unsigned runNumber, const flat_set<Trig1L>& trigs, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig1L::is1L(), bool>::type; - bool globalEfficiency_Several1L(const LeptonList& leptons, unsigned runNumber, - const flat_set<Trig1E>& trigs1E, const flat_set<Trig1MU>& trigs1MU, Efficiencies& globalEfficiencies); - // - - bool globalEfficiency_One2L(const LeptonList& leptons, unsigned runNumber, const TrigEMU trig, Efficiencies& globalEfficiencies); + auto globalEfficiency(const LeptonList&, unsigned, const flat_set<Trig1L>&, Efficiencies&) + -> std::enable_if_t<Trig1L::is1L(), bool>; + /// Several single-lepton triggers, two object types + template<typename Trig1L_obj1, typename Trig1L_obj2> + auto globalEfficiency(const LeptonList&, unsigned, const flat_set<Trig1L_obj1>& trigs1, const flat_set<Trig1L_obj2>& trigs2, Efficiencies&) + -> std::enable_if_t<Trig1L_obj1::is1L() + && Trig1L_obj2::is1L() + && Trig1L_obj1::object() != Trig1L_obj2::object(), + bool>; + /// One mixed-flavour dilepton trigger + template<typename Trig2Lmix> + auto globalEfficiency(const LeptonList&, unsigned, const Trig2Lmix, Efficiencies&) + -> std::enable_if_t<Trig2Lmix::is2Lmix(), bool>; + /// One symmetric dilepton trigger template<typename Trig2Lsym> - auto globalEfficiency_One2L(const LeptonList& leptons, unsigned runNumber, const Trig2Lsym trig , Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2Lsym::is2Lsym(), bool>::type; + auto globalEfficiency(const LeptonList&, unsigned, const Trig2Lsym , Efficiencies&) + -> std::enable_if_t<Trig2Lsym::is2Lsym(), bool>; + /// One asymmetric dilepton trigger template<typename Trig2Lasym> - auto globalEfficiency_One2L(const LeptonList& leptons, unsigned runNumber, const Trig2Lasym trig, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2Lasym::is2Lasym(), bool>::type; - - + auto globalEfficiency(const LeptonList&, unsigned, const Trig2Lasym, Efficiencies&) + -> std::enable_if_t<Trig2Lasym::is2Lasym(), bool>; + /// One mixed-flavour dilepton trigger + single-lepton triggers + template<typename Trig2Lmix, typename Trig1L_obj1, typename Trig1L_obj2> + auto globalEfficiency(const LeptonList&, unsigned, const Trig2Lmix, const flat_set<Trig1L_obj1>&, const flat_set<Trig1L_obj2>&, Efficiencies&) + -> std::enable_if_t<Trig2Lmix::is2Lmix() + && Trig1L_obj1::is1L() && Trig2Lmix::object1()==Trig1L_obj1::object() + && Trig1L_obj2::is1L() && Trig2Lmix::object2()==Trig1L_obj2::object(), + bool>; + /// One dilepton trigger + one single-lepton trigger template<typename Trig2L, typename Trig1L> - inline auto globalEfficiency_One2LSeveral1L(const LeptonList& leptons, unsigned runNumber, - const Trig2L trig2L, const Trig1L trig1L, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2L::is2L(Trig1L::object()) && Trig1L::is1L(), bool>::type; - bool globalEfficiency_One2LSeveral1L(const LeptonList& leptons, unsigned runNumber, - const TrigEMU trigEMU, const flat_set<Trig1E>& trigs1E, const flat_set<Trig1MU>& trigs1MU, Efficiencies& globalEfficiencies); + inline auto globalEfficiency(const LeptonList&, unsigned, const Trig2L, const Trig1L, Efficiencies&) + -> std::enable_if_t<Trig2L::is2Lnomix() + && Trig1L::is1L() + && Trig2L::object()==Trig1L::object(), + bool>; + /// One symmetric dilepton trigger + several single-lepton triggers template<typename Trig2Lsym, typename Trig1L> - auto globalEfficiency_One2LSeveral1L(const LeptonList& leptons, unsigned runNumber, - const Trig2Lsym trig2L, const flat_set<Trig1L>& trigs1L, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2Lsym::is2Lsym(Trig1L::object()) && Trig1L::is1L(), bool>::type; + auto globalEfficiency(const LeptonList&, unsigned, const Trig2Lsym, const flat_set<Trig1L>&, Efficiencies&) + -> std::enable_if_t<Trig2Lsym::is2Lsym() + && Trig1L::is1L() + && Trig1L::object() == Trig2Lsym::object(), + bool>; + /// One asymmetric dilepton trigger + several single-lepton triggers template<typename Trig2Lasym, typename Trig1L> - auto globalEfficiency_One2LSeveral1L(const LeptonList& leptons, unsigned runNumber, - const Trig2Lasym trig2L, const flat_set<Trig1L>& trigs1L, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2Lasym::is2Lasym(Trig1L::object()) && Trig1L::is1L(), bool>::type; - template<typename Trig2E> - auto globalEfficiency_One2LSeveral1L(const LeptonList& leptons, unsigned runNumber, - const Trig2E trig2E, const flat_set<Trig1E>& trigs1E, const flat_set<Trig1MU>& trigs1MU, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2E::is2L(xAOD::Type::Electron), bool>::type; - template<typename Trig2MU> - auto globalEfficiency_One2LSeveral1L(const LeptonList& leptons, unsigned runNumber, - const Trig2MU trig2MU, const flat_set<Trig1E>& trigs1E, const flat_set<Trig1MU>& trigs1MU, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2MU::is2L(xAOD::Type::Muon), bool>::type; - - template<typename Trig2L> // not sure this one is actually called by the code... - auto globalEfficiency_Two2L(const LeptonList& leptons, unsigned runNumber, const Trig2L trig2L, const TrigEMU trigEMU, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2L::is2L(), bool>::type; + auto globalEfficiency(const LeptonList&, unsigned, const Trig2Lasym, const flat_set<Trig1L>&, Efficiencies&) + -> std::enable_if_t<Trig2Lasym::is2Lasym() + && Trig1L::is1L() + && Trig1L::object() == Trig2Lasym::object(), + bool>; + /// Two symmetric dilepton triggers + several single-lepton triggers template<typename Trig2Lsym, typename Trig1L> - auto globalEfficiency_Two2LSeveral1L(const LeptonList& leptons, unsigned runNumber, - const Trig2Lsym trig2L1, const Trig2Lsym trig2L2, const flat_set<Trig1L>& trigs1L, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2Lsym::is2Lsym(Trig1L::object()) && Trig1L::is1L(), bool>::type; + auto globalEfficiency(const LeptonList&, unsigned, const Trig2Lsym, const Trig2Lsym, const flat_set<Trig1L>&, Efficiencies&) + -> std::enable_if_t<Trig2Lsym::is2Lsym() + && Trig1L::is1L() + && Trig1L::object() == Trig2Lsym::object(), + bool>; + /// Two dilepton triggers (one asym., one sym.) + several single-lepton triggers template<typename Trig2Lasym, typename Trig2Lsym, typename Trig1L> - auto globalEfficiency_Two2LSeveral1L(const LeptonList& leptons, unsigned runNumber, - const Trig2Lasym trig2Lasym, const Trig2Lsym trig2Lsym, const flat_set<Trig1L>& trigs1L, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2Lasym::is2Lasym(Trig1L::object()) && Trig2Lsym::is2Lsym(Trig1L::object()) && Trig1L::is1L(), bool>::type; - - template<typename Trig2E, typename Trig2MU> - auto globalEfficiency_Three2L(const LeptonList& leptons, unsigned runNumber, - const Trig2E trig2E, const Trig2MU trig2MU, const TrigEMU trigEMU, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2E::is2L(xAOD::Type::Electron) && Trig2MU::is2L(xAOD::Type::Muon), bool>::type; - template<typename Trig2E, typename Trig2MU> - auto globalEfficiency_Three2LSeveral1L(const LeptonList& leptons, unsigned runNumber, const Trig2E trig2E, const Trig2MU trig2MU, - const TrigEMU trigEMU, const flat_set<Trig1E>& trigs1E, const flat_set<Trig1MU>& trigs1MU, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2E::is2L(xAOD::Type::Electron) && Trig2MU::is2L(xAOD::Type::Muon), bool>::type; - - - template<typename Trig2L, typename Trig2Lsym, typename Trig1L> - auto globalEfficiency_Six2LSeveral1L_singleObjectFactor(const LeptonList& leptons, unsigned runNumber, - const Trig2L trig2L, const Trig2Lsym trig2Lsym, const TrigEMU trigEMU1, const TrigEMU trigEMU2, const flat_set<Trig1L>& trigs1L, Efficiencies (&efficiencies)[4]) - -> typename std::enable_if<Trig2L::is2L() && Trig2Lsym::is2Lsym(Trig2L::object()) && Trig1L::is1L(Trig2L::object()), bool>::type; - template<typename Trig2E, typename Trig2MU> - auto globalEfficiency_Six2LSeveral1L(const LeptonList& leptons, unsigned runNumber, - const Trig2E trig2E, const Trig2Esym trig2Esym, const Trig2MU trig2MU, const Trig2MUsym trig2MUsym, - const TrigEMU trigEMU1, const TrigEMU trigEMU2, const flat_set<Trig1E>& trigs1E, const flat_set<Trig1MU>& trigs1MU, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig2E::is2L(xAOD::Type::Electron) && Trig2MU::is2L(xAOD::Type::Muon), bool>::type; - + auto globalEfficiency(const LeptonList&, unsigned, const Trig2Lasym, const Trig2Lsym, const flat_set<Trig1L>&, Efficiencies&) + -> std::enable_if_t<Trig2Lasym::is2Lasym() + && Trig2Lsym::is2Lsym() && Trig2Lsym::object()==Trig2Lasym::object() + && Trig1L::is1L() && Trig1L::object()==Trig2Lasym::object(), + bool>; + /// One symmetric trilepton trigger template<typename Trig3Lsym> - auto globalEfficiency_One3L(const LeptonList& leptons, unsigned runNumber, const Trig3Lsym trig, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig3Lsym::is3Lsym(), bool>::type; + auto globalEfficiency(const LeptonList&, unsigned, const Trig3Lsym, Efficiencies&) + -> std::enable_if_t<Trig3Lsym::is3Lsym(), bool>; + /// One half-symmetric trilepton trigger template<typename Trig3Lhalfsym> - auto globalEfficiency_One3L(const LeptonList& leptons, unsigned runNumber, const Trig3Lhalfsym trig, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig3Lhalfsym::is3Lhalfsym(), bool>::type; + auto globalEfficiency(const LeptonList&, unsigned, const Trig3Lhalfsym, Efficiencies&) + -> std::enable_if_t<Trig3Lhalfsym::is3Lhalfsym(), bool>; + /// One dilepton trigger + one mixed-flavour dilepton trigger + template<typename Trig2L, typename Trig2Lmix> + auto globalEfficiency(const LeptonList&, unsigned, const Trig2L, const Trig2Lmix, Efficiencies&) + -> std::enable_if_t<Trig2L::is2Lnomix() + && Trig2Lmix::is2Lmix() + && (Trig2Lmix::object1()==Trig2L::object() || Trig2Lmix::object2()==Trig2L::object()), + bool>; + /// Combinaisons with 3 dilepton triggers including one mixed-flavour, and one sym./asym. dilepton for each flavour + template<typename Trig2L_obj1, typename Trig2L_obj2, typename Trig2Lmix> + auto globalEfficiency(const LeptonList&, unsigned, const Trig2L_obj1, const Trig2L_obj2, const Trig2Lmix, Efficiencies&) + -> std::enable_if_t<Trig2Lmix::is2Lmix() + && Trig2L_obj1::is2Lnomix() && Trig2L_obj1::object() == Trig2Lmix::object1() + && Trig2L_obj2::is2Lnomix() && Trig2L_obj2::object() == Trig2Lmix::object2(), + + bool>; + /// Same combinaisons with 3 dilepton triggers, + single-lepton triggers + template<typename Trig2L_obj1, typename Trig2L_obj2, typename Trig2Lmix, typename Trig1L_obj1, typename Trig1L_obj2> + auto globalEfficiency(const LeptonList&, unsigned, const Trig2L_obj1, const Trig2L_obj2, const Trig2Lmix, + const flat_set<Trig1L_obj1>&, const flat_set<Trig1L_obj2>&, Efficiencies&) + -> std::enable_if_t<Trig2Lmix::is2Lmix() + && Trig2L_obj1::is2Lnomix() && Trig2L_obj1::object()==Trig2Lmix::object1() + && Trig2L_obj2::is2Lnomix() && Trig2L_obj2::object()==Trig2Lmix::object2() + && Trig1L_obj1::is1L() && Trig1L_obj1::object()==Trig2Lmix::object1() + && Trig1L_obj2::is1L() && Trig1L_obj2::object()==Trig2Lmix::object2(), + + bool>; + /// Six dilepton triggers (two mixed-flavour, two sym., two asym./sym.) for two object types + template<typename Trig2L_obj1, typename Trig2Lsym_obj1, typename Trig2L_obj2, typename Trig2Lsym_obj2, + typename Trig2Lmix, typename Trig1L_obj1, typename Trig1L_obj2> + auto globalEfficiency(const LeptonList&, unsigned, const Trig2L_obj1, const Trig2Lsym_obj1, const Trig2L_obj2, const Trig2Lsym_obj2, + const Trig2Lmix, const Trig2Lmix, const flat_set<Trig1L_obj1>&, const flat_set<Trig1L_obj2>&, Efficiencies&) + -> std::enable_if_t<Trig2Lmix::is2Lmix() + && Trig2L_obj1::is2Lnomix() && Trig2L_obj1::object()==Trig2Lmix::object1() + && Trig2L_obj2::is2Lnomix() && Trig2L_obj2::object()==Trig2Lmix::object2() + && Trig2Lsym_obj1::is2Lsym() && Trig2Lsym_obj1::object()==Trig2Lmix::object1() + && Trig2Lsym_obj2::is2Lsym() && Trig2Lsym_obj2::object()==Trig2Lmix::object2() + && Trig1L_obj1::is1L() && Trig1L_obj1::object()==Trig2Lmix::object1() + && Trig1L_obj2::is1L() && Trig1L_obj2::object()==Trig2Lmix::object2(), + bool>; + /// One mixed-flavour trilepton trigger template<typename Trig3Lmix> - auto globalEfficiency_One3L(const LeptonList& leptons, unsigned runNumber, const Trig3Lmix trig, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig3Lmix::is3Lmix(), bool>::type; + auto globalEfficiency(const LeptonList&, unsigned, const Trig3Lmix, Efficiencies&) + -> std::enable_if_t<Trig3Lmix::is3Lmix(), bool>; + /// Two complementary mixed-flavour trilepton triggers template<typename Trig3Lmix1, typename Trig3Lmix2> - auto globalEfficiency_Two3L(const LeptonList& leptons, unsigned runNumber, const Trig3Lmix1 trig1, const Trig3Lmix2 trig2, Efficiencies& globalEfficiencies) - -> typename std::enable_if<Trig3Lmix1::is3Lmix() && Trig3Lmix2::is3Lmix() && (Trig3Lmix1::major_object()!=Trig3Lmix2::major_object()), bool>::type; + auto globalEfficiency(const LeptonList&, unsigned, const Trig3Lmix1, const Trig3Lmix2, Efficiencies&) + -> std::enable_if_t<Trig3Lmix1::is3Lmix() + && Trig3Lmix2::is3Lmix() + && Trig3Lmix1::object1() == Trig3Lmix2::object2() + && Trig3Lmix1::object2() == Trig3Lmix2::object1(), + bool>; + + bool globalEfficiency_Factorized2(const LeptonList& leptons, unsigned runNumber, GlobEffFunc func1, GlobEffFunc func2, Efficiencies& globalEfficiencies); + bool globalEfficiency_Factorized3(const LeptonList& leptons, unsigned runNumber, GlobEffFunc func1, GlobEffFunc func2, GlobEffFunc func3, Efficiencies& globalEfficiencies); - // bool globalEfficiency_Toys(const LeptonList&, unsigned, const std::vector<TrigDef>& triggers, Efficiencies&); private: @@ -158,30 +206,28 @@ private: { public: Helper(const std::vector<TrigDef>& defs); - const unsigned m_n1L, m_n2L, m_n3L; - const unsigned m_nPhotonTriggers; - template<typename Trig1L = void> bool bind_1x1L(); - template<typename Trig2L> bool bind_1x2L(); - template<typename Trig2L> bool bind_1x2L_singleFlavour(); - template<typename Trig2L1, typename Trig2L2> bool bind_2x2L_singleFlavour(); - template<typename Trig2E, typename Trig2MU> bool bind_3x2L(); - template<typename Trig2E, typename Trig2MU> bool bind_6x2L(); - template<typename Trig3L> bool bind_1x3L(); - template<typename Trig3L1, typename Trig3L2> bool bind_2x3L(); + Helper(Helper&&) = default; + bool duplicates() const; - std::function<bool(Calculator*,const LeptonList&,unsigned,Efficiencies&)> m_func; + std::function<bool(Calculator*,const LeptonList&,unsigned,Efficiencies&)> m_formula; + + bool findAndBindFunction(); + protected: - const std::vector<TrigDef>& m_defs; - template<typename Trig> Trig get(unsigned index = 0) const; - template<typename Trig1L> flat_set<Trig1L> get_all() const; - template<typename Trig> std::size_t count() const - { - return std::count_if(m_defs.cbegin(), m_defs.cend(), - [](const TrigDef& td)->bool{return td.type==Trig::type();}); - } - }; + std::vector<TrigDef> m_defs; + unsigned m_n1L = 0, m_n2L = 0, m_n3L = 0; - friend class Helper; + template<TriggerType object_flag> bool findAndBindFunction(); + template<TriggerType object1_flag, TriggerType object2_flag> bool findAndBindFunction(); + template<typename... Trigs> bool bindFunction(); + + template<typename Param> auto extract(); + struct NoSuchTrigger {}; + template<typename T> struct Optional{}; /// to decorate the parameters of the findAndBind() function(s) + template<typename T> struct BindPackedParam; + + }; + friend class CheckConfig; }; diff --git a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/CheckConfig.h b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/CheckConfig.h index 1e3ccef720b917bfcee8daa011d5f93c0e684eea..3f3a2558e53c053fa4c3f8e1e8545e538475fba4 100644 --- a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/CheckConfig.h +++ b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/CheckConfig.h @@ -17,9 +17,7 @@ namespace TrigGlobEffCorr { class CheckConfig : public asg::AsgMessaging -{ - template<typename Key> using flat_set = boost::container::flat_set<Key>; - +{ public: CheckConfig(TrigGlobalEfficiencyCorrectionTool& parent); diff --git a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/ImportData.h b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/ImportData.h index a4408f128d6e72303ad9e6b9716bf58cc2aa9885..044cdfed3e1331592f7c52a98da350eda5127b15 100644 --- a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/ImportData.h +++ b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/ImportData.h @@ -37,7 +37,7 @@ enum TriggerType TT_SINGLELEPTON_FLAG = 0x1000, TT_SINGLE_E = TT_SINGLELEPTON_FLAG| TT_ELECTRON_FLAG, TT_SINGLE_MU = TT_SINGLELEPTON_FLAG | TT_MUON_FLAG, - TT_SINGLE_PH = TT_SINGLELEPTON_FLAG | TT_PHOTON_FLAG, + TT_SINGLE_G = TT_SINGLELEPTON_FLAG | TT_PHOTON_FLAG, // dilepton triggers TT_DILEPTON_FLAG = 0x2000, TT_DILEPTON_SYM = TT_DILEPTON_FLAG | TT_SYM, @@ -46,9 +46,11 @@ enum TriggerType TT_2E_ASYM = TT_DILEPTON_ASYM | TT_ELECTRON_FLAG, TT_2MU_SYM = TT_DILEPTON_SYM | TT_MUON_FLAG, TT_2MU_ASYM = TT_DILEPTON_ASYM | TT_MUON_FLAG, - TT_EMU = TT_DILEPTON_FLAG | TT_ELECTRON_FLAG | TT_MUON_FLAG, - TT_2PH_SYM = TT_DILEPTON_SYM | TT_PHOTON_FLAG, - TT_2PH_ASYM = TT_DILEPTON_ASYM | TT_PHOTON_FLAG, + TT_E_MU = TT_DILEPTON_FLAG | TT_ELECTRON_FLAG | TT_MUON_FLAG, + TT_2G_SYM = TT_DILEPTON_SYM | TT_PHOTON_FLAG, + TT_2G_ASYM = TT_DILEPTON_ASYM | TT_PHOTON_FLAG, + TT_E_G = TT_DILEPTON_FLAG | TT_ELECTRON_FLAG | TT_PHOTON_FLAG, + TT_MU_G = TT_DILEPTON_FLAG | TT_MUON_FLAG | TT_PHOTON_FLAG, // trilepton triggers TT_TRILEPTON_FLAG = 0x4000, TT_TRILEPTON_SYM = TT_TRILEPTON_FLAG | TT_SYM, @@ -60,19 +62,26 @@ enum TriggerType TT_3MU_SYM = TT_TRILEPTON_SYM | TT_MUON_FLAG, TT_3MU_HALFSYM = TT_TRILEPTON_HALFSYM | TT_MUON_FLAG, TT_3MU_ASYM = TT_TRILEPTON_ASYM | TT_MUON_FLAG, - TT_2E_MU_SYM = TT_TRILEPTON_FLAG | TT_SYM | TT_ELECTRON_FLAG | TT_MUON_FLAG, + TT_2E_MU_SYM = TT_TRILEPTON_SYM | TT_ELECTRON_FLAG | TT_MUON_FLAG, TT_E_2MU_SYM = TT_2E_MU_SYM | TT_X2Y_FLAG, - TT_2E_MU_ASYM = TT_TRILEPTON_FLAG | TT_ASYM | TT_ELECTRON_FLAG | TT_MUON_FLAG, - TT_E_2MU_ASYM = TT_2E_MU_ASYM | TT_X2Y_FLAG , - TT_3PH_SYM = TT_TRILEPTON_SYM | TT_PHOTON_FLAG, - TT_3PH_HALFSYM = TT_TRILEPTON_HALFSYM | TT_PHOTON_FLAG, - TT_3PH_ASYM = TT_TRILEPTON_ASYM | TT_PHOTON_FLAG + TT_2E_MU_ASYM = TT_TRILEPTON_ASYM | TT_ELECTRON_FLAG | TT_MUON_FLAG, + TT_E_2MU_ASYM = TT_2E_MU_ASYM | TT_X2Y_FLAG, + TT_3G_SYM = TT_TRILEPTON_SYM | TT_PHOTON_FLAG, + TT_3G_HALFSYM = TT_TRILEPTON_HALFSYM | TT_PHOTON_FLAG, + TT_3G_ASYM = TT_TRILEPTON_ASYM | TT_PHOTON_FLAG, + TT_2E_G_SYM = TT_TRILEPTON_SYM | TT_ELECTRON_FLAG | TT_PHOTON_FLAG, + TT_E_2G_SYM = TT_2E_G_SYM | TT_X2Y_FLAG, + TT_2E_G_ASYM = TT_TRILEPTON_ASYM | TT_ELECTRON_FLAG | TT_PHOTON_FLAG, + TT_E_2G_ASYM = TT_2E_G_ASYM | TT_X2Y_FLAG, + TT_2MU_G_SYM = TT_TRILEPTON_SYM | TT_MUON_FLAG | TT_PHOTON_FLAG, + TT_MU_2G_SYM = TT_2MU_G_SYM | TT_X2Y_FLAG, + TT_2MU_G_ASYM = TT_TRILEPTON_ASYM | TT_MUON_FLAG | TT_PHOTON_FLAG, + TT_MU_2G_ASYM = TT_2MU_G_ASYM | TT_X2Y_FLAG, }; class ImportData : public asg::AsgMessaging { using Hierarchy = TrigGlobalEfficiencyCorrectionTool::Hierarchy; - template<typename Key> using flat_set = boost::container::flat_set<Key>; public: struct TrigDef @@ -80,6 +89,7 @@ public: TriggerType type; std::size_t name; std::array<std::size_t,3> leg; + bool used = false; /// auxiliary variable used by Calculator::Helper::extra() and bindFunction() TrigDef(TriggerType type=TT_UNKNOWN, std::size_t name=0, std::size_t leg0=0, std::size_t leg1=0, std::size_t leg2=0) : type(type), name(name), leg{leg0,leg1,leg2} {} }; diff --git a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrectionTool.h b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrectionTool.h index 779bfe8309f838530b39e3f3c5c95f6bbe3d4001..8d45ddc7f3398f5e93cfa153f3392d8c44a033a4 100644 --- a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrectionTool.h +++ b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrectionTool.h @@ -43,14 +43,6 @@ public: virtual StatusCode initialize() override; - virtual CP::CorrectionCode getEfficiencyScaleFactor(const std::vector<const xAOD::Electron*>& electrons, const std::vector<const xAOD::Muon*>& muons, double& efficiencyScaleFactor) override; - virtual CP::CorrectionCode getEfficiencyScaleFactor(unsigned runNumber, const std::vector<const xAOD::Electron*>& electrons, const std::vector<const xAOD::Muon*>& muons, double& efficiencyScaleFactor) override; - virtual CP::CorrectionCode getEfficiency(const std::vector<const xAOD::Electron*>& electrons, const std::vector<const xAOD::Muon*>& muons, double& efficiencyData, double& efficiencyMc) override; - virtual CP::CorrectionCode getEfficiency(unsigned runNumber, const std::vector<const xAOD::Electron*>& electrons, const std::vector<const xAOD::Muon*>& muons, double& efficiencyData, double& efficiencyMc) override; - - virtual CP::CorrectionCode getEfficiencyScaleFactor(const std::vector<const xAOD::Photon*>& photons, double& efficiencyScaleFactor) override; - virtual CP::CorrectionCode getEfficiency(const std::vector<const xAOD::Photon*>& photons, double& efficiencyData, double& efficiencyMc) override; - virtual CP::CorrectionCode getEfficiencyScaleFactor(const std::vector<const xAOD::IParticle*>& particles, double& efficiencyScaleFactor) override; virtual CP::CorrectionCode getEfficiencyScaleFactor(unsigned runNumber, const std::vector<const xAOD::IParticle*>& particles, double& efficiencyScaleFactor) override; virtual CP::CorrectionCode getEfficiency(const std::vector<const xAOD::IParticle*>& particles, double& efficiencyData, double& efficiencyMc) override; @@ -62,8 +54,7 @@ public: virtual CP::SystematicCode applySystematicVariation(const CP::SystematicSet& systConfig) override; virtual CP::CorrectionCode checkTriggerMatching(bool& matched, const std::vector<const xAOD::IParticle*>& particles) override; - virtual CP::CorrectionCode checkTriggerMatching(bool& matched, const std::vector<const xAOD::Electron*>& electrons, const std::vector<const xAOD::Muon*>& muons) override; - virtual CP::CorrectionCode checkTriggerMatching(bool& matched, const std::vector<const xAOD::Photon*>& photons) override; + virtual CP::CorrectionCode getRelevantTriggers(std::vector<std::string>& triggers) override; static CP::CorrectionCode suggestElectronMapKeys(const std::map<std::string,std::string>& triggerCombination, const std::string& version, std::map<std::string,std::string>& legsPerKey); @@ -188,9 +179,6 @@ private: { return *m_suppliedElectronEfficiencyTools[index]; } IAsgPhotonEfficiencyCorrectionTool& GetEfficiencyTool(const xAOD::Photon*, std::size_t index) { return *m_suppliedPhotonEfficiencyTools[index]; } - CP::CorrectionCode getEfficiencyScaleFactor(unsigned runNumber, const LeptonList& leptons, double& efficiencyScaleFactor); - CP::CorrectionCode getEfficiency(unsigned runNumber, const LeptonList& leptons, double& efficiencyData, double& efficiencyMc); - CP::CorrectionCode checkTriggerMatching(bool& matched, const LeptonList& leptons); std::size_t getCombinedHash(const flat_set<std::size_t>& legs); std::size_t getCombinedHash(std::size_t leg1, std::size_t leg2); static inline constexpr const flat_set<std::size_t>& forwardLegs(const flat_set<std::size_t>& legs); diff --git a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/Trigger.h b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/Trigger.h index 76563bbbd1abe80b4739fd6ebbfcf0cd218c9c33..9e80931ef55763ce624d4debb23b93e086b76f53 100644 --- a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/Trigger.h +++ b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/TrigGlobalEfficiencyCorrection/Trigger.h @@ -14,143 +14,220 @@ #include <algorithm> #include <type_traits> #include <boost/container/flat_set.hpp> +template<typename Key> using flat_set = boost::container::flat_set<Key>; namespace TrigGlobEffCorr { class UnusedArg { public: static constexpr xAOD::Type::ObjectType object() { return xAOD::Type::Other; } }; -class Trig1E; -class Trig1MU; -class Trig1PH; - -template<TriggerType tt, typename CastType1 = UnusedArg, typename CastType2 = UnusedArg> -class Trigger +class TriggerProperties { -private: - template<typename Key> using flat_set = boost::container::flat_set<Key>; - static constexpr bool extraCheck(xAOD::Type::ObjectType obj) { return (object()==obj || obj==xAOD::Type::Other); } public: - static constexpr TriggerType type() { return tt; } - - static constexpr bool mixed() + explicit constexpr TriggerProperties(TriggerType tt) : m_type(tt), m_legs{} {} + explicit TriggerProperties(const ImportData::TrigDef& def) : m_type(def.type) { loadLegs(def, m_legs); } + constexpr TriggerType type() const { return m_type; } + constexpr bool valid() const { - constexpr auto x = (tt&TT_MASK_FLAVOUR); - static_assert(!(x&~(TT_ELECTRON_FLAG|TT_MUON_FLAG|TT_PHOTON_FLAG)), "implementation needs to account for new flavours"); + return !((m_type&TT_MASK_FLAVOUR)&~(TT_ELECTRON_FLAG|TT_MUON_FLAG|TT_PHOTON_FLAG)); /// validity of mixed() function + } + constexpr bool mixed() const + { + auto x = m_type&TT_MASK_FLAVOUR; return (x!=TT_ELECTRON_FLAG) && (x!=TT_MUON_FLAG) && (x!=TT_PHOTON_FLAG); } - - static constexpr unsigned nDistinctLegs() + constexpr unsigned nDistinctLegs() const { - auto x = tt&TT_MASK_SYMMETRY; - if(tt&TT_SINGLELEPTON_FLAG) return 1; - else if(tt&TT_DILEPTON_FLAG) return 2 - 1*(x==TT_SYM); - else if(tt&TT_TRILEPTON_FLAG) return (x==TT_ASYM)? 3 : 1 + 1*(mixed()||(x!=TT_SYM)); + auto x = m_type&TT_MASK_SYMMETRY; + if(m_type&TT_SINGLELEPTON_FLAG) return 1; + else if(m_type&TT_DILEPTON_FLAG) return 2 - 1*(x==TT_SYM); + else if(m_type&TT_TRILEPTON_FLAG) return (x==TT_ASYM)? 3 : 1 + 1*(mixed()||(x!=TT_SYM)); return 0; } - - static constexpr unsigned nDistinctLegs(xAOD::Type::ObjectType obj) + constexpr unsigned nDistinctLegs(xAOD::Type::ObjectType obj) const { + bool firstPos = true; switch(obj) { case xAOD::Type::Electron: - return !!(tt&TT_ELECTRON_FLAG) * (mixed()? ((tt&TT_X2Y_FLAG)? 1 : nDistinctLegs()-1) : nDistinctLegs()); + if(!(m_type&TT_ELECTRON_FLAG)) return 0; + break; case xAOD::Type::Muon: - return !!(tt&TT_MUON_FLAG) * (mixed()? ((tt&TT_X2Y_FLAG)? nDistinctLegs()-1 : 1) : nDistinctLegs()); + if(!(m_type&TT_MUON_FLAG)) return 0; + firstPos = (m_type&TT_PHOTON_FLAG); + break; case xAOD::Type::Photon: - return (tt&TT_PHOTON_FLAG)? nDistinctLegs() : 0; + if(!(m_type&TT_PHOTON_FLAG)) return 0; + firstPos = false; + break; default: return 0; } + if(!mixed()) return nDistinctLegs(); + return (firstPos == (m_type&TT_X2Y_FLAG))? 1 : nDistinctLegs()-1; + } + template<typename Array> + void loadLegs(const ImportData::TrigDef& src, Array& dest) + { + if(src.type != m_type) throw; /// can't be thrown due to bad user action -- only in case of a bug in the Calculator class + std::fill(dest.begin(), dest.end(), 0); + if(m_type==TT_2E_MU_SYM || m_type==TT_2E_G_SYM || m_type==TT_2MU_G_SYM) /// special case needed to skip the duplicated leg for 2X_Y triggers + { + dest[0] = src.leg[0]; + dest[1] = src.leg[2]; + } + else /// Works as well for non-mixed trilepton triggers since the asymmetric leg is always stored first + { + std::copy_n(src.leg.cbegin(), nDistinctLegs(), dest.begin()); + } } - static constexpr xAOD::Type::ObjectType object() + constexpr int cbegin_offset(xAOD::Type::ObjectType obj) const { - if(mixed()) return xAOD::Type::Other; - if(tt&TT_ELECTRON_FLAG) return xAOD::Type::Electron; - if(tt&TT_MUON_FLAG) return xAOD::Type::Muon; - if(tt&TT_PHOTON_FLAG) return xAOD::Type::Photon; - return xAOD::Type::Other; + return (obj!=xAOD::Type::Electron) *(nDistinctLegs(xAOD::Type::Electron) + + (obj!=xAOD::Type::Muon)*nDistinctLegs(xAOD::Type::Muon)); + } + + auto cbegin(xAOD::Type::ObjectType obj) const + { + return m_legs.cbegin() + cbegin_offset(obj); + } + + constexpr int cend_offset(xAOD::Type::ObjectType obj) const + { + return -((obj!=xAOD::Type::Photon) *(nDistinctLegs(xAOD::Type::Photon) + + (obj!=xAOD::Type::Muon)*nDistinctLegs(xAOD::Type::Muon))); + } + + auto cend(xAOD::Type::ObjectType obj) const + { + return m_legs.cbegin() + nDistinctLegs() + cend_offset(obj); + } + +protected: + TriggerType m_type; + std::array<std::size_t, 3> m_legs; +}; + +template<TriggerType tt, typename CastType1 = UnusedArg, typename CastType2 = UnusedArg> +class Trigger +{ + static_assert(TriggerProperties(tt).valid(), "trigger type not supported"); +private: + static constexpr bool extraCheck(xAOD::Type::ObjectType obj) { return (object()==obj || obj==xAOD::Type::Other); } + template<typename T> struct Optional {}; +public: + + static constexpr TriggerType type() { return tt; } + + static constexpr bool mixed() + { + return TriggerProperties(tt).mixed(); } + + static constexpr unsigned nDistinctLegs() { return TriggerProperties(tt).nDistinctLegs(); } + + static constexpr unsigned nDistinctLegs(xAOD::Type::ObjectType obj) { return TriggerProperties(tt).nDistinctLegs(obj); } - static constexpr xAOD::Type::ObjectType major_object() + static constexpr xAOD::Type::ObjectType object1() { - if(tt==TT_2E_MU_SYM || tt==TT_2E_MU_ASYM) return xAOD::Type::Electron; - if(tt==TT_E_2MU_SYM || tt==TT_E_2MU_ASYM) return xAOD::Type::Muon; - return object(); + if(!is3Lmix()) + { + if(tt&TT_ELECTRON_FLAG) return xAOD::Type::Electron; + if(tt&TT_MUON_FLAG) return xAOD::Type::Muon; + if(tt&TT_PHOTON_FLAG) return xAOD::Type::Photon; + return xAOD::Type::Other; + } + if((tt&TT_ELECTRON_FLAG) && !(tt&TT_X2Y_FLAG)) return xAOD::Type::Electron; + if((tt&TT_PHOTON_FLAG) && (tt&TT_X2Y_FLAG)) return xAOD::Type::Photon; + return (tt&TT_MUON_FLAG)? xAOD::Type::Muon : xAOD::Type::Other; + } + + static constexpr xAOD::Type::ObjectType object2() + { + if(is2Lmix()) + { + if((tt&TT_ELECTRON_FLAG) && (tt&TT_MUON_FLAG)) return xAOD::Type::Muon; + if((tt&(TT_ELECTRON_FLAG|TT_MUON_FLAG)) && (tt&TT_PHOTON_FLAG)) return xAOD::Type::Photon; + return xAOD::Type::Other; + } + else if(!is3Lmix()) return xAOD::Type::Other; + if((tt&TT_ELECTRON_FLAG) && (tt&TT_X2Y_FLAG)) return xAOD::Type::Electron; + if((tt&TT_PHOTON_FLAG) && !(tt&TT_X2Y_FLAG)) return xAOD::Type::Photon; + return (tt&TT_MUON_FLAG)? xAOD::Type::Muon : xAOD::Type::Other; } - static constexpr xAOD::Type::ObjectType minor_object() + static constexpr xAOD::Type::ObjectType object() { - if(tt==TT_2E_MU_SYM || tt==TT_2E_MU_ASYM) return xAOD::Type::Muon; - if(tt==TT_E_2MU_SYM || tt==TT_E_2MU_ASYM) return xAOD::Type::Electron; - return xAOD::Type::Other; + if(mixed()) return xAOD::Type::Other; + return object1(); } static bool relevantFor(const Lepton& lepton) { return lepton.type()==object(); } static bool irrelevantFor(const Lepton& lepton) { return !relevantFor(lepton); } - static constexpr bool is1L() { return is1L (xAOD::Type::Other); } - static constexpr bool is1L(xAOD::Type::ObjectType obj) { return (tt&TT_SINGLELEPTON_FLAG) && extraCheck(obj); } - static constexpr bool is2Lasym(xAOD::Type::ObjectType obj = xAOD::Type::Other) { return ((tt&TT_MASK_TYPE)==TT_DILEPTON_ASYM) && extraCheck(obj); } - static constexpr bool is2Lsym(xAOD::Type::ObjectType obj = xAOD::Type::Other) { return ((tt&TT_MASK_TYPE)==TT_DILEPTON_SYM) && extraCheck(obj); } - static constexpr bool is2L(xAOD::Type::ObjectType obj = xAOD::Type::Other) { return (tt&TT_DILEPTON_FLAG) && !mixed() && extraCheck(obj); } - static constexpr bool is3Lsym(xAOD::Type::ObjectType obj = xAOD::Type::Other) { return ((tt&TT_MASK_TYPE)==TT_TRILEPTON_SYM) && !mixed() && extraCheck(obj); } - static constexpr bool is3Lhalfsym(xAOD::Type::ObjectType obj = xAOD::Type::Other) { return ((tt&TT_MASK_TYPE)==TT_TRILEPTON_HALFSYM) && !mixed() && extraCheck(obj); } - static constexpr bool isEMU() { return tt==TT_EMU; } + static constexpr bool is1L() { return (tt&TT_SINGLELEPTON_FLAG); } + static constexpr bool is2Lnomix() { return (tt&TT_DILEPTON_FLAG) && !mixed(); } + static constexpr bool is2Lasym() { return ((tt&TT_MASK_TYPE)==TT_DILEPTON_ASYM); } + static constexpr bool is2Lsym() { return ((tt&TT_MASK_TYPE)==TT_DILEPTON_SYM); } + static constexpr bool is3Lsym() { return ((tt&TT_MASK_TYPE)==TT_TRILEPTON_SYM) && !mixed(); } + static constexpr bool is3Lhalfsym() { return ((tt&TT_MASK_TYPE)==TT_TRILEPTON_HALFSYM) && !mixed(); } + static constexpr bool is2Lmix() { return (tt&TT_DILEPTON_FLAG) && mixed(); } static constexpr bool is3Lmix() { return (tt&TT_TRILEPTON_FLAG) && mixed(); } - - using companionTrig1LType = typename std::conditional<object()==xAOD::Type::Electron, Trig1E, - typename std::conditional<object()==xAOD::Type::Muon, Trig1MU, - typename std::conditional<object()==xAOD::Type::Photon, Trig1PH, UnusedArg>::type>::type>::type; + std::array<std::size_t, nDistinctLegs()> legs; explicit Trigger() { - static_assert(!((tt&TT_PHOTON_FLAG)&&mixed()), "mixed photon- electron/muon triggers not yet implemented"); std::fill(legs.begin(), legs.end(), 0); } - bool set_definition(const ImportData::TrigDef& def) + void setDefinition(const ImportData::TrigDef& def) { - if(def.type != tt) return false; - if(tt == TT_2E_MU_SYM) // special case needed to skip the duplicated electron leg - { - legs[0] = def.leg[0]; - legs[1] = def.leg[2]; - } - else // Works as well for non-mixed trilepton triggers since the asymmetric leg is always stored first - { - std::copy_n(def.leg.cbegin(), legs.size(), legs.begin()); - } - return true; + TriggerProperties(tt).loadLegs(def, legs); } - template<bool dummy=true> typename std::enable_if<(nDistinctLegs()==1)&&dummy, std::size_t>::type operator()(void) const { return legs[0]; } - std::size_t operator()(unsigned index) const { return legs[index]; } - template<bool dummy = true> typename std::enable_if<is1L()&&dummy, std::size_t>::type operator<(const Trigger& rhs) const + + template<bool=true> std::size_t operator()(void) const { + static_assert(nDistinctLegs()==1, "this function is not meaningful for this type of trigger, hence should not be used."); + return legs[0]; + } + + std::size_t operator()(unsigned index) const + { + return legs[index]; + } + + template<bool=true> std::size_t operator<(const Trigger& rhs) const + { + static_assert(is1L(), "this function is not meaningful for this type of trigger, hence should not be used."); return legs[0] < rhs.legs[0]; } - explicit operator bool() const { return std::all_of(legs.cbegin(), legs.cend(), [](const std::size_t& x)->bool{ return x; }); } - bool operator==(const Trigger& rhs) const { return legs == rhs.legs; } - template<xAOD::Type::ObjectType obj = object()> - decltype(legs.cbegin()) cbegin() const + explicit operator bool() const { - return legs.cbegin() + (obj!=xAOD::Type::Electron) *(nDistinctLegs(xAOD::Type::Electron) - + (obj!=xAOD::Type::Muon)*nDistinctLegs(xAOD::Type::Muon)); + return std::all_of(legs.cbegin(), legs.cend(), [](std::size_t x)->bool{ return x; }); } - template<xAOD::Type::ObjectType obj = object()> - decltype(legs.cend()) cend() const + bool operator==(const Trigger& rhs) const { - return legs.cend() - (obj!=xAOD::Type::Photon) *(nDistinctLegs(xAOD::Type::Photon) - + (obj!=xAOD::Type::Muon)*nDistinctLegs(xAOD::Type::Muon)); + return legs == rhs.legs; + } + + template<xAOD::Type::ObjectType obj = object()> auto cbegin() const + { + return legs.cbegin() + TriggerProperties(tt).cbegin_offset(obj); + } + + template<xAOD::Type::ObjectType obj = object()> auto cend() const + { + return legs.cend() + TriggerProperties(tt).cend_offset(obj); } template<typename Trig1L> auto hiddenBy(const Trig1L trig) const -> typename std::enable_if<Trig1L::is1L(), bool>::type { + static_assert(Trig1L::is1L(), "this function is not meaningful for this type of trigger, hence should not be used."); constexpr auto obj = Trig1L::object(); return std::find(cbegin<obj>(), cend<obj>(), trig()) != cend<obj>(); } @@ -158,87 +235,110 @@ public: template<typename Trig1L> auto hiddenBy(const flat_set<Trig1L>& trigs) const -> typename std::enable_if<Trig1L::is1L(), bool>::type { + static_assert(Trig1L::is1L(), "this function is not meaningful for this type of trigger, hence should not be used."); return std::any_of(trigs.cbegin(), trigs.cend(), [&](Trig1L t)->bool{ return hiddenBy(t); }); } - // Returns a pseudo trigger built only from the legs of flavour 'obj' - // If anti==true, uses instead only legs with flavours other than 'obj' + /// Returns a pseudo trigger built only from the legs of flavour 'obj' + /// If anti==true, uses instead only legs with flavours other than 'obj' template<xAOD::Type::ObjectType obj, bool anti=false> auto side() const - -> typename std::enable_if<mixed(), typename std::conditional<anti ^ (CastType1::object()==obj), CastType1, CastType2>::type>::type + -> std::conditional_t<anti ^ (CastType1::object()==obj), CastType1, CastType2> { - static_assert(obj != xAOD::Type::Other, ""); + static_assert(mixed(), "this function is not meaningful for this type of trigger, hence should not be used."); + static_assert(obj != xAOD::Type::Other, "implementation incomplete"); using CastType = decltype(side<obj, anti>()); CastType trig; std::copy(this->cbegin<CastType::object()>(), this->cend<CastType::object()>(), trig.legs.begin()); return trig; } - // Returns a pseudo trigger built only from the legs of the same flavour as the trigger 'TrigX' + /// Returns a pseudo trigger built only from the legs of the same flavour as the trigger 'TrigX' template<typename TrigX> auto side() const -> decltype(side<TrigX::object()>()) { return side<TrigX::object()>(); } - // Complement to the previous function + /// Complement to the previous function template<typename TrigX> auto antiside() const -> decltype(side<TrigX::object(),true>()) { return side<TrigX::object(),true>(); } + /// Returns a pseudo trigger of type CastType1/2 + CastType1 side1() const { return side<CastType1::object()>(); } + CastType2 side2() const { return side<CastType2::object()>(); } template<typename Trig1L> auto addTo(const flat_set<Trig1L>& trigs1L) const - -> typename std::enable_if<mixed()&&Trig1L::is1L()&&nDistinctLegs(Trig1L::object())==1, flat_set<Trig1L>>::type + -> std::enable_if_t<Trig1L::is1L() && nDistinctLegs(Trig1L::object())==1, flat_set<Trig1L>> { + static_assert(mixed(), "this function is not meaningful for this type of trigger, hence should not be used."); flat_set<Trig1L> trigs(trigs1L); trigs.insert(side<Trig1L>()); return trigs; } template<typename Trig1L> static auto anonymize(const flat_set<Trig1L>& triggers) - -> typename std::enable_if<is1L() && tt==Trig1L::type(), const flat_set<std::size_t>&>::type + -> std::enable_if_t<is1L() && tt==Trig1L::type(), const flat_set<std::size_t>&> { - static_assert(sizeof(Trig1L)==sizeof(std::size_t), ""); + static_assert(sizeof(Trig1L)==sizeof(std::size_t), "invalid cast if the key sizes differ"); return reinterpret_cast<const flat_set<std::size_t>&>(triggers); } - template<bool dummy=true> auto symmetric() const - -> typename std::enable_if<!std::is_same<CastType1, UnusedArg>::value && dummy, bool>::type + template<bool=true> bool symmetric() const { + static_assert(!std::is_same<CastType1, UnusedArg>::value, "this function is not meaningful for this type of trigger, hence should not be used."); return std::all_of(legs.cbegin()+1, legs.cend(), [&](std::size_t l)->bool{ return l==legs[0]; }); } - template<bool dummy=true> auto to_symmetric() const - -> typename std::enable_if<!std::is_same<CastType1, UnusedArg>::value&&dummy, CastType1>::type + template<bool=true> CastType1 to_symmetric() const { + static_assert(!std::is_same<CastType1, UnusedArg>::value, "this function is not meaningful for this type of trigger, hence should not be used."); CastType1 trig; trig.legs[0] = this->legs[0]; return trig; } - template<bool dummy=true> auto asymLeg() const - -> typename std::enable_if<((tt&TT_MASK_SYMMETRY)==TT_HALFSYM)&&dummy, std::size_t>::type + template<bool=true> std::size_t asymLeg() const { + static_assert((tt&TT_MASK_SYMMETRY)==TT_HALFSYM, "this function is not meaningful for this type of trigger, hence should not be used."); return legs[0]; } - template<bool dummy=true> auto symLeg() const - -> typename std::enable_if<((tt&TT_MASK_SYMMETRY)==TT_HALFSYM)&&dummy, std::size_t>::type + template<bool=true> std::size_t symLeg() const { + static_assert((tt&TT_MASK_SYMMETRY)==TT_HALFSYM, "this function is not meaningful for this type of trigger, hence should not be used."); return legs[1]; } }; -class Trig1E : public Trigger<TT_SINGLE_E> {}; -class Trig1MU : public Trigger<TT_SINGLE_MU> {}; -class Trig1PH : public Trigger<TT_SINGLE_PH> {}; -class Trig2Esym : public Trigger<TT_2E_SYM> {}; -class Trig2Easym : public Trigger<TT_2E_ASYM, Trig2Esym> {}; -class Trig2MUsym : public Trigger<TT_2MU_SYM> {}; -class Trig2MUasym : public Trigger<TT_2MU_ASYM, Trig2MUsym> {}; -class TrigEMU : public Trigger<TT_EMU, Trig1E, Trig1MU> {}; -class Trig2PHsym : public Trigger<TT_2PH_SYM> {}; -class Trig2PHasym : public Trigger<TT_2PH_ASYM, Trig2PHsym> {}; -class Trig3Esym : public Trigger<TT_3E_SYM> {}; -class Trig3Ehalfsym : public Trigger<TT_3E_HALFSYM, Trig3Esym> {}; -class Trig3MUsym : public Trigger<TT_3MU_SYM> {}; -class Trig3MUhalfsym : public Trigger<TT_3MU_HALFSYM, Trig3MUsym> {}; -class Trig2EMUsym : public Trigger<TT_2E_MU_SYM, Trig2Esym, Trig1MU> {}; -class Trig2EMUasym : public Trigger<TT_2E_MU_ASYM, Trig2Easym, Trig1MU> {}; -class TrigE2MUsym : public Trigger<TT_E_2MU_SYM, Trig1E, Trig2MUsym> {}; -class TrigE2MUasym : public Trigger<TT_E_2MU_ASYM, Trig1E, Trig2MUasym> {}; -class Trig3PHsym : public Trigger<TT_3PH_SYM> {}; -class Trig3PHhalfsym : public Trigger<TT_3PH_HALFSYM, Trig3PHsym> {}; +template<TriggerType, TriggerType=TT_UNKNOWN> struct TriggerClass; + +template<TriggerType object_flag> +struct TriggerClass<object_flag, TT_UNKNOWN> +{ + static constexpr auto addObjFlag(int tt) { return static_cast<TriggerType>(tt|object_flag); } + + /// single-lepton trigger (e24_lhmedium_L1EM20VH, mu24_imedium_OR_mu40...) + struct T_1 : public Trigger<addObjFlag(TT_SINGLELEPTON_FLAG)> {}; + /// symmetric dilepton trigger (2e17_lhvloose_nod0, 2mu14...) + struct T_2sym : public Trigger<addObjFlag(TT_DILEPTON_SYM)> {}; + /// asymmetric dilepton trigger (mu18_mu8noL1, g35_loose_g25_loose, ...): + struct T_2asym : public Trigger<addObjFlag(TT_DILEPTON_ASYM), T_2sym> {}; + /// symmetric trilepton trigger (3mu6, ...): + struct T_3sym : public Trigger<addObjFlag(TT_TRILEPTON_SYM)> {}; + /// half-symmetric trilepton trigger (e17_lhloose_2e9_lhloose, mu6_2mu4, ...): + struct T_3halfsym : public Trigger<addObjFlag(TT_TRILEPTON_HALFSYM), T_3sym> {}; +}; + +template<TriggerType object1_flag, TriggerType object2_flag> +struct TriggerClass +{ + using A = TriggerClass<object1_flag>; + using B = TriggerClass<object2_flag>; + static constexpr auto addObjFlags(int tt) { return static_cast<TriggerType>(tt|object1_flag|object2_flag); } + + /// mixed-flavour dilepton trigger (e17_lhloose_nod0_mu14, e7_lhmedium_mu24, ...): + struct T_1_1 : public Trigger<addObjFlags(TT_DILEPTON_FLAG), typename A::T_1, typename B::T_1> {}; + /// mixed-flavour trilepton trigger type 2x_y (2e12_lhloose_mu10, ...) + struct T_2sym_1 : public Trigger<addObjFlags(TT_TRILEPTON_SYM), typename A::T_2sym, typename B::T_1> {}; + /// mixed-flavour trilepton trigger type x_x_y + struct T_2asym_1: public Trigger<addObjFlags(TT_TRILEPTON_ASYM), typename A::T_2asym, typename B::T_1> {}; + /// mixed-flavour trilepton trigger type x_2y (e12_lhloose_2mu10, ...) + struct T_1_2sym: public Trigger<addObjFlags(TT_TRILEPTON_SYM|TT_X2Y_FLAG), typename A::T_1, typename B::T_2sym> {}; + /// mixed-flavour trilepton trigger type x_y_y + struct T_1_2asym: public Trigger<addObjFlags(TT_TRILEPTON_SYM|TT_X2Y_FLAG), typename A::T_1, typename B::T_2asym> {}; +}; } diff --git a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/data/Hierarchies.cfg b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/data/Hierarchies.cfg index 7d811ac12cfa8ee6a8c6b518684a2dedf3e5d59d..165207a5198c892b2bd31a5db1868258bdcef057 100644 --- a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/data/Hierarchies.cfg +++ b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/data/Hierarchies.cfg @@ -24,13 +24,13 @@ multi := mu24 > mu22 > mu20 > mu18 > mu14 > mu10 > mu6 > mu4 > mu8noL1 loose1 := e12_lhloose_L1EM10VH > e120_lhloose loose2 := e17_lhloose > e12_lhloose > e9_lhloose [-] e24_lhmedium_L1EM20VHI > e24_lhmedium_L1EM20VH > e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose -[-] e24_lhmedium_L1EM20VHI > e24_lhmedium_L1EM20VH > e60_lhmedium > e7_lhmedium > loose1 > loose2 -[<61 GeV] e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose > e60_lhmedium > e7_lhmedium > loose1 > loose2 -[61-121 GeV] e60_lhmedium > e7_lhmedium > e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose > loose1 > loose2 -[>121 GeV] e60_lhmedium > e7_lhmedium > loose1 > e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose > loose2 +[-] e24_lhmedium_L1EM20VHI > e24_lhmedium_L1EM20VH > e60_lhmedium > e24_lhmedium_L1EM15VH > e20_lhmedium > e7_lhmedium > loose1 > loose2 +[<61 GeV] e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose > e60_lhmedium > e24_lhmedium_L1EM15VH > e20_lhmedium > e7_lhmedium > loose1 > loose2 +[61-121 GeV] e60_lhmedium > e24_lhmedium_L1EM15VH > e20_lhmedium > e7_lhmedium > e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose > loose1 > loose2 +[>121 GeV] e60_lhmedium > e24_lhmedium_L1EM15VH > e20_lhmedium > e7_lhmedium > loose1 > e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose > loose2 ## 2016+2017 electron trigger legs (always '_nod0' suffix) -medium := e26_lhmedium_nod0_L1EM22VHI > e24_lhmedium_nod0_L1EM20VHI > e26_lhmedium_nod0 > e60_lhmedium_nod0 > e7_lhmedium_nod0 +medium := e26_lhmedium_nod0_L1EM22VHI > e24_lhmedium_nod0_L1EM20VHI > e26_lhmedium_nod0 > e24_lhmedium_nod0_L1EM20VH > e60_lhmedium_nod0 > e24_lhmedium_nod0_L1EM15VH > e20_lhmedium_nod0 > e7_lhmedium_nod0 loose1 := e17_lhloose_nod0_L1EM15VH > e10_lhloose_nod0_L1EM8VH > e140_lhloose_nod0 loose2 := e17_lhloose_nod0 > e12_lhloose_nod0 > e9_lhloose_nod0 > e17_lhvloose_nod0_L1EM15VHI > e24_lhvloose_nod0_L1EM20VH > e15_lhvloose_nod0_L1EM13VH > e12_lhvloose_nod0_L1EM10VH > e17_lhvloose_nod0 [-] e26_lhtight_nod0_ivarloose > e24_lhtight_nod0_ivarloose > medium > loose1 > loose2 @@ -39,4 +39,8 @@ loose2 := e17_lhloose_nod0 > e12_lhloose_nod0 > e9_lhloose_nod0 > e17_lhvloose_n [>141 GeV] medium > loose1 > e26_lhtight_nod0_ivarloose_OR_e60_lhmedium_nod0_OR_e140_lhloose_nod0 > e24_lhtight_nod0_ivarloose_OR_e60_lhmedium_nod0_OR_e140_lhloose_nod0 > loose2 ## photon triggers -[-] g20_tight_icalovloose_L1EM15VHI > g22_tight_L1EM15VHI > g35_medium_L1EM20VH > g25_medium_L1EM20VH > g50_loose_L1EM20VH > g35_loose > g25_loose +[-] g35_tight_icalotight_L1EM24VHI > g20_tight_icalovloose_L1EM15VHI > g22_tight_L1EM15VHI > g22_tight > g20_tight > g35_medium_L1EM20VH > g25_medium_L1EM20VH > g35_loose_L1EM24VHI > g35_loose_L1EM22VHI > g50_loose_L1EM20VH > g140_loose > g120_loose > g35_loose > g25_loose > g20_loose > g15_loose > g12_loose > g10_loose > g35_loose_L1EM15 > g25_loose_L1EM15 + + + + diff --git a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/data/Thresholds.cfg b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/data/Thresholds.cfg index da5b59e9bc4445f2d430e73538ae73f11909dd4c..5772af543277a438baf161fb1eecefaf92df0459 100644 --- a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/data/Thresholds.cfg +++ b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/data/Thresholds.cfg @@ -32,47 +32,70 @@ mu20_iloose_L1MU15_OR_mu40 21000 MeV mu20_iloose_L1MU15 21000 MeV mu20 21000 MeV mu18 19000 MeV +mu18noL1 18000 MeV +mu15 15000 MeV +mu15noL1 15000 MeV mu14 15000 MeV mu10 11000 MeV mu8noL1 10000 MeV mu6 7000 MeV mu4 5000 MeV +mu4noL1 4000 MeV +mu2noL1 2000 MeV -e140_lhloose_nod0 141000 MeV -e120_lhloose 121000 MeV -e60_lhmedium 61000 MeV -e60_lhmedium_nod0 61000 MeV -e26_lhtight_nod0_ivarloose_OR_e60_lhmedium_nod0_OR_e140_lhloose_nod0 27000 MeV -e26_lhtight_nod0_ivarloose 27000 MeV -e26_lhmedium_nod0 27000 MeV -e26_lhmedium_nod0_L1EM22VHI 27000 MeV -e24_lhtight_nod0_ivarloose_OR_e60_lhmedium_nod0_OR_e140_lhloose_nod0 25000 MeV -e24_lhtight_nod0_ivarloose 25000 MeV -e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose 25000 MeV -e24_lhmedium_L1EM20VH 25000 MeV -e24_lhmedium_L1EM20VHI 25000 MeV -e24_lhmedium_nod0_L1EM20VHI 25000 MeV -e24_lhvloose_nod0_L1EM20VH 25000 MeV -e17_lhloose 18000 MeV -e17_lhloose_nod0 18000 MeV -e17_lhvloose_nod0 18000 MeV -e17_lhvloose_nod0_L1EM15VHI 18000 MeV -e17_lhloose_nod0_L1EM15VH 18000 MeV -e15_lhvloose_nod0_L1EM13VH 16000 MeV -e12_lhloose 13000 MeV -e12_lhloose_nod0 13000 MeV -e12_lhloose_L1EM10VH 13000 MeV -e12_lhvloose_nod0_L1EM10VH 13000 MeV -e10_lhloose_nod0_L1EM8VH 11000 MeV -e9_lhloose 10000 MeV -e9_lhloose_nod0 10000 MeV -e7_lhmedium_nod0 8000 MeV -e7_lhmedium 8000 MeV +e140_lhloose_nod0 141 GeV +e120_lhloose 121 GeV +e60_lhmedium 61 GeV +e60_lhmedium_nod0 61 GeV +e26_lhtight_nod0_ivarloose_OR_e60_lhmedium_nod0_OR_e140_lhloose_nod0 27 GeV +e26_lhtight_nod0_ivarloose 27 GeV +e26_lhmedium_nod0 27 GeV +e26_lhmedium_nod0_L1EM22VHI 27 GeV +e24_lhtight_nod0_ivarloose_OR_e60_lhmedium_nod0_OR_e140_lhloose_nod0 25 GeV +e24_lhtight_nod0_ivarloose 25 GeV +e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose 25 GeV +e24_lhmedium_L1EM20VH 25 GeV +e24_lhmedium_nod0_L1EM20VH 25 GeV +e24_lhmedium_L1EM15VH 25 GeV +e24_lhmedium_L1EM20VHI 25 GeV +e24_lhmedium_nod0_L1EM20VHI 25 GeV +e24_lhmedium_nod0_L1EM15VH 25 GeV +e24_lhvloose_nod0_L1EM20VH 25 GeV +e20_lhmedium_nod0 21 GeV +e20_lhmedium 21 GeV +e17_lhloose 18 GeV +e17_lhloose_nod0 18 GeV +e17_lhvloose_nod0 18 GeV +e17_lhvloose_nod0_L1EM15VHI 18 GeV +e17_lhloose_nod0_L1EM15VH 18 GeV +e15_lhvloose_nod0_L1EM13VH 16 GeV +e12_lhloose 13 GeV +e12_lhloose_nod0 13 GeV +e12_lhloose_L1EM10VH 13 GeV +e12_lhvloose_nod0_L1EM10VH 13 GeV +e10_lhloose_nod0_L1EM8VH 11 GeV +e9_lhloose 10 GeV +e9_lhloose_nod0 10 GeV +e7_lhmedium_nod0 8 GeV +e7_lhmedium 8 GeV -g50_loose_L1EM20VH 51000 MeV -g35_medium_L1EM20VH 36000 MeV -g35_loose 36000 MeV -g25_medium_L1EM20VH 26000 MeV -g25_loose 26000 MeV -g22_tight_L1EM15VHI 23000 MeV -g20_tight_icalovloose_L1EM15VHI 21000 MeV \ No newline at end of file +g140_loose 141 GeV +g120_loose 121 GeV +g50_loose_L1EM20VH 51 GeV +g35_tight_icalotight_L1EM24VHI 36 GeV +g35_medium_L1EM20VH 36 GeV +g35_loose_L1EM24VHI 36 GeV +g35_loose_L1EM22VHI 36 GeV +g35_loose 36 GeV +g35_loose_L1EM15 36 GeV +g25_medium_L1EM20VH 26 GeV +g25_loose 26 GeV +g25_loose_L1EM15 26 GeV +g22_tight_L1EM15VHI 23 GeV +g22_tight 23 GeV +g20_tight_icalovloose_L1EM15VHI 21 GeV +g20_tight 21 GeV +g20_loose 21 GeV +g15_loose 16 GeV +g12_loose 13 GeV +g10_loose 11 GeV \ No newline at end of file diff --git a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/data/Triggers.cfg b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/data/Triggers.cfg index e311ca69d89b79de0dc7d04223a77d445eff2c40..0d6d1483660e582bd88dd82668f114bafbc824f5 100644 --- a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/data/Triggers.cfg +++ b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/data/Triggers.cfg @@ -40,11 +40,10 @@ mu22_mu8noL1 mu22 mu8noL1 3mu4 mu4 mu4 mu4 3mu6 mu6 mu6 mu6 mu6_2mu4 mu6 mu4 mu4 -# trigger3L( "mu18_2mu4noL1", "mu18", "mu4noL1", "mu4noL1" ); // check availability of SF for mu4noL1 -# trigger3L( "mu20_2mu4noL1", "mu20", "mu4noL1", "mu4noL1" ); // check availability of SF for mu4noL1 - -## Single electron triggers +mu18_2mu4noL1 mu18 mu4noL1 mu4noL1 +mu20_2mu4noL1 mu20 mu4noL1 mu4noL1 +## Single electron triggers e15_lhvloose_nod0_L1EM13VH e24_lhmedium_L1EM20VH e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose @@ -79,14 +78,47 @@ e24_lhmedium_L1EM20VHI_mu8noL1 e24_lhmedium_L1EM20VHI mu8noL1 e24_lhmedium_nod0_L1EM20VHI_mu8noL1 e24_lhmedium_nod0_L1EM20VHI mu8noL1 e26_lhmedium_nod0_mu8noL1 e26_lhmedium_nod0 mu8noL1 e26_lhmedium_nod0_L1EM22VHI_mu8noL1 e26_lhmedium_nod0_L1EM22VHI mu8noL1 -e12_lhloose_2mu10 e12_lhloose mu10 mu10 -e12_lhloose_nod0_2mu10 e12_lhloose_nod0 mu10 mu10 -2e12_lhloose_mu10 e12_lhloose e12_lhloose mu10 +e12_lhloose_2mu10 e12_lhloose mu10 mu10 +e12_lhloose_nod0_2mu10 e12_lhloose_nod0 mu10 mu10 +2e12_lhloose_mu10 e12_lhloose e12_lhloose mu10 2e12_lhloose_nod0_mu10 e12_lhloose_nod0 e12_lhloose_nod0 mu10 +## Single photon triggers +g140_loose +g120_loose + ## Diphoton triggers -2g20_tight_icalovloose_L12EM15VHI g20_tight_icalovloose_L1EM15VHI g20_tight_icalovloose_L1EM15VHI -2g22_tight_L12EM15VHI g22_tight_L1EM15VHI g22_tight_L1EM15VHI 2g50_loose_L12EM20VH g50_loose_L1EM20VH g50_loose_L1EM20VH g35_medium_g25_medium_L12EM20VH g35_medium_L1EM20VH g25_medium_L1EM20VH -g35_loose_g25_loose g35_loose g25_loose \ No newline at end of file +g35_loose_g25_loose g35_loose g25_loose +g35_loose_L1EM15_g25_loose_L1EM15 g35_loose_L1EM15 g25_loose_L1EM15 +2g20_tight_icalovloose_L12EM15VHI g20_tight_icalovloose_L1EM15VHI g20_tight_icalovloose_L1EM15VHI +2g22_tight_L12EM15VHI g22_tight_L1EM15VHI g22_tight_L1EM15VHI +2g22_tight g22_tight g22_tight +2g20_tight g20_tight g20_tight + +## Triphoton triggers +2g25_loose_g15_loose g25_loose g25_loose g15_loose +2g20_loose_g15_loose g20_loose g20_loose g15_loose +3g20_loose g20_loose g20_loose g20_loose +3g15_loose g15_loose g15_loose g15_loose + +## Electron-photon triggers +e24_lhmedium_nod0_L1EM20VH_g25_medium e24_lhmedium_nod0_L1EM20VH g25_medium_L1EM20VH +e24_lhmedium_nod0_L1EM15VH_g25_medium e24_lhmedium_nod0_L1EM15VH g25_medium_L1EM20VH +e24_lhmedium_L1EM15VH_g25_medium e24_lhmedium_L1EM15VH g25_medium_L1EM20VH +e20_lhmedium_nod0_g35_loose e20_lhmedium_nod0 g35_loose +e20_lhmedium_g35_loose e20_lhmedium g35_loose +e24_lhmedium_nod0_2g12_loose e24_lhmedium_nod0_L1EM20VH g12_loose g12_loose +e20_lhmedium_nod0_2g10_loose e24_lhmedium_nod0_L1EM20VH g10_loose g10_loose +e20_lhmedium_2g10_loose e20_lhmedium g10_loose g10_loose + +## Muon-photon triggers +g35_tight_icalotight_L1EM24VHI_mu18noL1 g35_tight_icalotight_L1EM24VHI mu18noL1 +g35_loose_L1EM22VHI_mu18noL1 g35_loose_L1EM22VHI mu18noL1 +g35_loose_L1EM24VHI_mu18 g35_loose_L1EM24VHI mu18 +g25_medium_mu24 g25_medium_L1EM20VH mu24 +g35_tight_icalotight_L1EM24VHI_mu15noL1_mu2noL1 g35_tight_icalotight_L1EM24VHI mu15noL1 mu2noL1 +g35_loose_L1EM24VHI_mu15_mu2noL1 g35_loose_L1EM24VHI mu15 mu2noL1 +g35_loose_L1EM22VHI_mu15noL1_mu2noL1 g35_loose_L1EM22VHI mu15noL1 mu2noL1 +2g10_loose_mu20 g10_loose g10_loose mu20 diff --git a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/util/TrigGlobEffCorrValidation.cxx b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/util/TrigGlobEffCorrValidation.cxx index 7ef166fb24b368ea0afdc68dc4471bc30c0ef330..5f2d0ee024a88cf67fb051738360bcec652bf65b 100644 --- a/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/util/TrigGlobEffCorrValidation.cxx +++ b/Trigger/TrigAnalysis/TrigGlobalEfficiencyCorrection/util/TrigGlobEffCorrValidation.cxx @@ -9,6 +9,7 @@ #include "AsgTools/AnaToolHandle.h" #include "TriggerAnalysisInterfaces/ITrigGlobalEfficiencyCorrectionTool.h" #include "EgammaAnalysisInterfaces/IAsgElectronEfficiencyCorrectionTool.h" +#include "EgammaAnalysisInterfaces/IAsgPhotonEfficiencyCorrectionTool.h" #include "MuonAnalysisInterfaces/IMuonTriggerScaleFactors.h" #include "xAODEgamma/Electron.h" #include "xAODEgamma/ElectronContainer.h" @@ -16,6 +17,9 @@ #include "xAODMuon/MuonContainer.h" #include "xAODMuon/MuonAuxContainer.h" #include "PATInterfaces/ISystematicsTool.h" +#include "xAODEgamma/Photon.h" +#include "xAODEgamma/PhotonContainer.h" +#include "xAODEgamma/PhotonAuxContainer.h" #include <random> #include <functional> @@ -37,7 +41,7 @@ public: efficiencyScaleFactor = m_func(electron.pt()); return CP::CorrectionCode::Ok; } - virtual CP::CorrectionCode applyEfficiencyScaleFactor(const xAOD::Electron&) const override { return CP::CorrectionCode::Ok; } + virtual CP::CorrectionCode applyEfficiencyScaleFactor(const xAOD::Electron&) const override { return CP::CorrectionCode::Error; } virtual bool isAffectedBySystematic(const CP::SystematicVariation&) const override { return false; } virtual CP::SystematicSet affectingSystematics() const override { return CP::SystematicSet(); } virtual CP::SystematicSet recommendedSystematics() const override { return CP::SystematicSet(); } @@ -45,6 +49,27 @@ public: virtual int systUncorrVariationIndex( const xAOD::Electron &) const override { return 0; } }; +class SimplePhotonEfficiencyCorrectionTool : virtual public IAsgPhotonEfficiencyCorrectionTool, public asg::AsgTool +{ + ASG_TOOL_CLASS(SimplePhotonEfficiencyCorrectionTool, IAsgPhotonEfficiencyCorrectionTool) + std::function<double(float)> m_func; +public: + SimplePhotonEfficiencyCorrectionTool(const std::string& name, double eff = 0.8) : AsgTool(name), m_func([=](float){return eff;}) {} + SimplePhotonEfficiencyCorrectionTool(const std::string& name, const std::function<double(float)>& func) : AsgTool(name), m_func(func) {} + virtual ~SimplePhotonEfficiencyCorrectionTool() {} + virtual CP::CorrectionCode getEfficiencyScaleFactor(const xAOD::Egamma& photon, double& efficiencyScaleFactor) const override + { + efficiencyScaleFactor = m_func(photon.pt()); + return CP::CorrectionCode::Ok; + } + virtual CP::CorrectionCode getEfficiencyScaleFactorError(const xAOD::Egamma&, double&) const override { return CP::CorrectionCode::Error; } + virtual CP::CorrectionCode applyEfficiencyScaleFactor(xAOD::Egamma&) const override { return CP::CorrectionCode::Error; } + virtual bool isAffectedBySystematic(const CP::SystematicVariation&) const override { return false; } + virtual CP::SystematicSet affectingSystematics() const override { return CP::SystematicSet(); } + virtual CP::SystematicSet recommendedSystematics() const override { return CP::SystematicSet(); } + virtual CP::SystematicCode applySystematicVariation(const CP::SystematicSet&) override { return CP::SystematicCode::Ok; } +}; + class SimpleMuonTriggerScaleFactors : public CP::IMuonTriggerScaleFactors, public asg::AsgTool { ASG_TOOL_CLASS(SimpleMuonTriggerScaleFactors, CP::IMuonTriggerScaleFactors) @@ -93,7 +118,7 @@ struct Config unsigned maxLeptons = 5; std::vector<float> leptonPtValues; std::map<std::string, std::function<double(float)>> efficiencies; - std::function<bool(const std::vector<const xAOD::Electron*>&,const std::vector<const xAOD::Muon*>&)> eventSelection = nullptr; + std::function<bool(const std::vector<const xAOD::Electron*>&,const std::vector<const xAOD::Muon*>&,const std::vector<const xAOD::Photon*>&)> eventSelection = nullptr; double expectedEfficiency = -1.; double expectedEfficiencyTolerance = 1e-6; bool debug = false; @@ -129,6 +154,7 @@ struct Config xAOD::ElectronContainer* electronContainer = nullptr; xAOD::MuonContainer* muonContainer = nullptr; +xAOD::PhotonContainer* photonContainer = nullptr; bool quiet = false, fast = false, skip = false; template<class Lepton> @@ -189,10 +215,22 @@ int main(int argc, char* argv[]) muonContainer->push_back(mu); } + photonContainer = new xAOD::PhotonContainer(); + ANA_CHECK(store.record(photonContainer, "Photons")); + auto photonContainerAux = new xAOD::PhotonAuxContainer(); + ANA_CHECK(store.record(photonContainerAux, "PhotonsAux")); + photonContainer->setStore(photonContainerAux); + for(int i=0;i<10;++i) + { + auto ph = new xAOD::Photon(); + photonContainer->push_back(ph); + } + using VE = const std::vector<const xAOD::Electron*>&; using VM = const std::vector<const xAOD::Muon*>&; + using VP = const std::vector<const xAOD::Photon*>&; - ANA_CHECK(run_test(Config("1L") + ANA_CHECK(run_test(Config("1L (1 lepton)") .setTriggers("e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose || mu20_iloose_L1MU15_OR_mu50") .setLeptonPDF(1, 1, {30e3f}) .setEfficiency("e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose", 0.60) @@ -200,34 +238,56 @@ int main(int argc, char* argv[]) .setExpectedEfficiency(0.60, 1e-6) )); - ANA_CHECK(run_test(Config("1L (multilepton)") + ANA_CHECK(run_test(Config("1L (2 flavours, 1-4 leptons)") .setTriggers("e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose || mu20_iloose_L1MU15_OR_mu50") .setLeptonPDF(1, 4, {30e3f}) .setEfficiency("e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose", 0.40) - .setEfficiency("mu20_iloose_L1MU15_OR_mu50", 0.40) + )); + + ANA_CHECK(run_test(Config("2e (2 leptons)") + .setTriggers("2e12_lhloose_L12EM10VH") + .setLeptonPDF(2, 2, {30e3f}) + .setEfficiency("e12_lhloose_L1EM10VH", 0.50) + .setExpectedEfficiency(0.25, 1e-6) )); - ANA_CHECK(run_test(Config("2e") + ANA_CHECK(run_test(Config("2e (2-3 leptons)") .setTriggers("2e12_lhloose_L12EM10VH") .setLeptonPDF(2, 3, {30e3f}) .setEfficiency("e12_lhloose_L1EM10VH", 0.50) - .setEventSelection([](VE ve, VM) { return count(ve,13e3f)>1; }) )); - ANA_CHECK(run_test(Config("emu") + ANA_CHECK(run_test(Config("emu (2 leptons)") .setTriggers("e17_lhloose_mu14") - .setLeptonPDF(2, 3, {16e3f, 20e3f}) + .setLeptonPDF(2, 2, {20e3f}) .setEfficiency("e17_lhloose", 0.60) .setEfficiency("mu14", 0.60) - .setEventSelection([](VE ve, VM vm) { return count(ve,18e3f)>0&&count(vm,15e3f)>0; }) + .setExpectedEfficiency(0.36, 1e-6) + .setEventSelection([](VE ve, VM vm, VP) { return count(ve,18e3f)>0&&count(vm,15e3f)>0; }) + )); + + ANA_CHECK(run_test(Config("emu (2-3 leptons)") + .setTriggers("e17_lhloose_mu14") + .setLeptonPDF(2, 3, {16e3f, 20e3f}) + .setEfficiency("e17_lhloose", 0.64) + .setEfficiency("mu14", 0.56) + .setEventSelection([](VE ve, VM vm, VP) { return count(ve,18e3f)>0&&count(vm,15e3f)>0; }) + )); + + ANA_CHECK(run_test(Config("2mu (asym) (2 leptons)") + .setTriggers("mu18_mu8noL1") + .setLeptonPDF(2, 2, {30e3f}) + .setEfficiency("mu18", 0.70) + .setEfficiency("mu8noL1", 0.70) + .setExpectedEfficiency(0.49, 1e-6) )); - ANA_CHECK(run_test(Config("2mu") + ANA_CHECK(run_test(Config("2mu (asym) (2-3 leptons)") .setTriggers("mu18_mu8noL1") .setLeptonPDF(2, 3, {11e3f, 21e3f}) .setEfficiency("mu18", 0.60) .setEfficiency("mu8noL1", 0.70) - .setEventSelection([](VE, VM vm) { return count(vm,19e3f)>0&&count(vm,10e3f)>1; }) + .setEventSelection([](VE, VM vm, VP) { return count(vm,19e3f)>0&&count(vm,10e3f)>1; }) )); ANA_CHECK(run_test(Config("2e||emu||2mu") @@ -238,7 +298,7 @@ int main(int argc, char* argv[]) .setEfficiency("mu18", 0.60) .setEfficiency("mu14", 0.60) .setEfficiency("mu8noL1", 0.70) - .setEventSelection([](VE ve, VM vm) { return count(ve,13e3f)>1 + .setEventSelection([](VE ve, VM vm, VP) { return count(ve,13e3f)>1 || (count(ve,18e3f)>0&&count(vm,15e3f)>0) || (count(vm,19e3f)>0&&count(vm,10e3f)>1); }) )); @@ -252,24 +312,39 @@ int main(int argc, char* argv[]) .setEfficiency("mu18", 0.60) .setEfficiency("mu14", 0.60) .setEfficiency("mu8noL1", 0.70) - .setEventSelection([](VE ve, VM vm) { return count(ve,13e3f)>1 + .setEventSelection([](VE ve, VM vm, VP) { return count(ve,13e3f)>1 || (count(ve,18e3f)>0&&count(vm,15e3f)>0) || (count(vm,19e3f)>0&&count(vm,10e3f)>1) || count(ve,25e3f)>0 || count(vm,21.5e3f)>0; }) )); - ANA_CHECK(run_test(Config("2e_e") + ANA_CHECK(run_test(Config("e_2e (3 leptons)") + .setTriggers("e17_lhloose_2e9_lhloose") + .setLeptonPDF(3, 3, {20e3f}) + .setEfficiency("e17_lhloose", 0.90) + .setEfficiency("e9_lhloose", 0.90) + .setExpectedEfficiency(0.729, 1e-6) + )); + + ANA_CHECK(run_test(Config("e_2e (3-5 leptons)") .setTriggers("e17_lhloose_2e9_lhloose") .setLeptonPDF(3, 5, {12e3f, 20e3f}) .setEfficiency("e17_lhloose", 0.60) .setEfficiency("e9_lhloose", 0.70) - .setEventSelection([](VE ve, VM) { return (count(ve,18e3f)>0&&count(ve,10e3f)>2); }) + .setEventSelection([](VE ve, VM, VP) { return (count(ve,18e3f)>0&&count(ve,10e3f)>2); }) + )); + + ANA_CHECK(run_test(Config("3mu (3 leptons)") + .setTriggers("3mu6") + .setLeptonPDF(3, 3, {10e3f}) + .setEfficiency("mu6", 0.90) + .setExpectedEfficiency(0.729, 1e-6) )); - ANA_CHECK(run_test(Config("3mu") + ANA_CHECK(run_test(Config("3mu (3-5 leptons)") .setTriggers("3mu6") .setLeptonPDF(3, 5, {10e3f}) .setEfficiency("mu6", 0.70) - .setEventSelection([](VE, VM vm) { return count(vm,7e3f)>2; }) + .setEventSelection([](VE, VM vm, VP) { return count(vm,7e3f)>2; }) )); ANA_CHECK(run_test(Config("2e_mu||e_2mu") @@ -277,17 +352,17 @@ int main(int argc, char* argv[]) .setLeptonPDF(3, 5, {14e3f}) .setEfficiency("e12_lhloose", 0.50) .setEfficiency("mu10", 0.60) - .setEventSelection([](VE ve, VM vm) { return (count(ve,13e3f)>1&&count(vm,11e3f)>0) || (count(ve,13e3f)>0&&count(vm,11e3f)>1); }) - )); - - // not a full test of the function since 2mu10 completely shadows 2mu14, but it validates at least part of the logic + .setEventSelection([](VE ve, VM vm, VP) { return (count(ve,13e3f)>1&&count(vm,11e3f)>0) || (count(ve,13e3f)>0&&count(vm,11e3f)>1); }) + )); + + // not a full test of the function since 2mu10 completely shadows 2mu14, but it validates at least part of the logic. Full test done with photons (see below). ANA_CHECK(run_test(Config("2mu||2mu||mu") .setTriggers("2mu10 || 2mu14 || mu24_iloose_L1MU15") .setLeptonPDF(1, 4, {13e3f, 16e3f, 30e3f}) .setEfficiency("mu10", 0.70) .setEfficiency("mu14", 0.60) .setEfficiency("mu24_iloose_L1MU15", 0.30) - .setEventSelection([](VE, VM vm) { return (count(vm,11e3f)>1) || (count(vm,25.5e3f)>1) ; }) + .setEventSelection([](VE, VM vm, VP) { return (count(vm,11e3f)>1) || (count(vm,25.5e3f)>1) ; }) )); ANA_CHECK(run_test(Config("mu_mu||2mu||mu") @@ -297,7 +372,7 @@ int main(int argc, char* argv[]) .setEfficiency("mu14", 0.70) .setEfficiency("mu18", 0.60) .setEfficiency("mu24_iloose_L1MU15", 0.30) - .setEventSelection([](VE, VM vm) { return (count(vm,25.5e3f)>0) || (count(vm,10e3f)>1&&count(vm,19e3f)>0) || (count(vm,15e3f)>1) ; }) + .setEventSelection([](VE, VM vm, VP) { return (count(vm,25.5e3f)>0) || (count(vm,10e3f)>1&&count(vm,19e3f)>0) || (count(vm,15e3f)>1) ; }) )); ANA_CHECK(run_test(Config("2e||mu_mu||2mu||emu||emu||e||mu") @@ -312,20 +387,94 @@ int main(int argc, char* argv[]) .setEfficiency("e12_lhloose_L1EM10VH", 0.73) .setEfficiency("e17_lhloose", 0.67) .setEfficiency("e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose", 0.42) - .setEventSelection([](VE ve, VM vm) { return (count(vm,25.5e3f)>0) || (count(ve,25e3f)>0) || (count(ve,13e3f)>1) || (count(vm,15e3f)>1) + .setEventSelection([](VE ve, VM vm, VP) { return (count(vm,25.5e3f)>0) || (count(ve,25e3f)>0) || (count(ve,13e3f)>1) || (count(vm,15e3f)>1) || (count(vm,10e3f)>1&&count(vm,19e3f)>0) || (count(ve,18e3f)>0&&count(vm,15e3f)>0) || (count(ve,8e3f)>0&&count(vm,25.5e3f)>0); }) )); + ANA_CHECK(run_test(Config("2g (sym)") + .setTriggers("2g22_tight_L12EM15VHI") + .setLeptonPDF(2, 3, {30e3f}) + .setEfficiency("g22_tight_L1EM15VHI", 0.60) + .setEventSelection([](VE, VM, VP vp) { return count(vp,23e3f)>1; }) + )); + + ANA_CHECK(run_test(Config("2g (sym) || 2g (sym) || 1g") + .setTriggers("2g50_loose_L12EM20VH || 2g22_tight_L12EM15VHI || g120_loose") + .setLeptonPDF(2, 3, {25e3f, 60e3f, 150e3f}) + .setEfficiency("g22_tight_L1EM15VHI", 0.43) + .setEfficiency("g50_loose_L1EM20VH", 0.74) + .setEfficiency("g120_loose", 0.82) + .setEventSelection([](VE, VM, VP vp) { return count(vp,23e3f)>1 || count(vp,121e3f)>0; }) + )); + + ANA_CHECK(run_test(Config("2g (sym) || 2g (asym)") + .setTriggers("2g22_tight_L12EM15VHI || g35_medium_g25_medium_L12EM20VH") + .setLeptonPDF(2, 4, {24e3f, 30e3f, 40e3f}) + .setEfficiency("g22_tight_L1EM15VHI", 0.43) + .setEfficiency("g35_medium_L1EM20VH", 0.74) + .setEfficiency("g25_medium_L1EM20VH", 0.82) + .setEventSelection([](VE, VM, VP vp) { return count(vp,23e3f)>1; }) + )); + + ANA_CHECK(run_test(Config("2g_g (3 photons)") + .setTriggers("2g25_loose_g15_loose") + .setLeptonPDF(3, 3, {30e3f}) + .setEfficiency("g25_loose", 0.8) + .setEfficiency("g15_loose", 0.9) + .setExpectedEfficiency(0.704, 1e-6) + )); + + ANA_CHECK(run_test(Config("2g_g (3-5 photons)") + .setTriggers("2g25_loose_g15_loose") + .setLeptonPDF(3, 5, {20e3f, 30e3f}) + .setEfficiency("g25_loose", 0.63) + .setEfficiency("g15_loose", 0.88) + .setEventSelection([](VE, VM, VP vp) { return count(vp,26e3f)>1 && count(vp,16e3f)>2; }) + )); + + ANA_CHECK(run_test(Config("e || mu || g (factorized)") + .setTriggers("e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose || mu20_iloose_L1MU15_OR_mu50 || g120_loose") + .setLeptonPDF(1, 2, {150e3f}) + .setEfficiency("e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose", 0.55) + .setEfficiency("mu20_iloose_L1MU15_OR_mu50", 0.66) + .setEfficiency("g120_loose", 0.77) + )); + + ANA_CHECK(run_test(Config("3e || 3mu || 3g (factorized)") + .setTriggers("e17_lhloose_2e9_lhloose || 3mu6 || 3g20_loose") + .setLeptonPDF(4, 6, {30e3f}) + .setEfficiency("e9_lhloose", 0.68) + .setEfficiency("e17_lhloose", 0.54) + .setEfficiency("mu6", 0.77) + .setEfficiency("g20_loose", 0.81) + .setEventSelection([](VE ve, VM vm, VP vp) { return count(ve,18e3f)>2 || count(vm,10e3f)>2 || count(vp,21e3f)>2; }) + )); + + ANA_CHECK(run_test(Config("e_2mu || 2g || 1g (factorized)") + .setTriggers("g120_loose || 2e12_lhloose_mu10 || 2g22_tight_L12EM15VHI") + .setLeptonPDF(3, 6, {150e3f}) + .setEfficiency("e12_lhloose", 0.48) + .setEfficiency("mu10", 0.62) + .setEfficiency("g22_tight_L1EM15VHI", 0.35) + .setEfficiency("g120_loose", 0.56) + .setEventSelection([](VE ve, VM vm, VP vp) { return (count(ve,13e3f)>1 && count(vm,11e3f)>0) || count(vp,21e3f)>0; }) + )); + //Info(MSGSOURCE, "Boost version: %i", BOOST_VERSION); return 0; } -bool configure(asg::AnaToolHandle<ITrigGlobalEfficiencyCorrectionTool>& tool, ToolHandleArray<IAsgElectronEfficiencyCorrectionTool>& electronEffToolsHandles, ToolHandleArray<IAsgElectronEfficiencyCorrectionTool>& electronSFToolsHandles, ToolHandleArray<CP::IMuonTriggerScaleFactors>& muonToolsHandles, +bool configure(asg::AnaToolHandle<ITrigGlobalEfficiencyCorrectionTool>& tool, + ToolHandleArray<IAsgElectronEfficiencyCorrectionTool>& electronEffToolsHandles, ToolHandleArray<IAsgElectronEfficiencyCorrectionTool>& electronSFToolsHandles, + ToolHandleArray<CP::IMuonTriggerScaleFactors>& muonToolsHandles, + ToolHandleArray<IAsgPhotonEfficiencyCorrectionTool>& photonEffToolsHandles, ToolHandleArray<IAsgPhotonEfficiencyCorrectionTool>& photonSFToolsHandles, const std::string& triggers, const std::map<std::string, std::string>& legsPerTool, unsigned long nToys, bool debug) { ANA_CHECK(tool.setProperty("ElectronEfficiencyTools", electronEffToolsHandles)); ANA_CHECK(tool.setProperty("ElectronScaleFactorTools", electronSFToolsHandles)); + ANA_CHECK(tool.setProperty("PhotonEfficiencyTools", photonEffToolsHandles)); + ANA_CHECK(tool.setProperty("PhotonScaleFactorTools", photonSFToolsHandles)); ANA_CHECK(tool.setProperty("ListOfLegsPerTool", legsPerTool)); ANA_CHECK(tool.setProperty("MuonTools", muonToolsHandles)); ANA_CHECK(tool.setProperty("TriggerCombination2015", triggers)); @@ -342,7 +491,10 @@ bool run_test(const Config& cfg, int toy_to_debug) const int nToysPerEvent = (fast? 250 : 500), nToysPerTest = (fast? 200 : 2000), nToySamples = 10; std::vector<SimpleElectronEfficiencyCorrectionTool*> electronTools; ToolHandleArray<IAsgElectronEfficiencyCorrectionTool> electronEffToolsHandles, electronSFToolsHandles; + std::vector<SimplePhotonEfficiencyCorrectionTool*> photonTools; + ToolHandleArray<IAsgPhotonEfficiencyCorrectionTool> photonEffToolsHandles, photonSFToolsHandles; std::map<std::string,std::string> legsPerTool; + bool generateElectrons = false, generateMuons = false, generatePhotons = false; for(auto& kv : cfg.efficiencies) { if(kv.first[0]=='e') @@ -357,7 +509,23 @@ bool run_test(const Config& cfg, int toy_to_debug) #ifdef XAOD_STANDALONE electronSFToolsHandles.push_back(electronTools.back()); #endif + generateElectrons =true; } + else if(kv.first[0]=='g') + { + photonTools.emplace_back(new SimplePhotonEfficiencyCorrectionTool("EFF-"+kv.first, kv.second)); + legsPerTool.emplace(photonTools.back()->name(), kv.first); + #ifdef XAOD_STANDALONE + photonEffToolsHandles.push_back(photonTools.back()); + #endif + photonTools.emplace_back(new SimplePhotonEfficiencyCorrectionTool("SF-"+kv.first, 1.)); + legsPerTool.emplace(photonTools.back()->name(), kv.first); + #ifdef XAOD_STANDALONE + photonSFToolsHandles.push_back(photonTools.back()); + #endif + generatePhotons = true; + } + else if(kv.first[0]=='m') generateMuons = true; } std::vector<SimpleMuonTriggerScaleFactors*> muonTools; muonTools.emplace_back(new SimpleMuonTriggerScaleFactors("EFF-muons", cfg.efficiencies)); @@ -369,14 +537,16 @@ bool run_test(const Config& cfg, int toy_to_debug) asg::AnaToolHandle<ITrigGlobalEfficiencyCorrectionTool> trigGlobTool("TrigGlobalEfficiencyCorrectionTool/trigGlobTool" + suffix); asg::AnaToolHandle<ITrigGlobalEfficiencyCorrectionTool> trigGlobTool_toys("TrigGlobalEfficiencyCorrectionTool/trigGlobTool_toys" + suffix); bool debug = cfg.debug || (toy_to_debug>=0); - ANA_CHECK(configure(trigGlobTool, electronEffToolsHandles, electronSFToolsHandles, muonToolsHandles, cfg.triggers, legsPerTool, 0, debug)); - ANA_CHECK(configure(trigGlobTool_toys, electronEffToolsHandles, electronSFToolsHandles, muonToolsHandles, cfg.triggers, legsPerTool, nToysPerEvent, debug)); + ANA_CHECK(configure(trigGlobTool, electronEffToolsHandles, electronSFToolsHandles, muonToolsHandles, photonEffToolsHandles, photonSFToolsHandles, cfg.triggers, legsPerTool, 0, debug)); + ANA_CHECK(configure(trigGlobTool_toys, electronEffToolsHandles, electronSFToolsHandles, muonToolsHandles, photonEffToolsHandles, photonSFToolsHandles, cfg.triggers, legsPerTool, nToysPerEvent, debug)); std::default_random_engine rdm; std::uniform_int_distribution<unsigned> nleptonsPdf(cfg.minLeptons, cfg.maxLeptons); - std::bernoulli_distribution flavourPdf; + std::discrete_distribution<> flavourPdf({1.*generateElectrons, 1.*generateMuons, 1.*generatePhotons}); std::uniform_int_distribution<unsigned> ptIndexPdf(0, cfg.leptonPtValues.size()-1); std::vector<const xAOD::Electron*> electrons; std::vector<const xAOD::Muon*> muons; + std::vector<const xAOD::Photon*> photons; + std::vector<const xAOD::IParticle*> particles; double sum_eff = 0., sum_eff_toys[nToySamples]; std::fill(std::begin(sum_eff_toys), std::end(sum_eff_toys), 0.); for(int toy=0; toy<nToysPerTest; ++toy) @@ -385,30 +555,47 @@ bool run_test(const Config& cfg, int toy_to_debug) { electrons.clear(); muons.clear(); - unsigned nLeptons = nleptonsPdf(rdm); + photons.clear(); + particles.clear(); + const unsigned nLeptons = nleptonsPdf(rdm); for(unsigned index=0;index<nLeptons;++index) { float pt = cfg.leptonPtValues[ptIndexPdf(rdm)]; - if(flavourPdf(rdm)) - { - auto electron = electronContainer->at(electrons.size()); - electrons.push_back(electron); - electron->setP4(pt, 0.f, 0.f, 0.511f); - } - else + switch(flavourPdf(rdm)) { - auto muon = muonContainer->at(muons.size()); - muons.push_back(muon); - muon->setP4(pt, 0.f, 0.f); + case 0: + { + auto electron = electronContainer->at(electrons.size()); + particles.push_back(electron); + electrons.push_back(electron); + electron->setP4(pt, 0.f, 0.f, 0.511f); + break; + } + case 1: + { + auto muon = muonContainer->at(muons.size()); + particles.push_back(muon); + muons.push_back(muon); + muon->setP4(pt, 0.f, 0.f); + break; + } + case 2: + { + auto photon = photonContainer->at(photons.size()); + particles.push_back(photon); + photons.push_back(photon); + photon->setP4(pt, 0.f, 0.f, 0.f); + break; + } } } } - while(cfg.eventSelection && !cfg.eventSelection(electrons, muons)); + while(cfg.eventSelection && !cfg.eventSelection(electrons, muons, photons)); if(toy_to_debug>=0 && toy!=toy_to_debug) continue; double dummy, eff = 0., eff_toys; const int runNumber = 281130; - if(trigGlobTool->getEfficiency(runNumber, electrons, muons, eff, dummy) != CP::CorrectionCode::Ok) + if(trigGlobTool->getEfficiency(runNumber, particles, eff, dummy) != CP::CorrectionCode::Ok) { if(toy_to_debug < 0) { @@ -421,7 +608,7 @@ bool run_test(const Config& cfg, int toy_to_debug) for(int spl=0;spl<nToySamples;++spl) { eff_toys = 0.; - if(trigGlobTool_toys->getEfficiency(runNumber, electrons, muons, eff_toys, dummy) != CP::CorrectionCode::Ok) + if(trigGlobTool_toys->getEfficiency(runNumber, particles, eff_toys, dummy) != CP::CorrectionCode::Ok) { if(toy_to_debug < 0) { @@ -458,5 +645,6 @@ bool run_test(const Config& cfg, int toy_to_debug) else if(sigma >= 2.) Warning(MSGSOURCE, "The difference isn't small"); for(auto tool : electronTools) delete tool; for(auto tool : muonTools) delete tool; + for(auto tool : photonTools) delete tool; return true; }