ATLAS Offline Software
Loading...
Searching...
No Matches
TrigTauInfo.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6#include <regex>
7#include <ranges> //std::views::split
8#include <cstdint>
9
10TrigTauInfo::TrigTauInfo(const std::string& trigger)
11 : m_trigger{trigger}
12{
14}
15
16TrigTauInfo::TrigTauInfo(const std::string& trigger, const std::map<std::string, float>& L1Phase1_thresholds)
17 : m_trigger{trigger}
18{
19 parseTriggerString(L1Phase1_thresholds);
20}
21
22TrigTauInfo::TrigTauInfo(const std::string& trigger, const std::map<std::string, float>& L1Phase1_thresholds, const std::map<std::string, uint64_t>& L1Phase1_threshold_patterns)
23 : m_trigger{trigger}
24{
25 parseTriggerString(L1Phase1_thresholds, L1Phase1_threshold_patterns);
26}
27
28TrigTauInfo::TrigTauInfo(const std::string& trigger, const std::map<int, int>& L1Phase1ThrMap_eTAU, const std::map<int, int>& L1Phase1ThrMap_jTAU)
29 : m_trigger{trigger}
30{
31 parseTriggerString(L1Phase1ThrMap_eTAU, L1Phase1ThrMap_jTAU);
32}
33
34void TrigTauInfo::parseTriggerString(bool remove_L1_phase1_thresholds)
35{
36 std::string clean_trigger = m_trigger;
37
38 // Change the "L1_" prefix to "L1" internally, in case the trigger being parsed is a pure L1 trigger with the usual L1 standalone naming scheme
39 if(clean_trigger.size() > 3 && clean_trigger.rfind("L1_", 0) == 0) {
40 clean_trigger = "L1" + clean_trigger.substr(3);
41 }
42
43 std::vector<std::string> sections;
44 for (auto&& subrange : std::views::split(m_trigger, '_')) sections.emplace_back(subrange.begin(), subrange.end());
45
46 std::regex tau_rgx("^(\\d*)tau(\\d+)$");
47 std::regex elec_rgx("^(\\d*)e(\\d+)$");
48 std::regex muon_rgx("^(\\d*)mu(\\d+)$");
49 std::regex gamma_rgx("^(\\d*)g(\\d+)$");
50 std::regex jet_rgx("^(\\d*)j(\\d+)$");
51 std::regex met_rgx("^xe(\\d+)$");
52 std::regex noalg_rgx("^noalg$");
53 std::regex l1_rgx("^L1.*$");
54 std::regex l1_tau_rgx("(\\d*)(e|j|c|)TAU(\\d+)(L|M|T|HL|HM|HT|H|IM|I|)");
55 std::regex l1_toposeparate_rgx("^(\\d{0,2})(DETA|DPHI)(\\d{0,2})$");
56 std::regex topo_rgx("^.*(invm|dR|deta|dphi)AB.*$");
57 std::regex ditauomni_rgx("^ditauOmni(\\d)+Trk(\\d)+$");
58 std::vector<std::regex*> all_regexes = {&tau_rgx, &elec_rgx, &muon_rgx, &gamma_rgx, &jet_rgx, &met_rgx, &l1_rgx, &ditauomni_rgx};
59
60 std::regex tau_type_rgx("^(ptonly|tracktwoMVA|tracktwoMVABDT|tracktwoLLP|trackLRT)$");
61 std::regex tau_ID_rgx("^(idperf|noperf|perfcore|perfiso|perf|veryloose.*|loose.*|medium.*|tight.*)$");
62
63 std::smatch match;
64 std::regex_token_iterator<std::string::iterator> rend;
65
66 // Check each leg
67 std::vector<std::string> leg;
68 for(size_t i = 0; i < sections.size(); i++) {
69 leg.push_back(sections[i]); // Attach to the current leg
70 //Match the beginning of a new leg, or the end of the chain
71 if(i == sections.size() - 1 || (std::any_of(all_regexes.begin(), all_regexes.end(), [&sections, i](const std::regex* rgx) { return std::regex_match(sections[i+1], *rgx); }))) {
72 // Process the previous leg, which starts with the item, multiplicity, and threshold
73 if(std::regex_match(leg[0], match, tau_rgx)) {
74 size_t multiplicity = match[1].str() == "" ? 1 : std::stoi(match[1].str());
75 unsigned int threshold = std::stoi(match[2].str());
76
77 // HLT Tau sequence
78 auto itr = find_if(leg.begin(), leg.end(), [tau_type_rgx](const std::string& s) { return std::regex_match(s, tau_type_rgx); });
79 std::string type = itr != leg.end() ? *itr : "tracktwoMVA"; // Default to the tracktwoMVA sequence
80
81 // HLT Tau ID
82 itr = find_if(leg.begin(), leg.end(), [tau_ID_rgx](const std::string& s) { return std::regex_match(s, tau_ID_rgx); });
83 std::string tau_id = itr != leg.end() ? *itr : "";
84 if(tau_id.starts_with("veryloose")) tau_id = tau_id.substr(9);
85 else if(tau_id.starts_with("loose")) tau_id = tau_id.substr(5);
86 else if(tau_id.starts_with("medium")) tau_id = tau_id.substr(6);
87 else if(tau_id.starts_with("tight")) tau_id = tau_id.substr(5);
88
89 // The WP is a variation (e.g. "mediumvar2GNTauDev1")
90 if(tau_id.starts_with("var")) {
91 std::size_t i = 3; // Take out the "var" prefix
92
93 // Now find the variation number
94 while(i < tau_id.size() && std::isdigit(static_cast<unsigned char>(tau_id[i]))) i++;
95
96 tau_id = tau_id.substr(i);
97 }
98
99 // Get the perf-selection suffix
100 if(tau_id.starts_with("pc")) tau_id = tau_id.substr(2);
101 else if(tau_id.starts_with("pi")) tau_id = tau_id.substr(2);
102 else if(tau_id.starts_with("np")) tau_id = tau_id.substr(2);
103
104 // Override for the old trigger names
105 if(tau_id == "RNN") {
106 if(type == "tracktwoMVA") tau_id = "DeepSet";
107 if(type == "tracktwoLLP" || type == "trackLRT") tau_id = "RNNLLP";
108 }
109
110 // Replacements (this is temporary, the entire TrigTauInfo class will be removed soon, and all this will be handled centrally in Python using the already available infrastructure)
111 if(tau_id == "DS") tau_id = "DeepSet";
112 else if(tau_id == "GNT") tau_id = "GNTau";
113
114 for(size_t j = 0; j < multiplicity; j++) {
115 m_HLTThr.push_back(threshold);
116 m_HLTTauTypes.push_back(type);
117 m_HLTTauIDs.push_back(tau_id);
118 }
119 } else if(std::regex_match(leg[0], match, elec_rgx)) {
120 size_t multiplicity = match[1].str() == "" ? 1 : std::stoi(match[1].str());
121 unsigned int threshold = std::stoi(match[2].str());
122 for(size_t j = 0; j < multiplicity; j++) m_HLTElecThr.push_back(threshold);
123 } else if(std::regex_match(leg[0], match, muon_rgx)) {
124 size_t multiplicity = match[1].str() == "" ? 1 : std::stoi(match[1].str());
125 unsigned int threshold = std::stoi(match[2].str());
126 for(size_t j = 0; j < multiplicity; j++) m_HLTMuonThr.push_back(threshold);
127 } else if(std::regex_match(leg[0], match, gamma_rgx)) {
128 size_t multiplicity = match[1].str() == "" ? 1 : std::stoi(match[1].str());
129 unsigned int threshold = std::stoi(match[2].str());
130 for(size_t j = 0; j < multiplicity; j++) m_HLTGammaThr.push_back(threshold);
131 } else if(std::regex_match(leg[0], match, jet_rgx)) {
132 size_t multiplicity = match[1].str() == "" ? 1 : std::stoi(match[1].str());
133 unsigned int threshold = std::stoi(match[2].str());
134 for(size_t j = 0; j < multiplicity; j++) m_HLTJetThr.push_back(threshold);
135 } else if(std::regex_match(leg[0], match, met_rgx)) {
136 unsigned int threshold = std::stoi(match[2].str());
137 m_HLTMETThr.push_back(threshold);
138 } else if(std::regex_match(leg[0], match, noalg_rgx)) {
139 m_isStreamer = true;
140 } else if (std::regex_match(leg[0], match, ditauomni_rgx)) {
141 m_HLTBoostedDitauName.push_back(leg[0]);
142 } else if(std::regex_match(leg[0], l1_rgx)){ // Treat the L1 items as a leg
143 for(size_t j = 0; j < leg.size(); j++) {
144 if(std::regex_match(leg[j], topo_rgx)) continue; // Remove HLT topo sections, not part of the L1 item
145
146 // L1Topo items (they all include a "-" in the name, or have a separate "##DETA/PHI##_" prefix):
147 if(leg[j].find('-') != std::string::npos || std::regex_match(leg[j], l1_toposeparate_rgx)) {
148 // We only keep information from the legacy L1Topo item, from which we will not always use all thresholds
149 // Since we won't be adding any more Legacy thresholds, let's hard-code it...
150 if(leg[0] == "L1TAU60" && leg[j] == "DR-TAU12ITAU12I") leg[j] = "TAU12IM"; // L1_TAU60_DR-TAU20ITAU12I, uses "TAU12IM" threshold from the L1Topo item
151 else if(leg.size() == 1 && (leg[0] == "L1DR-TAU20ITAU12I" || leg[0] == "L1DR-TAU20ITAU12I-J25")) {
152 // Uses both TAU items, in the M isolation threshold
153 leg[0] = "L1TAU20IM";
154 leg.push_back("TAU12IM");
155 // Even on combined chains using jets, we don't use the jets threshold
156 }
157 else continue; // Remove the Phase 1 L1Topo items, since we always use a multiplicity threshold
158 }
159
160 m_L1Items.push_back(j == 0 ? leg[j].substr(2, leg[j].size()) : leg[j]); // Remove the "L1" prefix on the first L1 item
161 }
162 }
163
164 // Start a new leg
165 leg = {};
166 }
167 }
168
169 if(!m_L1Items.empty()) {
170 // Build the full L1 string
171 m_L1Item = m_L1Items[0];
172 for(size_t j = 1; j < m_L1Items.size(); j++) m_L1Item += "_" + m_L1Items[j];
173
174 // Get all individual L1 TAU items
175 std::regex_token_iterator<std::string::iterator> rgx_iter(m_L1Item.begin(), m_L1Item.end(), l1_tau_rgx);
176 while(rgx_iter != rend) {
177 const std::string & s = *rgx_iter;
178 if (std::regex_match(s, match, l1_tau_rgx)){
179 size_t multiplicity = match[1].str() == "" ? 1 : std::stoi(match[1].str());
180 std::string item_type = match[2].str(); // e, j, c, or ""
181 int threshold = std::stoi(match[3].str());
182 std::string item_isolation = match[4].str(); // "", L, M, T, HL, HM, HT, IM, H
183
184 // Set the Phase 1 thresholds to -1
185 if(remove_L1_phase1_thresholds && (item_type == "e" || item_type == "j" || item_type == "c")) threshold = -1;
186
187 for(size_t j = 0; j < multiplicity; j++) {
188 m_tauL1Items.push_back(s.substr(match[1].str().size()));
189 m_tauL1Thr.push_back(threshold);
190 m_tauL1Type.push_back(item_type + "TAU");
191 m_tauL1Iso.push_back(item_isolation);
192 m_tauL1ThresholdPattern.push_back(-1);
193 }
194 }
195 rgx_iter++;
196 }
197
198 m_L1Item = "L1" + m_L1Items[0];
199 }
200}
201
202void TrigTauInfo::parseTriggerString(const std::map<std::string, float>& L1Phase1_thresholds)
203{
205
206 for(size_t i = 0; i < m_tauL1Items.size(); i++) {
207 if(m_tauL1Type.at(i) == "TAU") continue; // Skip the legacy items
208
209 const std::string& item = m_tauL1Items.at(i);
210
211 m_tauL1Thr[i] = L1Phase1_thresholds.at(item);
212 }
213}
214
215void TrigTauInfo::parseTriggerString(const std::map<std::string, float>& L1Phase1_thresholds, const std::map<std::string, uint64_t>& L1Phase1_threshold_patterns)
216{
218
219 for(size_t i = 0; i < m_tauL1Items.size(); i++) {
220 if(m_tauL1Type.at(i) == "TAU") continue; // Skip the legacy items
221
222 const std::string& item = m_tauL1Items.at(i);
223
224 m_tauL1Thr[i] = L1Phase1_thresholds.at(item);
225 m_tauL1ThresholdPattern[i] = L1Phase1_threshold_patterns.at(item);
226 }
227}
228
229void TrigTauInfo::parseTriggerString(const std::map<int, int>& L1Phase1ThrMap_eTAU, const std::map<int, int>& L1Phase1ThrMap_jTAU)
230{
231 parseTriggerString(false);
232
233 // Correct the Phase 1 thresholds:
234 for(size_t i = 0; i < m_tauL1Items.size(); i++) {
235 const std::string& item_type = m_tauL1Type.at(i);
236 if(item_type == "eTAU" || item_type == "cTAU") {
237 m_tauL1Thr[i] = L1Phase1ThrMap_eTAU.at(m_tauL1Thr.at(i));
238 } else if(item_type == "jTAU") {
239 m_tauL1Thr[i] = L1Phase1ThrMap_jTAU.at(m_tauL1Thr.at(i));
240 }
241 }
242}
std::vector< std::string > m_tauL1Iso
Definition TrigTauInfo.h:87
std::vector< float > m_HLTMuonThr
Definition TrigTauInfo.h:91
bool m_isStreamer
Definition TrigTauInfo.h:77
std::vector< float > m_HLTGammaThr
Definition TrigTauInfo.h:92
std::string m_L1Item
Definition TrigTauInfo.h:82
std::vector< std::string > m_L1Items
Definition TrigTauInfo.h:83
std::vector< std::string > m_HLTBoostedDitauName
Definition TrigTauInfo.h:96
std::string m_trigger
Definition TrigTauInfo.h:76
std::vector< float > m_HLTElecThr
Definition TrigTauInfo.h:90
std::vector< std::string > m_tauL1Type
Definition TrigTauInfo.h:86
std::vector< std::string > m_tauL1Items
Definition TrigTauInfo.h:85
std::vector< std::string > m_HLTTauTypes
Definition TrigTauInfo.h:79
void parseTriggerString(bool remove_L1_phase1_thresholds=true)
std::vector< std::string > m_HLTTauIDs
Definition TrigTauInfo.h:80
std::vector< int64_t > m_tauL1ThresholdPattern
Definition TrigTauInfo.h:88
std::vector< float > m_tauL1Thr
Definition TrigTauInfo.h:84
std::vector< float > m_HLTJetThr
Definition TrigTauInfo.h:93
std::vector< float > m_HLTMETThr
Definition TrigTauInfo.h:94
std::vector< float > m_HLTThr
Definition TrigTauInfo.h:78
std::string find(const std::string &s)
return a remapped string
Definition hcg.cxx:138
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition hcg.cxx:357