ATLAS Offline Software
Loading...
Searching...
No Matches
IParticleRetrievalTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5// Package includes
7#include <ostream>
8
9// Anonymous namespace contains helper functions
10namespace {
12 using CLIDTuple_t =
13 std::tuple<HLT::class_id_type, xAOD::Type::ObjectType, std::string>;
14
15 template <std::size_t FROM, std::size_t TO>
16 bool CLIDLookUp(
17 typename std::tuple_element<TO, CLIDTuple_t>::type& to,
18 const typename std::tuple_element<FROM, CLIDTuple_t>::type& from)
19 {
20 static const std::vector<CLIDTuple_t> CLIDVector {
21 {1178459224, xAOD::Type::Muon, "xAOD::MuonContainer"},
22 {1087532415, xAOD::Type::Electron, "xAOD::ElectronContainer"},
23 {1219821989, xAOD::Type::CaloCluster, "xAOD::CaloClusterContainer"},
24 {1105575213, xAOD::Type::Photon, "xAOD::PhotonContainer"},
25 {1177172564, xAOD::Type::Tau, "xAOD::TauJetContainer"}
26 };
27 auto itr = std::find_if(CLIDVector.begin(), CLIDVector.end(),
28 [from] (const CLIDTuple_t& tup) {
29 return std::get<FROM>(tup) == from;
30 });
31 if (itr == CLIDVector.end() )
32 return false;
33 else {
34 to = std::get<TO>(*itr);
35 return true;
36 }
37 }
38 bool CLIDToObjectType(xAOD::Type::ObjectType& type, HLT::class_id_type clid)
39 {
40 return CLIDLookUp<0, 1>(type, clid);
41 }
42 bool ObjectTypeToCLID(HLT::class_id_type& clid, xAOD::Type::ObjectType type)
43 {
44 return CLIDLookUp<1, 0>(clid, type);
45 }
46 bool CLIDToContainerType(std::string& name, HLT::class_id_type clid)
47 {
48 return CLIDLookUp<0, 2>(name, clid);
49 }
50
51} //> end anonymous namespace
52
53namespace Trig {
55 asg::AsgTool(name)
56 {
57 declareProperty("TrigDecisionTool", m_tdt,
58 "The trigger decision tool to use.");
59 declareProperty("WarnOnNavigationError", m_warnOnNavigationFailure = true,
60 "Only spit a warning on a navigation error, don't cause a job failure.");
61
62 }
63
65
67 {
68 ATH_MSG_INFO("Initializing " << name() );
69 ATH_CHECK( m_tdt.retrieve() );
70 return StatusCode::SUCCESS;
71 }
72
74 std::vector<std::vector<const xAOD::IParticle*>>& combinations,
75 const std::string& chain,
76 bool rerun) const
77 {
78 // Make sure what we're getting is cleared.
79 combinations.clear();
80 // Start by getting the chain group
81 const ChainGroup* cg = m_tdt->getChainGroup(chain);
82 // Make sure that this group actually contains triggers. If it doesn't then
83 // this is very wrong and the job shouldn't be allowed to continue
84 if (cg->getListOfTriggers().size() == 0) {
85 ATH_MSG_ERROR("Chain group " << chain
86 << " is empty! This means that no matching chains were found!");
87 return StatusCode::FAILURE;
88 }
89 unsigned int condition = TrigDefs::Physics;
90 if (rerun)
92 if (!cg->isPassed(condition) ) {
93 ATH_MSG_DEBUG("Chain: " << chain << " was not passed!");
94 return StatusCode::SUCCESS;
95 }
96
97 FeatureContainer features = cg->features(condition);
98 for (const Combination& combo : features.getCombinations() ) {
99 // The assumption here is that each combination represents a *single* way
100 // in which the trigger could have been passed. This should be true for
101 // the types of trigger that this tool expects to examine. It won't be
102 // true for (e.g.) jet triggers.
103 std::vector<const xAOD::IParticle*> currentCombination;
104 bool navFailure = false;
105 for (const HLT::TriggerElement* te : combo.tes() ) {
106 if (!retrieveParticles(currentCombination, te, navFailure).isSuccess() ) {
107 // Interpret a failure this way so that we can report the chain name
108 ATH_MSG_ERROR("Failed to retrieve particles for chain " << chain );
109 return StatusCode::FAILURE;
110 }
111 // If the navigation failed for this combination ignore it completely
112 if (navFailure)
113 break;
114 }
115 if (navFailure)
116 ATH_MSG_WARNING("Skipping combination for chain " << chain
117 << " due to navigation failure");
118 else
119 combinations.push_back(currentCombination);
120 }
121 return StatusCode::SUCCESS;
122 }
123
125 std::vector<const xAOD::IParticle*>& combination,
126 const HLT::TriggerElement* te,
127 bool& navFailure) const
128 {
129 ATH_MSG_DEBUG( "Processing TE " << Trig::getTEName(*te) );
130 // Keep track of whether or not we found a particle here.
131 const xAOD::IParticle* part = nullptr;
132 for (const auto& feature : te->getFeatureAccessHelpers() ) {
134 if (!CLIDToObjectType(type, feature.getCLID() ) )
135 // Skip any features that don't hold 'final' state particles
136 continue;
138 // If this is an egamma type we have to check if we are meant to be
139 // looking for a CaloCluster instead!
141 if (egType == xAOD::Type::Other) {
142 std::string message =
143 "Unable to determine the correct type for TE " + Trig::getTEName(*te);
144 navFailure = true;
146 ATH_MSG_WARNING( message );
147 return StatusCode::SUCCESS;
148 }
149 else {
150 ATH_MSG_ERROR( message );
151 return StatusCode::FAILURE;
152 }
153 }
154 else if (egType == xAOD::Type::CaloCluster) {
155 HLT::class_id_type clid = 0;
156 ObjectTypeToCLID(clid, egType);
157 // This will be where we store the TE containing the calo cluster
158 // feature
159 const HLT::TriggerElement* sourceTE = nullptr;
160 const HLT::TrigNavStructure* navigation =
161 m_tdt->ExperimentalAndExpertMethods().getNavigation();
163 navigation->getFeatureRecursively(te, clid, "", sourceTE);
164 if (!sourceTE) {
165 std::ostringstream os;
166 os << "Unable to retrieve feature of type " << egType
167 << " from TE " << Trig::getTEName(*te);
168 navFailure = true;
170 ATH_MSG_WARNING( os.str() );
171 return StatusCode::SUCCESS;
172 }
173 else {
174 ATH_MSG_ERROR( os.str() );
175 return StatusCode::FAILURE;
176 }
177 }
178 ATH_CHECK( retrieveFeatureParticle(part, egFeature, sourceTE, navFailure) );
179 if (navFailure)
180 return StatusCode::SUCCESS;
181 // If it's a calo-cluster like TE then stop here, otherwise we'll
182 // encounter the other EG type again and fail...
183 break;
184 }
185 else if (egType != type) {
186 // This is the wrong feature to be looking at
187 continue;
188 }
189 // Otherwise we continue as before
190 }
191 // If we found a particle from another feature access helper then this is
192 // a problem. Our assumption is that there is only one particle per leg!
193 if (part) {
194 std::string message = "TE" + Trig::getTEName(*te) + "has multiple " +
195 "'final' particles attached to it! This breaks this tool's asumptions!";
196 navFailure = true;
198 ATH_MSG_WARNING(message);
199 return StatusCode::SUCCESS;
200 }
201 else {
202 ATH_MSG_ERROR(message);
203 return StatusCode::FAILURE;
204 }
205 }
206 ATH_CHECK( retrieveFeatureParticle(part, feature, te, navFailure) );
207 if (navFailure)
208 return StatusCode::SUCCESS;
209 } //> end loop over features
210
211 // If we found a particle then we can stop going through this branch of the
212 // tree
213 if (part) {
214 combination.push_back(part);
215 return StatusCode::SUCCESS;
216 }
217
218 // Otherwise look at each of the next TEs separately
219 for (const HLT::TriggerElement* nextTE :
221 ATH_CHECK( retrieveParticles(combination, nextTE, navFailure) );
222
223 return StatusCode::SUCCESS;
224 }
225
227 const HLT::TriggerElement* te) const
228 {
229 // We need to check the TE name for this
230 std::string teName = Trig::getTEName(*te);
231 if (teName.find("etcut") != std::string::npos &&
232 teName.find("trkcut") == std::string::npos)
234 else if (teName.starts_with( "EF_e"))
236 else if (teName.starts_with( "EF_g"))
237 return xAOD::Type::Photon;
238 else
239 return xAOD::Type::Other;
240 }
241
243 const xAOD::IParticle*& particle,
245 const HLT::TriggerElement* te,
246 bool& navFailure) const
247 {
248 // Get the right container type name
249 std::string containerType;
250 if (!CLIDToContainerType(containerType, feature.getCLID() ) ) {
251 ATH_MSG_ERROR("Unrecognised CLID " << feature.getCLID() << " received!");
252 // This isn't a navigation error - this is a failure in the tool's
253 // internal logic!
254 return StatusCode::FAILURE;
255 }
256 // Build a vector of typeless features so that we can use the central
257 // functions.
258 const HLT::TrigNavStructure* navigation =
259 m_tdt->ExperimentalAndExpertMethods().getNavigation();
260
261
263 auto typelessHolder = navigation->getHolder(feature);
264
265 if (!typelessHolder) {
266 std::string message = "Typeless holder for feature not present!";
267 navFailure = true;
269 ATH_MSG_WARNING(message);
270 return StatusCode::SUCCESS;
271 }
272 else {
273 ATH_MSG_ERROR(message);
274 return StatusCode::FAILURE;
275 }
276 }
277 const xAOD::IParticleContainer* cont(nullptr);
278 // Get the name used in the event store
279 std::string key = HLTNavDetails::formatSGkey(
280 "HLT", containerType, typelessHolder->label() );
281 // Now things are *much* more familiar
283 std::string message = "Store does not contain " + key + "!";
284 navFailure = true;
286 ATH_MSG_WARNING(message);
287 return StatusCode::SUCCESS;
288 }
289 else {
290 ATH_MSG_ERROR(message);
291 return StatusCode::FAILURE;
292 }
293 }
294 ATH_CHECK( evtStore()->retrieve(cont, key) );
296 if (cont->size() < idx.objectsEnd() ) {
297 std::ostringstream os;
298 os << "Featured object end " << idx.objectsEnd()
299 << " is *after* the end of container " << key;
300 navFailure = true;
302 ATH_MSG_WARNING( os.str() );
303 return StatusCode::SUCCESS;
304 }
305 else {
306 ATH_MSG_ERROR( os.str() );
307 return StatusCode::FAILURE;
308 }
309 }
310 std::vector<const xAOD::IParticle*> particleFeatures;
311 particleFeatures.reserve(idx.objectsEnd() - idx.objectsBegin() );
312 auto begin = cont->begin();
313 auto end = cont->begin();
314 std::advance(begin, idx.objectsBegin() );
315 std::advance(end, idx.objectsEnd() );
316 particleFeatures.insert(particleFeatures.end(), begin, end);
317
318 // Make sure the answer is what we expect
319 std::ostringstream os;
320 switch (particleFeatures.size() ) {
321 case 0:
322 os << "No particles retrieved from feature "
323 << navigation->label(feature.getCLID(), feature.getIndex().subTypeIndex() )
324 << " from TE " << Trig::getTEName(*te);
325 navFailure = true;
327 ATH_MSG_WARNING(os.str() );
328 return StatusCode::SUCCESS;
329 }
330 else {
331 ATH_MSG_ERROR(os.str() );
332 return StatusCode::FAILURE;
333 }
334 case 1:
335 // Set the output.
336 particle = particleFeatures.at(0);
337 break;
338 default:
339 // Some TEs can end up reporting multiple outputs within the same RoI.
340 // AFAIK this only happens within EGamma TEs but I don't know that for
341 // sure. In any case this shouldn't matter too much for the matching
342 // given that they will be nearby each other. Just return the highest pT
343 // object.
344 particle = *(std::max_element(
345 particleFeatures.begin(), particleFeatures.end(),
346 [] (const xAOD::IParticle* lhs, const xAOD::IParticle* rhs)
347 { return lhs->pt() < rhs->pt(); }) );
348 }
349 return StatusCode::SUCCESS;
350 }
351
352} //> end namespace Trig
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
ServiceHandle< StoreGateSvc > & evtStore()
const_iterator begin() const noexcept
Return a const_iterator pointing at the beginning of the collection.
size_type size() const noexcept
Returns the number of elements in the collection.
const BaseHolder * getHolder(const TriggerElement::FeatureAccessHelper &fea) const
TriggerElement::FeatureAccessHelper getFeatureRecursively(const TriggerElement *startTE, class_id_type clid, const index_or_label_type &index_or_label, const TriggerElement *&sourceTE) const
recursive search for features the function is similar to the above butif th features is not found at ...
static const std::vector< TriggerElement * > & getDirectPredecessors(const TriggerElement *te)
returns list of direct predecessors (nodes seeding me)
std::string label(class_id_type clid, const index_or_label_type &sti_or_label) const
the FeatureAccessHelper is a class used to keep track of features attached to this TE.
const ObjectIndex & getIndex() const
index in the external ojects array
Helper class for conversion from/to int stored in TE and pair of ints used in Navigation Object point...
sub_index_type subTypeIndex() const
to get collection index
TriggerElement is the basic ingreedient of the interface between HLT algorithms and the navigation It...
const std::vector< FeatureAccessHelper > & getFeatureAccessHelpers() const
returns all features which ara attached to this TE
const FeatureContainer features(unsigned int condition=TrigDefs::Physics) const
returns all features related to given chain group of HLT chains or L1 items Note: This does not yet w...
bool isPassed(unsigned int condition=TrigDefs::Physics) const
tells if chain group passed
std::vector< std::string > getListOfTriggers() const
is a connector between chains and object It store single combination of trigger elements.
const std::vector< Trig::Combination > & getCombinations() const
gives back reference to combinations collected through append
~IParticleRetrievalTool() override
Default destructor.
IParticleRetrievalTool(const std::string &name)
Standard constructor.
xAOD::Type::ObjectType getEGammaTEType(const HLT::TriggerElement *te) const
Get the type of particle that should be retrieved from this TE.
StatusCode initialize() override
Initialise the tool.
bool m_warnOnNavigationFailure
Be forgiving about the navigation not matching our expectations.
StatusCode retrieveFeatureParticle(const xAOD::IParticle *&particle, const HLT::TriggerElement::FeatureAccessHelper &feature, const HLT::TriggerElement *te, bool &navFailure) const
Retrieve an IParticle from a feature.
ToolHandle< Trig::TrigDecisionTool > m_tdt
The TrigDecisionTool that will be used to get the navigation.
StatusCode retrieveParticles(std::vector< std::vector< const xAOD::IParticle * > > &combinations, const std::string &chain, bool rerun=false) const override
Retrieve the particles that caused this trigger to fire.
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
Class providing the definition of the 4-vector interface.
bool contains(const std::string &s, const std::string &regx)
does a string contain the substring
Definition hcg.cxx:114
CONT to(RANGE &&r)
Definition ranges.h:39
std::string formatSGkey(const std::string &prefix, const std::string &containername, const std::string &label)
declaration of formatting function.
Definition Holder.cxx:122
The common trigger namespace for trigger analysis tools.
std::string getTEName(const HLT::TriggerElement &te)
converts TEid to TE name (this may not always work, it depends on the availability of config)
ObjectType
Type of objects that have a representation in the xAOD EDM.
Definition ObjectType.h:32
@ Photon
The object is a photon.
Definition ObjectType.h:47
@ Other
An object not falling into any of the other categories.
Definition ObjectType.h:34
@ CaloCluster
The object is a calorimeter cluster.
Definition ObjectType.h:39
@ Muon
The object is a muon.
Definition ObjectType.h:48
@ Electron
The object is an electron.
Definition ObjectType.h:46
@ Tau
The object is a tau (jet)
Definition ObjectType.h:49
DataVector< IParticle > IParticleContainer
Simple convenience declaration of IParticleContainer.