16 #include <type_traits>
33 TrigGlobalEfficiencyCorrectionTool::TrigGlobalEfficiencyCorrectionTool(
34 const std::string&
name)
36 m_trigMatchTool(
"", nullptr),
37 m_checkElectronLegTag(false),
38 m_checkMuonLegTag(false),
40 m_validTrigMatchTool(false),
41 m_runNumberDecorator(
"RandomRunNumber"),
43 declareProperty(
"ElectronEfficiencyTools", m_suppliedElectronEfficiencyTools,
44 "electron MC efficiency tools (one for each kind of electron "
46 declareProperty(
"ElectronScaleFactorTools",
47 m_suppliedElectronScaleFactorTools,
48 "electron scale factor tools (one for each kind of electron "
51 "PhotonEfficiencyTools", m_suppliedPhotonEfficiencyTools,
52 "photon MC efficiency tools (one for each kind of photon trigger leg)");
54 "PhotonScaleFactorTools", m_suppliedPhotonScaleFactorTools,
55 "photon scale factor tools (one for each kind of photon trigger leg)");
56 declareProperty(
"MuonTools", m_suppliedMuonTools,
57 "muon efficiency/scale factor tool (one per year)");
58 declareProperty(
"ListOfLegsPerTool", m_legsPerTool,
59 "comma-separated list of trigger legs supported by each "
60 "electron or photon tool");
61 declareProperty(
"TriggerCombination", m_triggerCb,
62 "map of trigger combination per period and/or range of runs");
63 for (
int y : {15, 16, 17, 18, 22, 23, 24, 25, 26}) {
65 declareProperty(
"TriggerCombination" +
year, m_triggerCbPerYear[
year] =
"",
66 "trigger combination \"trigger1 || trigger2 || ...\"");
68 declareProperty(
"LeptonTagDecorations", m_leptonTagDecorations =
"",
69 "comma-separated list of decorations for the lepton "
70 "selection tags, ordered by increasing tightness. "
71 "If a name ends with =, the tag is the decorated value, "
72 "otherwise it is the decoration name");
74 "ListOfTagsPerTool", m_tagsPerTool,
75 "comma-separated list of lepton selection tags associated to each tool");
76 declareProperty(
"ElectronLegsPerTag", m_electronLegsPerTag,
77 "DEPRECATED, use ListOfLegsPerTag instead");
78 declareProperty(
"MuonLegsPerTag", m_muonLegsPerTag,
79 "DEPRECATED, use ListOfLegsPerTag instead");
80 declareProperty(
"ListOfLegsPerTag", m_legsPerTag,
81 "map of allowed trigger legs for each tag");
83 "NumberOfToys", m_numberOfToys = 0,
84 "if different from 0, use toy experiments instead of explicit formulas");
85 declareProperty(
"OverrideThresholds", m_overrideThresholds,
86 "new thresholds (in MeV) for the plateaux of the indicated "
87 "trigger legs -- use at your own risk!");
88 declareProperty(
"UseInternalSeed", m_useInternalSeed =
false,
89 "do not use event number as random number generation seed");
90 declareProperty(
"TriggerMatchingTool", m_trigMatchTool,
91 "handle to an IMatchingTool instance");
96 TrigGlobalEfficiencyCorrectionTool::~TrigGlobalEfficiencyCorrectionTool() {
103 return StatusCode::FAILURE;
110 return StatusCode::FAILURE;
115 return StatusCode::FAILURE;
128 return StatusCode::FAILURE;
131 ATH_MSG_DEBUG(
"Retrieving trigger matching tool (if provided)");
136 return StatusCode::FAILURE;
145 return StatusCode::FAILURE;
155 collectedMuonTags) ||
160 return StatusCode::FAILURE;
172 bool useDefaultElectronTools =
180 useDefaultPhotonTools))
181 return StatusCode::FAILURE;
185 collectedPhotonTags))
186 return StatusCode::FAILURE;
190 return StatusCode::FAILURE;
194 return StatusCode::FAILURE;
198 return StatusCode::SUCCESS;
204 "The property 'ElectronLegsPerTag' is deprecated, please use "
205 "'ListOfLegsPerTag' instead");
209 insert.first->second +=
"," + kv.second;
214 "The property 'MuonLegsPerTag' is deprecated, please use "
215 "'ListOfLegsPerTag' instead");
219 insert.first->second +=
"," + kv.second;
228 const std::size_t star =
m_hasher(
"*");
230 allTags.insert((
tag != star) ?
tag : 0);
234 <<
"\" is not provided in a valid format");
239 template <
class CPTool>
242 std::map<ToolKey, std::size_t>& toolIndex,
246 auto& handle = suppliedTools[
index];
247 const std::string&
name = handle.name();
248 const std::string& altname = handle->name();
251 if (suppliedTools.size() != 1 ||
m_legsPerTool.size() != 0) {
259 "The 'ListOfLegsPerTool' property has an invalid entry for the "
264 }
else if (std::is_same<CPTool,
273 listOfLegs.emplace();
276 listOfLegs.emplace();
284 collectedTags.insert(
tags.begin(),
tags.end());
289 unsigned short nUncheckedLegs = 0;
290 for (
auto&
key : listOfLegs) {
291 std::size_t
leg =
key.hash;
293 auto flavour =
data.associatedLeptonFlavour(
leg, success);
309 ATH_MSG_ERROR(
"Multiple tools associated to the selection tag '"
313 ATH_MSG_ERROR(
"Multiple tools associated to the trigger leg '"
316 ATH_MSG_ERROR(
"Multiple tools associated to the selection tag '"
320 "Multiple tools not associated to any trigger leg / selection "
327 if (!nUncheckedLegs) {
329 <<
" hasn't been associated to any trigger leg");
342 "\\s*([[:alnum:]_]+)\\s*(?:\\[\\s*([^,\\[\\]]+)\\s*\\]\\s*)?(?:,|$)");
349 if (!std::regex_search(itr,
inputList.cend(), sm, rx) ||
350 sm.prefix().length()) {
351 ATH_MSG_ERROR(
"Invalid format for the property \"ListOfLegsPerTool\"");
355 std::size_t
leg = m_hasher(sm[1].
str());
356 if (m_thresholds.find(
leg) == m_thresholds.end()) {
358 << sm[1].
str() <<
"' found in 'ListOfLegsPerTool'");
364 if (!
data.getPeriodBoundaries(sm[2].str(),
key.boundaries)) {
367 <<
"\"found in the property \"ListOfLegsPerTool\"");
372 if (!
keys.emplace(
key).second) {
375 <<
"' mentioned several times with overlapping time "
376 "periods in the property 'ListOfLegsPerTool'");
380 }
while (sm.suffix().length());
386 bool useDefaultPhotonTools) {
387 bool success =
true, mustBeEmpty =
m_triggerCb.size();
389 if (!kv.second.size())
393 "You're not allowed to use simultaneously the 'TriggerCombination' "
394 "and 'TriggerCombination"
395 << kv.first <<
"' properties.");
402 std::set<std::size_t> allUniqueElectronLegs, allUniquePhotonLegs;
404 std::pair<unsigned, unsigned> boundaries;
405 if (!
data.getPeriodBoundaries(kv.first, boundaries)) {
409 std::size_t uniqueElectronLeg = !useDefaultElectronTools,
410 uniquePhotonLeg = !useDefaultPhotonTools;
412 uniqueElectronLeg, uniquePhotonLeg)) {
416 if (uniqueElectronLeg && useDefaultElectronTools)
417 allUniqueElectronLegs.insert(uniqueElectronLeg);
418 if (uniquePhotonLeg && useDefaultPhotonTools)
419 allUniquePhotonLegs.insert(uniquePhotonLeg);
424 auto remapTools = [](
auto& toolIndex,
auto& allUniqueLegs) {
425 typename std::remove_reference<decltype(toolIndex)>
::type remappedToolIndex;
426 for (std::size_t
leg : allUniqueLegs) {
429 for (
auto& kv : toolIndex) {
432 const ToolKey&
key = kv.first;
433 remappedToolIndex.emplace(ToolKey(
leg,
key.hash,
key.boundaries),
437 toolIndex.swap(remappedToolIndex);
440 if (useDefaultElectronTools && allUniqueElectronLegs.size()) {
444 if (useDefaultPhotonTools && allUniquePhotonLegs.size()) {
458 collectedTags.insert(collectedMuonTags.begin(), collectedMuonTags.end());
459 collectedTags.insert(collectedPhotonTags.begin(), collectedPhotonTags.end());
465 std::stringstream
ss(
467 std::string decoration;
469 while (std::getline(
ss, decoration,
',')) {
470 if (!decoration.length() || decoration ==
"?") {
472 "Found an empty string in the 'LeptonTagDecorations' property");
477 bool found =
false, suffixed =
false;
479 if (decoration.back() !=
'?') {
482 found = (allTags.find(
h) != allTags.end());
485 decoration.pop_back();
487 for (std::size_t
tag :
491 if (
s.find(decoration) != 0)
493 if (std::all_of(
s.begin() + decoration.length(),
s.end(),
494 [](
char c) { return std::isdigit(c); })) {
501 if (!allDecorations.insert(
h).second) {
503 "The selection tag '"
505 <<
"' is listed twice in the property 'LeptonTagDecorations'");
511 "the selection tag '"
513 <<
"' is only referred to in the property 'LeptonTagDecorations'");
526 for (std::size_t
tag : collectedTags) {
531 [
tag](
const TagDecorator& ltd) {
532 return (!ltd.suffixed) && (ltd.hash == tag);
540 if (
s.find(
name) != 0)
542 if (std::all_of(
s.begin() +
name.length(),
s.end(),
543 [](
char c) { return std::isdigit(c); })) {
551 <<
"' hasn't been found in in 'LeptonTagDecorations'");
569 if (!kv.first.size() || kv.first ==
"*")
576 "The property 'ListOfLegsPerTag' has an invalid entry for the tag '"
580 for (std::size_t
leg : listOfLegs) {
586 ATH_MSG_ERROR(
"No electron tool has been provided for trigger leg '"
588 <<
" mentioned in the property 'ListOfLegsPerTag'");
593 ATH_MSG_ERROR(
"No muon tool has been provided for selection tag "
595 <<
" mentioned in the property 'ListOfLegsPerTag'");
600 ATH_MSG_ERROR(
"No photon tool has been provided for trigger leg '"
602 <<
" mentioned in the property 'ListOfLegsPerTag'");
615 <<
" is mentioned more than once in the property "
616 "'ListOfLegsPerTag'");
643 while (std::getline(
ss, token,
',')) {
644 if (token.length()) {
645 std::size_t
h = m_hasher(token);
647 m_dictionary.emplace(
h, std::move(token));
651 "Found duplicate entry while parsing comma-separated list '"
657 "Found null-length entry while parsing comma-separated list '"
666 template <
class ParticleType>
678 << ptype() <<
' ' <<
p <<
" (pt=" << pp->pt()
679 <<
", eta=" << pp->eta() <<
", tag='" << m_dictionary[
tag]
680 <<
"') for trigger leg " << m_dictionary[
leg]);
683 if (itrSf == GetScaleFactorToolIndex(
p).
end() ||
684 itrEff == GetEfficiencyToolIndex(
p).
end()) {
688 return TLE_UNAVAILABLE;
692 << ptype() <<
" tools needed for trigger leg "
697 << ptype() <<
" tools needed for trigger leg "
698 << m_dictionary[
leg] <<
" and selection tag "
705 checkAndRecord(GetScaleFactorTool(
p, itrSf->second)
706 .getEfficiencyScaleFactor(*
p,
sf)) &&
707 checkAndRecord(GetEfficiencyTool(
p, itrEff->second)
713 return success ? TLE_OK : TLE_ERROR;
732 <<
p <<
" (pt=" <<
p->pt() <<
", eta=" <<
p->eta() <<
", tag='"
733 << m_dictionary[
tag] <<
"') for trigger leg "
734 << m_dictionary[
leg]);
735 if (m_unsupportedLegs.size() &&
739 return TLE_UNAVAILABLE;
741 auto itr = m_muonToolIndex.find(ToolKey(0,
tag, 0));
742 if (itr == m_muonToolIndex.end()) {
746 ATH_MSG_ERROR(
"Unable to find muon tool needed for selection tag "
747 << m_dictionary[
tag]);
751 auto&
tool = *m_suppliedMuonTools[itr->second];
752 auto& hltTrig = m_dictionary[
leg ^ 0xB0DDD56fF8E3250D];
753 if (!hltTrig.size()) {
754 hltTrig =
"HLT_" + m_dictionary[
leg];
756 std::size_t
i = hltTrig.find(
"_OR_m");
757 if (
i == std::string::npos)
759 hltTrig.insert(
i + 4,
"HLT_", 4);
764 checkAndRecord(
tool.getTriggerEfficiency(
769 return success ? TLE_OK : TLE_ERROR;
782 ATH_MSG_ERROR(
"Can't retrieve 'RandomRunNumber' from EventInfo");
803 template <
class Particle>
805 LeptonList& leptons,
const std::vector<const Particle*>&
particles) {
809 if (ltd.decorator.isAvailable(*lep)) {
810 char v = ltd.decorator(*lep);
822 leptons.emplace_back(lep,
tag);
828 const std::vector<const xAOD::IParticle*>& leptons,
829 double& efficiencyScaleFactor) {
837 const std::vector<const xAOD::IParticle*>& leptons,
double& efficiencyData,
838 double& efficiencyMc) {
847 double& efficiencyScaleFactor) {
849 efficiencyScaleFactor = 1.;
860 efficiencyScaleFactor = 1.;
862 "Efficiencies do not seem valid, forcing the scale factor to 1.");
866 efficiencyScaleFactor = 1.;
872 double& efficiencyData,
double& efficiencyMc) {
878 ATH_MSG_DEBUG(
"Computing global trigger efficiency for this event with "
880 <<
" lepton(s) as input; run number = " <<
runNumber);
882 #ifdef XAOD_STANDALONE
919 "Unable to retrieve run number, aborting checkTriggerMatching()");
924 "A valid IMatchingTool instance should be provided via the property "
925 "'TriggerMatchingTool'");
936 std::vector<std::string>&
triggers) {
940 "Unable to retrieve run number, aborting getRelevantTriggers()");
949 const std::string& trigger, std::size_t& numberOfLegs) {
955 constexpr std::size_t magic = 0xa3bad03e613527c9;
958 if (!
value.length()) {
960 if (!
data.importTriggers())
962 auto itr =
data.getTriggerDefs().find(
name);
963 if (itr ==
data.getTriggerDefs().end()) {
965 ATH_MSG_ERROR(
"The trigger " << trigger <<
" is not recognized");
968 auto type = itr->second.type;
978 ATH_MSG_ERROR(
"Unrecognized trigger type, implementation must be fixed!");
982 numberOfLegs =
value.length();
987 std::size_t
leg)
const {
998 <<
") is " << (decision ?
"" :
"not ")
999 <<
"considered suitable for firing trigger leg "
1006 if (legs.size() < 2)
1008 std::size_t combinedHash = 0;
1009 for (
auto&
leg : legs)
1010 combinedHash ^=
leg;
1011 return combinedHash;
1015 std::size_t leg1, std::size_t leg2) {
1025 inline constexpr std::array<std::size_t, 2>
1029 return {leg1, leg2};
1031 return {leg2, leg1};
1034 template <
class... ListOfLegs>
1036 const Lepton& lepton, ListOfLegs... legs) {
1039 return 0xFEDCBA9876543210;
1041 auto rankingItr = cachedRankings.first;
1042 float pt = lepton.
pt();
1043 while (rankingItr != cachedRankings.second &&
1044 (pt < rankingItr->
second.minPt ||
pt >= rankingItr->second.maxPt))
1046 if (rankingItr == cachedRankings.second) {
1052 return rankingItr->second.ranking;
1055 template <
class Container>
1059 const std::size_t nLegs = legs.size();
1061 r.ranking = std::numeric_limits<decltype(
r.ranking)>
::max();
1064 if (nLegs >= 2 *
sizeof(
r.ranking)) {
1066 "Implementation currently doesn't support ranking of more than "
1067 << 2 *
sizeof(
r.ranking) <<
" trigger legs");
1070 std::vector<uint8_t>
counts(nLegs);
1075 auto legI = legs.begin();
1076 for (
unsigned i = 0;
i < nLegs; ++
i) {
1078 for (
unsigned j =
i + 1; j < nLegs; ++j) {
1081 for (
auto& meta : m_hierarchyMeta) {
1082 if (pt < meta.minPt || pt >= meta.maxPt)
1084 auto data = m_hierarchyData.begin() + meta.offset;
1102 << m_dictionary[*legI] <<
" and " << m_dictionary[*legJ]);
1108 decltype(
r.ranking) ranking = 0;
1109 for (
unsigned i = 0;
i < nLegs; ++
i) {
1110 unsigned char index =
1112 if (
index >= nLegs) {
1114 << nLegs <<
" trigger legs");
1117 ranking = (ranking << 4 |
index);
1119 r.ranking = ranking;
1124 const Lepton& lepton, std::size_t leg1, std::size_t leg2,
bool& success) {
1133 std::pair<std::size_t, std::size_t>
1141 std::pair<std::size_t, std::size_t> looseLegs{0, 0};
1142 looseLegs.first = *legs.nth(ranking & 0xF);
1143 if (legs.size() >= 2)
1144 looseLegs.second = *legs.nth((ranking >> 4) & 0xF);
1151 for (
auto leg : legs)
1153 validLegs.insert(
leg);
1154 if (validLegs.size() == 0)
1156 if (validLegs.size() == 1)
1157 return *validLegs.begin();
1163 return *legs.nth(ranking & 0xF);
1168 const int nLegs = legs.size();
1172 ranking = 0xFEDCBA9876543210;
1174 std::vector<std::size_t> sorted_legs(nLegs);
1175 for (
int i = 0;
i < nLegs; ++
i) {
1176 sorted_legs[
i] = *legs.nth(ranking & 0xF);
1183 const std::map<std::string, std::string>& triggerCombination,
1184 const std::string&
version, std::map<std::string, std::string>& legsPerKey,
1188 data.suggestEgammaMapKeys(triggerCombination,
version, legsPerKey,
type);
1195 return !systematic.
empty() &&
sys.find(systematic) !=
sys.end();
1211 ANA_CHECK(
t->applySystematicVariation(systematic));
1213 ANA_CHECK(
t->applySystematicVariation(systematic));
1215 ANA_CHECK(
t->applySystematicVariation(systematic));
1217 ANA_CHECK(
t->applySystematicVariation(systematic));
1219 ANA_CHECK(
t->applySystematicVariation(systematic));
1221 return StatusCode::SUCCESS;