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