38 [](
const Combo::MultiplicityReqMap::value_type&
a,
const Combo::MultiplicityReqMap::value_type& b ){
39 return a.second.size() < b.second.size();
42 const size_t maxMult = maxMultEl->second.size();
52 <<
" multiplicities: " << m.second
59 bool errorOccured =
false;
65 ATH_MSG_ERROR(key <<
" was not registered in the LegToInputCollectionMap");
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());
73 if ( value.size() > maxMult ) {
76 <<
" configured with input multiplicity " << value.size() <<
" like this: " << value
77 <<
" which is lower than for this chain " << maxMultEl->first <<
" " << maxMult);
82 return ( errorOccured ? StatusCode::FAILURE : StatusCode::SUCCESS );
88 for (
auto const& element : passingLegs) {
89 passing.insert(element.first);
92 ATH_MSG_DEBUG(
"Copying "<<passing.size()<<
" positive decision IDs to outputs");
94 for (
size_t input_counter = 0; input_counter <
m_inputs.size(); ++input_counter ) {
97 auto outDecisions = outputHandle.
ptr();
99 if ( inputHandle.isValid() ) {
101 for (
const Decision* inputDecision : *inputHandle) {
108 ATH_MSG_DEBUG(
"Searching this element in the map: ("<<thisEL.dataID() <<
" , " << thisEL.index()<<
")");
113 const std::vector<ElementLink<DecisionContainer>>& Comb=passingLegs.at(c);
114 if(std::find(Comb.begin(), Comb.end(), thisEL) == Comb.end()) {
117 ATH_MSG_DEBUG(
" Adding "<< cID <<
" because EL is found in the passingLegs map");
118 finalIds.insert( cID.
numeric() );
121 finalIds.insert( mainChain.
numeric() );
127 ATH_MSG_DEBUG(
"New decision (Container Index:" << input_counter <<
", Element Index:"<< newDec->
index() <<
") has "
136 ATH_MSG_DEBUG(
"Output Handle " <<
m_outputs.at(input_counter).key() <<
" with " << outputHandle->size() <<
" Decision objects");
137 for (
const Decision* d : *outputHandle){
140 ATH_MSG_DEBUG(
" Decision object #" << d->index() <<
" with " << objDecisions.size()<<
" positive decision IDs");
148 return StatusCode::SUCCESS;
156 Combo::LegDecisionsMap dmap;
160 Combo::LegDecisionsMap passingLegs;
169 allDecisionIds.insert(requiredDecisionID);
171 bool overallDecision =
true;
173 std::vector< SG::SGKeySet > legFeatureHashes;
174 legFeatureHashes.resize( multiplicityPerLeg.size() );
177 Combo::LegDecisionsMap thisChainCombMap;
190 for (
size_t legIndex = 0; legIndex < multiplicityPerLeg.size(); ++legIndex ) {
191 const size_t requiredMultiplicity = multiplicityPerLeg.at( legIndex );
195 if (multiplicityPerLeg.size() > 1) {
196 ATH_MSG_DEBUG(chainId <<
" has multiplicityPerLeg.size() > 1, so we use legXXX_HLT_YYY, instead of HLT_YYY");
201 ATH_MSG_DEBUG(
"Container " << legIndex <<
", looking at leg : " << legId );
203 Combo::LegDecisionsMap::const_iterator it = dmap.find(requiredDecisionIDLeg);
204 if ( it == dmap.end() ) {
209 const size_t nLegDecisionObjects = it->second.size();
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);
230 bool roiIsFullscan =
false;
231 bool objectRequestsNoMultiplicityCheck =
false;
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);
234 const bool thereIsNoFeatureYet = (featureKey == 0 and roiKey != 0);
235 if (objectRequestsNoMultiplicityCheck or (roiIsFullscan and (theFeatureIsTheROI or thereIsNoFeatureYet))) {
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") <<
")");
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 <<
".");
250 thisChainCombMap.insert (*it);
251 allDecisionIds.insert(requiredDecisionIDLeg);
259 size_t emergencyBreak = 0;
261 bool somethingChanged =
false;
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);
271 somethingChanged =
true;
275 if (somethingChanged) {
279 if (!somethingChanged or ++emergencyBreak == 500) {
280 if (emergencyBreak == 500) {
294 std::set<SG::sgkey_t> allFeatureHashes;
295 for (
const SG::SGKeySet& legHashes : legFeatureHashes) {
296 allFeatureHashes.insert(legHashes.begin(), legHashes.end());
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) {
307 const int32_t requiredMultiplicity = multiplicityPerLeg.at(legIndex);
308 const int32_t currentMultiplicity = legFeatureHashes.at(legIndex).size();
309 const int32_t safetyMargin = currentMultiplicity - requiredMultiplicity;
310 if (safetyMargin < keepLegMargin) {
311 keepLegMargin = safetyMargin;
312 keepLegIndex = legIndex;
315 if (legsWithHash == 1) {
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));
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));
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;
345 ATH_MSG_DEBUG(
"Chain " << chainId << ( overallDecision ?
" is accepted" :
" is rejected") <<
" after multiplicity requirements" );
346 if ( overallDecision ==
true ) {
347 for (
auto decID: allDecisionIds) {
349 passingLegs.insert (thisChainCombMap.begin(), thisChainCombMap.end());
355 if (passingLegs.size()!=0){
360 ATH_CHECK( tool->decide( passingLegs, context ) );
366 for (
auto const& [
id, decisions] : passingLegs) {
367 ATH_MSG_DEBUG(
"" << (decisions.empty() ?
"failing " :
"passing "+std::to_string(decisions.size())+
" decisions ") <<
id );
374 return StatusCode::SUCCESS;
385 bool& objectRequestsNoMultiplicityCheck,
386 SG::SGKeyMap<std::set<uint32_t>>& priorFeaturesMap)
const
397 ATH_MSG_ERROR(
"We are only expecting to search from a single navigation node in extractFeatureAndRoI");
398 return StatusCode::FAILURE;
402 std::vector<SG::sgkey_t> keys;
403 std::vector<uint32_t> clids;
404 std::vector<Decision::index_type> indicies;
405 std::vector<const Decision*> sources;
407 std::set<const Decision*> fullyExploredFrom;
412 const Decision* featureSource =
nullptr;
415 featureKey = keys.at(0);
416 featureIndex = indicies.at(0);
417 featureSource = sources.at(0);
420 objectRequestsNoMultiplicityCheck = (featureSource and featureSource->
hasDetail<int32_t>(
"noCombo") and featureSource->
getDetail<int32_t>(
"noCombo") == 1);
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);
427 if (keys.size() > 1) {
428 for (
size_t i = 1; i < keys.size(); ++i) {
430 if (featureKey + featureIndex == keys.at(i) + indicies.at(i)) {
433 priorFeaturesMap[featureKey + featureIndex].insert(keys.at(i) + indicies.at(i));
436 priorFeaturesMap.insert( std::pair<uint32_t, std::set<uint32_t>>(featureKey + featureIndex, std::set<uint32_t>()) );
447 roiIsFullscan = (*(roiEL))->isFullscan();
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);
454 if (!foundFeature && !foundROI) {
458 return StatusCode::SUCCESS;
463 for (
size_t inputContainerIndex = 0; inputContainerIndex <
m_inputs.size(); ++inputContainerIndex ) {
465 if ( !inputHandle.isValid() ) {
466 ATH_MSG_ERROR(
"No input ReadHandle from " << inputHandle.key() );
467 return StatusCode::FAILURE;
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:" );
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.");
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() <<
")");
503 for (
const auto& entry: dmap){
505 const std::vector<ElementLink<DecisionContainer>>& decisions = entry.second;
508 ATH_MSG_DEBUG(
" Decision: (ContainerKey:"<<d.dataID()<<
", DecisionElementIndex:"<<d.index()<<
")");
515 return StatusCode::SUCCESS;
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
bool isValid(const T &p)
Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.
ServiceHandle< StoreGateSvc > & evtStore()
bool msgLvl(const MSG::Level lvl) const
An algorithm that can be simultaneously executed in multiple threads.
ComboHypo(const std::string &name, ISvcLocator *pSvcLocator)
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...
Gaudi::Property< Combo::MultiplicityReqMap > m_multiplicitiesReqMap
virtual StatusCode execute(const EventContext &context) const override
virtual ~ComboHypo() override
SG::WriteHandleKeyArray< TrigCompositeUtils::DecisionContainer > m_outputs
Gaudi::Property< Combo::LegMap > m_legToInputCollectionMap
StatusCode fillDecisionsMap(Combo::LegDecisionsMap &dmap, const EventContext &context) const
iterates over all inputs, associating inputs to legs
Gaudi::Property< bool > m_checkMultiplicityMap
SG::ReadHandleKeyArray< TrigCompositeUtils::DecisionContainer > m_inputs
ToolHandleArray< ComboHypoToolBase > m_hypoTools
virtual StatusCode initialize() override
ElementLink implementation for ROOT usage.
const ID_type & dataID() const
Get the key that we reference, as a string.
index_type index() const
Get the index of the element inside of its container.
bool isValid() const
Test to see if the link can be dereferenced.
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...
Structure to hold a transient Directed Acyclic Graph (DAG) structure.
const std::vector< NavGraphNode * > & finalNodes() const
Get all final nodes.
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.
std::unordered_set< sgkey_t > SGKeySet
A set of sgkey_t values.
constexpr bool sgkeyEqual(const sgkey_t a, const sgkey_t b)
Compare two sgkeys for equality.
std::unordered_map< sgkey_t, T > SGKeyMap
A map using sgkey_t as a key.
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.
xAOD::TrigComposite Decision
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)