ATLAS Offline Software
Loading...
Searching...
No Matches
MuonScatteringAngleSignificanceTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
10#include "TrkTrack/Track.h"
12
13namespace Rec {
14
15 //<<<<<< PUBLIC MEMBER FUNCTION DEFINITIONS >>>>>>
17 ATH_MSG_INFO("Initializing MuonScatAngleSignificanceTool");
18
19 // tool needed to refit slimmed tracks
20 ATH_CHECK(m_fitter.retrieve(EnableTool{!m_fitter.empty()}));
21 // need to know which TrackingVolume we are in: indet/calo/spectrometer
23
24 ATH_MSG_DEBUG("Retrieved Svc " << m_trackingVolumesSvc);
27
28
29 return StatusCode::SUCCESS;
30 }
31
33 if (muon.muonType() == xAOD::Muon::MuonType::MuonStandAlone) {
35 }
36
37 const Trk::Track* theTrack =
38 muon.trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle) ?
39 muon.trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle)->track() : nullptr;
40
41 if (theTrack == nullptr) {
42 theTrack = muon.trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle)
43 ? muon.trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle)->track()
44 : nullptr;
45 }
46
47 if (theTrack == nullptr) {
48 ATH_MSG_DEBUG("No track, returning empty scatterer-significance object.");
50 } else
51 return scatteringAngleSignificance(*theTrack);
52 }
53
55 // provide refit for slimmed tracks
56 const Trk::Track* fullTrack = &track;
57 const Trk::Track* refittedTrack = nullptr;
58 // if (track.info().trackProperties(Trk::TrackInfo::SlimmedTrack)) {
59 if (isSlimmed(track)) { // TrackInfo::SlimmedTrack wouldn't detect STACO tracks as (half-)slimmed
60
61 if (!m_fitter.empty() && track.perigeeParameters() && track.measurementsOnTrack() && track.measurementsOnTrack()->size() > 3) {
62 ATH_MSG_VERBOSE(" perform refit as track has been slimmed");
63 if (m_refitInDetOnly) {
64 std::vector<const Trk::MeasurementBase*> vec;
65 DataVector<const Trk::MeasurementBase>::const_iterator measIter = track.measurementsOnTrack()->begin();
66 for (; measIter != track.measurementsOnTrack()->end(); ++measIter) {
67 const Amg::Vector3D& position = (*measIter)->globalPosition();
68 if (!m_indetVolume->inside(position)) continue;
69 vec.push_back((*measIter));
70 }
71 ATH_MSG_DEBUG("Refitting ID-part of track, meast vector of size " << vec.size());
72 refittedTrack = m_fitter->fit(Gaudi::Hive::currentContext(),
73 vec,
74 *(track.perigeeParameters()),
75 false,
76 Trk::muon).release();
77 } else {
78 refittedTrack = m_fitter->fit(
79 Gaudi::Hive::currentContext(), track, false, Trk::muon).release();
80 }
81 fullTrack = refittedTrack;
82 }
83 ATH_MSG_DEBUG("Detected slimmed track, " << (refittedTrack ? "refit was successful" : "but could not refit it!"));
84
85 if (!refittedTrack) return ScatteringAngleSignificance(0);
86 }
87
88 // collect sigma of phi scatterers up to last inDet measurement TSOS or to CaloDeposit TSOS
89 // (according to configuration).
90 // Define scattering in direction of curvature change to be +ve
91 double charge = fullTrack->perigeeParameters()->charge();
92 unsigned measurements = 0;
93 double neighbourRadius = 0.;
94 double neighbourSignificance = 0.;
95 unsigned neighbours = 0;
96 unsigned scatterers = 0;
97 unsigned startMeasurement = 0;
98 std::vector<bool> isMeasurement;
99 std::vector<unsigned> measurementNumber;
100 std::vector<double> radii;
101 std::vector<double> sigmas;
102 double significance = 0.;
103 double totalSigma = 0.;
104 double weightedRadius = 0.;
106 s != fullTrack->trackStateOnSurfaces()->end(); ++s) {
107 // skip leading material
108 if ((**s).measurementOnTrack()) {
109 ++measurements;
110 } else if (!measurements)
111 continue;
112
113 // select MaterialEffects up to calorimeter energy deposit
114 if (!(**s).materialEffectsOnTrack()) continue;
115 if ((**s).type(Trk::TrackStateOnSurface::CaloDeposit)) break;
116 const Amg::Vector3D& position = (**s).materialEffectsOnTrack()->associatedSurface().globalReferencePoint();
117 if (!m_calorimeterVolume->inside(position)) break;
118
119 const Trk::MaterialEffectsOnTrack* meot = dynamic_cast<const Trk::MaterialEffectsOnTrack*>((**s).materialEffectsOnTrack());
120 if (!meot) continue;
121
122 // get scattering angle
123 const Trk::ScatteringAngles* scattering = meot->scatteringAngles();
124 if (!scattering) continue;
125
126 ++scatterers;
127 double radius = (**s).trackParameters()->position().perp();
128 double sigma = charge * scattering->deltaPhi() / scattering->sigmaDeltaPhi();
129 if ((**s).measurementOnTrack()) {
130 isMeasurement.push_back(true);
131 } else {
132 isMeasurement.push_back(false);
133 }
134 measurementNumber.push_back(measurements);
135
136 // keep maximum neighbour significance
137 // (summed scattering significance for scatterers spanning neighbouring measurements)
138 ++neighbours;
139 significance += sigma;
140 weightedRadius += sigma * radius;
141 if (neighbours > 1 && measurements > startMeasurement) {
142 double norm = 1. / sqrt(static_cast<double>(neighbours));
143 if (norm * fabs(significance) > fabs(neighbourSignificance)) {
144 if (significance == 0.) {
145 neighbourRadius = radius;
146 } else {
147 neighbourRadius = weightedRadius / significance;
148 }
149 neighbourSignificance = norm * significance;
150 ATH_MSG_VERBOSE(" current maximum for neighbourSignificance " << neighbourSignificance << " from " << neighbours
151 << " scatterers at radius " << neighbourRadius);
152 }
153 ATH_MSG_VERBOSE(" reset neighbour after " << significance << " /sqrt(" << neighbours << ") at radius " << radius);
154 neighbours = 0;
155 significance = 0.;
156 startMeasurement = measurements;
157 weightedRadius = 0.;
158 if (isMeasurement.back()) {
159 ++neighbours;
160 significance += sigma;
161 weightedRadius += sigma * radius;
162 }
163 }
164
165 radii.push_back(radius);
166 sigmas.push_back(sigma);
167 totalSigma += sigma;
168
169 ATH_MSG_VERBOSE(scatterers << " " << measurements << " " << isMeasurement.back() << " radius "
170 << (**s).trackParameters()->position().perp() << " deltaPhi " << scattering->deltaPhi()
171 << " significance " << sigma << " integralSignificance " << totalSigma);
172 }
173
174 // pop_back to last measurement unless configured to use calo
175 delete refittedTrack;
176 if (m_inDetOnly) {
177 while (scatterers && measurementNumber.back() == measurements && !isMeasurement.back()) {
178 --scatterers;
179 totalSigma -= sigmas.back();
180 isMeasurement.pop_back();
181 measurementNumber.pop_back();
182 radii.pop_back();
183 sigmas.pop_back();
184 }
185 }
186
187 // quit if no scatterers selected
188 if (!scatterers) {
189 ATH_MSG_DEBUG(" no scatterers selected, giving up.");
191 }
192
193 // search for discontinuity point (sign change of integral scattering)
194 // maximum value determines curvatureSignificance
195 double curvatureSignificance = totalSigma;
196 double curvatureRadius = *radii.rbegin();
197 unsigned index = scatterers - 1;
198
199 ATH_MSG_VERBOSE(" scatteringAngleSignificance " << totalSigma << " at radius " << radii[index] << " at scatterer " << scatterers
200 << " sigmas.size() " << sigmas.size());
201
202 for (std::vector<double>::const_reverse_iterator r = sigmas.rbegin(); r != sigmas.rend(); ++r, --index) {
203 totalSigma -= 2. * (*r);
204 if (index > 1)
205 ATH_MSG_VERBOSE(" scatteringAngleSignificance " << totalSigma << " at radius " << radii[index - 1] << " at scatterer "
206 << index);
207
208 if (fabs(totalSigma) > fabs(curvatureSignificance) && index > 1) {
209 curvatureSignificance = totalSigma;
210 curvatureRadius = radii[index - 1];
211 }
212 }
213
214 // normalize final curvature significance
215 curvatureSignificance /= sqrt(static_cast<double>(scatterers));
216
217 ATH_MSG_DEBUG(" scatteringAngleSignificance" << std::setiosflags(std::ios::fixed) << std::setw(7) << std::setprecision(2)
218 << curvatureSignificance << " at radius " << std::setw(6) << std::setprecision(1)
219 << curvatureRadius << " neighbourSignificance " << std::setw(7) << std::setprecision(2)
220 << neighbourSignificance << " at radius " << std::setw(6) << std::setprecision(1)
221 << neighbourRadius << " from " << scatterers << " scatterers");
222
223 return ScatteringAngleSignificance(scatterers, curvatureRadius, curvatureSignificance, neighbourRadius, neighbourSignificance);
224 }
225
227 for (Trk::TrackStates::const_iterator s = track.trackStateOnSurfaces()->begin();
228 s != track.trackStateOnSurfaces()->end(); ++s) {
229 if ((**s).trackParameters()) continue;
230
231 ATH_MSG_VERBOSE("track is slimmed (found TSOS without trackParameters) ");
232 return true;
233 }
234
235 ATH_MSG_VERBOSE("track is not slimmed (all TSOS have trackParameters) ");
236
237 return false;
238 }
239
240} // namespace Rec
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
double charge(const T &p)
Definition AtlasPID.h:997
std::vector< size_t > vec
DataModel_detail::const_iterator< DataVector > const_iterator
Standard const_iterator.
Definition DataVector.h:838
const_iterator end() const noexcept
Return a const_iterator pointing past the end of the collection.
const_iterator begin() const noexcept
Return a const_iterator pointing at the beginning of the collection.
ToolHandle< Trk::ITrackFitter > m_fitter
tool for unslimming via track fit
bool isSlimmed(const Trk::Track &track) const
does track have TrackParameters at every TSOS ?
Gaudi::Property< bool > m_inDetOnly
scatterers from ID only (or ID + calo)
ServiceHandle< Trk::ITrackingVolumesSvc > m_trackingVolumesSvc
Gaudi::Property< bool > m_refitInDetOnly
steer if to unslim only ID
std::unique_ptr< const Trk::Volume > m_indetVolume
cache the ID volume pointer
std::unique_ptr< const Trk::Volume > m_calorimeterVolume
cache the calo volume pointer
ScatteringAngleSignificance scatteringAngleSignificance(const xAOD::Muon &muon) const
Calculate ScatteringAngleSignificance of a muon, stepping down to the relevant track.
lightweight return data-object for (mainly indet) scattering angle analysis by track query
@ CalorimeterEntryLayer
Tracking Volume which defines the entrance srufaces of the calorimeter.
@ MuonSpectrometerEntryLayer
Tracking Volume which defines the entrance surfaces of the MS.
represents the full description of deflection and e-loss of a track in material.
const ScatteringAngles * scatteringAngles() const
returns the MCS-angles object.
double charge() const
Returns the charge.
represents a deflection of the track caused through multiple scattering in material.
double sigmaDeltaPhi() const
returns the
double deltaPhi() const
returns the
@ CaloDeposit
This TSOS contains a CaloEnergy object.
const Trk::TrackStates * trackStateOnSurfaces() const
return a pointer to a const DataVector of const TrackStateOnSurfaces.
const Perigee * perigeeParameters() const
return Perigee.
int r
Definition globals.cxx:22
Eigen::Matrix< double, 3, 1 > Vector3D
Gaudi Tools.
Definition index.py:1
Muon_v1 Muon
Reference the current persistent version: