ATLAS Offline Software
Loading...
Searching...
No Matches
InputMakerBase.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
4
8
9using namespace TrigCompositeUtils;
10#define dodebug true
11
12InputMakerBase::InputMakerBase( const std::string& name, ISvcLocator* pSvcLocator )
13: ::AthReentrantAlgorithm( name, pSvcLocator ) {}
14
16
20
24
26 CHECK( AthReentrantAlgorithm::sysInitialize() ); // initialise base class
29 ATH_MSG_DEBUG("roisLink="<<m_roisLink);
30 CHECK( m_inputs.initialize() );
31 renounceArray(m_inputs); // make inputs implicit, i.e. not required by scheduler
32 ATH_MSG_DEBUG("Will consume implicit decisions:" );
33 for (auto& input: m_inputs){
34 ATH_MSG_DEBUG( " "<<input.key() );
35 }
36 CHECK( m_outputs.initialize() );
37 ATH_MSG_DEBUG(" and produce decisions: " << m_outputs.key());
38 return StatusCode::SUCCESS;
39}
40
41// Create one output container and merge all inputs into this, using heuristics to identify equal Decision objects.
42// If the input is invalid or empty, the output is not created, resulting as invalid
43StatusCode InputMakerBase::decisionInputToOutput(const EventContext& context, SG::WriteHandle<TrigCompositeUtils::DecisionContainer>& outputHandle) const{
44
45 ATH_MSG_DEBUG("Creating one merged output per Decision object, IsEmptyStep flag = " << m_isEmptyStep);
46 ATH_CHECK( outputHandle.isValid() );
47 TrigCompositeUtils::DecisionContainer* outDecisions = outputHandle.ptr();
48
49 // Empty IMs have a dynamic (runtime) matching configuration. But any single IM should find itself using exclusively-feature or exclusively-ROI based matching
50 size_t usedROIMatching = 0, usedFeatureMatching = 0;
51
52 MatchingCache matchingCache; // Used to remember temporarily which hash is associated with each Decision object when performing the de-duplication matching
53 size_t totalInput = 0;
54 for ( const auto& inputKey: decisionInputs() ) {
55 auto inputHandle = SG::makeHandle( inputKey, context );
56
57 if( not inputHandle.isValid() ) {
58 ATH_MSG_DEBUG( "Got no decisions from input "<< inputKey.key() << " because implicit handle not valid");
59 continue;
60 }
61 if( inputHandle->size() == 0){
62 ATH_MSG_DEBUG( "Got no decisions from input "<< inputKey.key()<<": implicit handle is valid but container is empty.");
63 continue;
64 }
65 ATH_MSG_DEBUG( "Running on input "<< inputKey.key()<<" with " << inputHandle->size() << " elements" );
66
67
68 size_t input_counter = 0;
69 for (const TrigCompositeUtils::Decision* inputDecision : *inputHandle){
70 ATH_MSG_DEBUG( " -- Input Decision " << input_counter <<": has " <<TrigCompositeUtils::getLinkToPrevious(inputDecision).size()<<" previous links");
71
72 bool usedROIMatchingFlag = false;
73 size_t alreadyAddedIndex = std::numeric_limits<std::size_t>::max();
74 const bool alreadyAdded = matchInCollection(outDecisions, inputDecision, alreadyAddedIndex, usedROIMatchingFlag, matchingCache);
75
76 TrigCompositeUtils::Decision* outputDecision = nullptr;
77 if (alreadyAdded) { // Already added, at alreadyAddedIndex
78 if (usedROIMatchingFlag) {
79 ++usedROIMatching;
80 } else {
81 ++usedFeatureMatching;
82 }
83 outputDecision = outDecisions->at( alreadyAddedIndex );
84 ATH_MSG_DEBUG( " -- Matched to existing, " << inputKey.key() << " index " << input_counter << " is merged into existing output index " << alreadyAddedIndex << (usedROIMatchingFlag ? " Matched using ROI" : " Matched using Feature"));
85 } else { // Not already added, make new
86 outputDecision = TrigCompositeUtils::newDecisionIn( outDecisions );
87 outputDecision->setName(inputMakerNodeName());
88 outputDecision->setDetail<int32_t>("isEmpty", static_cast<int32_t>(m_isEmptyStep)); // Transient detail (only used by runtime navigation validation, never persisted)
89 matchingCache.linkOutputToInput(outputDecision, inputDecision);
90 ATH_MSG_DEBUG( " -- Did not match to existing, " << inputKey.key() << " index " << input_counter << " creates output index " << outDecisions->size()-1);
91 }
92
93 // Note: We will call linkToPrevious and insertDecisionIDs N times on a single "outputDecision", where N is the number of inputDecision which checkExisting determines are the same object.
94 TrigCompositeUtils::linkToPrevious( outputDecision, inputDecision, context ); // Link inputDecision object as the 'seed' of outputDecision
95 TrigCompositeUtils::insertDecisionIDs( inputDecision, outputDecision ); // Copy decision IDs from inputDecision into outputDecision
96 ATH_MSG_DEBUG(" -- This output decision now has " << TrigCompositeUtils::getLinkToPrevious(outputDecision).size() << " seeds and "<< outputDecision->decisions().size() << " decisionIds");
97 input_counter++;
98 } // loop over input decisions
99 totalInput+=input_counter;
100 } // end of: for ( auto inputKey: decisionInputs() )
101
102 if (usedROIMatching and usedFeatureMatching) {
103 ATH_MSG_DEBUG("This input maker used Feature-based mapping on " << usedFeatureMatching << " inputs and ROI-based mapping on " << usedROIMatching
104 << " inputs. The isEmptyIM flag is " << m_isEmptyStep);
105 }
106
107 // Print some debug messages summarising the content of the outputHandles.
108 if (msgLvl(MSG::DEBUG)) {
109 debugPrintOut(context, outputHandle);
110 }
111 ATH_MSG_DEBUG("Merging complete: from "<<totalInput<<" input decision to "<<outputHandle->size()<<" output decisions");
112
113 return StatusCode::SUCCESS;
114}
115
116
117bool InputMakerBase::matchInCollection(const DecisionContainer* outDecisions, const Decision* toMatch, size_t& matchIndex, bool& usedROIMatchingFlag, MatchingCache& matchingCache) const {
118 std::set<const Decision*> cache;
119 std::vector<SG::sgkey_t> keys;
120 std::vector<uint32_t> clids;
121 std::vector<Decision::index_type> indicies;
122 std::vector<const Decision*> sources; // Unused
123 TrigCompositeUtils::typelessFindLinks(toMatch, featureString(), keys, clids, indicies, sources, TrigDefs::lastFeatureOfType, &cache);
124 bool hasFeature = false;
125 if (keys.size() != 0) hasFeature=true;
126 ATH_MSG_DEBUG("This decision hasFeature="<< hasFeature);
127 // Do feature based matching if configured to do so, or do it tentatively for empty step IMs (will not generate an ERROR if it fails for the empty step case)
128 if ( m_mergeUsingFeature == true or (m_isEmptyStep and hasFeature) ) {
129 matchIndex = matchDecision(outDecisions, toMatch, featureString(), matchingCache);
130 ATH_MSG_DEBUG("matchDecision in features: "<< matchIndex);
131 }
132 // Do ROI based batching if configured to do so, or if feature matching failed for an empty step IM.
133 else {
134 matchIndex = matchDecision(outDecisions, toMatch, m_roisLink.value(), matchingCache);
135 usedROIMatchingFlag = true;
136 }
137 return (matchIndex != std::numeric_limits<std::size_t>::max());
138}
139
140size_t InputMakerBase::matchDecision(const DecisionContainer* outDecisions, const Decision* toMatch, const std::string& linkNameToMatch, MatchingCache& matchingCache) const {
141 const uint64_t matchingHash = getMatchingHashForDecision(toMatch, linkNameToMatch);
142 ATH_MSG_DEBUG("matchDecision "<<linkNameToMatch<<" with matchingHash="<<matchingHash);
143 // Cache this matching hash, so that in subsequent calls we can compare other incoming decision object's matching hash against this one
144 matchingCache.setMatchingHash(toMatch, matchingHash);
145
146 // Look for match
147 for (size_t index = 0; index < outDecisions->size(); ++index) {
148 const TrigCompositeUtils::Decision* checkDecision = outDecisions->at(index);
149 const uint64_t checkHash = matchingCache.getMatchingHash(checkDecision);
150 ATH_MSG_DEBUG("matchDecision checkHash="<<checkHash<<" index="<<index);
151 if (checkHash == matchingHash) {
152 return index;
153 }
154 }
155
156 return std::numeric_limits<std::size_t>::max();
157}
158
159uint64_t InputMakerBase::getMatchingHashForDecision(const Decision* toMatch, const std::string& linkNameToMatch) const {
160 std::set<const Decision*> cache;
161 std::vector<SG::sgkey_t> keys;
162 std::vector<uint32_t> clids;
163 std::vector<Decision::index_type> indicies;
164 std::vector<const Decision*> sources; // Unused
165 TrigCompositeUtils::typelessFindLinks(toMatch, linkNameToMatch, keys, clids, indicies, sources, TrigDefs::lastFeatureOfType, &cache);
166 ATH_MSG_DEBUG("getMatchingHashForDecision keys.size()="<<keys.size());
167 if (keys.size() != 1) {
168 bool suppressError = false;
169 // We silence this ERROR when the IM isEmptyStep and we are tentatively testing at runtime if there is an available "feature" link.
170 if (m_isEmptyStep and linkNameToMatch == featureString()) {
171 suppressError = true;
172 }
173 // However... we _always_ want to print the ERROR if we got here not because keys.size() == 0 but because keys.size() > 1!
174 // This is an ambiguous situation, and such things are always bad.
175 if ( keys.size() > 1) {
176 suppressError = false;
177 }
178 if (not suppressError) {
179 ATH_MSG_ERROR("InputMakerBase::getMatchingHashForDecision Did not locate exactly one object having searched for a link named '" << linkNameToMatch
180 << "', found " << keys.size() << ". Unable to match this Decision object.");
181 for (size_t i = 0; i < keys.size(); ++i) {
182 const std::string* sgKeyStr = evtStore()->keyToString(keys.at(i));
183 ATH_MSG_ERROR(" -- Key:" << keys.at(i) << " KeyStr:" << (sgKeyStr ? *sgKeyStr : "UNKNOWN") << " Index:" << indicies.at(i) << " CLID:" << clids.at(i));
184 }
185 // Super verbose output
186 ATH_MSG_ERROR(" -- -- TRACKING FULL HISTORY ");
187 NavGraph navGraph;
188 recursiveGetDecisions(toMatch, navGraph);
189 navGraph.printAllPaths(msg(), MSG::ERROR);
190 }
191 return std::numeric_limits<std::size_t>::max();
192 }
193
194 // Construct a new hash by combining the SGkey (a hash), the CLID (a hash) and the index (an offset)
195 const uint64_t matchingHash = keys.at(0) + clids.at(0) + indicies.at(0);
196 return matchingHash;
197}
198
199
201 size_t validInput=0;
202 for ( const auto& inputKey: decisionInputs() ) {
203 auto inputHandle = SG::makeHandle( inputKey, context );
204 ATH_MSG_DEBUG(" " << inputKey.key() << " " << (inputHandle.isValid()? "valid": "not valid" ) );
205 if (inputHandle.isValid()) {
206 if (inputHandle->size() > 0) {
207 validInput++;
208 } else {
209 ATH_MSG_DEBUG(" " << inputKey.key() << " actually NOT valid due to size() == 0");
210 }
211 }
212 }
213 ATH_MSG_DEBUG( "Number of implicit ReadHandles for input decisions is " << decisionInputs().size() << ", " << validInput << " are valid/not-empty" );
214
215 ATH_MSG_DEBUG("Output " << outputHandle.key() <<" with "<< outputHandle->size() <<" decisions:");
216 for (const auto outdecision : *outputHandle){
218 TrigCompositeUtils::decisionIDs( outdecision, objDecisions );
219 ATH_MSG_DEBUG("Number of positive decisions for this output: " << objDecisions.size() );
220 for ( TrigCompositeUtils::DecisionID id : objDecisions ) {
221 ATH_MSG_DEBUG( " --- decision " << HLT::Identifier( id ) );
222 }
223 }
224}
225
226
227void InputMakerBase::MatchingCache::setMatchingHash(const Decision* inputDecision, const uint64_t matchingHash) {
228 m_inputDecToMatchingHash[inputDecision] = matchingHash;
229}
230
231
232void InputMakerBase::MatchingCache::linkOutputToInput(const Decision* outputDecision, const Decision* inputDecision) {
233 m_outputDecToInputDec[outputDecision] = inputDecision;
234}
235
236
237uint64_t InputMakerBase::MatchingCache::getMatchingHash(const Decision* outputDecision) const {
238 if (!outputDecision) {
239 throw std::runtime_error("InputMakerBase::MatchingCache::getMatchingHash: Called with nullptr.");
240 }
241
242 auto it_inDec = m_outputDecToInputDec.find(outputDecision);
243 if (it_inDec == m_outputDecToInputDec.end()) {
244 throw std::runtime_error("InputMakerBase::MatchingCache::getMatchingHash: No matching input Decision* for the supplied output Decision*");
245 }
246 const Decision* inputDecision = it_inDec->second;
247
248 auto it_hash = m_inputDecToMatchingHash.find(inputDecision);
249 if (it_hash == m_inputDecToMatchingHash.end()) {
250 throw std::runtime_error("InputMakerBase::MatchingCache::getMatchingHash: No matching hash for this input Decision*");
251 }
252 const uint64_t hash = it_hash->second;
253
254 return hash;
255}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_DEBUG(x)
#define CHECK(...)
Evaluate an expression and check for errors.
void renounceArray(SG::VarHandleKeyArray &handlesArray)
bool msgLvl(const MSG::Level lvl) const
An algorithm that can be simultaneously executed in multiple threads.
const T * at(size_type n) const
Access an element, as an rvalue.
size_type size() const noexcept
Returns the number of elements in the collection.
Gaudi::Property< bool > m_isEmptyStep
bool matchInCollection(const TrigCompositeUtils::DecisionContainer *outDecisions, const TrigCompositeUtils::Decision *toMatch, size_t &matchIndex, bool &usedROIMatchingFlag, MatchingCache &matchingCache) const
Wrapper around matchDecision. Returns boolean if the match was successful.
uint64_t getMatchingHashForDecision(const TrigCompositeUtils::Decision *toMatch, const std::string &linkNameToMatch) const
Searches from toMatch to locate a single (type-less) Element Link with given edge name....
StatusCode decisionInputToOutput(const EventContext &context, SG::WriteHandle< TrigCompositeUtils::DecisionContainer > &outputHandle) const
does the standard handling of input decisions: read from handles with all the checks,...
StringProperty m_roisLink
virtual StatusCode sysInitialize() override
initialise this base class and renounce input decision key handles
size_t matchDecision(const TrigCompositeUtils::DecisionContainer *outDecisions, const TrigCompositeUtils::Decision *toMatch, const std::string &linkNameToMatch, MatchingCache &matchingCache) const
Checks for merge-able Decision objects coming from N upstream filters. Check based on most-recent ele...
const SG::WriteHandleKey< TrigCompositeUtils::DecisionContainer > & decisionOutputs() const
methods for derived classes to access handles of the base class input and output decisions; other rea...
virtual ~InputMakerBase()
destructor
void debugPrintOut(const EventContext &context, SG::WriteHandle< TrigCompositeUtils::DecisionContainer > &outputHandle) const
provides debug printout of the output of the algorithm
InputMakerBase(const std::string &name, ISvcLocator *pSvcLocator)
constructor, to be called by sub-class constructors
SG::ReadHandleKeyArray< TrigCompositeUtils::DecisionContainer > m_inputs
input decisions array, will be implicit (renounced).
const SG::ReadHandleKeyArray< TrigCompositeUtils::DecisionContainer > & decisionInputs() const
methods for derived classes to access handles of the base class input and output decisions; other rea...
Gaudi::Property< bool > m_mergeUsingFeature
SG::WriteHandleKey< TrigCompositeUtils::DecisionContainer > m_outputs
output decisions
virtual const std::string & key() const override final
Return the StoreGate ID for the referenced object.
Property holding a SG store/key/clid from which a WriteHandle is made.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
pointer_type ptr()
Dereference the pointer.
Structure to hold a transient Directed Acyclic Graph (DAG) structure.
Definition NavGraph.h:111
void printAllPaths(MsgStream &log, MSG::Level msgLevel=MSG::VERBOSE) const
Helper function.
Definition NavGraph.cxx:165
void setName(const std::string &name)
Set a human-readable name for the object.
const std::vector< TrigCompositeUtils::DecisionID > & decisions() const
Get positive HLT chain decisions associated with this TrigComposite. Navigation use.
bool setDetail(const std::string &name, const TYPE &value)
Set an TYPE detail on the object.
HandleKeyArray< ReadHandle< T >, ReadHandleKey< T >, Gaudi::DataHandle::Reader > ReadHandleKeyArray
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
const std::string & inputMakerNodeName()
unsigned int DecisionID
void insertDecisionIDs(const Decision *src, Decision *dest)
Appends the decision IDs of src to the dest decision object.
Decision * newDecisionIn(DecisionContainer *dc, const std::string &name)
Helper method to create a Decision object, place it in the container and return a pointer to it.
const std::vector< ElementLink< DecisionContainer > > getLinkToPrevious(const Decision *d)
returns links to previous decision object 'seed'
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.
std::set< DecisionID > DecisionIDContainer
void linkToPrevious(Decision *d, const std::string &previousCollectionKey, size_t previousIndex)
Links to the previous object, location of previous 'seed' decision supplied by hand.
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.
static const unsigned int lastFeatureOfType
Run 3 "enum". Only return the final feature along each route through the navigation.
Definition index.py:1
Used to cache each incoming Decision object's ElementLink which is being used to identify the Decisio...
std::map< const TrigCompositeUtils::Decision *, const TrigCompositeUtils::Decision * > m_outputDecToInputDec
void linkOutputToInput(const TrigCompositeUtils::Decision *outputDecision, const TrigCompositeUtils::Decision *inputDecision)
void setMatchingHash(const TrigCompositeUtils::Decision *inputDecision, const uint64_t matchingHash)
uint64_t getMatchingHash(const TrigCompositeUtils::Decision *outputDecision) const
std::map< const TrigCompositeUtils::Decision *, uint64_t > m_inputDecToMatchingHash