ATLAS Offline Software
Loading...
Searching...
No Matches
MuonTrackSelectorTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <map>
8
14#include "TrkTrack/Track.h"
18namespace Muon {
19
20 MuonTrackSelectorTool::MuonTrackSelectorTool(const std::string& ty, const std::string& na, const IInterface* pa) :
21 AthAlgTool(ty, na, pa) {}
22
24 ATH_CHECK(m_edmHelperSvc.retrieve());
25 ATH_CHECK(m_printer.retrieve());
26 ATH_CHECK(m_idHelperSvc.retrieve());
27 ATH_CHECK(m_trackSummaryTool.retrieve());
28
29 return StatusCode::SUCCESS;
30 }
32 // print counters
33 ATH_MSG_INFO(" Number of tracks handled by selector " << m_ntotalTracks);
34 if (m_ntotalTracks != 0) {
35 double failedChi2NDofCutFraction = (double)m_failedChi2NDofCut / (double)m_ntotalTracks;
36 double failedRPCAveMinTimeCutFraction = (double)m_failedRPCAveMinTimeCut / (double)m_ntotalTracks;
37 double failedRPCAveMaxTimeCutFraction = (double)m_failedRPCAveMaxTimeCut / (double)m_ntotalTracks;
38 double failedRPCSpreadTimeCutFraction = (double)m_failedRPCSpreadTimeCut / (double)m_ntotalTracks;
39 double failedSingleStationsCutFraction = (double)m_failedSingleStationCut / (double)m_ntotalTracks;
40 double failedTwoStationsCutFraction = (double)m_failedTwoStationsCut / (double)m_ntotalTracks;
41 double failedTwoStationsMaxMDTHoleCutFraction = (double)m_failedTwoStationsMaxMDTHoleCut / (double)m_ntotalTracks;
42 double failedTwoStationsMaxHoleCutFraction = (double)m_failedTwoStationsMaxHoleCut / (double)m_ntotalTracks;
43 double failedTwoStationsGoodStationCutFraction = (double)m_failedTwoStationsGoodStationCut / (double)m_ntotalTracks;
44 double failedTriggerStationCutFraction = (double)m_failedTriggerStationCut / (double)m_ntotalTracks;
45 double failedMaxMDTHoleCutFraction = (double)m_failedMaxMDTHoleCut / (double)m_ntotalTracks;
46 double failedMaxHoleCutFraction = (double)m_failedMaxHoleCut / (double)m_ntotalTracks;
47 ATH_MSG_INFO(" Fractions failing selection cuts: "
48 << endmsg << std::setw(30) << " Chi2/Ndof Cut " << failedChi2NDofCutFraction << endmsg
49 << std::setw(30) << " RPC AveMin Time Cut " << failedRPCAveMinTimeCutFraction << endmsg << std::setw(30)
50 << " RPC AveMax Time Cut " << failedRPCAveMaxTimeCutFraction << endmsg << std::setw(30)
51 << " RPC Spread Time Cut " << failedRPCSpreadTimeCutFraction << endmsg << std::setw(30)
52 << " Single station Cut " << failedSingleStationsCutFraction << endmsg << std::setw(30)
53 << " Two station Cut " << failedTwoStationsCutFraction << endmsg << std::setw(30)
54 << " Two station Max MDT hole Cut " << failedTwoStationsMaxMDTHoleCutFraction << endmsg << std::setw(30)
55 << " Two station Max hole Cut " << failedTwoStationsMaxHoleCutFraction << endmsg << std::setw(30)
56 << " Two station good station Cut " << failedTwoStationsGoodStationCutFraction << endmsg << std::setw(30)
57 << " Trigger station cut " << failedTriggerStationCutFraction << endmsg << std::setw(30)
58 << " MDT hole Cut " << failedMaxMDTHoleCutFraction << endmsg << std::setw(30)
59 << " Max hole Cut " << failedMaxHoleCutFraction);
60 }
61
62 return StatusCode::SUCCESS;
63 }
64
66 // loop over track and calculate residuals
67 const Trk::TrackStates* states = track.trackStateOnSurfaces();
68 if (!states) {
69 ATH_MSG_DEBUG(" track without states, discarding track ");
70 return false;
71 }
73 if (!track.perigeeParameters() || !Amg::hasPositiveDiagElems(*track.perigeeParameters()->covariance())) return false;
74 }
75
77
78 ATH_MSG_VERBOSE(" new track " << m_printer->print(track) << std::endl << m_printer->printStations(track));
79
80 // get reduced chi2
81 const Trk::FitQuality* fq = track.fitQuality();
82 if (!fq) return false;
83 double reducedChi2 = fq->numberDoF() != 0. ? fq->chiSquared() / fq->numberDoF() : 1.;
84 if (reducedChi2 > m_chi2NDofCut) {
86 ATH_MSG_DEBUG(" Track discarded: too large chi2 " << reducedChi2);
87 return false;
88 }
89
91 int nrpcs = 0;
92 double aveRpcTime = 0.;
93 double minTime = 1e9;
94 double maxTime = -1e9;
95
96 // loop over TSOSs
97 Trk::TrackStates::const_iterator tsit = states->begin();
98 Trk::TrackStates::const_iterator tsit_end = states->end();
99 for (; tsit != tsit_end; ++tsit) {
100 if (!(*tsit)->type(Trk::TrackStateOnSurface::Measurement)) continue;
101
102 // check wther state is a measurement
103 const Trk::MeasurementBase* meas = (*tsit)->measurementOnTrack();
104 if (!meas) continue;
105
106 const RpcClusterOnTrack* rpc = dynamic_cast<const RpcClusterOnTrack*>(meas);
107 if (!rpc) {
108 const CompetingMuonClustersOnTrack* crot = dynamic_cast<const CompetingMuonClustersOnTrack*>(meas);
109 if (crot) { rpc = dynamic_cast<const RpcClusterOnTrack*>(crot->containedROTs().front()); }
110 }
111 if (rpc) {
112 double time = rpc->prepRawData()->time() - rpc->globalPosition().mag() / 300.;
113 ++nrpcs;
114 aveRpcTime += time;
115 if (time < minTime) minTime = time;
116 if (time > maxTime) maxTime = time;
117 }
118 }
119
120 if (nrpcs != 0) {
121 aveRpcTime /= nrpcs;
122 double timeMinCut = -2.;
123 double timeMaxCut = 20.;
124 ATH_MSG_VERBOSE(" ave RPC time " << aveRpcTime << " min " << minTime << " max " << maxTime);
125 if (aveRpcTime < timeMinCut) {
126 ATH_MSG_VERBOSE(" rejecting due too small average RPC time ");
128 return false;
129 }
130 if (aveRpcTime > timeMaxCut) {
131 ATH_MSG_VERBOSE(" rejecting due too large average RPC time ");
133 return false;
134 }
135 if (maxTime > timeMaxCut && minTime < timeMinCut) {
136 ATH_MSG_VERBOSE(" rejecting due too larger RPC time spread ");
138 return false;
139 }
140 }
141 }
142
143 unsigned int mdtHoles = 0;
144 unsigned int mdtOutliers = 0;
145 unsigned int nholes = 0;
146 std::map<MuonStationIndex::StIndex, StationData> stations;
147
148 Trk::TrackSummary* summary = track.trackSummary();
149 Trk::MuonTrackSummary muonSummary;
150 if (summary) {
151 if (summary->muonTrackSummary())
152 muonSummary = *summary->muonTrackSummary();
153 else {
154 m_trackSummaryTool->addDetailedTrackSummary(track, *summary);
155 if (summary->muonTrackSummary()) muonSummary = *summary->muonTrackSummary();
156 }
157 } else {
158 Trk::TrackSummary tmpSummary;
159 m_trackSummaryTool->addDetailedTrackSummary(track, tmpSummary);
160 if (tmpSummary.muonTrackSummary()) muonSummary = *tmpSummary.muonTrackSummary();
161 }
162
163 std::vector<Trk::MuonTrackSummary::ChamberHitSummary>::const_iterator chit = muonSummary.chamberHitSummary().begin();
164 std::vector<Trk::MuonTrackSummary::ChamberHitSummary>::const_iterator chit_end = muonSummary.chamberHitSummary().end();
165 for (; chit != chit_end; ++chit) {
166 const Identifier& chId = chit->chamberId();
167
168 bool isMdt = m_idHelperSvc->isMdt(chId);
169 bool isCsc = m_idHelperSvc->isCsc(chId);
170 bool isRpc = m_idHelperSvc->isRpc(chId);
171 bool isTgc = m_idHelperSvc->isTgc(chId);
172 bool issTgc = m_idHelperSvc->issTgc(chId);
173 bool isMM = m_idHelperSvc->isMM(chId);
174
175 // check whether we should use holes in this chamber
176 bool useHoles = false;
177 if ((isMdt && m_useMDTHoles) || (isTgc && m_useTGCHoles) || (isRpc && m_useRPCHoles) || (isCsc && m_useCSCHoles))
178 useHoles = true;
179
180 if (isMdt) {
181 MuonStationIndex::StIndex stIndex = m_idHelperSvc->stationIndex(chId);
182 StationData& stData = stations[stIndex];
183 stData.netaHits += chit->nhits();
184 if (useHoles) stData.netaHoles += chit->nholes();
185 if (!stData.mdtHasHitsinMl1 && chit->mdtMl1().nhits > 0) stData.mdtHasHitsinMl1 = true;
186 if (!stData.mdtHasHitsinMl2 && chit->mdtMl2().nhits > 0) stData.mdtHasHitsinMl2 = true;
187
188 if (useHoles) {
189 mdtHoles += chit->nholes();
190 nholes += chit->nholes();
191 mdtOutliers += chit->noutliers();
192 }
193
194 stData.isMdt = true;
195
196 } else if (isCsc || issTgc || isMM) {
197 MuonStationIndex::StIndex stIndex = m_idHelperSvc->stationIndex(chId);
198 StationData& stData = stations[stIndex];
199 stData.netaHits += chit->etaProjection().nhits;
200 if (useHoles) {
201 stData.netaHoles += chit->etaProjection().nholes;
202 stData.nphiHoles += chit->phiProjection().nholes;
203 nholes += chit->nholes();
204 }
205 stData.nphiHits += chit->phiProjection().nhits;
206 stData.isCsc = isCsc;
207 stData.isNSW = issTgc || isMM;
208
209 } else if (isRpc || isTgc) {
210 MuonStationIndex::StIndex stIndex = m_idHelperSvc->stationIndex(chId);
211 StationData& stData = stations[stIndex];
212 stData.netaTrigHits += chit->etaProjection().nhits > 0 ? 1 : 0;
213 stData.nphiTrigHits += chit->phiProjection().nhits > 0 ? 1 : 0;
214 if (useHoles) {
215 // add trigger holes
216 if (!m_ignoreTriggerHolesInLayersWithHits || chit->etaProjection().nhits == 0) {
217 stData.netaTrigHoles += chit->etaProjection().nholes;
218 nholes += chit->etaProjection().nholes;
219 }
220 if (!m_ignoreTriggerHolesInLayersWithHits || chit->phiProjection().nhits == 0) {
221 stData.nphiTrigHoles += chit->phiProjection().nholes;
222 nholes += chit->phiProjection().nholes;
223 }
224 }
225
226 // make sure this station is not already present as MDT or CSC station
227 if (!stData.isMdt && !stData.isCsc) stData.isTrigger = true;
228 }
229 }
230
231 unsigned int nGoodStations = 0;
232 unsigned int nstations = 0;
233 unsigned int nTwoMlStations = 0;
234 unsigned int nGoodCscStations = 0;
235 unsigned int nGoodTriggerStations = 0;
236
237 std::map<MuonStationIndex::StIndex, StationData>::iterator sit = stations.begin();
238 std::map<MuonStationIndex::StIndex, StationData>::iterator sit_end = stations.end();
239 for (; sit != sit_end; ++sit) {
240 StationData& stData = sit->second;
241
242 if (stData.nphiTrigHits != 0 && stData.netaTrigHits != 0) { ++nGoodTriggerStations; }
243
244 if (stData.isMdt) {
245 if (stData.netaHits < m_minMdtHitsPerStation) {
246 ATH_MSG_VERBOSE(" Not counting MDT station too few MDT hits: nhits " << stData.netaHits << " cut "
248 continue;
249 }
250 ++nstations;
251 double holeHitRatio = (double)stData.netaHoles / stData.netaHits;
252 if (holeHitRatio > m_holeHitRatioCutPerStation) {
253 ATH_MSG_VERBOSE(" Not counting MDT station too many holes: nhits " << stData.netaHits << " nholes " << stData.netaHoles
254 << " ratio " << holeHitRatio << " cut "
256 continue;
257 }
258 if (stData.mdtHasHitsinBothMl()) ++nTwoMlStations;
259 } else if (stData.isCsc || stData.isNSW) {
260 if (stData.isCsc && stData.nphiHits == 0) {
261 ATH_MSG_VERBOSE(" Not counting CSC station no phi hits: netaHits " << stData.netaHits << " nphiHits "
262 << stData.nphiHits);
263 continue;
264 }
265
266 if (stData.netaHits < m_minCscHitsPerStation) {
267 ATH_MSG_VERBOSE(" Not counting CSC station too few hits: netaHits "
268 << stData.netaHits << " nphiHits " << stData.nphiHits << " cut " << m_minCscHitsPerStation);
269 continue;
270 }
271 ++nstations;
272 ++nGoodCscStations;
273 }
274
275 ++nGoodStations;
276 }
277
278 ATH_MSG_DEBUG(" good stations " << nGoodStations << " MDT stations with two ml " << nTwoMlStations << " MDT holes " << mdtHoles
279 << " outliers " << mdtOutliers << " good CSC stations " << nGoodCscStations << " trigger stations "
280 << nGoodTriggerStations);
281
282 if (m_removeSingleStationTracks && stations.size() < 2) {
283 ATH_MSG_DEBUG(" Track discarded: too few stations " << stations.size());
285 return false;
286 }
287
288 // special treatment of single station tracks
289 if (stations.size() == 1) {
290 using namespace MuonStationIndex;
291 if (!stations.count(StIndex::EM)) return false;
292
293 StationData& stData = stations[StIndex::EM];
294
295 unsigned int nExpectedTriggerStations = m_tightSingleStationCuts ? 3 : 2;
296 unsigned int maxHolesSingle = m_tightSingleStationCuts ? 0 : 1;
297
298 ATH_MSG_DEBUG(" Single station track: trigger phi " << stData.nphiTrigHits << " eta " << stData.netaTrigHits << " cut "
299 << nExpectedTriggerStations << " holes " << stData.netaHoles << " cut "
300 << maxHolesSingle);
301
302 bool ok = true;
303 // require two multi layers in MDT
304 if (nTwoMlStations == 0) ok = false;
305
306 // require all three trigger layers
307 if (stData.nphiTrigHits < nExpectedTriggerStations || stData.netaTrigHits < nExpectedTriggerStations) ok = false;
308
309 // no holes
310 if (stData.netaHoles > maxHolesSingle) ok = false;
311
312 if (!ok) {
313 ATH_MSG_DEBUG(" Track discarded: failed single track cuts ");
315 }
316 return ok;
317 }
318
319 if (nGoodStations < 2) {
320 ATH_MSG_DEBUG(" Track discarded: too few good stations " << nGoodStations);
322 return false;
323 }
324
325 if (m_countMdtOutliersAsHoles) mdtHoles += mdtOutliers;
326
327 if (nstations < 3) {
328 if (mdtHoles > m_maxMdtHolesPerTwoStationTrack) {
329 ATH_MSG_DEBUG(" Track discarded: good stations " << nGoodStations << " and " << mdtHoles << " mdt holes ");
331 return false;
332 }
333 if (nholes > m_maxMdtHolesPerTwoStationTrack) {
334 ATH_MSG_DEBUG(" Track discarded: good stations " << nGoodStations << " and " << nholes << " holes ");
336 return false;
337 }
338 if (nTwoMlStations == 0 && nGoodCscStations == 0) {
339 ATH_MSG_DEBUG(" Track discarded: good stations "
340 << nGoodStations << " but no MDT station with hits in two multilayers nor good CSC station ");
342 return false;
343 }
344 if (m_removeTwoStationTrackWithoutTriggerHits && nGoodTriggerStations == 0) {
345 ATH_MSG_DEBUG(" Track discarded: stations " << nstations << " but no trigger hits nor good CSC station ");
347 return false;
348 }
349 } else {
350 if (mdtHoles > m_maxMdtHolesPerTrack) {
351 ATH_MSG_DEBUG(" Track discarded: good stations " << nGoodStations << " and " << mdtHoles << " mdt holes ");
353 return false;
354 }
355 if (nholes > m_maxMdtHolesPerTrack) {
356 ATH_MSG_DEBUG(" Track discarded: good stations " << nGoodStations << " and " << nholes << " holes ");
358 return false;
359 }
360 }
361
362 ATH_MSG_DEBUG(" Track passed selection ");
363
364 return true;
365 }
366
367} // namespace Muon
#define endmsg
#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)
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
DataModel_detail::const_iterator< DataVector > const_iterator
Definition DataVector.h:838
Class for competing MuonClusters, it extends the Trk::CompetingRIOsOnTrack base class.
const std::vector< const MuonClusterOnTrack * > & containedROTs() const
returns the vector of SCT_ClusterOnTrack objects .
virtual const Amg::Vector3D & globalPosition() const override
Returns global position.
Gaudi::Property< unsigned int > m_minMdtHitsPerStation
Gaudi::Property< bool > m_removeTwoStationTrackWithoutTriggerHits
Gaudi::Property< bool > m_removeSingleStationTracks
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
std::atomic_uint m_ntotalTracks
counter for statistics
Gaudi::Property< unsigned int > m_maxMdtHolesPerTrack
Gaudi::Property< bool > m_useRPCHoles
ServiceHandle< Muon::IMuonEDMHelperSvc > m_edmHelperSvc
EDM Helper tool.
std::atomic_uint m_failedTwoStationsMaxMDTHoleCut
Gaudi::Property< double > m_chi2NDofCut
ToolHandle< Trk::ITrackSummaryHelperTool > m_trackSummaryTool
StatusCode initialize()
AlgTool initilize.
MuonTrackSelectorTool(const std::string &, const std::string &, const IInterface *)
constructor
Gaudi::Property< double > m_holeHitRatioCutPerStation
Gaudi::Property< bool > m_useCSCHoles
std::atomic_uint m_failedTwoStationsMaxHoleCut
Gaudi::Property< bool > m_tightSingleStationCuts
Gaudi::Property< bool > m_ignoreTriggerHolesInLayersWithHits
StatusCode finalize()
AlgTool finalize.
PublicToolHandle< Muon::MuonEDMPrinterTool > m_printer
bool decision(Trk::Track &track) const
returns true if the track satisfies the selection criteria else false
std::atomic_uint m_failedTwoStationsGoodStationCut
Gaudi::Property< bool > m_useRPCTimeWindow
Gaudi::Property< unsigned int > m_minCscHitsPerStation
Gaudi::Property< bool > m_requireSanePerigee
Gaudi::Property< unsigned int > m_maxMdtHolesPerTwoStationTrack
Gaudi::Property< bool > m_useTGCHoles
Gaudi::Property< bool > m_useMDTHoles
Gaudi::Property< bool > m_countMdtOutliersAsHoles
Class to represent calibrated clusters formed from RPC strips.
virtual const RpcPrepData * prepRawData() const override final
Returns the RpcPrepData - is a TRT_DriftCircle in this scope.
float time() const
Returns the time.
Class to represent and store fit qualities from track reconstruction in terms of and number of degre...
Definition FitQuality.h:97
int numberDoF() const
returns the number of degrees of freedom of the overall track or vertex fit as integer
Definition FitQuality.h:60
double chiSquared() const
returns the of the overall track fit
Definition FitQuality.h:56
This class is the pure abstract base class for all fittable tracking measurements.
Detailed track summary for the muon system Give access to hit counts per chamber.
const std::vector< ChamberHitSummary > & chamberHitSummary() const
access to the vector of chamber hit summaries on the track
@ Measurement
This is a measurement, and will at least contain a Trk::MeasurementBase.
A summary of the information contained by a track.
const MuonTrackSummary * muonTrackSummary() const
returns a pointer to the MuonTrackSummary if available
bool hasPositiveDiagElems(const AmgSymMatrix(N) &mat)
Returns true if all diagonal elements of the covariance matrix are finite aka sane in the above defin...
StIndex
enum to classify the different station layers in the muon spectrometer
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.
DataVector< const Trk::TrackStateOnSurface > TrackStates