ATLAS Offline Software
Loading...
Searching...
No Matches
MuonMatchQuality.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
4
6// get quality of combined track match
8
9#include "MuonMatchQuality.h"
10
11#include <cmath>
12#include <iomanip>
13#include <memory>
14
15#include "CLHEP/GenericFunctions/CumulativeChiSquare.hh"
17#include "TrkTrack/Track.h"
18namespace Rec {
19
20 MuonMatchQuality::MuonMatchQuality(const std::string& type, const std::string& name, const IInterface* parent) :
21 AthAlgTool(type, name, parent), m_alignmentUncertainty(nullptr) {
22 declareInterface<IMuonMatchQuality>(this);
23 }
24
26 ATH_MSG_DEBUG("MuonMatchQuality::initialize().");
27
28 // get the tools
29 if (!m_tagTool.name().empty()) { ATH_CHECK(m_tagTool.retrieve()); }
30 ATH_CHECK(m_trackQuery.retrieve());
31
32 // set up alignment uncertainty between ID and MS tracking systems
33 m_alignmentUncertainty = std::make_unique<AmgSymMatrix(5)>();
34 m_alignmentUncertainty->setZero();
35 (*m_alignmentUncertainty)(0, 0) = m_positionUncertainty * m_positionUncertainty;
36 (*m_alignmentUncertainty)(1, 1) = m_positionUncertainty * m_positionUncertainty;
37 (*m_alignmentUncertainty)(2, 2) = m_directionUncertainty * m_directionUncertainty;
38 (*m_alignmentUncertainty)(3, 3) = m_directionUncertainty * m_directionUncertainty;
39
40 return StatusCode::SUCCESS;
41 }
42
45 double MuonMatchQuality::innerMatchChi2(const Trk::Track& track1, const Trk::Track& track2, const EventContext& ctx) const {
46 MuonMatchQuality::CacheAll CA = setCache(track1, track2, ctx);
47 return CA.innerMatchChi2;
48 }
49
51 int MuonMatchQuality::innerMatchDOF(const Trk::Track& track1, const Trk::Track& track2) const {
52 int matchDOF = 0;
53
54 const Trk::Perigee* perigee1 = track1.perigeeParameters();
55 const Trk::Perigee* perigee2 = track2.perigeeParameters();
56
57 if (perigee1 && perigee2 && (*perigee1).associatedSurface().center() == (*perigee2).associatedSurface().center()) {
58 if (m_trackQuery->isLineFit(track1) || m_trackQuery->isLineFit(track2)) {
59 matchDOF = 4;
60 } else {
61 matchDOF = 5;
62 }
63 }
64
65 return matchDOF;
66 }
67 double MuonMatchQuality::innerMatchProbability(const Trk::Track& track1, const Trk::Track& track2, const EventContext& ctx) const {
68 MuonMatchQuality::CacheAll CA = setCache(track1, track2, ctx);
69 return CA.innerMatchProbability;
70 }
71
72 std::pair<int, std::pair<double, double> > MuonMatchQuality::innerMatchAll(const Trk::Track& track1, const Trk::Track& track2,
73 const EventContext& ctx) const {
74 MuonMatchQuality::CacheAll CA = setCache(track1, track2, ctx);
75
76 std::pair<int, std::pair<double, double> > aTriad =
77 std::make_pair(CA.innerMatchDOF, std::make_pair(CA.innerMatchChi2, CA.innerMatchProbability));
78
79 return aTriad;
80 }
81 double MuonMatchQuality::outerMatchChi2(const Trk::Track& track1, const Trk::Track& track2, const EventContext& ctx) const {
82 // caching needs some development...
83 // setCache(track1,track2);
84 double outerMatchChi2 = 999999.;
85 if (!m_tagTool.empty()) { outerMatchChi2 = m_tagTool->chi2(track1, track2, ctx); }
86
87 return outerMatchChi2;
88 }
89
91 int MuonMatchQuality::outerMatchDOF(const Trk::Track& /*track1*/, const Trk::Track& /*track2*/) const { return 4; }
92 double MuonMatchQuality::outerMatchProbability(const Trk::Track& track1, const Trk::Track& track2, const EventContext& ctx) const {
93 double outerMatchProbability = 0.;
94 if (!m_tagTool.empty()) {
95 double outer_chi2 = outerMatchChi2(track1, track2, ctx);
96
97 // probability of MS chi2
98 if (outer_chi2 > 0. && outer_chi2 < 1000.) {
99 Genfun::CumulativeChiSquare func(4);
100 outerMatchProbability = 1. - func(outer_chi2);
101 }
102 }
104 }
105
107 bool MuonMatchQuality::shareOrigin(const Trk::Track& track1, const Trk::Track& track2) const {
108 const Trk::Perigee* perigee1 = track1.perigeeParameters();
109 const Trk::Perigee* perigee2 = track2.perigeeParameters();
110
111 return perigee1 && perigee2 && (*perigee1).associatedSurface().center() == (*perigee2).associatedSurface().center();
112 }
113 double MuonMatchQuality::simpleChi2(const Trk::Track& track1, const Trk::Track& track2, const EventContext& ctx) const {
114 MuonMatchQuality::CacheAll CA = setCache(track1, track2, ctx);
115 return CA.simpleChi2;
116 }
117
118 /* private method to fill cache */
120 const EventContext& ctx) const {
122 // set match degrees of freedom
123 CA.innerMatchDOF = innerMatchDOF(track1, track2);
124 if (!CA.innerMatchDOF) return CA;
125
126 // parameter difference
127 const Trk::Perigee* perigee1 = track1.perigeeParameters();
128 const Trk::Perigee* perigee2 = track2.perigeeParameters();
129
130 // coverity false positive (as null pointers cause innerMatchDOF failure)
131 if (!perigee1 || !perigee2) return CA;
132
133 double deltaD0 = perigee1->parameters()[Trk::d0] - perigee2->parameters()[Trk::d0];
134 double deltaZ0 = perigee1->parameters()[Trk::z0] - perigee2->parameters()[Trk::z0];
135 double deltaPhi0 = xAOD::P4Helpers::deltaPhi(perigee1->parameters()[Trk::phi0], perigee2->parameters()[Trk::phi0]);
136 double deltaTheta = perigee1->parameters()[Trk::theta] - perigee2->parameters()[Trk::theta];
137 double deltaQoverP = perigee1->parameters()[Trk::qOverP] - perigee2->parameters()[Trk::qOverP];
138
139 // weight matrix for differences
140 const AmgSymMatrix(5)* cov1 = perigee1->covariance();
141 const AmgSymMatrix(5)* cov2 = perigee2->covariance();
142
143 AmgSymMatrix(5) covariance;
144 covariance.setZero();
145
146 if (m_trackQuery->isCombined(track1, ctx)) {
147 // FIXME: should take weighted difference etc -
148 // but this is anyway unreliable due to rounding errors
149 ATH_MSG_WARNING("track1 isCombined: results unreliable ");
150 } else if (m_trackQuery->isCombined(track2, ctx)) {
151 // FIXME: weighted difference etc
152 ATH_MSG_WARNING("track2 isCombined: results unreliable ");
153 }
154
155 covariance = *cov1 + *cov2 + *m_alignmentUncertainty;
156 if (CA.innerMatchDOF < 5) {
157 deltaQoverP = 0.;
158 for (int i = 0; i != Trk::qOverP; ++i) {
159 covariance(i, Trk::qOverP) = covariance(Trk::qOverP, i) = 0.;
160 }
161 covariance(Trk::qOverP, Trk::qOverP) = 1.;
162 } else {
163 deltaQoverP /= Units::TeV;
164 for (int i = 0; i != Trk::qOverP; ++i) {
165 covariance(i, Trk::qOverP) /= Units::TeV;
166 covariance(Trk::qOverP, i) /= Units::TeV;
167 }
168 covariance(Trk::qOverP, Trk::qOverP) /= (Units::TeV * Units::TeV);
169 }
170
171 // invert summed covariance
172 AmgMatrix(5, 5) weight = covariance.inverse().eval();
173
174 AmgMatrix(5, 1) paramDifference;
175 paramDifference.setZero();
176 paramDifference(Trk::d0, 0) = deltaD0;
177 paramDifference(Trk::z0, 0) = deltaZ0;
178 paramDifference(Trk::phi0, 0) = deltaPhi0;
179 paramDifference(Trk::theta, 0) = deltaTheta;
180 paramDifference(Trk::qOverP, 0) = deltaQoverP;
181
182 double matchChi2 = paramDifference.dot(weight * paramDifference);
183 CA.innerMatchChi2 = matchChi2;
184
185 // probability of chi2
186 if (CA.innerMatchChi2 >= 0. && CA.innerMatchChi2 < 1000.) {
187 CA.innerMatchProbability = 1. - Genfun::CumulativeChiSquare(CA.innerMatchDOF)(CA.innerMatchChi2);
188 }
189
190 // Protect against zero division
191 bool nonzerocov = true;
192 for (int k = 0; k < covariance.cols(); k++) {
193 if (covariance(k, k) == 0) nonzerocov = false;
194 }
195
196 if (nonzerocov) {
197 // simple chi2 as sometimes correlations overestimated
198 CA.simpleChi2 = deltaD0 * deltaD0 / covariance(Trk::d0, Trk::d0) + deltaZ0 * deltaZ0 / covariance(Trk::z0, Trk::z0) +
199 deltaPhi0 * deltaPhi0 / covariance(Trk::phi0, Trk::phi0) +
200 deltaTheta * deltaTheta / covariance(Trk::theta, Trk::theta) +
201 deltaQoverP * deltaQoverP / covariance(Trk::qOverP, Trk::qOverP);
202
203 if (CA.simpleChi2 + 5. < CA.innerMatchChi2) {
204 ATH_MSG_DEBUG("problem with matchChi2 " << CA.innerMatchChi2 << ", simpleChi2 " << CA.simpleChi2);
205 }
206 } else {
207 ATH_MSG_WARNING("Could not compute simpleChi2. Covariance matrix contains zeros");
208 }
209
210 ATH_MSG_VERBOSE(std::setiosflags(std::ios::fixed)
211 << "matchDOF" << std::setw(2) << CA.innerMatchDOF << " matchChi2:" << std::setw(6) << std::setprecision(1)
212 << CA.innerMatchChi2 << " simpleChi2:" << std::setw(6) << std::setprecision(1) << CA.simpleChi2 << " pullD0 "
213 << std::setw(5) << std::setprecision(1) << deltaD0 / std::sqrt(covariance(0, 0)) << " pullZ0 " << std::setw(5)
214 << std::setprecision(1) << deltaZ0 / std::sqrt(covariance(1, 1)) << " pullPhi0 " << std::setw(5)
215 << std::setprecision(1) << deltaPhi0 / std::sqrt(covariance(2, 2)) << " pullTheta " << std::setw(5)
216 << std::setprecision(1) << deltaTheta / std::sqrt(covariance(3, 3)) << " pullQoverP " << std::setw(5)
217 << std::setprecision(1) << deltaQoverP / std::sqrt(covariance(4, 4)));
218
219 return CA;
220 }
221
222} // namespace Rec
#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)
#define AmgSymMatrix(dim)
#define AmgMatrix(rows, cols)
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Gaudi::Property< double > m_directionUncertainty
virtual bool shareOrigin(const Trk::Track &track1, const Trk::Track &track2) const override
IMuonMatchQuality interface: check the track perigee parameters are expressed at the same surface.
double innerMatchProbability(const Trk::Track &track1, const Trk::Track &track2, const EventContext &ctx) const override
IMuonMatchQuality interface: match probability for chi2 match at IP.
Gaudi::Property< double > m_positionUncertainty
double outerMatchChi2(const Trk::Track &track1, const Trk::Track &track2, const EventContext &ctx) const override
IMuonMatchQuality interface: match chiSquared between two tracks expressed at first muon spectrometer...
double simpleChi2(const Trk::Track &track1, const Trk::Track &track2, const EventContext &ctx) const override
IMuonMatchQuality interface: as inner match chiSquared but simplified to just use diagonal errors.
int innerMatchDOF(const Trk::Track &track1, const Trk::Track &track2) const override
IMuonMatchQuality interface: degrees of freedom for chi2 match at IP.
MuonMatchQuality(const std::string &type, const std::string &name, const IInterface *parent)
double outerMatchProbability(const Trk::Track &track1, const Trk::Track &track2, const EventContext &ctx) const override
IMuonMatchQuality interface: match probability for chi2 match at first MS hit.
CacheAll setCache(const Trk::Track &track1, const Trk::Track &track2, const EventContext &ctx) const
ToolHandle< MuonCombined::IMuonTrackTagTool > m_tagTool
StatusCode initialize() override
virtual int outerMatchDOF(const Trk::Track &track1, const Trk::Track &track2) const override
IMuonMatchQuality interface: degrees of freedom for chi2 match at first MS hit.
ToolHandle< IMuonTrackQuery > m_trackQuery
std::unique_ptr< AmgSymMatrix(5)> m_alignmentUncertainty
std::pair< int, std::pair< double, double > > innerMatchAll(const Trk::Track &track1, const Trk::Track &track2, const EventContext &ctx) const override
IMuonMatchQuality interface: degrees of freedom, chi2, probability for chi2 match at IP.
double innerMatchChi2(const Trk::Track &track1, const Trk::Track &track2, const EventContext &ctx) const override
IMuonMatchQuality interface: match chiSquared between two tracks expressed at same inner (IP) surface...
virtual const S & associatedSurface() const override final
Access to the Surface method.
const Amg::Vector3D & center() const
Returns the center position of the Surface.
const Perigee * perigeeParameters() const
return Perigee.
Gaudi Tools.
ParametersT< TrackParametersDim, Charged, PerigeeSurface > Perigee
@ phi0
Definition ParamDefs.h:65
@ theta
Definition ParamDefs.h:66
@ qOverP
perigee
Definition ParamDefs.h:67
@ d0
Definition ParamDefs.h:63
@ z0
Definition ParamDefs.h:64
double deltaPhi(double phiA, double phiB)
delta Phi in range [-pi,pi[