ATLAS Offline Software
ComboHypo.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 
8 #include "AthViews/View.h"
9 #include <sstream>
10 
11 using namespace TrigCompositeUtils;
12 
13 ComboHypo::ComboHypo(const std::string& name, ISvcLocator* pSvcLocator)
14 : ::AthReentrantAlgorithm(name, pSvcLocator)
15 {}
16 
17 
19 {}
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 
86 StatusCode 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 "
128  << (TrigCompositeUtils::findLink<TrigRoiDescriptorCollection>(newDec, initialRoIString())).isValid()
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 
152 StatusCode 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
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& m : m_multiplicitiesReqMap ) {
165  const HLT::Identifier chainId = HLT::Identifier(m.first);
166  const std::vector<int>& multiplicityPerLeg = m.second;
167  const DecisionID requiredDecisionID = chainId.numeric();
168 
169  DecisionIDContainer allDecisionIds;
170  allDecisionIds.insert(requiredDecisionID);
171 
172  bool overallDecision = true;
173 
174  std::vector< SG::SGKeySet > legFeatureHashes;
175  legFeatureHashes.resize( multiplicityPerLeg.size() );
176  SG::sgkey_t passthroughCounter = 0;
177 
178  Combo::LegDecisionsMap thisChainCombMap;
179 
180  // This map records the history for any given feature.
181  // 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
182  // features from within the same ROI.
183  //
184  // 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.
185  //
186  // 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.
187  // step features on the probe leg to final-step features on the tag leg.
188  SG::SGKeyMap<std::set<uint32_t>> priorFeaturesMap;
189 
190  // Check multiplicity of each leg of this chain
191  for ( size_t legIndex = 0; legIndex < multiplicityPerLeg.size(); ++legIndex ) {
192  const size_t requiredMultiplicity = multiplicityPerLeg.at( legIndex );
193 
194  HLT::Identifier legId = chainId;
195  // If there is only one leg, then we just use the chain's name.
196  if (multiplicityPerLeg.size() > 1) {
197  ATH_MSG_DEBUG(chainId << " has multiplicityPerLeg.size() > 1, so we use legXXX_HLT_YYY, instead of HLT_YYY");
198  legId = TrigCompositeUtils::createLegName(chainId, legIndex);
199  }
200 
201  const DecisionID requiredDecisionIDLeg = legId.numeric();
202  ATH_MSG_DEBUG("Container " << legIndex << ", looking at leg : " << legId );
203 
204  Combo::LegDecisionsMap::const_iterator it = dmap.find(requiredDecisionIDLeg);
205  if ( it == dmap.end() ) {
206  continue;
207  }
208 
209  // Check the total number of decision objects we have available on this leg from which to satisfy its multiplicity requirement
210  const size_t nLegDecisionObjects = it->second.size();
211 
212  ATH_MSG_DEBUG( "Will attempt to meet the required multiplicity of " << requiredMultiplicity << " for leg " << legId
213  << " with " << nLegDecisionObjects << " Decision Objects in leg " << legIndex << " of " << legId);
214 
215  // 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
216  // 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.
217  // This is regardless of whether or not other legs also use the same FS ROI. Regardless of if the leg's required multiplicity.
218  // This keeps the leg alive until the actual FS reconstruction may occur. At which point, the following ComboHypo will begin
219  // to cut on the actual reconstructed physics objects.
220  //
221  // The behaviour may also be kept even after we have started to process a leg through HypoAlgs. This is done by the HypoAlg
222  // setting the "feature" to be the same as the initialRoI. The initialRoI must still be a FullScan ROI for this to work.
223  //
224  // Finally, the same behaviour may also be triggered by the HypoAlg adding an an int32_t decoration called "noCombo" with value 1
225  // to the Decision Object.
226 
227  for (const ElementLink<DecisionContainer>& dEL : it->second){
228  SG::sgkey_t featureKey = 0; // The container hash of the DecisionObject's most-recent feature, and its initial ROI
229  SG::sgkey_t roiKey = 0;
230  Decision::index_type featureIndex = 0, roiIndex = 0; // The container index of the DecisionObject's most-recent feature, and its initial ROI
231  bool roiIsFullscan = false; // Will be set to true if the DecisionObject's initial ROI is flagged as FullScan
232  bool objectRequestsNoMultiplicityCheck = false; // Will be set to true if the object has been flagged as independently satisfying all requirements on a leg
233  ATH_CHECK( extractFeatureAndRoI(it->first, dEL, featureKey, featureIndex, roiKey, roiIndex, roiIsFullscan, objectRequestsNoMultiplicityCheck, priorFeaturesMap) );
234  const bool theFeatureIsTheROI = (SG::sgkeyEqual (featureKey, roiKey) and featureIndex == roiIndex); // The user explicitly set the feature === the RoI
235  const bool thereIsNoFeatureYet = (featureKey == 0 and roiKey != 0); // The leg has not yet started to process
236  if (objectRequestsNoMultiplicityCheck or (roiIsFullscan and (theFeatureIsTheROI or thereIsNoFeatureYet))) {
237  // This passthroughCounter integer is being to generate unique "hash" values to allow Jets or FS ROI to meet the multiplicity requirements of this leg
238  for (size_t i = 0; i < requiredMultiplicity; ++i) {
239  legFeatureHashes.at( legIndex ).insert( ++passthroughCounter );
240  ATH_MSG_DEBUG(" -- Add feature hash '" << passthroughCounter << "' to leg " << legIndex
241  << ". (Note: unique passing hash generated from " << (objectRequestsNoMultiplicityCheck ? "an object requesting NO multiplicity checks" : "an FullScan ROI") << ")");
242  }
243  } else {
244  const SG::sgkey_t uniquenessHash = (featureKey != 0 ? (featureKey + featureIndex) : (roiKey + roiIndex));
245  legFeatureHashes.at( legIndex ).insert( uniquenessHash );
246  ATH_MSG_DEBUG(" -- Add feature hash '" << uniquenessHash << "' to leg " << legIndex << ".");
247  }
248  }
249 
250  // save combinations of all legs for the tools
251  thisChainCombMap.insert (*it);
252  allDecisionIds.insert(requiredDecisionIDLeg);
253 
254  } // end loop over legIndex
255 
256  // Up-cast any features which are actually earlier-step versions of other features (see priorFeaturesMap above)
257  // to be considered as equivalent to the later step version, note that this is for combo uniqueness comparison purposes only.
258  for (SG::SGKeySet& legHashes : legFeatureHashes) {
259  // 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.
260  size_t emergencyBreak = 0;
261  while (true) {
262  bool somethingChanged = false;
263  for (const SG::sgkey_t legHash : legHashes) {
264  for (auto const& [key, payloadSet] : priorFeaturesMap) {
265  if (payloadSet.count(legHash) == 1) {
266  ATH_MSG_DEBUG("Feature hash=" << legHash << " identified as a prior feature of hash=" << key
267  << ", we will up-cast this hash to the later version for ComboHypo uniqueness comparison purposes.");
268  legHashes.erase(legHash);
269  legHashes.insert(key);
270  // CAUTION we have mutated a set we're iterating over. We must now break out of the loop over legHashes. This requires two breaks.
271  // 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.
272  somethingChanged = true;
273  break;
274  }
275  } // End inner for loop (over priorFeaturesMap)
276  if (somethingChanged) {
277  break; // Break out of the outer loop when something changes, this avoids a continued invalid iteration over a mutated container.
278  }
279  } // End outer for loop (over legHashes)
280  if (!somethingChanged or ++emergencyBreak == 500) {
281  if (emergencyBreak == 500) {
282  ATH_MSG_WARNING("ComboHypo emergency loop break activated!");
283  }
284  break; // Break out of the while(true) loop when all elements of legHashes have been checked and none were upcast
285  }
286  }
287  } // Loop over the different legs
288 
289  // Remove any duplicated features which are shared between legs.
290  // Keep the feature only in the leg which can afford to lose the least number of object, given its multiplicity requirement.
291  // FIXME: The order in which we iterate over allFeatureHashes can
292  // affect the trigger results. But OK not to use SGKeySet here,
293  // since any duplicates will already have been removed
294  // in legFeatureHashes.
295  std::set<SG::sgkey_t> allFeatureHashes;
296  for (const SG::SGKeySet& legHashes : legFeatureHashes) {
297  allFeatureHashes.insert(legHashes.begin(), legHashes.end());
298  }
299  for (const SG::sgkey_t featureHash : allFeatureHashes) {
300  size_t legsWithHash = 0;
301  size_t keepLegIndex = 0;
302  int32_t keepLegMargin = std::numeric_limits<int32_t>::max();
303  for (size_t legIndex = 0; legIndex < multiplicityPerLeg.size(); ++legIndex) {
304  if (legFeatureHashes.at(legIndex).count(featureHash) == 0) {
305  continue;
306  }
307  ++legsWithHash;
308  const int32_t requiredMultiplicity = multiplicityPerLeg.at(legIndex);
309  const int32_t currentMultiplicity = legFeatureHashes.at(legIndex).size();
310  const int32_t safetyMargin = currentMultiplicity - requiredMultiplicity; // Signed, if -ve then the chain has already been failed by the leg at legIndex
311  if (safetyMargin < keepLegMargin) {
312  keepLegMargin = safetyMargin;
313  keepLegIndex = legIndex;
314  }
315  }
316  if (legsWithHash == 1) {
317  continue;
318  }
319  // If a feature is found on multiple legs, then remove it from all but the leg which can afford to lose it the least
320  for (size_t legIndex = 0; legIndex < multiplicityPerLeg.size(); ++legIndex) {
321  if (legIndex == keepLegIndex) {
322  ATH_MSG_DEBUG("Keeping feature hash '" << featureHash << "', on leg " << legIndex << ". This leg can least afford to lose it. "
323  << "Leg has " << legFeatureHashes.at(legIndex).size()
324  << " features, and a multiplicity requirement of " << multiplicityPerLeg.at(legIndex));
325  continue;
326  }
327  if (legFeatureHashes.at(legIndex).erase(featureHash)) {
328  ATH_MSG_DEBUG("Removed duplicate feature hash '" << featureHash << "', from leg " << legIndex << ". Leg now has " << legFeatureHashes.at(legIndex).size()
329  << " remaining features, and a multiplicity requirement of " << multiplicityPerLeg.at(legIndex));
330  }
331  }
332  }
333 
334  //check that the multiplicity of unique features is high enough
335  for (size_t legIndex = 0; legIndex < multiplicityPerLeg.size(); ++legIndex) {
336  const size_t requiredMultiplicity = multiplicityPerLeg.at(legIndex);
337  const size_t currentMultiplicity = legFeatureHashes.at(legIndex).size();
338  if (currentMultiplicity < requiredMultiplicity) {
339  ATH_MSG_DEBUG("Leg " << legIndex << " fails multiplicity check. Required unique features:" << requiredMultiplicity << ", found unique features: " << currentMultiplicity);
340  overallDecision = false;
341  break;
342  }
343  }
344 
345  //Overall chain decision
346  ATH_MSG_DEBUG( "Chain " << chainId << ( overallDecision ? " is accepted" : " is rejected") <<" after multiplicity requirements" );
347  if ( overallDecision == true ) {
348  for (auto decID: allDecisionIds) {
349  // saving the good combinations
350  passingLegs.insert (thisChainCombMap.begin(), thisChainCombMap.end());
351  ATH_MSG_DEBUG(" Passing " << HLT::Identifier(decID)<<" after multiplicity test");
352  }
353  }
354  }
355 
356  if (passingLegs.size()!=0){
357  // launching the tools:
359  for ( auto& tool: m_hypoTools ) {
360  ATH_MSG_DEBUG( "Calling tool "<<tool->name());
361  ATH_CHECK( tool->decide( passingLegs, context ) );
362  }
363  }
364 
365  // this is only for debug:
366  if (msgLvl(MSG::DEBUG)){
367  for (auto const& [id, decisions] : passingLegs) {
368  ATH_MSG_DEBUG("" << (decisions.empty() ? "failing " : "passing "+std::to_string(decisions.size())+" decisions ") << id );
369  }
370  }
371 
372  // need to pass all combinations, since not all element pass the decID
373  ATH_CHECK( copyDecisions( passingLegs, context ) );
374 
375  return StatusCode::SUCCESS;
376 }
377 
378 
381  SG::sgkey_t& featureKey,
382  Decision::index_type& featureIndex,
383  SG::sgkey_t& roiKey,
384  Decision::index_type& roiIndex,
385  bool& roiIsFullscan,
386  bool& objectRequestsNoMultiplicityCheck,
387  SG::SGKeyMap<std::set<uint32_t>>& priorFeaturesMap) const
388 {
389  // Return collections for the findLinks call.
390  // 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.
391 
392  // Construct a sub-graph following just this leg back through the nav
393  DecisionIDContainer chainLegIdSet = {chainLegId.numeric()};
395  recursiveGetDecisions((*dEL), subGraph, chainLegIdSet, /*enforceDecisionOnStartNode =*/ true);
396 
397  if (subGraph.finalNodes().size() != 1) {
398  ATH_MSG_ERROR("We are only expecting to search from a single navigation node in extractFeatureAndRoI");
399  return StatusCode::FAILURE;
400  }
401  const NavGraphNode* start = *(subGraph.finalNodes().begin());
402 
403  std::vector<SG::sgkey_t> keys;
404  std::vector<uint32_t> clids; // We don't care about the class ID. This part gets ignored.
405  std::vector<Decision::index_type> indicies;
406  std::vector<const Decision*> sources;
407 
408  std::set<const Decision*> fullyExploredFrom; // This is a cache which typelessFindLinks will use to avoid re-visiting already explored regions of the graph
409  // Note: This call to typelessFindLinks is exploring from a NavGraphNode* rather than a Decision*,
410  // this indicates that the search is restricted to a sub-graph (specifically, only following one chain-leg)
411  const bool foundFeature = typelessFindLinks(start, featureString(), keys, clids, indicies, sources, TrigDefs::allFeaturesOfType, &fullyExploredFrom);
412 
413  const Decision* featureSource = nullptr;
414  // The "most recent" feature (from the step just run) is the one we find first. Hence it's at index 0
415  if (foundFeature) {
416  featureKey = keys.at(0);
417  featureIndex = indicies.at(0);
418  featureSource = sources.at(0);
419  }
420 
421  objectRequestsNoMultiplicityCheck = (featureSource and featureSource->hasDetail<int32_t>("noCombo") and featureSource->getDetail<int32_t>("noCombo") == 1);
422 
423  if (foundFeature and priorFeaturesMap.count(featureKey + featureIndex) == 0) {
424  const std::string* key_str = evtStore()->keyToString(featureKey);
425  ATH_MSG_DEBUG("Note: Will use feature hash " << featureKey + featureIndex << ", for " << (key_str ? *key_str : "UNKNOWN") << " index=" << featureIndex);
426  // Use the deep-search data to look further back than .at(0)
427  // Here's where we keep the record of the features in previous steps. Step ordering is unimportant, we can use a set.
428  if (keys.size() > 1) {
429  for (size_t i = 1; i < keys.size(); ++i) { // Skip the 1st entry, this will be equal to featureKey and featureIndex from typelessFindLink above.
430  // featureKey + featureIndex should be considered as equivalent to a per-feature hash (featureKey is a real hash, featureIndex is an offset index)
431  if (featureKey + featureIndex == keys.at(i) + indicies.at(i)) {
432  continue; // Do not add the case where a feature is re-attached to more than one step.
433  }
434  priorFeaturesMap[featureKey + featureIndex].insert(keys.at(i) + indicies.at(i));
435  }
436  } else { // Exactly one feature. Make a note of this by inserting an empty set, such that we don't do this search again.
437  priorFeaturesMap.insert( std::pair<uint32_t, std::set<uint32_t>>(featureKey + featureIndex, std::set<uint32_t>()) );
438  }
439  }
440 
441  // Try and get seeding ROI data too.
442  uint32_t roiClid{0}; // Unused
443  const Decision* roiSource{nullptr}; // Unused
444  const bool foundROI = typelessFindLink(subGraph, initialRoIString(), roiKey, roiClid, roiIndex, roiSource);
445  if (foundROI) {
446  ElementLink<TrigRoiDescriptorCollection> roiEL(roiKey, roiIndex);
447  ATH_CHECK( roiEL.isValid() );
448  roiIsFullscan = (*(roiEL))->isFullscan();
449  if (!foundFeature) {
450  const std::string* roi_str = evtStore()->keyToString(roiKey);
451  ATH_MSG_DEBUG("Note: Located fallback-ROI, if used this will have feature hash =" << roiKey + roiIndex << ", for " << (roi_str ? *roi_str : "UNKNOWN") << " index=" << roiIndex);
452  }
453  }
454 
455  if (!foundFeature && !foundROI) {
456  ATH_MSG_WARNING("Did not find the feature or initialRoI for " << dEL.dataID() << " index " << dEL.index());
457  }
458 
459  return StatusCode::SUCCESS;
460 }
461 
462 
463 StatusCode ComboHypo::fillDecisionsMap( Combo::LegDecisionsMap & dmap, const EventContext& context) const {
464  for ( size_t inputContainerIndex = 0; inputContainerIndex < m_inputs.size(); ++inputContainerIndex ) {
465  auto inputHandle = SG::makeHandle( m_inputs.at(inputContainerIndex), context );
466  if ( !inputHandle.isValid() ) {
467  ATH_MSG_ERROR( "No input ReadHandle from " << inputHandle.key() );
468  return StatusCode::FAILURE;
469  }
470  ATH_MSG_DEBUG( "-- Found ReadHandle from " << inputHandle.key() <<" with "<< inputHandle->size() << " elements:" );
471  for ( const Decision* decision : *inputHandle ) {
472  ATH_MSG_DEBUG( "-- -- Input Decision #"<< decision->index() <<" with "<< decisionIDs( decision ).size() << " active IDs. Populating the multiplicity map:" );
473  for ( const DecisionID id: decisionIDs( decision ) ) {
474  HLT::Identifier chainID = HLT::Identifier(id);
475  int32_t chainLeg = 0; // Assume initially that the chain is not multi-leg, and update these two values if it is.
476  if (isLegId(id)) {
477  chainID = getIDFromLeg(id);
478  chainLeg = getIndexFromLeg(id);
479  }
480 
481  // We need to check if we are configured to accept DecisionObjects passing 'chainID' ...
482  Combo::LegMap::const_iterator it = m_legToInputCollectionMap.find(chainID.name());
483  if (it == m_legToInputCollectionMap.end()) {
484  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.");
485  continue;
486  }
487 
488  // ... and if so we need to further check that we are accepting passing IDs for chainLeg on the current inputContainerIndex
489  const std::vector<int>& legToInputCollectionIndex = it->second;
490  const size_t requiredInputContainerIndex = static_cast<size_t>(legToInputCollectionIndex.at(chainLeg));
491  if (requiredInputContainerIndex != inputContainerIndex) {
492  ATH_MSG_VERBOSE("-- -- -- Ignoring the DecisionID " << id << " on leg " << chainLeg << " as we are only permitted to accept passing objects on leg #" << chainLeg << " of " << chainID.name()
493  << " which come from input collection index " << requiredInputContainerIndex << " (which is " << m_inputs.at(requiredInputContainerIndex).key() << ")"
494  << ". Not the current index " << inputContainerIndex << " (which is " << m_inputs.at(inputContainerIndex).key() << ")");
495  continue;
496  }
497 
498  ATH_MSG_DEBUG( " ++++ " << HLT::Identifier( id ) );
499  dmap[id].push_back( TrigCompositeUtils::decisionToElementLink(decision, context) );
500  }
501  }
502  }
503 
504  if (msgLvl(MSG::DEBUG)){
505  ATH_MSG_DEBUG( "Decision map filled :" );
506  size_t legCount = 0;
507  for (const auto& entry: dmap){
508  ATH_MSG_DEBUG("leg ["<<legCount<<"]: ");
509  const std::vector<ElementLink<DecisionContainer>>& decisions = entry.second;
510  ATH_MSG_DEBUG(" ++++ " << HLT::Identifier( entry.first ) <<" Number Decisions: "<< decisions.size());
512  ATH_MSG_DEBUG(" Decision: (ContainerKey:"<<d.dataID()<<", DecisionElementIndex:"<<d.index()<<")");
513  }
514  legCount++;
515  }
516  }
517 
518 
519  return StatusCode::SUCCESS;
520 }
ComboHypo::m_multiplicitiesReqMap
Gaudi::Property< Combo::MultiplicityReqMap > m_multiplicitiesReqMap
Definition: ComboHypo.h:56
ComboHypo::extractFeatureAndRoI
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...
Definition: ComboHypo.cxx:379
ComboHypo::copyDecisions
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
python.SystemOfUnits.m
int m
Definition: SystemOfUnits.py:91
TrigCompositeUtils::DecisionID
unsigned int DecisionID
Definition: TrigComposite_v1.h:27
TrigCompositeUtils::recursiveGetDecisions
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.
Definition: TrigCompositeUtilsRoot.cxx:422
find
std::string find(const std::string &s)
return a remapped string
Definition: hcg.cxx:135
HLT::Identifier::numeric
TrigCompositeUtils::DecisionID numeric() const
numeric ID
Definition: TrigCompositeUtils/TrigCompositeUtils/HLTIdentifier.h:47
ComboHypo::fillDecisionsMap
StatusCode fillDecisionsMap(Combo::LegDecisionsMap &dmap, const EventContext &context) const
iterates over all inputs, associating inputs to legs
Definition: ComboHypo.cxx:463
xAOD::uint32_t
setEventNumber uint32_t
Definition: EventInfo_v1.cxx:127
TrigCompositeUtils::newDecisionIn
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.
Definition: TrigCompositeUtilsRoot.cxx:46
hist_file_dump.d
d
Definition: hist_file_dump.py:137
max
constexpr double max()
Definition: ap_fixedTest.cxx:33
TrigCompositeUtils::NavGraph::finalNodes
const std::vector< NavGraphNode * > & finalNodes() const
Get all final nodes.
Definition: NavGraph.cxx:100
mergePhysValFiles.start
start
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:14
python.TrigCompositeUtils.isLegId
def isLegId(chainName)
Definition: DecisionHandling/python/TrigCompositeUtils.py:18
skel.it
it
Definition: skel.GENtoEVGEN.py:396
TrigCompositeUtils::insertDecisionIDs
void insertDecisionIDs(const Decision *src, Decision *dest)
Appends the decision IDs of src to the dest decision object.
Definition: TrigCompositeUtilsRoot.cxx:80
TrigCompositeUtils::passedDecisionIDs
DecisionIDContainer passedDecisionIDs(const Decision *d, const T &required)
return DecisionIDs in Decision object that match the required ones
AthCommonMsg< Gaudi::Algorithm >::msgLvl
bool msgLvl(const MSG::Level lvl) const
Definition: AthCommonMsg.h:30
athena.value
value
Definition: athena.py:124
xAOD::TrigComposite_v1::hasDetail
bool hasDetail(const std::string &name) const
Check if a given type of detail is available.
TrigCompositeUtils::comboHypoAlgNodeName
const std::string & comboHypoAlgNodeName()
Definition: TrigCompositeUtilsRoot.cxx:908
TrigCompositeUtils::createAndStore
SG::WriteHandle< DecisionContainer > createAndStore(const SG::WriteHandleKey< DecisionContainer > &key, const EventContext &ctx)
Creates and right away records the DecisionContainer with the key.
Definition: TrigCompositeUtilsRoot.cxx:30
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
isValid
bool isValid(const T &p)
Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.
Definition: AtlasPID.h:620
Combo::LegDecisionsMap
std::map< TrigCompositeUtils::DecisionID, std::vector< ElementLink< TrigCompositeUtils::DecisionContainer > > > LegDecisionsMap
LegDecisionsMap For a given chain leg key, this map holds all Decision Objects which are active on th...
Definition: IComboHypoTool.h:28
AthReentrantAlgorithm
An algorithm that can be simultaneously executed in multiple threads.
Definition: AthReentrantAlgorithm.h:83
SG::makeHandle
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
Definition: ReadCondHandle.h:270
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::evtStore
ServiceHandle< StoreGateSvc > & evtStore()
The standard StoreGateSvc (event store) Returns (kind of) a pointer to the StoreGateSvc.
Definition: AthCommonDataStore.h:85
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
ComboHypo::ComboHypo
ComboHypo(const std::string &name, ISvcLocator *pSvcLocator)
Definition: ComboHypo.cxx:13
lumiFormat.i
int i
Definition: lumiFormat.py:85
TrigCompositeUtils::initialRoIString
const std::string & initialRoIString()
Definition: TrigCompositeUtilsRoot.cxx:868
TrigCompositeUtils::getLinkToPrevious
const std::vector< ElementLink< DecisionContainer > > getLinkToPrevious(const Decision *d)
returns links to previous decision object 'seed'
Definition: TrigCompositeUtilsRoot.cxx:156
TrigCompositeUtils::typelessFindLinks
bool typelessFindLinks(const Decision *start, const std::string &linkName, std::vector< sgkey_t > &keyVec, std::vector< uint32_t > &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...
Definition: TrigCompositeUtilsRoot.cxx:579
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
SG::WriteHandle::ptr
pointer_type ptr()
Dereference the pointer.
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
ComboHypo::execute
virtual StatusCode execute(const EventContext &context) const override
Definition: ComboHypo.cxx:152
ComboHypo::~ComboHypo
virtual ~ComboHypo() override
Definition: ComboHypo.cxx:18
ComboHypo::m_hypoTools
ToolHandleArray< ComboHypoToolBase > m_hypoTools
Definition: ComboHypo.h:106
TrigCompositeUtils::decisionToElementLink
ElementLink< DecisionContainer > decisionToElementLink(const Decision *d, const EventContext &ctx)
Takes a raw pointer to a Decision and returns an ElementLink to the Decision.
Definition: TrigCompositeUtilsRoot.cxx:122
TrigCompositeUtils::NavGraph
Structure to hold a transient Directed Acyclic Graph (DAG) structure. NavGraph is populated from,...
Definition: NavGraph.h:111
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
ComboHypo::m_outputs
SG::WriteHandleKeyArray< TrigCompositeUtils::DecisionContainer > m_outputs
Definition: ComboHypo.h:51
xAOD::TrigComposite_v1
Class used to describe composite objects in the HLT.
Definition: TrigComposite_v1.h:52
ComboHypo.h
SG::AuxElement::index
size_t index() const
Return the index of this element within its container.
HLT::Identifier
Definition: TrigCompositeUtils/TrigCompositeUtils/HLTIdentifier.h:20
xAOD::decisions
decisions
Definition: TrigComposite_v1.cxx:101
TrigCompositeUtils::featureString
const std::string & featureString()
Definition: TrigCompositeUtilsRoot.cxx:884
ComboHypo::initialize
virtual StatusCode initialize() override
Definition: ComboHypo.cxx:22
GetAllXsec.entry
list entry
Definition: GetAllXsec.py:132
ComboHypo::m_legToInputCollectionMap
Gaudi::Property< Combo::LegMap > m_legToInputCollectionMap
Definition: ComboHypo.h:60
SG::SGKeySet
std::unordered_set< sgkey_t > SGKeySet
A set of sgkey_t values.
Definition: CxxUtils/CxxUtils/sgkey_t.h:97
id
SG::auxid_t id
Definition: Control/AthContainers/Root/debug.cxx:227
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:228
ActsTrk::to_string
std::string to_string(const DetectorType &type)
Definition: GeometryDefs.h:34
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
AtlCoolConsole.tool
tool
Definition: AtlCoolConsole.py:453
xAOD::TrigComposite_v1::index_type
uint32_t index_type
Definition: TrigComposite_v1.h:56
SG::sgkey_t
uint32_t sgkey_t
Type used for hashed StoreGate key+CLID pairs.
Definition: CxxUtils/CxxUtils/sgkey_t.h:32
ComboHypo::m_inputs
SG::ReadHandleKeyArray< TrigCompositeUtils::DecisionContainer > m_inputs
Definition: ComboHypo.h:50
TrigCompositeUtils::createLegName
HLT::Identifier createLegName(const HLT::Identifier &chainIdentifier, size_t counter)
Generate the HLT::Identifier which corresponds to a specific leg of a given chain.
Definition: TrigCompositeUtilsRoot.cxx:166
SG::WriteHandle
Definition: StoreGate/StoreGate/WriteHandle.h:76
TrigCompositeUtils::isLegId
bool isLegId(const HLT::Identifier &legIdentifier)
Recognise whether the chain ID is a leg ID.
Definition: TrigCompositeUtilsRoot.cxx:204
TrigCompositeUtils::getIndexFromLeg
int32_t getIndexFromLeg(const HLT::Identifier &legIdentifier)
Extract the numeric index of a leg identifier.
Definition: TrigCompositeUtilsRoot.cxx:191
a
TList * a
Definition: liststreamerinfos.cxx:10
TrigCompositeUtils::DecisionIDContainer
std::set< DecisionID > DecisionIDContainer
Definition: TrigComposite_v1.h:28
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
TrigCompositeUtils::NavGraphNode
Transient utility class to represent a node in a graph (m_decisionObject), and a vector of edges (m_f...
Definition: NavGraph.h:20
DEBUG
#define DEBUG
Definition: page_access.h:11
SG::SGKeyMap
std::unordered_map< sgkey_t, T > SGKeyMap
A map using sgkey_t as a key.
Definition: CxxUtils/CxxUtils/sgkey_t.h:93
HLTIdentifier.h
TrigCompositeUtils::decisionIDs
void decisionIDs(const Decision *d, DecisionIDContainer &destination)
Extracts DecisionIDs stored in the Decision object.
Definition: TrigCompositeUtilsRoot.cxx:67
HLT::Identifier::name
std::string name() const
reports human redable name if it is enabled or, empty string
Definition: HLTIdentifier.cxx:14
TrigCompositeUtils
Definition: Event/xAOD/xAODTrigger/xAODTrigger/TrigComposite.h:19
python.Bindings.keys
keys
Definition: Control/AthenaPython/python/Bindings.py:798
TrigCompositeUtils::getIDFromLeg
HLT::Identifier getIDFromLeg(const HLT::Identifier &legIdentifier)
Generate the HLT::Identifier which corresponds to the chain name from the leg name.
Definition: TrigCompositeUtilsRoot.cxx:180
View.h
xAOD::TrigComposite_v1::getDetail
bool getDetail(const std::string &name, TYPE &value) const
Get an TYPE detail from the object.
python.compressB64.c
def c
Definition: compressB64.py:93
DataVector::size
size_type size() const noexcept
Returns the number of elements in the collection.
TrigRoiDescriptorCollection.h
SG::sgkeyEqual
constexpr bool sgkeyEqual(const sgkey_t a, const sgkey_t b)
Compare two sgkeys for equality.
Definition: CxxUtils/CxxUtils/sgkey_t.h:39
common
Definition: common.py:1
mapkey::key
key
Definition: TElectronEfficiencyCorrectionTool.cxx:37
TrigCompositeUtils::typelessFindLink
bool typelessFindLink(const Decision *start, const std::string &linkName, sgkey_t &key, uint32_t &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...
Definition: TrigCompositeUtilsRoot.cxx:723
ComboHypo::m_checkMultiplicityMap
Gaudi::Property< bool > m_checkMultiplicityMap
Definition: ComboHypo.h:64