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