ATLAS Offline Software
Loading...
Searching...
No Matches
NavigationTesterAlg.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
9#include "SpecialCases.h"
10#include <set>
11#include <algorithm>
12#include <iterator>
13#include <iostream>
14
15
16// anonymous namespace for convenience functions
17namespace {
18 std::set<std::set<const xAOD::IParticle *>> vectorToSet(
19 const std::vector<std::vector<const xAOD::IParticle *>>& vec)
20 {
21 std::set<std::set<const xAOD::IParticle *>> ret;
22 for (const std::vector<const xAOD::IParticle *> &combination : vec)
23 ret.emplace(combination.begin(), combination.end());
24 return ret;
25 }
26
27}
28
29namespace xAOD {
30 std::ostream &operator<<(std::ostream &os, const xAOD::IParticle *p)
31 {
32 return os << "["
33 << "type = " << p->type() << ", "
34 << "pt = " << p->pt() << ", "
35 << "eta = " << p->eta() << ", "
36 << "phi = " << p->phi() << ", "
37 << "ptr = " << reinterpret_cast<const void*>(p)
38 << "]";
39
40 }
41}
42
43namespace std {
44 // Define printing operators for the set and IParticle pointers
45 template <typename T>
46 std::ostream &operator<<(std::ostream &os, const std::set<T> &s)
47 {
48 os << "{";
49 for (auto itr = s.begin(); itr != s.end(); ++itr)
50 {
51 if (itr != s.begin())
52 os << ", ";
53 os << *itr;
54 }
55 return os << "}";
56 }
57}
58
59namespace Trig {
60
61 NavigationTesterAlg::NavigationTesterAlg(const std::string &name, ISvcLocator *pSvcLocator) :
62 AthReentrantAlgorithm(name, pSvcLocator)
63 {}
64
66 {
67 ATH_CHECK(m_tdt.retrieve());
68 ATH_CHECK(m_tdtRun2.retrieve());
69 ATH_CHECK(m_tdtRun3.retrieve());
70 ATH_CHECK(m_toolRun2.retrieve());
71 ATH_CHECK(m_toolRun3.retrieve());
72
73 if (m_chains.size() == 0)
74 ATH_MSG_WARNING("No chains provided, algorithm will be no-op");
75 return StatusCode::SUCCESS;
76 }
77
78 StatusCode NavigationTesterAlg::execute(const EventContext &) const
79 {
80 for (const std::string &chain : m_chains)
81 {
82 const bool chainPassed = m_tdt->isPassed(chain, TrigDefs::Physics | TrigDefs::allowResurrectedDecision);
83 ATH_MSG_DEBUG("Begin testing chain " << chain << (chainPassed ? " and will dive into details as the chain passed " : " but will not do anything as the chain did not pass"));
84 if (!chainPassed) continue;
85
86 // explicitely excluded chains
87 bool isExcluded = false;
88 for (const auto& excludedChain : SpecialCases::excludedChains) {
89 if (chain == excludedChain) {
90 isExcluded = true;
91 break; // Break out of the exclusion check loop
92 }
93 }
94
95 if (isExcluded) {
96 continue; // Skip the current iteration of the main loop
97 }
98
99 // We assume that the navigation is ultimately a set of element links
100 // We're comparing two types of navigation but they should both point to the same
101 // objects.
102 // We don't care about the order of the combinations, or the order within the
103 // combinations, we just care that they are the same. Therefore, we can convert the
104 // vectors to sets and just look at the differences between them
105 CombinationsVector vecCombinationsRun2;
106 ATH_MSG_DEBUG("Checking features of chain " << chain);
107 ATH_CHECK(m_toolRun2->retrieveParticles(vecCombinationsRun2, chain));
108 auto combsRun2 = vectorToSet(vecCombinationsRun2);
109 ATH_MSG_DEBUG("Run 2 size " << combsRun2.size());
110 // if Run 2 size is 0 we discard any further testing
111 if (combsRun2.size() == 0)
112 {
113 ATH_MSG_DEBUG("Chain " << chain << " testing discarded due to detected Run 2 size == 0");
114 continue;
115 }
116 for (auto& c : combsRun2 ) {
117 ATH_MSG_DEBUG(c);
118 }
119 CombinationsVector vecCombinationsRun3;
120 ATH_CHECK(m_toolRun3->retrieveParticles(vecCombinationsRun3, chain));
121 auto combsRun3 = vectorToSet(vecCombinationsRun3);
122 ATH_MSG_DEBUG("Run 3 size " << combsRun3.size());
123
124 if (combinationsEmpty(vecCombinationsRun2) and combinationsEmpty(vecCombinationsRun3)) {
125 ATH_MSG_DEBUG("Both, Run2 and Run3 combinations are effectively empty");
126 continue;
127 }
128
129
130 for (auto& c : combsRun3 ) {
131 ATH_MSG_DEBUG(c);
132 }
133 if ( std::regex_match(chain, SpecialCases::gammaXeChain) ) {
135 } else {
137 ATH_CHECK(verifyCombinationsSize(vecCombinationsRun2, vecCombinationsRun3, chain));
138 }
139 if ( m_verifyCombinations ) {
140 ATH_CHECK(verifyCombinationsContent(combsRun2, combsRun3, chain));
141 }
142 }
143
144 ATH_MSG_DEBUG("Verified chain " << chain);
145 }
146 return StatusCode::SUCCESS;
147 }
148
149 StatusCode NavigationTesterAlg::verifyFlatContent(const std::string& chain) const {
150 const auto &run3 = m_tdtRun3->features<xAOD::IParticleContainer>(chain);
151 std::set<const xAOD::IParticle*> particlesRun3;
152 for ( auto l: run3) {
153 if ( l.link.isValid() )
154 particlesRun3.insert(*(l.link));
155 }
156
157 CombinationsVector vecCombinationsRun2;
158 ATH_CHECK(m_toolRun2->retrieveParticles(vecCombinationsRun2, chain));
159 std::set<const xAOD::IParticle*> particlesRun2;
160 for ( auto& comb: vecCombinationsRun2) {
161 for ( auto el: comb) {
162 particlesRun2.insert(el);
163 }
164 }
165
166 for ( auto f2: particlesRun2 ) {
167 bool found=false;
168 for ( auto f3: particlesRun3 ) {
169 ATH_MSG_DEBUG("Serial set of features " << f3 );
170 if ( f2 == f3)
171 found = true;
172 }
173 if ( not found ) {
174 ATH_MSG_ERROR("Missing feature in Run 3 that is present in Run 2 " << f2 << " chain " << chain << " enable DEBUG to see more details" );
175 if ( m_failOnDifference ) {
176 return StatusCode::FAILURE;
177 }
178 }
179 }
180 return StatusCode::SUCCESS;
181 }
182
183
184 StatusCode NavigationTesterAlg::verifyCombinationsSize(const CombinationsVector& run2, const CombinationsVector& run3, const std::string& chain) const {
185 // In Run3 we do not use decision per RoI but per object, so for a single RoI with
186 // more than one object we will have more combinations in Run3 than Run2.
187 if (run2.size() > run3.size()) {
188 ATH_MSG_WARNING("Combination size mismatch for chain " << chain
189 << ": Run2=" << run2.size() << " Run3=" << run3.size()
190 << " (possible false positive from chain config decoding)");
191 if ( m_failOnDifference ) {
192 return StatusCode::FAILURE;
193 }
194 }
195 return StatusCode::SUCCESS;
196 }
197
198 StatusCode NavigationTesterAlg::verifyCombinationsContent(const CombinationsSet& run2, const CombinationsSet& run3, const std::string& chain) const {
199 // compare combinations
200
201 using xAODParticle = const xAOD::IParticle;
202
203 auto isSubsetPresent = [](const std::set<xAODParticle*>& subset, const CombinationsSet& r2) {
204 for (const auto& setInRun2 : r2) {
205 // Manual check for all particles in subset
206 bool allFound = true;
207 for (auto particle : subset) {
208 if (setInRun2.find(particle) == setInRun2.end()) {
209 allFound = false;
210 break; // If any particle is not found, no need to check further
211 }
212 }
213 if (allFound) return true; // Found all particles in this subset of Run2
214 }
215 return false; // Did not find the subset
216 };
217
218
219 auto isAnySubsetPresent = [&isSubsetPresent](const CombinationsSet& r3, const CombinationsSet& r2) {
220 for (const auto& subset : r3) {
221 if (isSubsetPresent(subset, r2)) {
222 return true; // At least one subset from Run3 is found in Run2
223 }
224 }
225 return false; // No subset from Run3 was found in Run2
226 };
227
228 bool result { false };
229 // hack for "HLT_e26_lhmedium_nod0_mu8noL1" case
230 // hack for "HLT_e24_lhmedium_L1EM20VHI_mu8noL1" type case
231 // hack for "HLT_mu11_2mu4noL1_nscan03_L1MU11_2MU6" type case
232 if ( std::regex_match(chain, SpecialCases::specialEchain) or
233 std::regex_match(chain, SpecialCases::specialElMuChain) or
234 std::regex_match(chain, SpecialCases::mu2MunoL1Special) ) {
235 result = isAnySubsetPresent(run3, run2);
236 } else {
237 // now subset checked on a level of objects, instead of group of objects
238 result = isAnySubsetPresent(run2, run3);
239 }
240
241 if (not result) {
242 // Subset check failed - this is the more severe condition
243 ATH_MSG_WARNING("Run2 objects not within subset of Run3 for chain " << chain
244 << " (multiplicities: " << ChainNameParser::multiplicities(chain) << ")");
245 ATH_MSG_WARNING(" Run2 combs: " << run2);
246 ATH_MSG_WARNING(" Run3 combs: " << run3);
247 if ( m_failOnDifference ) {
248 return StatusCode::FAILURE;
249 }
250 } else if (run2 != run3) {
251 // Combinations differ but subset check passed - informational
252 ATH_MSG_WARNING("Run2/Run3 combinations differ (but subset OK) for chain " << chain
253 << " (multiplicities: " << ChainNameParser::multiplicities(chain) << ")");
254 ATH_MSG_DEBUG(" Run2 combs: " << run2);
255 ATH_MSG_DEBUG(" Run3 combs: " << run3);
256 }
257
258 return StatusCode::SUCCESS;
259 }
260
262 size_t counter = 0;
263 for ( const std::vector<const xAOD::IParticle*>& outerc: combs )
264 counter += outerc.size();
265 return counter == 0;
266 }
267
268} //> end namespace Trig
269
270
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
std::vector< size_t > vec
An algorithm that can be simultaneously executed in multiple threads.
StatusCode verifyFlatContent(const std::string &chain) const
PublicToolHandle< Trig::TrigDecisionTool > m_tdtRun3
StatusCode verifyCombinationsSize(const CombinationsVector &run2, const CombinationsVector &run3, const std::string &chain) const
PublicToolHandle< Trig::TrigDecisionTool > m_tdtRun2
PublicToolHandle< Trig::TrigDecisionTool > m_tdt
std::vector< std::vector< const xAOD::IParticle * > > CombinationsVector
ToolHandle< Trig::IIParticleRetrievalTool > m_toolRun3
std::set< std::set< const xAOD::IParticle * > > CombinationsSet
StatusCode execute(const EventContext &context) const override
StatusCode initialize() override
StatusCode verifyCombinationsContent(const CombinationsSet &run2, const CombinationsSet &run3, const std::string &chain) const
Gaudi::Property< bool > m_verifyCombinations
Gaudi::Property< bool > m_verifyCombinationsSize
Gaudi::Property< bool > m_failOnDifference
bool combinationsEmpty(const CombinationsVector &combs) const
ToolHandle< Trig::IIParticleRetrievalTool > m_toolRun2
Gaudi::Property< std::vector< std::string > > m_chains
NavigationTesterAlg(const std::string &name, ISvcLocator *pSvcLocator)
Class providing the definition of the 4-vector interface.
std::vector< int > multiplicities(const std::string &chain)
const std::regex gammaXeChain
const std::regex specialElMuChain
const std::vector< std::string > excludedChains
Definition SpecialCases.h:8
const std::regex specialEchain
const std::regex mu2MunoL1Special
The common trigger namespace for trigger analysis tools.
STL namespace.
ostream & operator<<(ostream &s, const SG::VarHandleKey &m)
ICaloAffectedTool is abstract interface for tools checking if 4 mom is in calo affected region.
std::ostream & operator<<(std::ostream &out, const std::pair< FIRST, SECOND > &pair)
Helper print operator.
DataVector< IParticle > IParticleContainer
Simple convenience declaration of IParticleContainer.