ATLAS Offline Software
Loading...
Searching...
No Matches
MuonScatteringAngleSignificanceTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
6
11#include "TrkTrack/Track.h"
13
14namespace Rec {
15
17 const IInterface* parent) :
18 AthAlgTool(type, name, parent), m_calorimeterVolume(nullptr), m_indetVolume(nullptr), m_inDetOnly(true), m_refitInDetOnly(true) {
19 declareInterface<IMuonScatteringAngleSignificance>(this);
20 declareProperty("InDetOnly", m_inDetOnly);
21 declareProperty("RefitInDetOnly", m_refitInDetOnly);
22 }
23
24 //<<<<<< PUBLIC MEMBER FUNCTION DEFINITIONS >>>>>>
26 ATH_MSG_INFO("Initializing MuonScatAngleSignificanceTool");
27
28 // tool needed to refit slimmed tracks
29 if (!m_fitter.empty()) {
30 if (m_fitter.retrieve().isFailure()) {
31 ATH_MSG_FATAL("Failed to retrieve tool " << m_fitter);
32 m_fitter.setTypeAndName(""); // Bang!
33 } else {
34 ATH_MSG_DEBUG("Retrieved tool " << m_fitter);
35 }
36 }
37
38 // need to know which TrackingVolume we are in: indet/calo/spectrometer
39 if (m_trackingVolumesSvc.retrieve().isFailure()) {
40 ATH_MSG_FATAL("Failed to retrieve Svc " << m_trackingVolumesSvc);
41 return StatusCode::FAILURE;
42 } else {
43 ATH_MSG_DEBUG("Retrieved Svc " << m_trackingVolumesSvc);
46 }
47
48 return StatusCode::SUCCESS;
49 }
50
52 if (muon.muonType() == xAOD::Muon::MuonStandAlone) return ScatteringAngleSignificance(0);
53
54 const Trk::Track* theTrack =
55 muon.trackParticle(xAOD::Muon::CombinedTrackParticle) ? muon.trackParticle(xAOD::Muon::CombinedTrackParticle)->track() : nullptr;
56
57 if (theTrack == nullptr) {
58 theTrack = muon.trackParticle(xAOD::Muon::InnerDetectorTrackParticle)
59 ? muon.trackParticle(xAOD::Muon::InnerDetectorTrackParticle)->track()
60 : nullptr;
61 }
62
63 if (theTrack == nullptr) {
64 ATH_MSG_DEBUG("No track, returning empty scatterer-significance object.");
66 } else
67 return scatteringAngleSignificance(*theTrack);
68 }
69
71 // provide refit for slimmed tracks
72 const Trk::Track* fullTrack = &track;
73 const Trk::Track* refittedTrack = nullptr;
74 // if (track.info().trackProperties(Trk::TrackInfo::SlimmedTrack)) {
75 if (isSlimmed(track)) { // TrackInfo::SlimmedTrack wouldn't detect STACO tracks as (half-)slimmed
76
77 if (!m_fitter.empty() && track.perigeeParameters() && track.measurementsOnTrack() && track.measurementsOnTrack()->size() > 3) {
78 ATH_MSG_VERBOSE(" perform refit as track has been slimmed");
79 if (m_refitInDetOnly) {
80 std::vector<const Trk::MeasurementBase*> vec;
81 DataVector<const Trk::MeasurementBase>::const_iterator measIter = track.measurementsOnTrack()->begin();
82 for (; measIter != track.measurementsOnTrack()->end(); ++measIter) {
83 const Amg::Vector3D& position = (*measIter)->globalPosition();
84 if (!m_indetVolume->inside(position)) continue;
85 vec.push_back((*measIter));
86 }
87 ATH_MSG_DEBUG("Refitting ID-part of track, meast vector of size " << vec.size());
88 refittedTrack = m_fitter->fit(Gaudi::Hive::currentContext(),
89 vec,
90 *(track.perigeeParameters()),
91 false,
92 Trk::muon).release();
93 } else {
94 refittedTrack = m_fitter->fit(
95 Gaudi::Hive::currentContext(), track, false, Trk::muon).release();
96 }
97 fullTrack = refittedTrack;
98 }
99 ATH_MSG_DEBUG("Detected slimmed track, " << (refittedTrack ? "refit was successful" : "but could not refit it!"));
100
101 if (!refittedTrack) return ScatteringAngleSignificance(0);
102 }
103
104 // collect sigma of phi scatterers up to last inDet measurement TSOS or to CaloDeposit TSOS
105 // (according to configuration).
106 // Define scattering in direction of curvature change to be +ve
107 double charge = fullTrack->perigeeParameters()->charge();
108 unsigned measurements = 0;
109 double neighbourRadius = 0.;
110 double neighbourSignificance = 0.;
111 unsigned neighbours = 0;
112 unsigned scatterers = 0;
113 unsigned startMeasurement = 0;
114 std::vector<bool> isMeasurement;
115 std::vector<unsigned> measurementNumber;
116 std::vector<double> radii;
117 std::vector<double> sigmas;
118 double significance = 0.;
119 double totalSigma = 0.;
120 double weightedRadius = 0.;
122 s != fullTrack->trackStateOnSurfaces()->end(); ++s) {
123 // skip leading material
124 if ((**s).measurementOnTrack()) {
125 ++measurements;
126 } else if (!measurements)
127 continue;
128
129 // select MaterialEffects up to calorimeter energy deposit
130 if (!(**s).materialEffectsOnTrack()) continue;
131 if ((**s).type(Trk::TrackStateOnSurface::CaloDeposit)) break;
132 const Amg::Vector3D& position = (**s).materialEffectsOnTrack()->associatedSurface().globalReferencePoint();
133 if (!m_calorimeterVolume->inside(position)) break;
134
135 const Trk::MaterialEffectsOnTrack* meot = dynamic_cast<const Trk::MaterialEffectsOnTrack*>((**s).materialEffectsOnTrack());
136 if (!meot) continue;
137
138 // get scattering angle
139 const Trk::ScatteringAngles* scattering = meot->scatteringAngles();
140 if (!scattering) continue;
141
142 ++scatterers;
143 double radius = (**s).trackParameters()->position().perp();
144 double sigma = charge * scattering->deltaPhi() / scattering->sigmaDeltaPhi();
145 if ((**s).measurementOnTrack()) {
146 isMeasurement.push_back(true);
147 } else {
148 isMeasurement.push_back(false);
149 }
150 measurementNumber.push_back(measurements);
151
152 // keep maximum neighbour significance
153 // (summed scattering significance for scatterers spanning neighbouring measurements)
154 ++neighbours;
155 significance += sigma;
156 weightedRadius += sigma * radius;
157 if (neighbours > 1 && measurements > startMeasurement) {
158 double norm = 1. / sqrt(static_cast<double>(neighbours));
159 if (norm * fabs(significance) > fabs(neighbourSignificance)) {
160 if (significance == 0.) {
161 neighbourRadius = radius;
162 } else {
163 neighbourRadius = weightedRadius / significance;
164 }
165 neighbourSignificance = norm * significance;
166 ATH_MSG_VERBOSE(" current maximum for neighbourSignificance " << neighbourSignificance << " from " << neighbours
167 << " scatterers at radius " << neighbourRadius);
168 }
169 ATH_MSG_VERBOSE(" reset neighbour after " << significance << " /sqrt(" << neighbours << ") at radius " << radius);
170 neighbours = 0;
171 significance = 0.;
172 startMeasurement = measurements;
173 weightedRadius = 0.;
174 if (isMeasurement.back()) {
175 ++neighbours;
176 significance += sigma;
177 weightedRadius += sigma * radius;
178 }
179 }
180
181 radii.push_back(radius);
182 sigmas.push_back(sigma);
183 totalSigma += sigma;
184
185 ATH_MSG_VERBOSE(scatterers << " " << measurements << " " << isMeasurement.back() << " radius "
186 << (**s).trackParameters()->position().perp() << " deltaPhi " << scattering->deltaPhi()
187 << " significance " << sigma << " integralSignificance " << totalSigma);
188 }
189
190 // pop_back to last measurement unless configured to use calo
191 delete refittedTrack;
192 if (m_inDetOnly) {
193 while (scatterers && measurementNumber.back() == measurements && !isMeasurement.back()) {
194 --scatterers;
195 totalSigma -= sigmas.back();
196 isMeasurement.pop_back();
197 measurementNumber.pop_back();
198 radii.pop_back();
199 sigmas.pop_back();
200 }
201 }
202
203 // quit if no scatterers selected
204 if (!scatterers) {
205 ATH_MSG_DEBUG(" no scatterers selected, giving up.");
207 }
208
209 // search for discontinuity point (sign change of integral scattering)
210 // maximum value determines curvatureSignificance
211 double curvatureSignificance = totalSigma;
212 double curvatureRadius = *radii.rbegin();
213 unsigned index = scatterers - 1;
214
215 ATH_MSG_VERBOSE(" scatteringAngleSignificance " << totalSigma << " at radius " << radii[index] << " at scatterer " << scatterers
216 << " sigmas.size() " << sigmas.size());
217
218 for (std::vector<double>::const_reverse_iterator r = sigmas.rbegin(); r != sigmas.rend(); ++r, --index) {
219 totalSigma -= 2. * (*r);
220 if (index > 1)
221 ATH_MSG_VERBOSE(" scatteringAngleSignificance " << totalSigma << " at radius " << radii[index - 1] << " at scatterer "
222 << index);
223
224 if (fabs(totalSigma) > fabs(curvatureSignificance) && index > 1) {
225 curvatureSignificance = totalSigma;
226 curvatureRadius = radii[index - 1];
227 }
228 }
229
230 // normalize final curvature significance
231 curvatureSignificance /= sqrt(static_cast<double>(scatterers));
232
233 ATH_MSG_DEBUG(" scatteringAngleSignificance" << std::setiosflags(std::ios::fixed) << std::setw(7) << std::setprecision(2)
234 << curvatureSignificance << " at radius " << std::setw(6) << std::setprecision(1)
235 << curvatureRadius << " neighbourSignificance " << std::setw(7) << std::setprecision(2)
236 << neighbourSignificance << " at radius " << std::setw(6) << std::setprecision(1)
237 << neighbourRadius << " from " << scatterers << " scatterers");
238
239 return ScatteringAngleSignificance(scatterers, curvatureRadius, curvatureSignificance, neighbourRadius, neighbourSignificance);
240 }
241
243 for (Trk::TrackStates::const_iterator s = track.trackStateOnSurfaces()->begin();
244 s != track.trackStateOnSurfaces()->end(); ++s) {
245 if ((**s).trackParameters()) continue;
246
247 ATH_MSG_VERBOSE("track is slimmed (found TSOS without trackParameters) ");
248 return true;
249 }
250
251 ATH_MSG_VERBOSE("track is not slimmed (all TSOS have trackParameters) ");
252
253 return false;
254 }
255
256} // namespace Rec
#define ATH_MSG_FATAL(x)
#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
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
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 ?
MuonScatteringAngleSignificanceTool(const std::string &type, const std::string &name, const IInterface *parent)
const Trk::Volume * m_indetVolume
cache the ID volume pointer
ServiceHandle< Trk::ITrackingVolumesSvc > m_trackingVolumesSvc
const Trk::Volume * m_calorimeterVolume
cache the calo volume pointer
bool m_inDetOnly
scatterers from ID only (or ID + calo)
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.
Base class for all volumes inside the tracking realm, it defines the interface for inherited Volume c...
Definition Volume.h:36
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: