ATLAS Offline Software
Loading...
Searching...
No Matches
ComboHypo.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
8#include "AthViews/View.h"
9#include <sstream>
10
11using namespace TrigCompositeUtils;
12
13ComboHypo::ComboHypo(const std::string& name, ISvcLocator* pSvcLocator)
14: ::AthReentrantAlgorithm(name, pSvcLocator)
15{}
16
17
20
21
23
24 ATH_CHECK( m_outputs.initialize() );
25 ATH_CHECK( m_inputs.initialize() );
26 ATH_CHECK( m_inputs.size() == m_outputs.size() );
27
28 if (m_hypoTools.size()>0) {
29 ATH_CHECK(m_hypoTools.retrieve());
30 }
31
32 for (auto& tool: m_hypoTools ) {
33 ATH_CHECK(tool->setLegMultiplicity(m_multiplicitiesReqMap));
34 }
35
36 // find max inputs size
37 auto maxMultEl = std::max_element( m_multiplicitiesReqMap.begin(), m_multiplicitiesReqMap.end(),
38 []( const Combo::MultiplicityReqMap::value_type& a, const Combo::MultiplicityReqMap::value_type& b ){
39 return a.second.size() < b.second.size();
40 });
41
42 const size_t maxMult = maxMultEl->second.size();
43
44 if (msgLvl(MSG::DEBUG)){
45 ATH_MSG_DEBUG( "with these inputs:");
46 for (const auto& inp : m_inputs) {
47 ATH_MSG_DEBUG("-- "<< inp.key());
48 }
49 ATH_MSG_DEBUG( "with this multiplicity map:");
50 for ( const auto& m : m_multiplicitiesReqMap ) {
51 ATH_MSG_DEBUG("-- " << m.first
52 << " multiplicities: " << m.second
53 <<", input-collection-indicies: " << m_legToInputCollectionMap[m.first]);
54 }
55 }
56
57 ATH_CHECK( m_multiplicitiesReqMap.size() != 0 );
58
59 bool errorOccured = false;
61 for ( const auto& [key, value] : m_multiplicitiesReqMap ) {
62 // Check the size of the multiplicities-required-per-leg vector is the same as the input-collection-index-per-leg vector
63 Combo::LegMap::const_iterator it_input = m_legToInputCollectionMap.find(key);
64 if (it_input == m_legToInputCollectionMap.end()) {
65 ATH_MSG_ERROR(key << " was not registered in the LegToInputCollectionMap");
66 errorOccured = true;
67 } else if (value.size() != it_input->second.size()) {
68 ATH_MSG_ERROR("Inconsistent configuration vector sizes for " << key << " Multiplicities Required size:" << value.size()
69 << ", Input Collections Index size:" << it_input->second.size());
70 errorOccured = true;
71 }
72 // TimM Jult 21: What is this check doing?
73 if ( value.size() > maxMult ) {
74 errorOccured = true;
75 ATH_MSG_ERROR( "Chain " << key
76 << " configured with input multiplicity " << value.size() << " like this: " << value
77 << " which is lower than for this chain " << maxMultEl->first << " " << maxMult);
78 }
79 }
80 }
81
82 return ( errorOccured ? StatusCode::FAILURE : StatusCode::SUCCESS );
83}
84
85
86StatusCode ComboHypo::copyDecisions( const Combo::LegDecisionsMap & passingLegs, const EventContext& context ) const {
87 DecisionIDContainer passing;
88 for (auto const& element : passingLegs) {
89 passing.insert(element.first);
90 }
91
92 ATH_MSG_DEBUG( "Copying "<<passing.size()<<" positive decision IDs to outputs");
93
94 for ( size_t input_counter = 0; input_counter < m_inputs.size(); ++input_counter ) {
95 // new output decisions
96 SG::WriteHandle<DecisionContainer> outputHandle = createAndStore(m_outputs.at(input_counter), context );
97 auto outDecisions = outputHandle.ptr();
98 auto inputHandle = SG::makeHandle( m_inputs.at(input_counter), context );
99 if ( inputHandle.isValid() ) {
100
101 for (const Decision* inputDecision : *inputHandle) {
102 auto thisEL = TrigCompositeUtils::decisionToElementLink(inputDecision, context);
103
104 // from all positive decision in the input only the ones that survived counting are passed over
105 const DecisionIDContainer& common = passedDecisionIDs(inputDecision, passing);
106
107 // check if this EL is in the combination map for the passing decIDs:
108 ATH_MSG_DEBUG("Searching this element in the map: ("<<thisEL.dataID() << " , " << thisEL.index()<<")");
109 DecisionIDContainer finalIds;
110 for (const DecisionID c : common){
111 const HLT::Identifier cID = HLT::Identifier(c);
112 // add the decID only if this candidate passed the combination selection
113 const std::vector<ElementLink<DecisionContainer>>& Comb=passingLegs.at(c);
114 if(std::find(Comb.begin(), Comb.end(), thisEL) == Comb.end()) {
115 continue;
116 }
117 ATH_MSG_DEBUG(" Adding "<< cID <<" because EL is found in the passingLegs map");
118 finalIds.insert( cID.numeric() ); // all Ids used by the Filter, including legs
119 if (TrigCompositeUtils::isLegId ( cID )){
120 const HLT::Identifier mainChain = TrigCompositeUtils::getIDFromLeg( cID );
121 finalIds.insert( mainChain.numeric() );
122 ATH_MSG_DEBUG(" Adding "<< mainChain <<" consequently");
123 }
124 }
125
126 Decision* newDec = newDecisionIn( outDecisions, inputDecision, comboHypoAlgNodeName(), context );
127 ATH_MSG_DEBUG("New decision (Container Index:" << input_counter << ", Element Index:"<< newDec->index() <<") has "
129 << " valid initialRoI, "<< TrigCompositeUtils::getLinkToPrevious(newDec).size() <<" previous decisions and "<<finalIds.size()<<" decision IDs") ;
130 insertDecisionIDs( finalIds, newDec );
131
132 }
133 }
134
135 if (msgLvl(MSG::DEBUG)) {
136 ATH_MSG_DEBUG("Output Handle " << m_outputs.at(input_counter).key() << " with " << outputHandle->size() <<" Decision objects");
137 for (const Decision* d : *outputHandle){
138 DecisionIDContainer objDecisions;
139 decisionIDs( d, objDecisions );
140 ATH_MSG_DEBUG(" Decision object #" << d->index() << " with " << objDecisions.size()<<" positive decision IDs");
141 for (const TrigCompositeUtils::DecisionID id : objDecisions ) {
142 ATH_MSG_DEBUG(" --- Passes: " << HLT::Identifier( id ));
143 }
144 }
145 }
146 }
147
148 return StatusCode::SUCCESS;
149}
150
151
152StatusCode ComboHypo::execute(const EventContext& context ) const {
153 ATH_MSG_DEBUG( "Executing " << name() << "..." );
154
155 // it maps decidionID to the combinations (list of dec object) that passed that ID
156 Combo::LegDecisionsMap dmap;
157 ATH_CHECK( fillDecisionsMap( dmap, context ) );
158
159 //this is added for saving good combinations for the hypocombo tools
160 Combo::LegDecisionsMap passingLegs;
161
162
163 // loop over all chains in the mult-map
164 for ( const auto& [chainName, multiplicityPerLeg] : m_multiplicitiesReqMap ) {
165 const HLT::Identifier chainId = HLT::Identifier(chainName);
166 const DecisionID requiredDecisionID = chainId.numeric();
167
168 DecisionIDContainer allDecisionIds;
169 allDecisionIds.insert(requiredDecisionID);
170
171 bool overallDecision = true;
172
173 std::vector< SG::SGKeySet > legFeatureHashes;
174 legFeatureHashes.resize( multiplicityPerLeg.size() );
175 SG::sgkey_t passthroughCounter = 0;
176
177 Combo::LegDecisionsMap thisChainCombMap;
178
179 // This map records the history for any given feature.
180 // E.g. for a key corresponding to a 4th Step muon, the entries in the payload std::set will be the 3rd step, 2nd step and 1st step
181 // features from within the same ROI.
182 //
183 // Using this information the combo hypo is able to deduce that a 4th-step-muon and its prior 2nd-step-muon should not be considered as two distinct candidates.
184 //
185 // Such a check is needed when implementing tag-and-probe style chains as when performing the probe processing we will be comparing 1st, 2nd, 3rd,. etc.
186 // step features on the probe leg to final-step features on the tag leg.
187 SG::SGKeyMap<std::set<uint32_t>> priorFeaturesMap;
188
189 // Check multiplicity of each leg of this chain
190 for ( size_t legIndex = 0; legIndex < multiplicityPerLeg.size(); ++legIndex ) {
191 const size_t requiredMultiplicity = multiplicityPerLeg.at( legIndex );
192
193 HLT::Identifier legId = chainId;
194 // If there is only one leg, then we just use the chain's name.
195 if (multiplicityPerLeg.size() > 1) {
196 ATH_MSG_DEBUG(chainId << " has multiplicityPerLeg.size() > 1, so we use legXXX_HLT_YYY, instead of HLT_YYY");
197 legId = TrigCompositeUtils::createLegName(chainName, legIndex);
198 }
199
200 const DecisionID requiredDecisionIDLeg = legId.numeric();
201 ATH_MSG_DEBUG("Container " << legIndex << ", looking at leg : " << legId );
202
203 Combo::LegDecisionsMap::const_iterator it = dmap.find(requiredDecisionIDLeg);
204 if ( it == dmap.end() ) {
205 continue;
206 }
207
208 // Check the total number of decision objects we have available on this leg from which to satisfy its multiplicity requirement
209 const size_t nLegDecisionObjects = it->second.size();
210
211 ATH_MSG_DEBUG( "Will attempt to meet the required multiplicity of " << requiredMultiplicity << " for leg " << legId
212 << " with " << nLegDecisionObjects << " Decision Objects in leg " << legIndex << " of " << legId);
213
214 // We extract unique passing features on the leg, if there are no features yet - then the L1 ROI is used as a fall-back feature
215 // A special behaviour is that if this fall-back activates, and the L1 ROI is a full-scan ROI, then the leg is assumed valid.
216 // This is regardless of whether or not other legs also use the same FS ROI. Regardless of if the leg's required multiplicity.
217 // This keeps the leg alive until the actual FS reconstruction may occur. At which point, the following ComboHypo will begin
218 // to cut on the actual reconstructed physics objects.
219 //
220 // The behaviour may also be kept even after we have started to process a leg through HypoAlgs. This is done by the HypoAlg
221 // setting the "feature" to be the same as the initialRoI. The initialRoI must still be a FullScan ROI for this to work.
222 //
223 // Finally, the same behaviour may also be triggered by the HypoAlg adding an an int32_t decoration called "noCombo" with value 1
224 // to the Decision Object.
225
226 for (const ElementLink<DecisionContainer>& dEL : it->second){
227 SG::sgkey_t featureKey = 0; // The container hash of the DecisionObject's most-recent feature, and its initial ROI
228 SG::sgkey_t roiKey = 0;
229 Decision::index_type featureIndex = 0, roiIndex = 0; // The container index of the DecisionObject's most-recent feature, and its initial ROI
230 bool roiIsFullscan = false; // Will be set to true if the DecisionObject's initial ROI is flagged as FullScan
231 bool objectRequestsNoMultiplicityCheck = false; // Will be set to true if the object has been flagged as independently satisfying all requirements on a leg
232 ATH_CHECK( extractFeatureAndRoI(it->first, dEL, featureKey, featureIndex, roiKey, roiIndex, roiIsFullscan, objectRequestsNoMultiplicityCheck, priorFeaturesMap) );
233 const bool theFeatureIsTheROI = (SG::sgkeyEqual (featureKey, roiKey) and featureIndex == roiIndex); // The user explicitly set the feature === the RoI
234 const bool thereIsNoFeatureYet = (featureKey == 0 and roiKey != 0); // The leg has not yet started to process
235 if (objectRequestsNoMultiplicityCheck or (roiIsFullscan and (theFeatureIsTheROI or thereIsNoFeatureYet))) {
236 // This passthroughCounter integer is being to generate unique "hash" values to allow Jets or FS ROI to meet the multiplicity requirements of this leg
237 for (size_t i = 0; i < requiredMultiplicity; ++i) {
238 legFeatureHashes.at( legIndex ).insert( ++passthroughCounter );
239 ATH_MSG_DEBUG(" -- Add feature hash '" << passthroughCounter << "' to leg " << legIndex
240 << ". (Note: unique passing hash generated from " << (objectRequestsNoMultiplicityCheck ? "an object requesting NO multiplicity checks" : "an FullScan ROI") << ")");
241 }
242 } else {
243 const SG::sgkey_t uniquenessHash = (featureKey != 0 ? (featureKey + featureIndex) : (roiKey + roiIndex));
244 legFeatureHashes.at( legIndex ).insert( uniquenessHash );
245 ATH_MSG_DEBUG(" -- Add feature hash '" << uniquenessHash << "' to leg " << legIndex << ".");
246 }
247 }
248
249 // save combinations of all legs for the tools
250 thisChainCombMap.insert (*it);
251 allDecisionIds.insert(requiredDecisionIDLeg);
252
253 } // end loop over legIndex
254
255 // Up-cast any features which are actually earlier-step versions of other features (see priorFeaturesMap above)
256 // to be considered as equivalent to the later step version, note that this is for combo uniqueness comparison purposes only.
257 for (SG::SGKeySet& legHashes : legFeatureHashes) {
258 // We will continue to up-cast a single feature at a time in each leg's set of features, until no more upcast opportunities are available.
259 size_t emergencyBreak = 0;
260 while (true) {
261 bool somethingChanged = false;
262 for (const SG::sgkey_t legHash : legHashes) {
263 for (auto const& [key, payloadSet] : priorFeaturesMap) {
264 if (payloadSet.count(legHash) == 1) {
265 ATH_MSG_DEBUG("Feature hash=" << legHash << " identified as a prior feature of hash=" << key
266 << ", we will up-cast this hash to the later version for ComboHypo uniqueness comparison purposes.");
267 legHashes.erase(legHash);
268 legHashes.insert(key);
269 // CAUTION we have mutated a set we're iterating over. We must now break out of the loop over legHashes. This requires two breaks.
270 // This also lets the upcast cascade, i.e. what we insert as 'key' here could trigger another up-cast when considered as 'legHash' in the next iteration of the while(true) loop.
271 somethingChanged = true;
272 break;
273 }
274 } // End inner for loop (over priorFeaturesMap)
275 if (somethingChanged) {
276 break; // Break out of the outer loop when something changes, this avoids a continued invalid iteration over a mutated container.
277 }
278 } // End outer for loop (over legHashes)
279 if (!somethingChanged or ++emergencyBreak == 500) {
280 if (emergencyBreak == 500) {
281 ATH_MSG_WARNING("ComboHypo emergency loop break activated!");
282 }
283 break; // Break out of the while(true) loop when all elements of legHashes have been checked and none were upcast
284 }
285 }
286 } // Loop over the different legs
287
288 // Remove any duplicated features which are shared between legs.
289 // Keep the feature only in the leg which can afford to lose the least number of object, given its multiplicity requirement.
290 // FIXME: The order in which we iterate over allFeatureHashes can
291 // affect the trigger results. But OK not to use SGKeySet here,
292 // since any duplicates will already have been removed
293 // in legFeatureHashes.
294 std::set<SG::sgkey_t> allFeatureHashes;
295 for (const SG::SGKeySet& legHashes : legFeatureHashes) {
296 allFeatureHashes.insert(legHashes.begin(), legHashes.end());
297 }
298 for (const SG::sgkey_t featureHash : allFeatureHashes) {
299 size_t legsWithHash = 0;
300 size_t keepLegIndex = 0;
301 int32_t keepLegMargin = std::numeric_limits<int32_t>::max();
302 for (size_t legIndex = 0; legIndex < multiplicityPerLeg.size(); ++legIndex) {
303 if (legFeatureHashes.at(legIndex).count(featureHash) == 0) {
304 continue;
305 }
306 ++legsWithHash;
307 const int32_t requiredMultiplicity = multiplicityPerLeg.at(legIndex);
308 const int32_t currentMultiplicity = legFeatureHashes.at(legIndex).size();
309 const int32_t safetyMargin = currentMultiplicity - requiredMultiplicity; // Signed, if -ve then the chain has already been failed by the leg at legIndex
310 if (safetyMargin < keepLegMargin) {
311 keepLegMargin = safetyMargin;
312 keepLegIndex = legIndex;
313 }
314 }
315 if (legsWithHash == 1) {
316 continue;
317 }
318 // If a feature is found on multiple legs, then remove it from all but the leg which can afford to lose it the least
319 for (size_t legIndex = 0; legIndex < multiplicityPerLeg.size(); ++legIndex) {
320 if (legIndex == keepLegIndex) {
321 ATH_MSG_DEBUG("Keeping feature hash '" << featureHash << "', on leg " << legIndex << ". This leg can least afford to lose it. "
322 << "Leg has " << legFeatureHashes.at(legIndex).size()
323 << " features, and a multiplicity requirement of " << multiplicityPerLeg.at(legIndex));
324 continue;
325 }
326 if (legFeatureHashes.at(legIndex).erase(featureHash)) {
327 ATH_MSG_DEBUG("Removed duplicate feature hash '" << featureHash << "', from leg " << legIndex << ". Leg now has " << legFeatureHashes.at(legIndex).size()
328 << " remaining features, and a multiplicity requirement of " << multiplicityPerLeg.at(legIndex));
329 }
330 }
331 }
332
333 //check that the multiplicity of unique features is high enough
334 for (size_t legIndex = 0; legIndex < multiplicityPerLeg.size(); ++legIndex) {
335 const size_t requiredMultiplicity = multiplicityPerLeg.at(legIndex);
336 const size_t currentMultiplicity = legFeatureHashes.at(legIndex).size();
337 if (currentMultiplicity < requiredMultiplicity) {
338 ATH_MSG_DEBUG("Leg " << legIndex << " fails multiplicity check. Required unique features:" << requiredMultiplicity << ", found unique features: " << currentMultiplicity);
339 overallDecision = false;
340 break;
341 }
342 }
343
344 //Overall chain decision
345 ATH_MSG_DEBUG( "Chain " << chainId << ( overallDecision ? " is accepted" : " is rejected") <<" after multiplicity requirements" );
346 if ( overallDecision == true ) {
347 for (auto decID: allDecisionIds) {
348 // saving the good combinations
349 passingLegs.insert (thisChainCombMap.begin(), thisChainCombMap.end());
350 ATH_MSG_DEBUG(" Passing " << HLT::Identifier(decID)<<" after multiplicity test");
351 }
352 }
353 }
354
355 if (passingLegs.size()!=0){
356 // launching the tools:
358 for ( auto& tool: m_hypoTools ) {
359 ATH_MSG_DEBUG( "Calling tool "<<tool->name());
360 ATH_CHECK( tool->decide( passingLegs, context ) );
361 }
362 }
363
364 // this is only for debug:
365 if (msgLvl(MSG::DEBUG)){
366 for (auto const& [id, decisions] : passingLegs) {
367 ATH_MSG_DEBUG("" << (decisions.empty() ? "failing " : "passing "+std::to_string(decisions.size())+" decisions ") << id );
368 }
369 }
370
371 // need to pass all combinations, since not all element pass the decID
372 ATH_CHECK( copyDecisions( passingLegs, context ) );
373
374 return StatusCode::SUCCESS;
375}
376
377
380 SG::sgkey_t& featureKey,
381 Decision::index_type& featureIndex,
382 SG::sgkey_t& roiKey,
383 Decision::index_type& roiIndex,
384 bool& roiIsFullscan,
385 bool& objectRequestsNoMultiplicityCheck,
386 SG::SGKeyMap<std::set<uint32_t>>& priorFeaturesMap) const
387{
388 // Return collections for the findLinks call.
389 // While we will be focusing on the most recent feature, for tag-and-probe we need to keep a record of the features from the prior steps too.
390
391 // Construct a sub-graph following just this leg back through the nav
392 DecisionIDContainer chainLegIdSet = {chainLegId.numeric()};
394 recursiveGetDecisions((*dEL), subGraph, chainLegIdSet, /*enforceDecisionOnStartNode =*/ true);
395
396 if (subGraph.finalNodes().size() != 1) {
397 ATH_MSG_ERROR("We are only expecting to search from a single navigation node in extractFeatureAndRoI");
398 return StatusCode::FAILURE;
399 }
400 const NavGraphNode* start = *(subGraph.finalNodes().begin());
401
402 std::vector<SG::sgkey_t> keys;
403 std::vector<uint32_t> clids; // We don't care about the class ID. This part gets ignored.
404 std::vector<Decision::index_type> indicies;
405 std::vector<const Decision*> sources;
406
407 std::set<const Decision*> fullyExploredFrom; // This is a cache which typelessFindLinks will use to avoid re-visiting already explored regions of the graph
408 // Note: This call to typelessFindLinks is exploring from a NavGraphNode* rather than a Decision*,
409 // this indicates that the search is restricted to a sub-graph (specifically, only following one chain-leg)
410 const bool foundFeature = typelessFindLinks(start, featureString(), keys, clids, indicies, sources, TrigDefs::allFeaturesOfType, &fullyExploredFrom);
411
412 const Decision* featureSource = nullptr;
413 // The "most recent" feature (from the step just run) is the one we find first. Hence it's at index 0
414 if (foundFeature) {
415 featureKey = keys.at(0);
416 featureIndex = indicies.at(0);
417 featureSource = sources.at(0);
418 }
419
420 objectRequestsNoMultiplicityCheck = (featureSource and featureSource->hasDetail<int32_t>("noCombo") and featureSource->getDetail<int32_t>("noCombo") == 1);
421
422 if (foundFeature and priorFeaturesMap.count(featureKey + featureIndex) == 0) {
423 const std::string* key_str = evtStore()->keyToString(featureKey);
424 ATH_MSG_DEBUG("Note: Will use feature hash " << featureKey + featureIndex << ", for " << (key_str ? *key_str : "UNKNOWN") << " index=" << featureIndex);
425 // Use the deep-search data to look further back than .at(0)
426 // Here's where we keep the record of the features in previous steps. Step ordering is unimportant, we can use a set.
427 if (keys.size() > 1) {
428 for (size_t i = 1; i < keys.size(); ++i) { // Skip the 1st entry, this will be equal to featureKey and featureIndex from typelessFindLink above.
429 // featureKey + featureIndex should be considered as equivalent to a per-feature hash (featureKey is a real hash, featureIndex is an offset index)
430 if (featureKey + featureIndex == keys.at(i) + indicies.at(i)) {
431 continue; // Do not add the case where a feature is re-attached to more than one step.
432 }
433 priorFeaturesMap[featureKey + featureIndex].insert(keys.at(i) + indicies.at(i));
434 }
435 } else { // Exactly one feature. Make a note of this by inserting an empty set, such that we don't do this search again.
436 priorFeaturesMap.insert( std::pair<uint32_t, std::set<uint32_t>>(featureKey + featureIndex, std::set<uint32_t>()) );
437 }
438 }
439
440 // Try and get seeding ROI data too.
441 uint32_t roiClid{0}; // Unused
442 const Decision* roiSource{nullptr}; // Unused
443 const bool foundROI = typelessFindLink(subGraph, initialRoIString(), roiKey, roiClid, roiIndex, roiSource);
444 if (foundROI) {
445 ElementLink<TrigRoiDescriptorCollection> roiEL(roiKey, roiIndex);
446 ATH_CHECK( roiEL.isValid() );
447 roiIsFullscan = (*(roiEL))->isFullscan();
448 if (!foundFeature) {
449 const std::string* roi_str = evtStore()->keyToString(roiKey);
450 ATH_MSG_DEBUG("Note: Located fallback-ROI, if used this will have feature hash =" << roiKey + roiIndex << ", for " << (roi_str ? *roi_str : "UNKNOWN") << " index=" << roiIndex);
451 }
452 }
453
454 if (!foundFeature && !foundROI) {
455 ATH_MSG_WARNING("Did not find the feature or initialRoI for " << dEL.dataID() << " index " << dEL.index());
456 }
457
458 return StatusCode::SUCCESS;
459}
460
461
462StatusCode ComboHypo::fillDecisionsMap( Combo::LegDecisionsMap & dmap, const EventContext& context) const {
463 for ( size_t inputContainerIndex = 0; inputContainerIndex < m_inputs.size(); ++inputContainerIndex ) {
464 auto inputHandle = SG::makeHandle( m_inputs.at(inputContainerIndex), context );
465 if ( !inputHandle.isValid() ) {
466 ATH_MSG_ERROR( "No input ReadHandle from " << inputHandle.key() );
467 return StatusCode::FAILURE;
468 }
469 ATH_MSG_DEBUG( "-- Found ReadHandle from " << inputHandle.key() <<" with "<< inputHandle->size() << " elements:" );
470 for ( const Decision* decision : *inputHandle ) {
471 ATH_MSG_DEBUG( "-- -- Input Decision #"<< decision->index() <<" with "<< decisionIDs( decision ).size() << " active IDs. Populating the multiplicity map:" );
472 for ( const DecisionID id: decisionIDs( decision ) ) {
473
474 // Handles regular and multi-leg case
475 const auto& [chainName, chainLeg] = getNameAndIndexFromLeg(HLT::Identifier(id).name());
476
477 // We need to check if we are configured to accept DecisionObjects passing 'chainName' ...
478 Combo::LegMap::const_iterator it = m_legToInputCollectionMap.find(chainName);
479 if (it == m_legToInputCollectionMap.end()) {
480 ATH_MSG_VERBOSE("-- -- -- Ignoring the DecsionID " << id << " on leg " << chainLeg << " as it does not correspond to any of the " << m_legToInputCollectionMap.size() << " chains this Alg is processing.");
481 continue;
482 }
483
484 // ... and if so we need to further check that we are accepting passing IDs for chainLeg on the current inputContainerIndex
485 const std::vector<int>& legToInputCollectionIndex = it->second;
486 const size_t requiredInputContainerIndex = static_cast<size_t>(legToInputCollectionIndex.at(chainLeg));
487 if (requiredInputContainerIndex != inputContainerIndex) {
488 ATH_MSG_VERBOSE("-- -- -- Ignoring the DecisionID " << id << " on leg " << chainLeg << " as we are only permitted to accept passing objects on leg #" << chainLeg << " of " << chainName
489 << " which come from input collection index " << requiredInputContainerIndex << " (which is " << m_inputs.at(requiredInputContainerIndex).key() << ")"
490 << ". Not the current index " << inputContainerIndex << " (which is " << m_inputs.at(inputContainerIndex).key() << ")");
491 continue;
492 }
493
494 ATH_MSG_DEBUG( " ++++ " << HLT::Identifier( id ) );
495 dmap[id].push_back( TrigCompositeUtils::decisionToElementLink(decision, context) );
496 }
497 }
498 }
499
500 if (msgLvl(MSG::DEBUG)){
501 ATH_MSG_DEBUG( "Decision map filled :" );
502 size_t legCount = 0;
503 for (const auto& entry: dmap){
504 ATH_MSG_DEBUG("leg ["<<legCount<<"]: ");
505 const std::vector<ElementLink<DecisionContainer>>& decisions = entry.second;
506 ATH_MSG_DEBUG(" ++++ " << HLT::Identifier( entry.first ) <<" Number Decisions: "<< decisions.size());
507 for (const ElementLink<DecisionContainer>& d : decisions){
508 ATH_MSG_DEBUG(" Decision: (ContainerKey:"<<d.dataID()<<", DecisionElementIndex:"<<d.index()<<")");
509 }
510 legCount++;
511 }
512 }
513
514
515 return StatusCode::SUCCESS;
516}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
bool isValid(const T &p)
Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.
Definition AtlasPID.h:878
static Double_t a
bool msgLvl(const MSG::Level lvl) const
An algorithm that can be simultaneously executed in multiple threads.
ComboHypo(const std::string &name, ISvcLocator *pSvcLocator)
Definition ComboHypo.cxx:13
StatusCode extractFeatureAndRoI(const HLT::Identifier &chainLegId, const ElementLink< TrigCompositeUtils::DecisionContainer > &EL, SG::sgkey_t &featureKey, TrigCompositeUtils::Decision::index_type &featureIndex, SG::sgkey_t &roiKey, TrigCompositeUtils::Decision::index_type &roiIndex, bool &roiFullscan, bool &objectRequestsNoMultiplicityCheck, SG::SGKeyMap< std::set< uint32_t > > &priorFeaturesMap) const
For a given Decision node from a HypoAlg, extracts type-less identification data on the node's Featur...
StatusCode copyDecisions(const Combo::LegDecisionsMap &passingLegs, const EventContext &context) const
iterates over the inputs and for every object (no filtering) crates output object linked to input mov...
Definition ComboHypo.cxx:86
Gaudi::Property< Combo::MultiplicityReqMap > m_multiplicitiesReqMap
Definition ComboHypo.h:56
virtual StatusCode execute(const EventContext &context) const override
virtual ~ComboHypo() override
Definition ComboHypo.cxx:18
SG::WriteHandleKeyArray< TrigCompositeUtils::DecisionContainer > m_outputs
Definition ComboHypo.h:51
Gaudi::Property< Combo::LegMap > m_legToInputCollectionMap
Definition ComboHypo.h:59
StatusCode fillDecisionsMap(Combo::LegDecisionsMap &dmap, const EventContext &context) const
iterates over all inputs, associating inputs to legs
Gaudi::Property< bool > m_checkMultiplicityMap
Definition ComboHypo.h:62
SG::ReadHandleKeyArray< TrigCompositeUtils::DecisionContainer > m_inputs
Definition ComboHypo.h:50
ToolHandleArray< ComboHypoToolBase > m_hypoTools
Definition ComboHypo.h:104
virtual StatusCode initialize() override
Definition ComboHypo.cxx:22
TrigCompositeUtils::DecisionID numeric() const
numeric ID
size_t index() const
Return the index of this element within its container.
pointer_type ptr()
Dereference the pointer.
Transient utility class to represent a node in a graph (m_decisionObject), and a vector of edges (m_f...
Definition NavGraph.h:20
Structure to hold a transient Directed Acyclic Graph (DAG) structure.
Definition NavGraph.h:111
const std::vector< NavGraphNode * > & finalNodes() const
Get all final nodes.
Definition NavGraph.cxx:99
bool hasDetail(const std::string &name) const
Check if a given type of detail is available.
bool getDetail(const std::string &name, TYPE &value) const
Get an TYPE detail from the object.
uint32_t sgkey_t
Type used for hashed StoreGate key+CLID pairs.
Definition sgkey_t.h:32
std::unordered_set< sgkey_t > SGKeySet
A set of sgkey_t values.
Definition sgkey_t.h:97
constexpr bool sgkeyEqual(const sgkey_t a, const sgkey_t b)
Compare two sgkeys for equality.
Definition sgkey_t.h:39
std::unordered_map< sgkey_t, T > SGKeyMap
A map using sgkey_t as a key.
Definition sgkey_t.h:93
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
HLT::Identifier createLegName(const HLT::Identifier &chainIdentifier, size_t counter)
Generate the HLT::Identifier which corresponds to a specific leg of a given chain.
unsigned int DecisionID
void insertDecisionIDs(const Decision *src, Decision *dest)
Appends the decision IDs of src to the dest decision object.
Decision * newDecisionIn(DecisionContainer *dc, const std::string &name)
Helper method to create a Decision object, place it in the container and return a pointer to it.
const std::vector< ElementLink< DecisionContainer > > getLinkToPrevious(const Decision *d)
returns links to previous decision object 'seed'
DecisionIDContainer passedDecisionIDs(const Decision *d, const T &required)
return DecisionIDs in Decision object that match the required ones
const std::string & featureString()
void recursiveGetDecisions(const Decision *start, NavGraph &navGraph, const DecisionIDContainer &ids, const bool enforceDecisionOnStartNode)
Search back in time from "node" and locate all paths back through Decision objects for a given chain.
HLT::Identifier getIDFromLeg(const HLT::Identifier &legIdentifier)
Generate the HLT::Identifier which corresponds to the chain name from the leg name.
const std::string & comboHypoAlgNodeName()
std::set< DecisionID > DecisionIDContainer
SG::WriteHandle< DecisionContainer > createAndStore(const SG::WriteHandleKey< DecisionContainer > &key, const EventContext &ctx)
Creates and right away records the DecisionContainer with the key.
LinkInfo< T > findLink(const Decision *start, const std::string &linkName, const bool suppressMultipleLinksWarning=false)
Perform a recursive search for ElementLinks of type T and name 'linkName', starting from Decision obj...
const std::string & initialRoIString()
std::pair< std::string, int32_t > getNameAndIndexFromLeg(const std::string &name)
Extract the name and numeric index of a leg identifier.
bool typelessFindLinks(const Decision *start, const std::string &linkName, std::vector< sgkey_t > &keyVec, std::vector< CLID > &clidVec, std::vector< Decision::index_type > &indexVec, std::vector< const Decision * > &sourceVec, const unsigned int behaviour, std::set< const Decision * > *fullyExploredFrom)
search back the TC links for the object of type T linked to the one of TC (recursively) Returns the l...
void decisionIDs(const Decision *d, DecisionIDContainer &destination)
Extracts DecisionIDs stored in the Decision object.
ElementLink< DecisionContainer > decisionToElementLink(const Decision *d, const EventContext &ctx)
Takes a raw pointer to a Decision and returns an ElementLink to the Decision.
bool isLegId(const HLT::Identifier &legIdentifier)
Recognise whether the chain ID is a leg ID.
bool typelessFindLink(const Decision *start, const std::string &linkName, sgkey_t &key, CLID &clid, Decision::index_type &index, const Decision *&source, const bool suppressMultipleLinksWarning)
Perform a recursive search for ElementLinks of any time and name 'linkName', starting from Decision o...
static const unsigned int allFeaturesOfType
Run 3 "enum". Return all features along legs (still with type and container checks)