ATLAS Offline Software
Loading...
Searching...
No Matches
L1DataConsistencyChecker.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4// Local includes
7// Trigger includes
11// Athena includes
14// System includes
15#include <unordered_map>
16#include <sstream>
17
18namespace{
19 // this can be constexpr in C++20
20 bool vectorContains(const std::vector<std::string>& vec, const std::string& str) {
21 return (std::find(vec.cbegin(),vec.cend(),str)!=vec.cend());
22 }
23}
24
25// =============================================================================
27 ATH_CHECK(m_hltMenuKey.initialize());
28 ATH_CHECK(m_l1MenuKey.initialize());
29 if (!m_monTool.empty()) {
30 ATH_CHECK(m_monTool.retrieve());
31 }
32 return StatusCode::SUCCESS;
33}
34
35// =============================================================================
38 ATH_CHECK(l1Menu.isValid());
40 ATH_CHECK(hltMenu.isValid());
41
42 TrigConf::LogicParser logicParser;
43
44 m_thresholdMap.clear();
45 m_thresholdNames.clear();
46 m_thresholdTypes.clear();
48
49 for (const TrigConf::Chain& chain : *hltMenu) {
50 try {
51 // For chains with multiple seeds, we cannot determine in this tool which seed passed and which didn't,
52 // so we need to skip these kinds of chains
53 if (chain.l1item().empty() || chain.l1item().find(',')!=std::string::npos) {continue;}
54
55 TrigConf::L1Item item = l1Menu->item(chain.l1item());
56 std::map<std::string,unsigned int> thresholds = logicParser.parse(item.definition())->elementsCount();
57 for (const auto& [thrName, multiplicity] : thresholds) {
58 const TrigConf::L1Threshold& thr = l1Menu->threshold(thrName);
59 // Skip thresholds for which there are no TOBs, e.g. randoms
60 if (vectorContains(m_excludedThresholdTypes.value(), thr.type())) {
61 continue;
62 }
63 TrigCompositeUtils::DecisionID thrNameHash = HLT::Identifier(thr.name());
64 m_thresholdMap[chain.namehash()].insert({thrNameHash, multiplicity});
65 m_monitoredThresholds.insert(thrNameHash);
66 }
67 }
68 catch (const std::exception& ex) {
69 ATH_MSG_ERROR("Exception caught while parsing L1 thresholds for chain " << chain.name() << ": " << ex.what());
70 return StatusCode::FAILURE;
71 }
72 }
73
74 for (const std::shared_ptr<TrigConf::L1Threshold>& thr : l1Menu->thresholds()) {
75 TrigCompositeUtils::DecisionID thrNameHash = HLT::Identifier(thr->name());
76 m_thresholdNames[thrNameHash] = thr->name();
77 m_thresholdTypes[thrNameHash] = thr->type();
78 }
79
80 return StatusCode::SUCCESS;
81}
82
83// =============================================================================
84StatusCode L1DataConsistencyChecker::consistencyCheck(const HLT::IDVec& l1SeededChains, const EventContext& ctx) const {
85 auto monTimer = Monitored::Timer<std::chrono::duration<float, std::milli>>("TIME_consistencyCheck");
86 StatusCode sc = StatusCode::SUCCESS;
87
88 // ---------------------------------------------------------------------------
89 // Get information from TOBs
90 // ---------------------------------------------------------------------------
91 std::ostringstream ssPassedThresholds; // ss for debug printouts, allocate before loop
92 std::unordered_map<TrigCompositeUtils::DecisionID, size_t> tobThresholdCounts; // {thrName hash, nTOBs passing thr}
93 std::unordered_set<std::string> overflowThresholdTypes; // threshold types for which overflow was detected
94 // Loop over threshold types
95 for (const auto& [thrType, decisionsKey] : m_thresholdToDecisionMap.value()) {
96 SG::ReadHandle<TrigCompositeUtils::DecisionContainer> decisions{decisionsKey, ctx.getExtension<Atlas::ExtendedEventContext>().proxy()->name()};
97 if (!decisions.isValid()) {
98 ATH_MSG_DEBUG("No DecisionContainer " << decisionsKey << " for threshold type " << thrType << " found in this event");
99 continue;
100 }
101 size_t idec{0};
102 // Loop over TOBs of the given threshold type (one decision = one TOB)
103
104 for (const TrigCompositeUtils::Decision* d : *decisions) {
105 std::vector<TrigCompositeUtils::DecisionID> passedThresholdIDs;
106 static const std::string thresholdsStr{"thresholds"};
107 const bool hasDetail = d->getDetail(thresholdsStr, passedThresholdIDs);
108 if (!hasDetail) {
109 ATH_MSG_ERROR("Detail \"thresholds\" missing from Decision in the container " << decisionsKey);
110 return StatusCode::FAILURE;
111 }
112 bool overflow{false};
113 if (d->hasDetail<char>("overflow")) {
114 overflow = static_cast<bool>(d->getDetail<char>("overflow"));
115 }
116 if (doDebug()) {ssPassedThresholds.str("");}
117 for (const TrigCompositeUtils::DecisionID thrNameHash : passedThresholdIDs) {
118 if (overflow) {
119 overflowThresholdTypes.insert(m_thresholdTypes.at(thrNameHash));
120 }
121 if (tobThresholdCounts.find(thrNameHash)==tobThresholdCounts.end()) {
122 tobThresholdCounts[thrNameHash] = 1;
123 }
124 else {
125 tobThresholdCounts[thrNameHash] += 1;
126 }
127 if (doDebug()) {
128 if (!ssPassedThresholds.str().empty()) ssPassedThresholds << ", ";
129 ssPassedThresholds << m_thresholdNames.at(thrNameHash);
130 }
131 }
132 if (doDebug()) {
133 namespace RoIDefs = HLTSeedingRoIToolDefs;
134 std::optional<RoIDefs::AnyRoIPointer> optTob = RoIDefs::roiFromLink(*d, TrigCompositeUtils::initialRecRoIString());
135 if (optTob.has_value()) {
136 const RoIDefs::AnyRoIPointer& tob = optTob.value();
137 ATH_MSG_DEBUG("Decision " << decisionsKey << "[" << idec << "] corresponds to TOB with word / et / eta / phi = 0x"
138 << MSG::hex << RoIDefs::roiWord(tob) << MSG::dec << " / " << RoIDefs::roiTobEt(tob)
139 << " / " << RoIDefs::roiEta(tob) << " / " << RoIDefs::roiPhi(tob));
140 } else {
141 ATH_MSG_DEBUG("Decision " << decisionsKey << "[" << idec << "] TOB type not supported by template code for "
142 << "debug printout of word / et / eta / phi");
143 }
144 ATH_MSG_DEBUG("Decision " << decisionsKey << "[" << idec << "] TOB passes " << passedThresholdIDs.size()
145 << " thresholds: " << ssPassedThresholds.str());
146 ++idec;
147 }
148 }
149 }
150
151 // ---------------------------------------------------------------------------
152 // Get information from CTP
153 // ---------------------------------------------------------------------------
154 std::unordered_map<TrigCompositeUtils::DecisionID, size_t> ctpThresholdCounts; // {thrName hash, max CTP multiplicity}
155 // Loop over HLT chains activated by CTP
156 for (const TrigCompositeUtils::DecisionID chainID : l1SeededChains) {
157 const auto it = m_thresholdMap.find(chainID);
158 if (it==m_thresholdMap.end()) {
159 ATH_MSG_DEBUG("Cannot monitor chain " << chainID << " -> " << HLT::Identifier(chainID).name() << ", skipping");
160 continue;
161 }
162 const MultiplicityInfo& thresholds = it->second;
163 // Loop over all thresholds required to activate this chain
164 for (const auto& [thrNameHash, multiplicity] : thresholds) {
165 if (ctpThresholdCounts.find(thrNameHash)==ctpThresholdCounts.end()) {
166 ctpThresholdCounts[thrNameHash] = multiplicity;
167 }
168 else if (multiplicity > ctpThresholdCounts[thrNameHash]) {
169 ctpThresholdCounts[thrNameHash] = multiplicity;
170 }
171 }
172 }
173
174 // ---------------------------------------------------------------------------
175 // Perform the consistency check
176 // ---------------------------------------------------------------------------
177 for (const auto& [thrNameHash, ctpCount] : ctpThresholdCounts) {
178 size_t tobCount{0};
179 bool tooFew{false};
180 const auto it = m_thresholdNames.find(thrNameHash);
181 if (it==m_thresholdNames.end()) {
182 ATH_MSG_ERROR("Threshold with hash " << thrNameHash << " not found in the hash->name map");
183 return StatusCode::FAILURE;
184 }
185 const std::string& thrName = it->second;
186 const std::string& thrType = m_thresholdTypes.at(thrNameHash);
187
188 // Check if overflow was detected
189 bool overflow{overflowThresholdTypes.find(thrType)!=overflowThresholdTypes.end()};
190 if (overflow) {
191 ATH_MSG_DEBUG("Threshold " << thrName << " accepted by the CTP with multiplicity " << ctpCount
192 << " is flagged as overflow and thus may be missing TOBs");
193 }
194
195 // True if no TOBs found for this threshold but CTP accepted
196 bool missing = (tobThresholdCounts.find(thrNameHash)==tobThresholdCounts.end());
197
198 if (missing) {
199 if (overflow || !m_errorOnMissingTOB) {
200 ATH_MSG_WARNING("No TOBs found passing the threshold " << thrName
201 << " accepted by the CTP with multiplicity " << ctpCount
202 << (overflow ? ", likely due to overflow" : ""));
203
204 } else {
205 ATH_MSG_ERROR("No TOBs found passing the threshold " << thrName
206 << " accepted by the CTP with multiplicity " << ctpCount);
207 sc = StatusCode::FAILURE;
208 }
209 }
210 else {
211 tobCount = tobThresholdCounts.at(thrNameHash);
212 // True if fewer TOBs found for this threshold than the multiplicity accepted by CTP
213 tooFew = (tobCount < ctpCount);
214 }
215
216 if (tooFew) {
217 if (overflow || !m_errorOnMissingTOB) {
218 ATH_MSG_WARNING("Too few (" << tobCount << ") TOBs found passing the threshold " << thrName
219 << " accepted by the CTP with multiplicity " << ctpCount
220 << (overflow ? ", likely due to overflow" : ""));
221 } else {
222 ATH_MSG_ERROR("Too few (" << tobCount << ") TOBs found passing the threshold " << thrName
223 << " accepted by the CTP with multiplicity " << ctpCount);
224 sc = StatusCode::FAILURE;
225 }
226 }
227
228 if (missing || tooFew) {
229 // Fill the histograms
230 Monitored::Scalar monMissingTOBsIncludingOverflow{"MissingTOBsIncludingOverflow", thrName};
231 if (overflow) {
232 Monitored::Group{m_monTool, monMissingTOBsIncludingOverflow};
233 }
234 else {
235 Monitored::Scalar monMissingTOBs{"MissingTOBs", thrName};
236 Monitored::Group{m_monTool, monMissingTOBs, monMissingTOBsIncludingOverflow};
237 }
238 }
239 else {
240 ATH_MSG_DEBUG("Check passed. Found " << tobCount << " TOBs passing the threshold " << thrName
241 << " accepted by the CTP with multiplicity " << ctpCount);
242 }
243 }
244
245 // Fill extra histograms for debugging
246 for (const TrigCompositeUtils::DecisionID thrNameHash : m_monitoredThresholds) {
247 const auto ctpIt = ctpThresholdCounts.find(thrNameHash);
248 size_t ctpCount = (ctpIt==ctpThresholdCounts.cend()) ? 0 : ctpIt->second;
249 const auto tobIt = tobThresholdCounts.find(thrNameHash);
250 size_t tobCount = (tobIt==tobThresholdCounts.cend()) ? 0 : tobIt->second;
251 int tobMinusCtpCount = static_cast<int>(ctpCount) - static_cast<int>(tobCount); // negative when TOBs are missing
252 const std::string& thrName = m_thresholdNames.at(thrNameHash);
253
254 Monitored::Scalar monThrName{"ThrName", thrName};
255 Monitored::Scalar monCtpCount{"CtpCount", ctpCount};
256 Monitored::Scalar monTobCount{"TobCount", tobCount};
257 Monitored::Scalar monTobMinusCtpCount{"TobMinusCtpCount", tobMinusCtpCount};
258 Monitored::Group{m_monTool, monThrName, monCtpCount, monTobCount, monTobMinusCtpCount};
259 }
260
261 Monitored::Group(m_monTool, monTimer);
262 return sc;
263}
#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
static Double_t sc
Header file to be included by clients of the Monitored infrastructure.
Property holding a SG store/key/clid from which a ReadHandle is made.
std::unordered_map< TrigCompositeUtils::DecisionID, MultiplicityInfo > m_thresholdMap
SG::ReadHandleKey< TrigConf::HLTMenu > m_hltMenuKey
Gaudi::Property< std::map< std::string, std::string > > m_thresholdToDecisionMap
std::set< TrigCompositeUtils::DecisionID > m_monitoredThresholds
std::unordered_map< TrigCompositeUtils::DecisionID, std::string > m_thresholdTypes
std::unordered_map< TrigCompositeUtils::DecisionID, unsigned int > MultiplicityInfo
SG::ReadHandleKey< TrigConf::L1Menu > m_l1MenuKey
Gaudi::Property< std::vector< std::string > > m_excludedThresholdTypes
std::unordered_map< TrigCompositeUtils::DecisionID, std::string > m_thresholdNames
virtual StatusCode initialize() override
virtual StatusCode start() override
ToolHandle< GenericMonitoringTool > m_monTool
bool doDebug() const
Shorter alias for a check whether we are in DEBUG logging mode.
Gaudi::Property< bool > m_errorOnMissingTOB
StatusCode consistencyCheck(const HLT::IDVec &l1SeededChains, const EventContext &ctx) const
Perform the check and fill the corresponding histograms.
Group of local monitoring quantities and retain correlation when filling histograms
Declare a monitored scalar variable.
A monitored timer.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
L1 threshold configuration.
Definition L1Item.h:18
const std::string & definition() const
Accessor to the item definition.
Definition L1Item.cxx:40
Standard L1 threshold configuration.
Collection of template parameter values for the RoIThresholdsTool and RoIsUnpackingToolPhase1 class t...
std::vector< HLT::Identifier > IDVec
unsigned int DecisionID
xAOD::TrigComposite Decision
const std::string & initialRecRoIString()