ATLAS Offline Software
Loading...
Searching...
No Matches
METMuonAssociator.cxx
Go to the documentation of this file.
1
2
3/*
4 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
5*/
6
7// METMuonAssociator.cxx
8// Implementation file for class METMuonAssociator
9//
10// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
11//
12// Author: P Loch, S Resconi, TJ Khoo, AS Mete
14
15// METReconstruction includes
18
19// Muon EDM
21
22// Tracking EDM
23#include "xAODTracking/Vertex.h"
24
25// DeltaR calculation
27
28
31
32namespace met {
33
34 using namespace xAOD;
35
36 //accessor for PV
37 const static SG::ConstAccessor<char> PVMatchedAcc("matchedToPV");
38
39 // Constructors
44 {
45 }
46
47 // Athena algtool's Hooks
50 {
52 ATH_MSG_VERBOSE ("Initializing " << name() << "...");
53 ATH_CHECK( m_muContKey.initialize());
57
58 return StatusCode::SUCCESS;
59 }
60
61 // executeTool
63 StatusCode METMuonAssociator::executeTool(xAOD::MissingETContainer* /*metCont*/, xAOD::MissingETAssociationMap* metMap, const EventContext& ctx) const
64 {
65 ATH_MSG_VERBOSE ("In execute: " << name() << "...");
66
68 if (!muonCont.isValid()) {
69 ATH_MSG_WARNING("Unable to retrieve input muon container " << m_muContKey.key());
70 return StatusCode::FAILURE;
71 }
72
73 ATH_MSG_DEBUG("Successfully retrieved muon collection");
74 if (fillAssocMap(metMap,muonCont.cptr(), ctx).isFailure()) {
75 ATH_MSG_WARNING("Unable to fill map with muon container " << m_muContKey.key());
76 return StatusCode::FAILURE;
77 }
78 return StatusCode::SUCCESS;
79 }
80
81 // *********************************************************************************************************
82 // Get constituents
84 std::vector<const xAOD::IParticle*>& tclist,
85 const met::METAssociator::ConstitHolder& /*constits*/, const EventContext& ctx) const
86 {
87 const xAOD::Muon *mu = static_cast<const xAOD::Muon*>(obj);
88 const CaloCluster* muclus = mu->cluster();
89 if(muclus && m_doMuonClusterMatch) {
90 ATH_MSG_VERBOSE("Muon " << mu->index() << " with pt " << mu->pt()
91 << ", eta " << mu->eta()
92 << ", phi " << mu->phi()
93 << " has cluster with "
94 << "eta " << muclus->calEta()
95 << ", phi " << muclus->calPhi()
96 << ", E " << muclus->calE()
97 << " formed of " << muclus->size() << " cells.");
98 ATH_MSG_VERBOSE("Muon Eloss type: " << mu->energyLossType()
99 << " Eloss: " << mu->floatParameter(xAOD::Muon::EnergyLoss)
100 << " MeasuredEloss: " << mu->floatParameter(xAOD::Muon::MeasEnergyLoss)
101 << " FSR E: " << mu->floatParameter(xAOD::Muon::FSR_CandidateEnergy) );
102
104 for(const auto& matchel : tcLinkAcc(*muclus)) {
105 if(!matchel.isValid()) {continue;} // In case of thinned cluster collection
106 ATH_MSG_VERBOSE("Tool found cluster " << (*matchel)->index() << " with pt " << (*matchel)->pt() );
107 if((*matchel)->e()>1e-9) { // +ve E
108 tclist.push_back(*matchel);
109 }
110 }
111 } // muon has linked cluster
112
113 return StatusCode::SUCCESS;
114 }
115
117 std::vector<const xAOD::IParticle*>& constlist,
118 const met::METAssociator::ConstitHolder& constits) const
119 {
120 const xAOD::Muon *mu = static_cast<const xAOD::Muon*>(obj);
121 const TrackParticle* idtrack = mu->trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
122 if(idtrack && acceptTrack(idtrack,constits.pv) && isGoodEoverP(idtrack)) {
123 // if(idtrack && acceptTrack(idtrack,pv)) {
124 ATH_MSG_VERBOSE("Accept muon track " << idtrack << " px, py = " << idtrack->p4().Px() << ", " << idtrack->p4().Py());
125 ATH_MSG_VERBOSE("Muon ID track ptr: " << idtrack);
126 constlist.push_back(idtrack);
127 // if(mu->pt()>10e3 && (mu->muonType()==xAOD::Muon::Combined || mu->muonType()==xAOD::Muon::SegmentTagged)) {
128 // mutracks.push_back(idtrack);
129 // }
130 }
131 return StatusCode::SUCCESS;
132 }
133
134 // *********************************************************************************************************
135 // Get constituents
137 std::vector<const xAOD::IParticle*>& pfolist,
138 const met::METAssociator::ConstitHolder& constits,
139 std::map<const IParticle*,MissingETBase::Types::constvec_t>& /*momenta*/, const EventContext& ctx) const
140 {
141 const xAOD::Muon *mu = static_cast<const xAOD::Muon*>(obj);
142 const TrackParticle* idtrack = mu->trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
143 const CaloCluster* muclus = mu->cluster();
144
145 ATH_MSG_VERBOSE("Muon " << mu->index() << " with pt " << mu->pt()
146 << ", eta " << mu->eta()
147 << ", phi " << mu->phi());
148 if(muclus) {
149 ATH_MSG_VERBOSE(" has cluster with "
150 << "eta " << muclus->calEta()
151 << ", phi " << muclus->calPhi()
152 << ", E " << muclus->calE()
153 << " formed of " << muclus->size() << " cells.");
154 }
155 ATH_MSG_VERBOSE("Muon Eloss type: " << mu->energyLossType()
156 << " Eloss: " << mu->floatParameter(xAOD::Muon::EnergyLoss)
157 << " MeasuredEloss: " << mu->floatParameter(xAOD::Muon::MeasEnergyLoss)
158 << " FSR E: " << mu->floatParameter(xAOD::Muon::FSR_CandidateEnergy) );
159
160 // One loop over PFOs
161 for(const auto *const pfo : *constits.pfoCont) {
162 if(pfo->isCharged()) {
163 // get charged PFOs by matching the muon ID track
164 // We set a small -ve pt for cPFOs that were rejected
165 // by the ChargedHadronSubtractionTool
166 const static SG::ConstAccessor<char> PVMatchedAcc("matchedToPV");
167 if(idtrack && pfo->track(0) == idtrack && PVMatchedAcc(*pfo) &&
168 ( !m_cleanChargedPFO || isGoodEoverP(pfo->track(0)) )
169 ) {
170 ATH_MSG_VERBOSE("Accept muon PFO " << pfo << " px, py = " << pfo->p4().Px() << ", " << pfo->p4().Py());
171 ATH_MSG_VERBOSE("Muon PFO index: " << pfo->index() << ", pt: " << pfo->pt() << ", eta: " << pfo->eta() << ", phi: " << pfo->phi() );
172 ATH_MSG_VERBOSE("Muon ID Track index: " << idtrack->index() << ", pt: " << idtrack->pt() << ", eta: " << idtrack->eta() << ", phi: " << idtrack->phi() );
173 pfolist.push_back(pfo);
174 break;
175 } // track match
176 } else {
177 // get neutral PFOs by matching the muon cluster
178 if(muclus && m_doMuonClusterMatch) {
179
181 for(const auto& matchel : tcLinkAcc(*muclus)) {
182 if(!matchel.isValid()) {
183 ATH_MSG_DEBUG("Invalid muon-cluster elementLink");
184 } else {
185 if((*matchel)->e()>FLT_MIN && pfo->cluster(0) == *matchel) { // +ve E && matches cluster
186 ATH_MSG_VERBOSE("Tool found cluster " << (*matchel)->index() << " with pt " << (*matchel)->pt() );
187 pfolist.push_back(pfo);
188 }
189 }
190 }
191 } // muon has linked cluster
192 }
193 } // end of cluster loop
194
195 return StatusCode::SUCCESS;
196 }
197
198
200 std::vector<const xAOD::IParticle*>& felist,
201 const met::METAssociator::ConstitHolder& constits,
202 std::map<const IParticle*,MissingETBase::Types::constvec_t> &/*momenta*/, const EventContext& ctx) const
203 {
204 const xAOD::Muon *mu = static_cast<const xAOD::Muon*>(obj);
205 if (m_useFELinks)
206 ATH_CHECK( extractFEsFromLinks(mu, felist,constits, ctx) );
207 else
208 ATH_CHECK( extractFEs(mu, felist, constits, ctx) );
209
210 return StatusCode::SUCCESS;
211 }
212
213 StatusCode METMuonAssociator::extractFEsFromLinks(const xAOD::Muon* mu, //TODO to be tested
214 std::vector<const xAOD::IParticle*>& felist,
215 const met::METAssociator::ConstitHolder& constits, const EventContext& ctx) const
216 {
217 ATH_MSG_DEBUG("Extract FEs From Links for " << mu->type() << " with pT " << mu->pt());
218
219 std::vector<FELink_t> nFELinks;
220 std::vector<FELink_t> cFELinks;
221
224 nFELinks=neutralFEReadDecorHandle(*mu);
225 cFELinks=chargedFEReadDecorHandle(*mu);
226
227 // Charged FEs
228 for (const FELink_t& feLink : cFELinks) {
229 if (!feLink.isValid()) continue;
230 const xAOD::FlowElement* fe_init = *feLink;
231 for (const auto *const fe : *constits.feCont){
232 if (fe->index() == fe_init->index() && fe->isCharged()){ //index-based match between JetETmiss and CHSFlowElements collections
233 const static SG::ConstAccessor<char> PVMatchedAcc("matchedToPV");
234 if( fe->isCharged() && PVMatchedAcc(*fe)&& ( !m_cleanChargedPFO || isGoodEoverP(static_cast<const xAOD::TrackParticle*>(fe->chargedObject(0))) ) ) {
235 ATH_MSG_DEBUG("Accept cFE with pt " << fe->pt() << ", e " << fe->e() << ", eta " << fe->eta() << ", phi " << fe->phi() );
236 felist.push_back(fe);
237 }
238 }
239 }
240 } // end cFE loop
241
242 // Neutral FEs
243 for (const FELink_t& feLink : nFELinks) {
244 if (!feLink.isValid()) continue;
245 const xAOD::FlowElement* fe_init = *feLink;
246 for (const auto *const fe : *constits.feCont){
247 if (fe->index() == fe_init->index() && !fe->isCharged()){ //index-based match between JetETmiss and CHSFlowElements collections
248 if( ( !fe->isCharged()&& fe->e() > FLT_MIN ) ){
249 ATH_MSG_DEBUG("Accept nFE with pt " << fe->pt() << ", e " << fe->e() << ", eta " << fe->eta() << ", phi " << fe->phi() << " in sum.");
250 felist.push_back(fe);
251 }
252 }
253 }
254 } // end nFE links loop
255
256
257 return StatusCode::SUCCESS;
258 }
259
261 std::vector<const xAOD::IParticle*>& felist,
262 const met::METAssociator::ConstitHolder& constits, const EventContext& ctx) const
263 {
264 const TrackParticle* idtrack = mu->trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
265 const CaloCluster* muclus = mu->cluster();
266 ATH_MSG_VERBOSE("Muon " << mu->index() << " with pt " << mu->pt()
267 << ", eta " << mu->eta()
268 << ", phi " << mu->phi());
269 if(muclus) {
270 ATH_MSG_VERBOSE(" has cluster with "
271 << "eta " << muclus->calEta()
272 << ", phi " << muclus->calPhi()
273 << ", E " << muclus->calE()
274 << " formed of " << muclus->size() << " cells.");
275 }
276 ATH_MSG_VERBOSE("Muon Eloss type: " << mu->energyLossType()
277 << " Eloss: " << mu->floatParameter(xAOD::Muon::EnergyLoss)
278 << " MeasuredEloss: " << mu->floatParameter(xAOD::Muon::MeasEnergyLoss)
279 << " FSR E: " << mu->floatParameter(xAOD::Muon::FSR_CandidateEnergy) );
280
281 // One loop over PFOs
282 for(const xAOD::FlowElement* fe : *constits.feCont) {
283 if(fe->isCharged()) {
284 // get charged FEs by matching the muon ID track
285 // We set a small -ve pt for cPFOs that were rejected
286 // by the ChargedHadronSubtractionTool
287 const static SG::ConstAccessor<char> PVMatchedAcc("matchedToPV");
288 if(idtrack && fe->chargedObject(0) == idtrack && PVMatchedAcc(*fe) &&
289 ( !m_cleanChargedPFO || isGoodEoverP(static_cast<const xAOD::TrackParticle*>(fe->chargedObject(0))) )
290 ) {
291 ATH_MSG_VERBOSE("Accept muon PFO (FE) " << fe << " px, py = " << fe->p4().Px() << ", " << fe->p4().Py());
292 ATH_MSG_VERBOSE("Muon PFO index: " << fe->index() << ", pt: " << fe->pt() << ", eta: " << fe->eta() << ", phi: " << fe->phi() );
293 ATH_MSG_VERBOSE("Muon ID Track index: " << idtrack->index() << ", pt: " << idtrack->pt() << ", eta: " << idtrack->eta() << ", phi: " << idtrack->phi() );
294 felist.push_back(fe);
295 break;
296 } // track match
297 } else {
298 // get neutral PFOs by matching the muon cluster
299 if(muclus && m_doMuonClusterMatch) {
300
302 for(const auto& matchel : tcLinkAcc(*muclus)) {
303 if(!matchel.isValid()) {
304 ATH_MSG_DEBUG("Invalid muon-cluster elementLink");
305 } else {
306 if((*matchel)->e()>FLT_MIN && fe->otherObject(0) == *matchel) { // +ve E && matches cluster
307 ATH_MSG_VERBOSE("Tool found cluster " << (*matchel)->index() << " with pt " << (*matchel)->pt() );
308 felist.push_back(fe);
309 }
310 }
311 }
312 } // muon has linked cluster
313 }
314 } // end of cluster loop
315
316 return StatusCode::SUCCESS;
317 }
318
319 // add HR implementation from release 21.2
320 // extractFE for W precision-type measurements
322 std::vector<const xAOD::IParticle*> hardObjs,
323 std::vector<const xAOD::IParticle*>& felist,
324 const met::METAssociator::ConstitHolder& constits,
325 std::map<const IParticle*,MissingETBase::Types::constvec_t> & /*momenta*/,
326 float& UEcorr) const
327 {
328 if(obj->type() != xAOD::Type::ObjectType::Muon){
329 UEcorr=0.0;
330 felist={};
331 return StatusCode::SUCCESS;
332 }
333 const xAOD::Muon* mu = static_cast<const xAOD::Muon*>(obj);
334
335 // Get PFOs associated to muons
336 for(const auto fe : *constits.feCont) {
337 if( fe->isCharged()) { // Fill list with charged PFOs (using muon tracks)
338 if( mu && P4Helpers::isInDeltaR(*fe, *mu, m_Drcone, m_useRapidity) && PVMatchedAcc(*fe) &&
339 ( !m_cleanChargedPFO || isGoodEoverP(static_cast<const xAOD::TrackParticle*>(fe->chargedObject(0))) ) ){
340 felist.push_back(fe);
341 }
342 }
343 else{ // Fill list with neutral PFOs (using muon clusters)
344 if( mu && P4Helpers::isInDeltaR(*fe, *mu, m_Drcone, m_useRapidity) ){
345 felist.push_back(fe);
346 }
347 } // neutral PFO condition
348 } // loop over all PFOs
349
350 // Calculating UE energy correction for a given lepton (using mu)
351 if(mu){
352 // Vectoral sum of all FE
353 TLorentzVector HR; // uncorrected HR (initialized with 0,0,0,0 automatically)
354 for(const auto fe_itr : *constits.feCont) {
355 if( fe_itr->pt() < 0 || fe_itr->e() < 0 ) { // sanity check
356 continue;
357 }
358
359 //remove charged FE that are not matched to the PV
360 if(fe_itr->isCharged() && !PVMatchedAcc(*fe_itr)){
361 continue;
362 }
363 HR += fe_itr->p4();
364 }
365
366 // Create vectors of muons
367 std::vector<const xAOD::Muon*> v_mu;
368 for(const auto& obj_i : hardObjs) {
369 if(obj_i->pt()<5e3 && obj_i->type() != xAOD::Type::Muon) { // sanity check
370 continue;
371 }
372 const xAOD::Muon* mu_curr = static_cast<const xAOD::Muon*>(obj_i); // current muon
373 v_mu.push_back(mu_curr);
374 }
375
376
377 // Subtracting PFOs matched to muons from HR
378 for(const auto fe_i : *constits.feCont) { // charged and neutral PFOs
379 if( fe_i->pt() < 0 || fe_i->e() < 0 ) { // sanity check
380 continue;
381 }
382 for(const auto& mu_i : v_mu) { // loop over muons
383 double dR = P4Helpers::deltaR( fe_i->eta(), fe_i->phi(), mu_i->eta(), mu_i->phi() );
384 if( dR < m_Drcone ) { // if PFO is in a cone around muon
385 HR -= fe_i->p4();
386 break;
387 } // cone requirement
388 } // over v_mu
389 } // over PFOs
390
391 // Save v_mu as a vector TLV (as commonn type for electrons and muons)
392 std::vector<TLorentzVector> v_muTLV;
393 v_muTLV.reserve(v_mu.size());
394 for(const auto& mu_i : v_mu) { // loop over v_mu
395 v_muTLV.push_back( mu_i->p4() );
396 }
397
398 // Save current mu as TLV
399 TLorentzVector muTLV = mu->p4();
400
401 // Get UE correction
402 ATH_CHECK( GetUEcorr(constits, v_muTLV, muTLV, HR, m_Drcone, m_MinDistCone, UEcorr) );
403 } // available mu requirement
404
405
406 return StatusCode::SUCCESS;
407 }
408}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
ElementLink< xAOD::MuonContainer > MuonLink_t
ElementLink< xAOD::FlowElementContainer > FELink_t
Handle class for reading a decoration on an object.
Helper class to provide constant type-safe access to aux data.
Handle class for reading a decoration on an object.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const_pointer_type cptr()
Dereference the pointer.
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
Gaudi::Property< bool > m_useFELinks
virtual StatusCode initialize() override
Dummy implementation of the initialisation function.
Gaudi::Property< bool > m_useRapidity
Gaudi::Property< bool > m_cleanChargedPFO
virtual StatusCode fillAssocMap(xAOD::MissingETAssociationMap *metMap, const xAOD::IParticleContainer *hardObjs, const EventContext &ctx) const
METAssociator(const std::string &name)
bool isGoodEoverP(const xAOD::TrackParticle *trk) const
StatusCode GetUEcorr(const met::METAssociator::ConstitHolder &constits, std::vector< TLorentzVector > &v_clus, TLorentzVector &clus, TLorentzVector &HR, const float Drcone, const float MinDistCone, float &UEcorr) const
bool acceptTrack(const xAOD::TrackParticle *trk, const xAOD::Vertex *pv) const
StatusCode extractTracks(const xAOD::IParticle *obj, std::vector< const xAOD::IParticle * > &constlist, const met::METAssociator::ConstitHolder &constits) const final
StatusCode executeTool(xAOD::MissingETContainer *metCont, xAOD::MissingETAssociationMap *metMap, const EventContext &ctx) const final
METMuonAssociator()
Default constructor:
SG::ReadDecorHandleKey< xAOD::MuonContainer > m_neutralFEReadDecorKey
StatusCode extractFEsFromLinks(const xAOD::Muon *mu, std::vector< const xAOD::IParticle * > &felist, const met::METAssociator::ConstitHolder &constits, const EventContext &ctx) const
Gaudi::Property< bool > m_doMuonClusterMatch
StatusCode extractFEs(const xAOD::Muon *mu, std::vector< const xAOD::IParticle * > &felist, const met::METAssociator::ConstitHolder &constits, const EventContext &ctx) const
virtual StatusCode extractFE(const xAOD::IParticle *obj, std::vector< const xAOD::IParticle * > &felist, const met::METAssociator::ConstitHolder &constits, std::map< const xAOD::IParticle *, MissingETBase::Types::constvec_t > &momenta, const EventContext &ctx) const final
SG::ReadDecorHandleKey< xAOD::MuonContainer > m_chargedFEReadDecorKey
virtual StatusCode extractPFO(const xAOD::IParticle *obj, std::vector< const xAOD::IParticle * > &pfolist, const met::METAssociator::ConstitHolder &constits, std::map< const xAOD::IParticle *, MissingETBase::Types::constvec_t > &momenta, const EventContext &ctx) const final
StatusCode extractFEHR(const xAOD::IParticle *obj, std::vector< const xAOD::IParticle * > hardObjs, std::vector< const xAOD::IParticle * > &felist, const met::METAssociator::ConstitHolder &constits, std::map< const xAOD::IParticle *, MissingETBase::Types::constvec_t > &momenta, float &UEcorr) const final
SG::ReadHandleKey< xAOD::MuonContainer > m_muContKey
static constexpr float m_Drcone
virtual StatusCode extractTopoClusters(const xAOD::IParticle *obj, std::vector< const xAOD::IParticle * > &tclist, const met::METAssociator::ConstitHolder &constits, const EventContext &ctx) const final
static constexpr float m_MinDistCone
virtual StatusCode initialize() override
Dummy implementation of the initialisation function.
SG::ReadDecorHandleKey< xAOD::CaloClusterContainer > m_elementLinkName
flt_t calPhi() const
Get in signal state CALIBRATED.
size_t size() const
size method (forwarded from CaloClusterCellLink obj)
flt_t calEta() const
Get in signal state CALIBRATED.
flt_t calE() const
Geet Energy in signal state CALIBRATED.
virtual double pt() const override
virtual double phi() const override
The azimuthal angle ( ) of the particle.
virtual double eta() const override
The pseudorapidity ( ) of the particle.
const xAOD::IParticle * chargedObject(std::size_t i) const
const xAOD::IParticle * otherObject(std::size_t i) const
virtual FourMom_t p4() const override
The full 4-momentum of the particle.
Class providing the definition of the 4-vector interface.
virtual FourMom_t p4() const override final
The full 4-momentum of the particle.
const Trk::Track * track() const
Returns a pointer (which can be NULL) to the Trk::Track which was used to make this TrackParticle.
virtual double phi() const override final
The azimuthal angle ( ) of the particle (has range to .).
virtual double pt() const override final
The transverse momentum ( ) of the particle.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
static const SG::ConstAccessor< char > PVMatchedAcc("matchedToPV")
@ Muon
The object is a muon.
Definition ObjectType.h:48
bool isInDeltaR(const xAOD::IParticle &p1, const xAOD::IParticle &p2, double dR, bool useRapidity=true)
Check if 2 xAOD::IParticle are in a cone.
double deltaR(double rapidity1, double phi1, double rapidity2, double phi2)
from bare bare rapidity,phi
ICaloAffectedTool is abstract interface for tools checking if 4 mom is in calo affected region.
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
FlowElement_v1 FlowElement
Definition of the current "pfo version".
Definition FlowElement.h:16
TrackParticle_v1 TrackParticle
Reference the current persistent version:
Muon_v1 Muon
Reference the current persistent version:
MissingETAssociationMap_v1 MissingETAssociationMap
Version control by type defintion.
const xAOD::FlowElementContainer * feCont
const xAOD::PFOContainer * pfoCont