ATLAS Offline Software
Loading...
Searching...
No Matches
TrigThresholdDecisionTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
10
11namespace LVL1
12{
14 const char ContainerName[] = "LVL1MuonRoIs";
15 const char ThresholdType[] = "MU";
16 }
17
19 const std::string& name,
20 const IInterface* parent)
21 : base_class(type, name, parent) {}
22
24 {
25 ATH_MSG_DEBUG( "========================================" );
26 ATH_MSG_DEBUG( "Initialize for TrigThresholdDecisionTool" );
27 ATH_MSG_DEBUG( "========================================" );
28
30 ATH_CHECK( m_rpcTool.retrieve() );
31 ATH_CHECK( m_tgcTool.retrieve() );
32
33 if(m_MenuFromxAOD) {
34 ATH_CHECK( m_configSvc.retrieve() );
35 }
36 return StatusCode::SUCCESS;
37 }
38
40 {
41 ATH_MSG_DEBUG( "==========================================" );
42 ATH_MSG_DEBUG( "Start for Phase1 TrigThresholdDecisionTool" );
43 ATH_MSG_DEBUG( "==========================================" );
44
45 // we configure the tool here only if we are not running from xAOD
46 if (!m_MenuFromxAOD){
47
49 ATH_CHECK(l1Menu.isValid());
51 }
52 return StatusCode::SUCCESS;
53 }
54
56
57 std::lock_guard guard{m_mutex};
58 if (m_isInitialized) {
59 return StatusCode::SUCCESS;
60 }
61
62 //buffered parsed TGC/RPC flags
63 parsedFlagsMap parsed_flags;
64 m_tgcFlag_decisions.clear();
65 m_rpcFlag_decisions.clear();
66
67 //front-load the TGC flag parsing and all possible 3-bit decisions for the menu
68 std::optional<ThrVecRef> menuThresholds = getMenuThresholds(l1Menu);
69 ATH_CHECK(menuThresholds.has_value());
70
71 for (const std::shared_ptr<TrigConf::L1Threshold>& thrBase : menuThresholds.value().get()) {
72 auto thr = static_cast<TrigConf::L1Threshold_MU*>(thrBase.get());
73
74 //parse the tgc flags and buffer them
75 std::string tgcFlags = getShapedFlags( thr->tgcFlags() );
76 parseFlags(tgcFlags, parsed_flags);
77
78 //loop over all 3-bit flag combinations
79 for (unsigned flags=0;flags<8;flags++) {
80 bool F=flags&0b100;
81 bool C=flags&0b010;
82 bool H=flags&0b001;
83 makeTGCDecision(tgcFlags, F, C, H, parsed_flags);
84 }
85
86 //parse the rpc flags and buffer them
87 std::string rpcFlags = getShapedFlags( thr->rpcFlags() );
88 parseFlags(rpcFlags, parsed_flags);
89
90 //loop over all 2-bit flag combinations
91 for (unsigned flags=0;flags<2;flags++){
92 bool M=flags&0b1;
93 makeRPCDecision(rpcFlags, M, parsed_flags);
94 }
95 }
96 m_isInitialized = true;
97 return StatusCode::SUCCESS;
98}
99
100 uint64_t TrigThresholdDecisionTool::getPattern(const EventContext& /*ctx*/,
101 const xAOD::MuonRoI& roi,
102 const ThrVec& menuThresholds,
103 const TrigConf::L1ThrExtraInfoBase& menuExtraInfo) const {
104 return getPattern(roi.roiWord(), menuThresholds, menuExtraInfo);
105 }
106
107 uint64_t TrigThresholdDecisionTool::getPattern(uint32_t dataWord,
108 const ThrVec& menuThresholds,
109 const TrigConf::L1ThrExtraInfoBase& menuExtraInfo) const {
110 if (m_MenuFromxAOD and !m_isInitialized){
111 const TrigConf::L1Menu& l1Menu = m_configSvc->l1Menu( Gaudi::Hive::currentContext());
112 if (configureToolFromMenu(l1Menu) != StatusCode::SUCCESS){
113 throw std::runtime_error("Error configuring the TrigThresholdDecisionTool from metadata!");
114 }
115 }
116
117 uint64_t thresholdsPattern = 0;
118
119 //first figure out if we need to use the RPC or TGC tool for decoding the ROI
120 LVL1::ITrigT1MuonRecRoiTool::MuonTriggerSystem system = m_rpcTool->getSystem(dataWord);
121 const LVL1::ITrigT1MuonRecRoiTool* roiTool;
122 if (system == LVL1::ITrigT1MuonRecRoiTool::Barrel) roiTool = &(*m_rpcTool);
123 else roiTool = &(*m_tgcTool);
124
125 //buffer the some information
126 unsigned isub = roiTool->getBitMaskValue(&dataWord, roiTool->SubSysIDMask());
128 unsigned ptword = roiTool->getBitMaskValue(&dataWord, roiTool->ThresholdMask());
129 unsigned roi, sectorID;
131 roi = roiTool->getBitMaskValue(&dataWord, roiTool->BarrelRoIMask());
132 sectorID = roiTool->getBitMaskValue(&dataWord, roiTool->BarrelSectorIDMask());
133 } else if (system == LVL1::ITrigT1MuonRecRoiTool::Endcap) {
134 roi = roiTool->getBitMaskValue(&dataWord, roiTool->EndcapRoIMask());
135 sectorID = roiTool->getBitMaskValue(&dataWord, roiTool->EndcapSectorIDMask());
136 } else { // Forward
137 roi = roiTool->getBitMaskValue(&dataWord, roiTool->ForwardRoIMask());
138 sectorID = roiTool->getBitMaskValue(&dataWord, roiTool->ForwardSectorIDMask());
139 }
140 const TrigConf::L1ThrExtraInfo_MU& muThrExtraInfo = dynamic_cast<const TrigConf::L1ThrExtraInfo_MU&>(menuExtraInfo);
141
142 //buffer (notional) TGC/RPC flags
143 bool F=false, C=false, H=false, M=false;
145 {
146 M = dataWord & roiTool->OverflowPerRoIMask();
147 }
148 else
149 {
150 F = dataWord & roiTool->BW2Or3Mask();
151 C = dataWord & roiTool->InnerCoinMask();
152 H = dataWord & roiTool->GoodMFMask();
153 }
154
155 //loop over the thresholds
156 for (const std::shared_ptr<TrigConf::L1Threshold>& thrBase : menuThresholds) {
157 auto thr = static_cast<TrigConf::L1Threshold_MU*>(thrBase.get());
158
159 bool passed{false};
161 //skip the threshold with regions not corresponding to ALL or barrel
162 if (thr->region().find("ALL") == std::string::npos &&
163 thr->region().find("BA") == std::string::npos) continue;
164
165 //veto this candidate from this multiplicity if it's part of the excluded ROI list
166 const bool isSideC = (side == LVL1MUONIF::Lvl1MuCTPIInputPhase1::idSideC());
167 if (isExcludedRPCROI(muThrExtraInfo, thr->rpcExclROIList(), roi, sectorID, isSideC)) continue;
168
169 if (ptword >= thr->idxBarrel()) {
170 // mark this threshold as passed
171 passed = true;
172 }
173
174 passed &= getRPCDecision(getShapedFlags(thr->rpcFlags()), M);
175 }
176 else { // Endcap or Forward
177 if (system == LVL1MUONIF::Lvl1MuCTPIInputPhase1::idEndcapSystem()) { // Endcap
178 //skip the threshold with regions not corresponding to ALL or endcap
179 if (thr->region().find("ALL") == std::string::npos &&
180 thr->region().find("EC") == std::string::npos) continue;
181
182 if (ptword >= thr->idxEndcap()) {
183 // mark this threshold as passed
184 passed = true;
185 }
186 }
187 else { // Forward
188 //skip the threshold with regions not corresponding to ALL or forward
189 if (thr->region().find("ALL") == std::string::npos &&
190 thr->region().find("FW") == std::string::npos) continue;
191
192 if (ptword >= thr->idxForward()) {
193 // mark this threshold as passed
194 passed = true;
195 }
196 }
197
198 passed &= getTGCDecision(getShapedFlags(thr->tgcFlags()), F, C, H);
199 } // end Endcap or Forward
200
201 if (passed) {
202 // set the corresponding bit in the pattern
203 thresholdsPattern |= (1ull << thr->mapping());
204 }
205
206 } // loop over thresholds
207
208 return thresholdsPattern;
209 }
210
211 std::vector<std::pair<std::shared_ptr<TrigConf::L1Threshold>, bool> >
213 const EventContext& eventContext) const {
214 // Retrieve the L1 menu configuration
215 const TrigConf::L1Menu* l1Menu;
216 if (m_MenuFromxAOD){
217 l1Menu = &m_configSvc->l1Menu( eventContext );
218 if (!m_isInitialized){
219 if (configureToolFromMenu(*l1Menu) != StatusCode::SUCCESS){
220 throw std::runtime_error("Error configuring the TrigThresholdDecisionTool from metadata!");
221 }
222 }
223 }
224 else{
225 SG::ReadHandle<TrigConf::L1Menu> l1MenuHandle = SG::makeHandle(m_l1MenuKey, eventContext);
226 l1Menu = l1MenuHandle.cptr();
227 }
228
229 std::optional<ThrVecRef> menuThresholds = getMenuThresholds(*l1Menu);
230 std::optional<ExtraInfoRef> menuExtraInfo = getMenuThresholdExtraInfo(*l1Menu);
231 // Call the other overload
232 return getThresholdDecisions(dataWord, menuThresholds.value().get(), menuExtraInfo.value().get());
233 }
234
235 std::vector<std::pair<std::shared_ptr<TrigConf::L1Threshold>, bool> >
237 const ThrVec& menuThresholds,
238 const TrigConf::L1ThrExtraInfoBase& menuExtraInfo) const {
239 if (m_MenuFromxAOD and !m_isInitialized){
240 const TrigConf::L1Menu& l1Menu = m_configSvc->l1Menu( Gaudi::Hive::currentContext());
241 if (configureToolFromMenu(l1Menu) != StatusCode::SUCCESS){
242 throw std::runtime_error("Error configuring the TrigThresholdDecisionTool from metadata!");
243 }
244 }
245
246 const uint64_t pattern = getPattern(dataWord, menuThresholds, menuExtraInfo);
247
248 //the object that will be returned: pairs of thresholds and pass/fail decisions
249 std::vector<std::pair<std::shared_ptr<TrigConf::L1Threshold>, bool> > threshold_decisions;
250 threshold_decisions.resize(menuThresholds.size());
251 for (const std::shared_ptr<TrigConf::L1Threshold>& thr : menuThresholds) {
252 const bool decision = pattern & (1 << thr->mapping());
253 threshold_decisions[thr->mapping()] = std::make_pair(thr, decision);
254 }
255 return threshold_decisions;
256 }
257
258 std::pair<std::string, double> TrigThresholdDecisionTool::getMinThresholdNameAndValue(const std::vector<std::pair<std::shared_ptr<TrigConf::L1Threshold>, bool> >& decisions, const double& eta) const
259 {
260 if (m_MenuFromxAOD and !m_isInitialized){
261 const TrigConf::L1Menu& l1Menu = m_configSvc->l1Menu( Gaudi::Hive::currentContext());
262 if (configureToolFromMenu(l1Menu) != StatusCode::SUCCESS){
263 throw std::runtime_error("Error configuring the TrigThresholdDecisionTool from metadata!");
264 }
265 }
266
267 //find the highest pt threshold passed - depite the name of this function
268 std::string thrName="";
269 double thrVal=0;
270 double thrValTmp=0;
271 for (unsigned idec=0;idec<decisions.size();++idec) {
272 if (!decisions[idec].second) continue;
273 const TrigConf::L1Threshold_MU* thr = static_cast<TrigConf::L1Threshold_MU*>(decisions[idec].first.get());
274 if(std::abs(eta)<1.05){
275 thrValTmp = thr->ptBarrel();
276 }
277 else{
278 thrValTmp = thr->ptEndcap();
279 }
280 if (thrValTmp > thrVal)
281 {
282 thrVal = thrValTmp;
283 thrName = thr->name();
284 }
285 }
286 return std::make_pair(thrName, thrVal);
287 }
288
290 const std::string& rpcExclROIList,
291 const unsigned roi,
292 const unsigned sectorID,
293 const bool isSideC) const {
294 if (rpcExclROIList != "")
295 {
296 const std::map<std::string, std::vector<unsigned int> >& exclList = menuExtraInfo.exclusionList(rpcExclROIList);
297 if (exclList.size() != 0)
298 {
299 //build the sector name of this ROI to compare against the exclusion list
300 std::string sectorName("B");
301
302 int sectorNumber=sectorID;
303 if (isSideC) sectorNumber += 32;
304 if (sectorNumber < 10) sectorName += '0';
305 sectorName += std::to_string(sectorNumber);
306
307 //do the comparison
308 auto exclROIs = exclList.find(sectorName);
309 if (exclROIs != exclList.end())
310 {
311 for (auto roi_itr=exclROIs->second.begin();roi_itr!=exclROIs->second.end();roi_itr++)
312 {
313 if (*roi_itr == roi) return true;
314 }
315 }
316 }
317 } // rpcExclList != ""
318
319 return false;
320 }
321
322 bool TrigThresholdDecisionTool::getTGCDecision(const std::string& tgcFlags, const bool F, const bool C, const bool H) const
323 {
324 //check if the word has been checked before for this string of flags (it should always, as we've buffered them in 'start')
325 TGCFlagDecision decision(F,C,H);
326 auto previous_decisions = m_tgcFlag_decisions.find(tgcFlags);
327 if (previous_decisions == m_tgcFlag_decisions.end()) return false;
328
329 auto previous_decision_itr = previous_decisions->second.find(decision);
330 if (previous_decision_itr != previous_decisions->second.end()) return previous_decision_itr->pass;
331 return false;
332 }
333
334 void TrigThresholdDecisionTool::makeTGCDecision(const std::string& tgcFlags, const bool F, const bool C, const bool H, const parsedFlagsMap& parsed_flags) const
335 {
336 //check if the word has been checked before for this string of flags
337 TGCFlagDecision decision(F,C,H);
338 auto previous_decisions = &m_tgcFlag_decisions[tgcFlags];
339 auto previous_decision_itr = previous_decisions->find(decision);
340 if (previous_decision_itr != previous_decisions->end()) return;
341 else if (tgcFlags == "") {
342 decision.pass=true;
343 previous_decisions->insert(decision);
344 }
345 else { // make the decision
346
347 //check the quality based on the flags.
348 //loop over outer layer of "ors" and 'or' the results
349 bool passedFlags = false;
350 const auto* vec_flags = &parsed_flags.at(tgcFlags);
351 for (auto or_itr = vec_flags->begin();or_itr!=vec_flags->end();or_itr++)
352 {
353 //loop over the inner layer of "ands" and 'and' the results
354 bool passedAnd = true;
355 for (auto and_itr = or_itr->begin();and_itr!=or_itr->end();and_itr++)
356 {
357 if (*and_itr == "F") passedAnd = passedAnd && F;
358 else if (*and_itr == "C") passedAnd = passedAnd && C;
359 else if (*and_itr == "H") passedAnd = passedAnd && H;
360 }
361 passedFlags = passedFlags || passedAnd;
362 }
363 //buffer the decision
364 decision.pass = passedFlags;
365 previous_decisions->insert(decision);
366 }
367 }
368
369 bool TrigThresholdDecisionTool::getRPCDecision(const std::string& rpcFlags, const bool M) const
370 {
371 //check if the word has been checked before for this string of flags (it should always, as we've buffered them in 'start')
372 RPCFlagDecision decision(M);
373 auto previous_decisions = m_rpcFlag_decisions.find(rpcFlags);
374 if (previous_decisions == m_rpcFlag_decisions.end()) return false;
375
376 auto previous_decision_itr = previous_decisions->second.find(decision);
377 if (previous_decision_itr != previous_decisions->second.end()) return previous_decision_itr->pass;
378 return false;
379 }
380
381 void TrigThresholdDecisionTool::makeRPCDecision(const std::string& rpcFlags, const bool M, const parsedFlagsMap& parsed_flags) const
382 {
383 //check if the word has been checked before for this string of flags
384 RPCFlagDecision decision(M);
385 auto previous_decisions = &m_rpcFlag_decisions[rpcFlags];
386 auto previous_decision_itr = previous_decisions->find(decision);
387 if (previous_decision_itr != previous_decisions->end()) return;
388 else if (rpcFlags == "") {
389 decision.pass=true;
390 previous_decisions->insert(decision);
391 }
392 else { // make the decision
393
394 //check the quality based on the flags.
395 //loop over outer layer of "ors" and 'or' the results
396 bool passedFlags = false;
397 const auto* vec_flags = &parsed_flags.at(rpcFlags);
398 for (auto or_itr = vec_flags->begin();or_itr!=vec_flags->end();or_itr++)
399 {
400 //loop over the inner layer of "ands" and 'and' the results
401 bool passedAnd = true;
402 for (auto and_itr = or_itr->begin();and_itr!=or_itr->end();and_itr++)
403 {
404 if (*and_itr == "M") passedAnd = passedAnd && M;
405 }
406 passedFlags = passedFlags || passedAnd;
407 }
408 //buffer the decision
409 decision.pass = passedFlags;
410 previous_decisions->insert(decision);
411 }
412 }
413
414 void TrigThresholdDecisionTool::parseFlags(const std::string& flags, parsedFlagsMap& parsed_flags) const
415 {
416 //parse the logic of the quality flag into a 2D vector, where outer layer contains the logic |'s and inner layer contains the logical &'s.
417 //save the 2D vector in a map so we don't have to parse it each time we want to check the flags.
418
419 // 1. Single-lookup insertion check using try_emplace.
420 // If the key exists, it returns immediately without doing any work.
421 auto [it, inserted] = parsed_flags.try_emplace(flags);
422
423 if (!inserted) {
424 return;
425 }
426 std::string_view stable_key = it->first;
427 std::vector<std::string_view> vec_ors = tokenize<std::string_view>(stable_key, '|');
428 std::vector<std::vector<std::string_view> > vec_flags;
429 for (unsigned ior=0;ior<vec_ors.size();ior++)
430 {
431 vec_flags.push_back(tokenize<std::string_view>(vec_ors[ior],'&'));
432 }
433 it->second = std::move(vec_flags);
434 }
435
436
437 std::string TrigThresholdDecisionTool::getShapedFlags(const std::string& flags) const
438 {
439 std::string shapedFlags = flags;
440 shapedFlags.erase(std::remove_if(shapedFlags.begin(), shapedFlags.end(),
441 [](unsigned char c) { return std::isspace(c); }), shapedFlags.end());
442 std::vector<std::string_view> vec_ors = tokenize<std::string_view>(shapedFlags,'|');
443 std::set<std::string> set_ors;
444 for(const auto& ors : vec_ors){
445 std::vector<std::string_view> vec_ands = tokenize<std::string_view>(ors,'&');
446 std::set<std::string_view> set_ands;
447 for(const auto& ands : vec_ands){
448 set_ands.insert(ands);
449 }
450 std::string aa = "";
451 for(const auto& ands : set_ands){
452 aa += ands;
453 aa += '&';
454 }
455 if(!aa.empty()) aa.pop_back(); // remove the last "&"
456 set_ors.insert(std::move(aa));
457 }
458 std::string aa = "";
459 for(const auto& ors : set_ors){
460 aa += ors;
461 aa += '|';
462 }
463 if(!aa.empty()) aa.pop_back();// remove the last "|"
464 return aa;
465 }
466}
Scalar eta() const
pseudorapidity method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x)
std::vector< std::string > tokenize(std::string_view the_str, std::string_view delimiters)
Splits the string into smaller substrings.
bool passed(DecisionID id, const DecisionIDContainer &)
checks if required decision ID is in the set of IDs in the container
#define F(x, y, z)
Definition MD5.cxx:112
#define H(x, y, z)
Definition MD5.cxx:114
unsigned int ForwardSectorIDMask() const
unsigned int OverflowPerRoIMask() const
unsigned int BarrelSectorIDMask() const
unsigned int ForwardRoIMask() const
unsigned int getBitMaskValue(const unsigned int *uintValue, const unsigned int mask) const
unsigned int EndcapSectorIDMask() const
bool getTGCDecision(const std::string &tgcFlags, bool F, bool C, bool H) const
ToolHandle< LVL1::ITrigT1MuonRecRoiTool > m_tgcTool
std::string getShapedFlags(const std::string &flags) const
virtual uint64_t getPattern(const EventContext &ctx, const xAOD::MuonRoI &roi, const ThrVec &menuThresholds, const TrigConf::L1ThrExtraInfoBase &menuExtraInfo) const override
bool isExcludedRPCROI(const TrigConf::L1ThrExtraInfo_MU &menuExtraInfo, const std::string &rpcExclROIList, unsigned roi, unsigned sectorID, bool isSideC) const
virtual std::vector< std::pair< std::shared_ptr< TrigConf::L1Threshold >, bool > > getThresholdDecisions(uint32_t dataWord, const EventContext &eventContext) const override
void parseFlags(const std::string &flags, parsedFlagsMap &parsed_flags) const
void makeRPCDecision(const std::string &rpcFlags, bool M, const parsedFlagsMap &parsed_flags) const
std::unordered_map< std::string, std::vector< std::vector< std::string_view > > > parsedFlagsMap
ServiceHandle< TrigConf::ITrigConfigSvc > m_configSvc
void makeTGCDecision(const std::string &tgcFlags, bool F, bool C, bool H, const parsedFlagsMap &parsed_flags) const
virtual std::pair< std::string, double > getMinThresholdNameAndValue(const std::vector< std::pair< std::shared_ptr< TrigConf::L1Threshold >, bool > > &decisions, const double &eta=0) const override
StatusCode configureToolFromMenu(const TrigConf::L1Menu &l1Menu) const
ToolHandle< LVL1::ITrigT1MuonRecRoiTool > m_rpcTool
virtual StatusCode initialize() override
TrigThresholdDecisionTool(const std::string &type, const std::string &name, const IInterface *parent)
bool getRPCDecision(const std::string &rpcFlags, bool M) const
virtual StatusCode initialize() override
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const_pointer_type cptr()
Dereference the pointer.
L1 menu configuration.
Definition L1Menu.h:29
L1 extra information for certain threshold types.
const std::map< std::string, std::vector< unsigned int > > & exclusionList(const std::string &listName) const
uint32_t roiWord() const
The "raw" RoI word describing the muon candidate.
struct color C
std::vector< std::string > tokenize(std::string_view the_str, std::string_view delimiters)
Splits the string into smaller substrings.
eFexTowerBuilder creates xAOD::eFexTowerContainer from supercells (LATOME) and triggerTowers (TREX) i...
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
DataModel_detail::iterator< DVL > remove_if(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end, Predicate pred)
Specialization of remove_if for DataVector/List.
MuonRoI_v1 MuonRoI
Definition MuonRoI.h:15