35auto nth (
const CONT& c,
size_t n)
37 return *(c.begin() + n);
43TrigGlobalEfficiencyCorrectionTool::TrigGlobalEfficiencyCorrectionTool(
44 const std::string& name)
46 m_trigMatchTool(
"", nullptr),
47 m_checkElectronLegTag(false),
48 m_checkMuonLegTag(false),
50 m_validTrigMatchTool(false),
51 m_runNumberDecorator(
"RandomRunNumber"),
53 declareProperty(
"ElectronEfficiencyTools", m_suppliedElectronEfficiencyTools,
54 "electron MC efficiency tools (one for each kind of electron "
56 declareProperty(
"ElectronScaleFactorTools",
57 m_suppliedElectronScaleFactorTools,
58 "electron scale factor tools (one for each kind of electron "
61 "PhotonEfficiencyTools", m_suppliedPhotonEfficiencyTools,
62 "photon MC efficiency tools (one for each kind of photon trigger leg)");
64 "PhotonScaleFactorTools", m_suppliedPhotonScaleFactorTools,
65 "photon scale factor tools (one for each kind of photon trigger leg)");
66 declareProperty(
"MuonTools", m_suppliedMuonTools,
67 "muon efficiency/scale factor tool (one per year)");
68 declareProperty(
"ListOfLegsPerTool", m_legsPerTool,
69 "comma-separated list of trigger legs supported by each "
70 "electron or photon tool");
71 declareProperty(
"TriggerCombination", m_triggerCb,
72 "map of trigger combination per period and/or range of runs");
73 for (
int y : {15, 16, 17, 18, 22, 23, 24, 25, 26}) {
74 std::string
year = std::to_string(2000 +
y);
75 declareProperty(
"TriggerCombination" + year, m_triggerCbPerYear[year] =
"",
76 "trigger combination \"trigger1 || trigger2 || ...\"");
78 declareProperty(
"LeptonTagDecorations", m_leptonTagDecorations =
"",
79 "comma-separated list of decorations for the lepton "
80 "selection tags, ordered by increasing tightness. "
81 "If a name ends with =, the tag is the decorated value, "
82 "otherwise it is the decoration name");
84 "ListOfTagsPerTool", m_tagsPerTool,
85 "comma-separated list of lepton selection tags associated to each tool");
86 declareProperty(
"ElectronLegsPerTag", m_electronLegsPerTag,
87 "DEPRECATED, use ListOfLegsPerTag instead");
88 declareProperty(
"MuonLegsPerTag", m_muonLegsPerTag,
89 "DEPRECATED, use ListOfLegsPerTag instead");
90 declareProperty(
"ListOfLegsPerTag", m_legsPerTag,
91 "map of allowed trigger legs for each tag");
93 "NumberOfToys", m_numberOfToys = 0,
94 "if different from 0, use toy experiments instead of explicit formulas");
95 declareProperty(
"OverrideThresholds", m_overrideThresholds,
96 "new thresholds (in MeV) for the plateaux of the indicated "
97 "trigger legs -- use at your own risk!");
98 declareProperty(
"UseInternalSeed", m_useInternalSeed =
false,
99 "do not use event number as random number generation seed");
100 declareProperty(
"TriggerMatchingTool", m_trigMatchTool,
101 "handle to an IMatchingTool instance");
113 return StatusCode::FAILURE;
120 return StatusCode::FAILURE;
125 return StatusCode::FAILURE;
138 return StatusCode::FAILURE;
141 ATH_MSG_DEBUG(
"Retrieving trigger matching tool (if provided)");
146 return StatusCode::FAILURE;
155 return StatusCode::FAILURE;
158 std::flat_set<std::size_t> collectedElectronTags, collectedMuonTags,
165 collectedMuonTags) ||
170 return StatusCode::FAILURE;
182 bool useDefaultElectronTools =
190 useDefaultPhotonTools))
191 return StatusCode::FAILURE;
195 collectedPhotonTags))
196 return StatusCode::FAILURE;
200 return StatusCode::FAILURE;
204 return StatusCode::FAILURE;
208 return StatusCode::SUCCESS;
214 "The property 'ElectronLegsPerTag' is deprecated, please use "
215 "'ListOfLegsPerTag' instead");
219 insert.first->second +=
"," + kv.second;
224 "The property 'MuonLegsPerTag' is deprecated, please use "
225 "'ListOfLegsPerTag' instead");
229 insert.first->second +=
"," + kv.second;
236 const std::string& tagstring, std::flat_set<std::size_t>& allTags) {
238 const std::size_t star =
m_hasher(
"*");
240 allTags.insert((tag != star) ? tag : 0);
244 <<
"\" is not provided in a valid format");
249template <
class CPTool>
251 ImportData& data, ToolHandleArray<CPTool>& suppliedTools,
252 std::map<ToolKey, std::size_t>& toolIndex,
253 std::flat_set<std::size_t>& collectedTags) {
256 auto& handle = suppliedTools[
index];
257 const std::string& name = handle.name();
258 const std::string& altname = handle->name();
259 std::flat_set<ToolKey> listOfLegs;
261 if (suppliedTools.size() != 1 ||
m_legsPerTool.size() != 0) {
269 "The 'ListOfLegsPerTool' property has an invalid entry for the "
274 }
else if (std::is_same<CPTool,
278 ATH_MSG_ERROR(
"Property 'ListOfLegsPerTool' empty for tool '" << name
283 listOfLegs.emplace();
286 listOfLegs.emplace();
288 std::flat_set<std::size_t>
tags;
294 collectedTags.insert(
tags.begin(),
tags.end());
299 unsigned short nUncheckedLegs = 0;
300 for (
auto& key : listOfLegs) {
301 std::size_t leg = key.hash;
303 auto flavour = data.associatedLeptonFlavour(leg, success);
315 for (std::size_t tag :
tags) {
316 if (!toolIndex.emplace(
ToolKey(leg, tag, key.boundaries),
index)
319 ATH_MSG_ERROR(
"Multiple tools associated to the selection tag '"
323 ATH_MSG_ERROR(
"Multiple tools associated to the trigger leg '"
326 ATH_MSG_ERROR(
"Multiple tools associated to the selection tag '"
330 "Multiple tools not associated to any trigger leg / selection "
337 if (!nUncheckedLegs) {
339 <<
" hasn't been associated to any trigger leg");
347 ImportData& data,
const std::string& inputList,
bool& success)
348 -> std::flat_set<ToolKey> {
349 if (!inputList.length())
352 "\\s*([[:alnum:]_]+)\\s*(?:\\[\\s*([^,\\[\\]]+)\\s*\\]\\s*)?(?:,|$)");
353 std::flat_set<ToolKey> keys;
355 auto itr = inputList.cbegin();
359 if (!std::regex_search(itr, inputList.cend(), sm, rx) ||
360 sm.prefix().length()) {
361 ATH_MSG_ERROR(
"Invalid format for the property \"ListOfLegsPerTool\"");
368 << sm[1].
str() <<
"' found in 'ListOfLegsPerTool'");
374 if (!data.getPeriodBoundaries(sm[2].str(), key.boundaries)) {
377 <<
"\"found in the property \"ListOfLegsPerTool\"");
382 if (!keys.emplace(key).second) {
385 <<
"' mentioned several times with overlapping time "
386 "periods in the property 'ListOfLegsPerTool'");
390 }
while (sm.suffix().length());
395 ImportData& data,
bool useDefaultElectronTools,
396 bool useDefaultPhotonTools) {
397 bool success =
true, mustBeEmpty =
m_triggerCb.size();
399 if (!kv.second.size())
403 "You're not allowed to use simultaneously the 'TriggerCombination' "
404 "and 'TriggerCombination"
405 << kv.first <<
"' properties.");
412 std::set<std::size_t> allUniqueElectronLegs, allUniquePhotonLegs;
414 std::pair<unsigned, unsigned> boundaries;
415 if (!data.getPeriodBoundaries(kv.first, boundaries)) {
419 std::size_t uniqueElectronLeg = !useDefaultElectronTools,
420 uniquePhotonLeg = !useDefaultPhotonTools;
422 uniqueElectronLeg, uniquePhotonLeg)) {
426 if (uniqueElectronLeg && useDefaultElectronTools)
427 allUniqueElectronLegs.insert(uniqueElectronLeg);
428 if (uniquePhotonLeg && useDefaultPhotonTools)
429 allUniquePhotonLegs.insert(uniquePhotonLeg);
434 auto remapTools = [](
auto& toolIndex,
auto& allUniqueLegs) {
435 typename std::remove_reference<
decltype(toolIndex)>
::type remappedToolIndex;
436 for (std::size_t leg : allUniqueLegs) {
439 for (
auto& kv : toolIndex) {
443 remappedToolIndex.emplace(
ToolKey(leg, key.hash, key.boundaries),
447 toolIndex.swap(remappedToolIndex);
450 if (useDefaultElectronTools && allUniqueElectronLegs.size()) {
454 if (useDefaultPhotonTools && allUniquePhotonLegs.size()) {
462 const std::flat_set<std::size_t>& collectedElectronTags,
463 const std::flat_set<std::size_t>& collectedMuonTags,
464 const std::flat_set<std::size_t>& collectedPhotonTags) {
467 std::flat_set<std::size_t> collectedTags(collectedElectronTags);
468 collectedTags.insert(collectedMuonTags.begin(), collectedMuonTags.end());
469 collectedTags.insert(collectedPhotonTags.begin(), collectedPhotonTags.end());
470 std::flat_set<std::size_t> allTags = collectedTags;
475 std::stringstream
ss(
477 std::string decoration;
478 std::flat_set<std::size_t> allDecorations;
479 while (std::getline(
ss, decoration,
',')) {
480 if (!decoration.length() || decoration ==
"?") {
482 "Found an empty string in the 'LeptonTagDecorations' property");
487 bool found =
false, suffixed =
false;
489 if (decoration.back() !=
'?') {
492 found = (allTags.find(
h) != allTags.end());
495 decoration.pop_back();
497 for (std::size_t tag :
501 if (s.find(decoration) != 0)
503 if (std::all_of(s.begin() + decoration.length(), s.end(),
504 [](
char c) { return std::isdigit(c); })) {
511 if (!allDecorations.insert(
h).second) {
513 "The selection tag '"
515 <<
"' is listed twice in the property 'LeptonTagDecorations'");
521 "the selection tag '"
523 <<
"' is only referred to in the property 'LeptonTagDecorations'");
536 for (std::size_t tag : collectedTags) {
542 return (!ltd.suffixed) && (ltd.hash == tag);
550 if (s.find(name) != 0)
552 if (std::all_of(s.begin() + name.length(), s.end(),
553 [](
char c) { return std::isdigit(c); })) {
561 <<
"' hasn't been found in in 'LeptonTagDecorations'");
579 if (!kv.first.size() || kv.first ==
"*")
586 "The property 'ListOfLegsPerTag' has an invalid entry for the tag '"
590 for (std::size_t leg : listOfLegs) {
596 ATH_MSG_ERROR(
"No electron tool has been provided for trigger leg '"
597 <<
m_dictionary[leg] <<
"' and selection tag " << kv.first
598 <<
" mentioned in the property 'ListOfLegsPerTag'");
603 ATH_MSG_ERROR(
"No muon tool has been provided for selection tag "
605 <<
" mentioned in the property 'ListOfLegsPerTag'");
610 ATH_MSG_ERROR(
"No photon tool has been provided for trigger leg '"
611 <<
m_dictionary[leg] <<
"' and selection tag " << kv.first
612 <<
" mentioned in the property 'ListOfLegsPerTag'");
624 <<
m_dictionary[leg] <<
"' and selection tag " << kv.first
625 <<
" is mentioned more than once in the property "
626 "'ListOfLegsPerTag'");
649 const std::string& s,
bool& success) -> std::flat_set<std::size_t> {
651 std::flat_set<std::size_t> hashes;
653 while (std::getline(
ss, token,
',')) {
654 if (token.length()) {
656 if (hashes.insert(
h).second) {
661 "Found duplicate entry while parsing comma-separated list '"
667 "Found null-length entry while parsing comma-separated list '"
676template <
class ParticleType>
678 const ParticleType* p,
unsigned runNumber, std::size_t leg, std::size_t tag,
682 return std::is_same<ParticleType, xAOD::Electron>::value ?
"electron"
683 : std::is_same<ParticleType, xAOD::Photon>::value ?
"photon"
688 << ptype() <<
' ' << p <<
" (pt=" << pp->pt()
689 <<
", eta=" << pp->eta() <<
", tag='" <<
m_dictionary[tag]
696 efficiencies.data() = 0.5;
697 efficiencies.mc() = 0.5;
702 << ptype() <<
" tools needed for trigger leg "
707 << ptype() <<
" tools needed for trigger leg "
716 .getEfficiencyScaleFactor(*p, sf)) &&
718 .getEfficiencyScaleFactor(*p, efficiencies.mc()));
719 efficiencies.data() = sf * efficiencies.mc();
721 <<
" eff(data) = " << efficiencies.data()
722 <<
" and eff(MC) = " << efficiencies.mc());
733 const xAOD::Photon* p,
unsigned runNumber, std::size_t leg, std::size_t tag,
739 const xAOD::Muon* p,
unsigned runNumber, std::size_t leg, std::size_t tag,
742 << p <<
" (pt=" << p->pt() <<
", eta=" << p->eta() <<
", tag='"
747 efficiencies.data() = 0.5;
748 efficiencies.mc() = 0.5;
756 ATH_MSG_ERROR(
"Unable to find muon tool needed for selection tag "
763 if (!hltTrig.size()) {
766 std::size_t i = hltTrig.find(
"_OR_m");
767 if (i == std::string::npos)
769 hltTrig.insert(i + 4,
"HLT_", 4);
772 bool success =
checkAndRecord(tool.getTriggerEfficiency(*p, efficiencies.mc(),
775 *p, efficiencies.data(), hltTrig, kTRUE));
776 ATH_MSG_DEBUG(
"found for that muon eff(data) = " << efficiencies.data()
778 << efficiencies.mc());
783 unsigned& runNumber) {
792 ATH_MSG_ERROR(
"Can't retrieve 'RandomRunNumber' from EventInfo");
797 runNumber = eventInfo->runNumber();
802 unsigned long& eventNumber) {
809 eventNumber = eventInfo->eventNumber();
813template <
class Particle>
815 LeptonList& leptons,
const std::vector<const Particle*>& particles) {
816 for (
auto lep : particles) {
819 if (ltd.decorator.isAvailable(*lep)) {
820 char v = ltd.decorator(*lep);
824 std::string s =
m_dictionary.at(ltd.hash) + std::to_string(v);
832 leptons.emplace_back(lep, tag);
838 const std::vector<const xAOD::IParticle*>& leptons,
839 double& efficiencyScaleFactor) {
847 const std::vector<const xAOD::IParticle*>& leptons,
double& efficiencyData,
848 double& efficiencyMc) {
852 return getEfficiency(runNumber, leptons, efficiencyData, efficiencyMc);
856 unsigned runNumber,
const std::vector<const xAOD::IParticle*>& particles,
857 double& efficiencyScaleFactor) {
860 efficiencyScaleFactor = 1.;
863 auto cc =
getEfficiency(runNumber, particles, efficiencies.data(),
866 if (efficiencies.data() > 0. && efficiencies.mc() > 0.) {
867 efficiencyScaleFactor = efficiencies.data() / efficiencies.mc();
870 efficiencyScaleFactor = 1.;
872 "Efficiencies do not seem valid, forcing the scale factor to 1.");
876 efficiencyScaleFactor = 1.;
881 unsigned runNumber,
const std::vector<const xAOD::IParticle*>& particles,
882 double& efficiencyData,
double& efficiencyMc) {
888 ATH_MSG_DEBUG(
"Computing global trigger efficiency for this event with "
890 <<
" lepton(s) as input; run number = " << runNumber);
892#ifdef XAOD_STANDALONE
907 if (
m_calculator->compute(*
this, leptons, runNumber, efficiencies)) {
908 efficiencyData = efficiencies.data();
909 efficiencyMc = efficiencies.mc();
910 if (std::isnan(efficiencies.data()) || efficiencies.data() <= 0. ||
911 std::isnan(efficiencies.mc()) || efficiencies.mc() <= 0.) {
926 const std::vector<const xAOD::IParticle*>& particles) {
930 "Unable to retrieve run number, aborting checkTriggerMatching()");
935 "A valid IMatchingTool instance should be provided via the property "
936 "'TriggerMatchingTool'");
941 return m_calculator->checkTriggerMatching(*
this, matched,
nullptr, leptons, runNumber)
947 std::unordered_map<std::string, bool>& matched_per_trigger,
948 const std::vector<const xAOD::IParticle*>& particles) {
952 "Unable to retrieve run number, aborting checkTriggerMatching()");
957 "A valid IMatchingTool instance should be provided via the property "
958 "'TriggerMatchingTool'");
964 return m_calculator->checkTriggerMatching(*
this, flag, &matched_per_trigger, leptons, runNumber)
970 std::vector<std::string>& triggers) {
974 "Unable to retrieve run number, aborting getRelevantTriggers()");
977 return m_calculator->getRelevantTriggersForUser(*
this, triggers, runNumber)
983 const std::string& trigger, std::size_t& numberOfLegs) {
989 constexpr std::size_t magic = 0xa3bad03e613527c9;
990 const std::size_t name =
m_hasher(trigger), key = name ^ magic;
992 if (!value.length()) {
994 if (!data.importTriggers())
996 auto itr = data.getTriggerDefs().find(name);
997 if (itr == data.getTriggerDefs().end()) {
999 ATH_MSG_ERROR(
"The trigger " << trigger <<
" is not recognized");
1004 if (
type & TriggerType::TT_SINGLELEPTON_FLAG)
1006 else if (
type & TriggerType::TT_DILEPTON_FLAG)
1008 else if (
type & TriggerType::TT_TRILEPTON_FLAG)
1012 ATH_MSG_ERROR(
"Unrecognized trigger type, implementation must be fixed!");
1016 numberOfLegs = value.length();
1021 std::size_t leg)
const {
1032 <<
") is " << (decision ?
"" :
"not ")
1033 <<
"considered suitable for firing trigger leg "
1039 const std::flat_set<std::size_t>& legs) {
1040 if (legs.size() < 2)
1042 std::size_t combinedHash = 0;
1043 for (
auto& leg : legs)
1044 combinedHash ^= leg;
1045 return combinedHash;
1049 std::size_t leg1, std::size_t leg2) {
1055 const std::flat_set<std::size_t>& legs) ->
const std::flat_set<std::size_t>& {
1059inline constexpr std::array<std::size_t, 2>
1063 return {leg1, leg2};
1065 return {leg2, leg1};
1068template <
class... ListOfLegs>
1070 const Lepton& lepton, ListOfLegs... legs) {
1073 return 0xFEDCBA9876543210;
1075 auto rankingItr = cachedRankings.first;
1076 float pt = lepton.
pt();
1077 while (rankingItr != cachedRankings.second &&
1078 (pt < rankingItr->second.minPt || pt >= rankingItr->second.maxPt))
1080 if (rankingItr == cachedRankings.second) {
1086 return rankingItr->second.ranking;
1089template <
class Container>
1093 const std::size_t nLegs = legs.size();
1095 r.ranking = std::numeric_limits<
decltype(
r.ranking)>
::max();
1097 r.maxPt = std::numeric_limits<float>::max();
1098 if (nLegs >= 2 *
sizeof(
r.ranking)) {
1100 "Implementation currently doesn't support ranking of more than "
1101 << 2 *
sizeof(
r.ranking) <<
" trigger legs");
1104 std::vector<uint8_t> counts(nLegs);
1109 auto legI = legs.begin();
1110 for (
unsigned i = 0; i < nLegs; ++i) {
1112 for (
unsigned j = i + 1; j < nLegs; ++j) {
1116 if (pt < meta.minPt || pt >=
meta.maxPt)
1119 auto end = data +
meta.nLegs;
1120 auto a = std::find(data, end, *legI);
1123 auto b = std::find(data, end, *legJ);
1126 r.minPt = std::max(
r.minPt,
meta.minPt);
1127 r.maxPt = std::min(
r.maxPt,
meta.maxPt);
1128 ++(counts[(
a > b) ? i : j]);
1142 decltype(
r.ranking) ranking = 0;
1143 for (
unsigned i = 0; i < nLegs; ++i) {
1144 unsigned char index =
1145 std::find(counts.begin(), counts.end(), i) - counts.begin();
1146 if (
index >= nLegs) {
1148 << nLegs <<
" trigger legs");
1151 ranking = (ranking << 4 |
index);
1153 r.ranking = ranking;
1158 const Lepton& lepton, std::size_t leg1, std::size_t leg2,
bool& success) {
1167std::pair<std::size_t, std::size_t>
1169 const Lepton& lepton,
const std::flat_set<std::size_t>& legs,
bool& success) {
1175 std::pair<std::size_t, std::size_t> looseLegs{0, 0};
1176 looseLegs.first = nth (legs, ranking & 0xF);
1177 if (legs.size() >= 2)
1178 looseLegs.second = nth (legs, (ranking >> 4) & 0xF);
1183 const Lepton& lepton,
const std::flat_set<std::size_t>& legs,
bool& success) {
1184 std::flat_set<std::size_t> validLegs;
1185 for (
auto leg : legs)
1187 validLegs.insert(leg);
1188 if (validLegs.size() == 0)
1190 if (validLegs.size() == 1)
1191 return *validLegs.begin();
1197 return nth (legs, ranking & 0xF);
1201 const Lepton& lepton,
const std::flat_set<std::size_t>& legs,
bool& success) {
1202 const int nLegs = legs.size();
1206 ranking = 0xFEDCBA9876543210;
1208 std::vector<std::size_t> sorted_legs(nLegs);
1209 for (
int i = 0; i < nLegs; ++i) {
1210 sorted_legs[i] = nth (legs, ranking & 0xF);
1217 const std::map<std::string, std::string>& triggerCombination,
1218 const std::string& version, std::map<std::string, std::string>& legsPerKey,
1222 data.suggestEgammaMapKeys(triggerCombination, version, legsPerKey,
type);
1229 return !systematic.
empty() && sys.find(systematic) != sys.end();
1245 ANA_CHECK(t->applySystematicVariation(systematic));
1247 ANA_CHECK(t->applySystematicVariation(systematic));
1249 ANA_CHECK(t->applySystematicVariation(systematic));
1251 ANA_CHECK(t->applySystematicVariation(systematic));
1253 ANA_CHECK(t->applySystematicVariation(systematic));
1255 return StatusCode::SUCCESS;
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_INFO(x,...)
TrigGlobEffCorr::ImportData ImportData
TrigGlobEffCorr::CheckConfig CheckConfig
ServiceHandle< StoreGateSvc > & evtStore()
Header file for AthHistogramAlgorithm.
Return value from object correction CP tools.
@ Error
Some error happened during the object correction.
@ OutOfValidityRange
Input object is out of validity range.
@ Ok
The correction was done successfully.
Class to wrap a set of SystematicVariations.
bool empty() const
returns: whether this is an empty systematic, i.e.
storage of the time histories of all the cells
bool advancedConfigChecks()
xAOD::Type::ObjectType associatedLeptonFlavour(std::size_t leg, bool &success)
const xAOD::IParticle * particle() const
xAOD::Type::ObjectType type() const
@ IS_SIMULATION
true: simulation, false: data
Class providing the definition of the 4-vector interface.
std::vector< std::string > tags
std::string removeWhitespaces(const std::string &s)
void reverse(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of reverse for DataVector/List.
ObjectType
Type of objects that have a representation in the xAOD EDM.
@ Photon
The object is a photon.
@ Muon
The object is a muon.
@ Electron
The object is an electron.
EventInfo_v1 EventInfo
Definition of the latest event info version.
Muon_v1 Muon
Reference the current persistent version:
Photon_v1 Photon
Definition of the current "egamma version".
Electron_v1 Electron
Definition of the current "egamma version".
ElementLink_p1< typename GenerateELinkIndexType_p1< typename LINK::index_type >::type > type