ATLAS Offline Software
TriggerMatchingTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 #include "TriggerMatchingTool.h"
6 #include "BuildCombinations.h"
7 #include "GaudiKernel/ServiceHandle.h"
8 #include "GaudiKernel/IIncidentSvc.h"
9 #include "GaudiKernel/ThreadLocalContext.h"
13 #include <memory>
14 #include <algorithm>
17 #include "StoreGate/ReadHandle.h"
18 
19 namespace {
21  template <typename T>
22  using constAcc_t = SG::AuxElement::ConstAccessor<T>;
23  template <typename T>
24  using acc_t = SG::AuxElement::Accessor<T>;
25  template <typename T>
26  using vecLink_t = std::vector<ElementLink<T>>;
27 
28  template <typename T>
29  ElementLink<T> makeLink(typename T::const_value_type element, IProxyDict *proxyDct)
30  {
31  SG::DataProxy *proxy = proxyDct->proxy(element->container());
32  // This will be null if the container isn't in the store. This shouldn't really happen
33  if (!proxy)
34  return {};
35  else
36  return ElementLink<T>(proxy->sgkey(), element->index(), proxyDct);
37  }
38 } //> end anonymous namespace
39 
40 namespace DerivationFramework {
41 
43  const std::string& type,
44  const std::string& name,
45  const IInterface* pSvcLocator) :
46  AthAlgTool(type, name, pSvcLocator)
47  {
48  declareInterface<IAugmentationTool>(this);
49  declareProperty("ChainNames", m_chainNames,
50  "The list of trigger chains to match.");
51  declareProperty("OnlineParticleTool", m_trigParticleTool,
52  "The tool to retrieve online particles from the navigation.");
53  declareProperty("InputElectrons",
55  "Offline electron candidates for matching.");
56  declareProperty("InputPhotons",
58  "Offline photon candidates for matching.");
59  declareProperty("InputMuons",
61  "Offline muon candidates for matching.");
62  declareProperty("InputTaus",
63  m_offlineInputs[xAOD::Type::Tau] = "TauJets",
64  "Offline tau candidates for matching.");
65  declareProperty("DRThreshold", m_drThreshold = 0.1,
66  "The maximum dR between an offline and an online particle to consider "
67  "a match between them.");
68  declareProperty("Rerun", m_rerun = true,
69  "Whether to match triggers in rerun mode.");
70  declareProperty("OutputContainerPrefix", m_outputPrefix="TrigMatch_",
71  "The prefix to add to the output containers.");
72  declareProperty("CheckEmptyChainGroups", m_checkEmptyChainGroups = true,
73  "If set, discard any empty chain groups. Otherwise these will cause "
74  "a job failure.");
75  declareProperty("InputDependentConfig", m_inputDependentConfig=false,
76  "Warn when a trigger is removed (if the configuration is dependent "
77  "on the inputs, removal is not expected).");
78  }
79 
81  {
82  ATH_MSG_INFO( "Initializing " << name() );
83 
84  // Remove any duplicates from the list of chain names
85  std::sort(m_chainNames.begin(), m_chainNames.end() );
86  m_chainNames.erase(std::unique(m_chainNames.begin(), m_chainNames.end() ), m_chainNames.end() );
87 
88  ATH_CHECK( m_trigParticleTool.retrieve() );
89  ATH_CHECK( m_scoreTool.retrieve() );
90  for (auto &p : m_offlineInputs)
91  {
92  ATH_CHECK(p.second.initialize(SG::AllowEmpty));
93  }
94  return StatusCode::SUCCESS;
95  }
96 
98  {
99  [[maybe_unused]] static const bool firstEvent = [&](){
100  auto itr = m_chainNames.begin();
101  while (itr != m_chainNames.end() ) {
102  const Trig::ChainGroup* cg = m_tdt->getChainGroup(*itr);
103  if (cg->getListOfTriggers().size() == 0){
105  ATH_MSG_WARNING("Removing trigger " << (*itr) << " -- suggests a bad tool configuration (asking for triggers not in the menu)");
106  // We are now modifying the mutable m_chainNames but since it is done
107  // within this static initialization this is thread-safe:
108  itr = m_chainNames.erase(itr);
109  } else
110  ++itr;
111  }
112  return false;
113  }();
114 
115  const EventContext &ctx = Gaudi::Hive::currentContext();
117 
118  // Now, get all the possible offline candidates
119  std::map<xAOD::Type::ObjectType, const xAOD::IParticleContainer *> offlineContainers;
120  std::map<xAOD::Type::ObjectType, particleVec_t> offlineCandidates;
121  for (const auto& p : m_offlineInputs) {
122  // Skip any that may have been disabled by providing an empty string to
123  // the corresponding property
124  if (p.second.empty() )
125  continue;
126  auto handle = SG::makeHandle(p.second, ctx);
127  if (!handle.isValid())
128  {
129  ATH_MSG_ERROR("Failed to retrieve " << p.second);
130  return StatusCode::FAILURE;
131  }
132  offlineContainers[p.first] = handle.ptr();
133  offlineCandidates.emplace(std::make_pair(
134  p.first,
135  particleVec_t(handle->begin(), handle->end() )
136  ) );
137  }
138 
139  // Store possible matches from online to offline particles here
140  // We do this as multiple chains may use the same online particles so we can
141  // reuse this information.
142  std::map<const xAOD::IParticle*, particleVec_t> matches;
143 
144  // Iterate through the chains to get the matchings
145  for (const std::string& chain : m_chainNames) {
146  // Create the output
147  xAOD::TrigCompositeContainer* container(nullptr);
148  ATH_CHECK( createOutputContainer(container, chain) );
149 
150  // Get the list of online combinations
151  std::vector<particleVec_t> onlineCombinations;
152  ATH_CHECK( m_trigParticleTool->retrieveParticles(onlineCombinations, chain, m_rerun) );
153 
155  onlineCombinations.size() << " combinations found for chain" << chain);
156 
157  // If no combinations were found (because the trigger was not passed) then
158  // we can skip this trigger
159  if (onlineCombinations.size() == 0)
160  continue;
161 
163  // Now build up the list of offline combinations;
164  std::vector<particleVec_t> offlineCombinations;
165  for (const particleVec_t& combination : onlineCombinations) {
166  // Here we store the possible candidates for the matching. We use the
167  // range type as a lightweight method to carry around a view of a vector
168  // without copying it (the RangedItr is essentially a combination of 3
169  // iterators).
170  std::vector<particleRange_t> matchCandidates;
171  for (const xAOD::IParticle* part : combination) {
172  const particleVec_t& possibleMatches = getCandidateMatchesFor(
173  part, offlineCandidates, matches);
174  matchCandidates.emplace_back(possibleMatches.begin(), possibleMatches.end() );
175  } //> end loop over particles
176  // Get all possible combinations of offline objects that could match to
177  // this particular online combination.
178  auto theseOfflineCombinations =
179  TriggerMatchingUtils::getAllDistinctCombinations<const xAOD::IParticle*>(
180  matchCandidates);
181  if (msgLvl(MSG::VERBOSE) ) {
182  // Spit out some verbose information
184  "Checking matching for chain " << chain
185  << " with " << matchCandidates.size() << " legs");
186  std::size_t idx = 0;
187  for (const particleRange_t& range : matchCandidates)
188  ATH_MSG_VERBOSE( "Leg #" << idx++ << " has " << range.size()
189  << " offline candidates." );
191  "Matching generated " << theseOfflineCombinations.size()
192  << " offline combinations");
193  }
194  // Now push them back into the output. Use a specialised function for
195  // inserting into a sorted vector that ensures that we only output
196  // unique combinations
197  for (const particleVec_t& vec : theseOfflineCombinations)
199  } //> end loop over combinations
200 
201 
202  // Decorate the found combinations onto trigger composites.
203  for (const particleVec_t& foundCombination : offlineCombinations) {
204  xAOD::TrigComposite* composite = new xAOD::TrigComposite();
205  container->push_back(composite);
206  static const acc_t<vecLink_t<xAOD::IParticleContainer>> dec_links(
207  "TrigMatchedObjects");
208  vecLink_t<xAOD::IParticleContainer>& links = dec_links(*composite);
209  for (const xAOD::IParticle* part : foundCombination) {
210  const xAOD::IParticleContainer *container = offlineContainers.at(part->type());
211  // If we have an owning container then things are relatively simple:
212  // we can just construct the element link from its SG key and the
213  // index. Otherwise we have to locate the correct proxy from the element
214  if (container->trackIndices())
215  links.emplace_back(
216  m_offlineInputs.at(part->type()).key(),
217  part->index(),
218  extendedCtx.proxy());
219  else
220  links.push_back(makeLink<xAOD::IParticleContainer>(part, extendedCtx.proxy()));
221  }
222  } //> end loop over the found combinations
223  } //> end loop over chains
224  return StatusCode::SUCCESS;
225  }
226 
228  xAOD::TrigCompositeContainer*& container,
229  const std::string& chain) const
230  {
231  auto uniqueContainer = std::make_unique<xAOD::TrigCompositeContainer>();
232  auto aux = std::make_unique<xAOD::AuxContainerBase>();
233  uniqueContainer->setStore(aux.get() );
234  container = uniqueContainer.get();
235  std::string name = m_outputPrefix+chain;
236  // We have to replace '.' characters with '_' characters so that these are
237  // valid container names...
238  std::replace(name.begin(), name.end(), '.', '_');
239  ATH_CHECK( evtStore()->record(std::move(uniqueContainer), name) );
240  ATH_CHECK( evtStore()->record(std::move(aux), name+"Aux.") );
241  return StatusCode::SUCCESS;
242  }
243 
245  const xAOD::IParticle* part,
246  std::map<xAOD::Type::ObjectType, particleVec_t>& offlineParticles,
247  std::map<const xAOD::IParticle*, particleVec_t>& cache) const
248  {
249  // Build up all the possible matches between online and offline particles
250  auto cacheItr = cache.find(part);
251  if (cacheItr == cache.end() ) {
252  xAOD::Type::ObjectType type = part->type();
254  if (type == xAOD::Type::CaloCluster) {
255  // If it's a calo cluster then we need to get the cluster from the
256  // egamma types.
257  static const constAcc_t<vecLink_t<xAOD::CaloClusterContainer>> acc_calo("caloClusterLinks");
258  for (xAOD::Type::ObjectType egType : {
260  {
261  for (const xAOD::IParticle* cand : offlineParticles[egType]) {
262  const vecLink_t<xAOD::CaloClusterContainer>& links = acc_calo(*cand);
263  if (links.size() == 0 || !links.at(0).isValid() )
264  continue;
265  const xAOD::CaloCluster* clus = *links.at(0);
266  if (matchParticles(part, clus) )
267  candidates.push_back(cand);
268  }
269  }
270  }
271  else {
272  for (const xAOD::IParticle* cand : offlineParticles[type])
273  if (matchParticles(part, cand) )
274  candidates.push_back(cand);
275  }
276  cacheItr = cache.emplace(
277  std::make_pair(part, std::move(candidates) ) ).first;
278  }
279  return cacheItr->second;
280  }
281 
283  const xAOD::IParticle* lhs,
284  const xAOD::IParticle* rhs) const
285  {
286  return m_scoreTool->score(*lhs, *rhs) < m_drThreshold;
287  }
288 
289 } //> end namespace DerivationFramework
LArG4FSStartPointFilter.part
part
Definition: LArG4FSStartPointFilter.py:21
replace
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition: hcg.cxx:307
DerivationFramework::TriggerMatchingTool::m_drThreshold
float m_drThreshold
The DR threshold to use.
Definition: TriggerMatchingTool.h:74
DerivationFramework::TriggerMatchingTool::matchParticles
bool matchParticles(const xAOD::IParticle *lhs, const xAOD::IParticle *rhs) const
Check if the dR between two particles is below threshold.
Definition: TriggerMatchingTool.cxx:282
xAOD::Electron
Electron_v1 Electron
Definition of the current "egamma version".
Definition: Event/xAOD/xAODEgamma/xAODEgamma/Electron.h:17
BuildCombinations.h
IProxyDict::proxy
virtual SG::DataProxy * proxy(const CLID &id, const std::string &key) const =0
Get proxy with given id and key.
StateLessPT_NewConfig.proxy
proxy
Definition: StateLessPT_NewConfig.py:392
runLayerRecalibration.chain
chain
Definition: runLayerRecalibration.py:175
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
DerivationFramework::TriggerMatchingTool::m_outputPrefix
std::string m_outputPrefix
The prefix to place at the beginning of the output containers.
Definition: TriggerMatchingTool.h:80
xAOD::TrigComposite
TrigComposite_v1 TrigComposite
Declare the latest version of the class.
Definition: Event/xAOD/xAODTrigger/xAODTrigger/TrigComposite.h:16
ObjectType
ObjectType
Definition: BaseObject.h:11
SG::Accessor
Helper class to provide type-safe access to aux data.
Definition: Control/AthContainers/AthContainers/Accessor.h:68
drawFromPickle.candidates
candidates
Definition: drawFromPickle.py:271
xAODP4Helpers.h
AthCommonDataStore< AthCommonMsg< AlgTool > >::declareProperty
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T > &t)
Definition: AthCommonDataStore.h:145
ExtendedEventContext.h
ViewHelper::makeLink
ElementLink< T > makeLink(const SG::View *view, const SG::ReadHandle< T > &handle, size_t index)
Create EL to a collection in view.
Definition: ViewHelper.h:297
AuxContainerBase.h
DataVector::get
const T * get(size_type n) const
Access an element, as an rvalue.
AthCommonMsg< AlgTool >::msgLvl
bool msgLvl(const MSG::Level lvl) const
Definition: AthCommonMsg.h:30
DerivationFramework::TriggerMatchingTool::m_scoreTool
ToolHandle< Trig::IMatchScoringTool > m_scoreTool
The pair scoring tool.
Definition: TriggerMatchingTool.h:94
vec
std::vector< size_t > vec
Definition: CombinationsGeneratorTest.cxx:12
DerivationFramework::TriggerMatchingTool::TriggerMatchingTool
TriggerMatchingTool(const std::string &type, const std::string &name, const IInterface *pSvcLocator)
Constructor.
Definition: TriggerMatchingTool.cxx:42
SG::ConstAccessor
Helper class to provide constant type-safe access to aux data.
Definition: ConstAccessor.h:55
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
xAOD::IParticle
Class providing the definition of the 4-vector interface.
Definition: Event/xAOD/xAODBase/xAODBase/IParticle.h:41
IProxyDict
A proxy dictionary.
Definition: AthenaKernel/AthenaKernel/IProxyDict.h:47
xAOD::CaloCluster
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
Definition: Event/xAOD/xAODCaloEvent/xAODCaloEvent/CaloCluster.h:19
DerivationFramework::TriggerMatchingUtils::insertIntoSortedVector
bool insertIntoSortedVector(std::vector< T > &vec, const T &ele)
Helper function for inserting an element into a sorted vector.
DerivationFramework::TriggerMatchingTool::m_checkEmptyChainGroups
bool m_checkEmptyChainGroups
If set, discard any triggers with empty chain groups (break the job otherwise).
Definition: TriggerMatchingTool.h:84
SG::makeHandle
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
Definition: ReadCondHandle.h:270
Atlas::getExtendedEventContext
const ExtendedEventContext & getExtendedEventContext(const EventContext &ctx)
Retrieve an extended context from a context object.
Definition: ExtendedEventContext.cxx:32
DerivationFramework::TriggerMatchingTool::addBranches
virtual StatusCode addBranches() const override
Calculate the matchings.
Definition: TriggerMatchingTool.cxx:97
AthCommonDataStore< AthCommonMsg< AlgTool > >::evtStore
ServiceHandle< StoreGateSvc > & evtStore()
The standard StoreGateSvc (event store) Returns (kind of) a pointer to the StoreGateSvc.
Definition: AthCommonDataStore.h:85
xAOD::CaloCluster_v1
Description of a calorimeter cluster.
Definition: CaloCluster_v1.h:59
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:210
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
DerivationFramework::TriggerMatchingTool::m_trigParticleTool
ToolHandle< Trig::IIParticleRetrievalTool > m_trigParticleTool
The tool to retrieve the online candidates.
Definition: TriggerMatchingTool.h:68
Atlas::ExtendedEventContext
Definition: ExtendedEventContext.h:23
DerivationFramework::TriggerMatchingTool::particleVec_t
std::vector< const xAOD::IParticle * > particleVec_t
Helper typedefs.
Definition: TriggerMatchingTool.h:43
DerivationFramework::TriggerMatchingTool::m_rerun
bool m_rerun
Whether to match in rerun mode or not.
Definition: TriggerMatchingTool.h:77
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
DMTest::links
links
Definition: CLinks_v1.cxx:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
DerivationFramework::TriggerMatchingTool::m_tdt
ToolHandle< Trig::TrigDecisionTool > m_tdt
The trig decision tool.
Definition: TriggerMatchingTool.h:91
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:195
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
DerivationFramework::TriggerMatchingUtils::RangedItr
utility class that acts wraps a bidirectional iterator.
Definition: RangedItr.h:18
DerivationFramework
THE reconstruction tool.
Definition: ParticleSortingAlg.h:24
xAOD::TrigComposite_v1
Class used to describe composite objects in the HLT.
Definition: TrigComposite_v1.h:52
DataVector
Derived DataVector<T>.
Definition: DataVector.h:794
Trig::ChainGroup
Definition: ChainGroup.h:51
IProxyDict.h
DerivationFramework::TriggerMatchingTool::getCandidateMatchesFor
const particleVec_t & getCandidateMatchesFor(const xAOD::IParticle *part, std::map< xAOD::Type::ObjectType, particleVec_t > &offlineParticles, std::map< const xAOD::IParticle *, particleVec_t > &cache) const
Get all offline particles that could match a given online one.
Definition: TriggerMatchingTool.cxx:244
DerivationFramework::TriggerMatchingTool::m_offlineInputs
std::map< xAOD::Type::ObjectType, SG::ReadHandleKey< xAOD::IParticleContainer > > m_offlineInputs
The input containers to use. These are keyed by xAOD object type.
Definition: TriggerMatchingTool.h:71
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:228
DataVector::push_back
value_type push_back(value_type pElem)
Add an element to the end of the collection.
DerivationFramework::TriggerMatchingTool::m_inputDependentConfig
bool m_inputDependentConfig
If using an input-file-dependent config then we warn when triggers are removed.
Definition: TriggerMatchingTool.h:88
xAOD::Photon
Photon_v1 Photon
Definition of the current "egamma version".
Definition: Event/xAOD/xAODEgamma/xAODEgamma/Photon.h:17
Muon
struct TBPatternUnitContext Muon
TriggerMatchingTool.h
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
LArNewCalib_DelayDump_OFC_Cali.idx
idx
Definition: LArNewCalib_DelayDump_OFC_Cali.py:69
CaloClusterContainer.h
xAODType::Tau
@ Tau
The object is a tau (jet)
Definition: ObjectType.h:49
DerivationFramework::TriggerMatchingTool::initialize
virtual StatusCode initialize() override
Initialize the tool.
Definition: TriggerMatchingTool.cxx:80
python.Constants.VERBOSE
int VERBOSE
Definition: Control/AthenaCommon/python/Constants.py:14
ReadHandle.h
Handle class for reading from StoreGate.
AthAlgTool
Definition: AthAlgTool.h:26
Trig::ChainGroup::getListOfTriggers
std::vector< std::string > getListOfTriggers() const
Definition: ChainGroup.cxx:467
SG::DataProxy
Definition: DataProxy.h:45
SG::AllowEmpty
@ AllowEmpty
Definition: StoreGate/StoreGate/VarHandleKey.h:30
DerivationFramework::TriggerMatchingTool::createOutputContainer
StatusCode createOutputContainer(xAOD::TrigCompositeContainer *&container, const std::string &chain) const
Create an output container for the named chain.
Definition: TriggerMatchingTool.cxx:227