ATLAS Offline Software
MuonTrackCleaner.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 #include "MuonTrackCleaner.h"
5 
6 #include <iostream>
7 
31 #include "TrkSurfaces/Surface.h"
32 #include "TrkTrack/Track.h"
33 #include "CxxUtils/trapping_fp.h"
34 
35 namespace Muon {
36  using namespace MuonStationIndex;
38  ATH_CHECK(m_trackFitter.retrieve());
39  ATH_CHECK(m_slTrackFitter.retrieve());
40  ATH_CHECK(m_idHelperSvc.retrieve());
41  ATH_CHECK(m_edmHelperSvc.retrieve());
42  ATH_CHECK(m_printer.retrieve());
43  ATH_CHECK(m_extrapolator.retrieve());
44  ATH_CHECK(m_pullCalculator.retrieve());
45  ATH_CHECK(m_mdtRotCreator.retrieve());
46  ATH_CHECK(m_compRotCreator.retrieve());
47  ATH_CHECK(m_measurementUpdator.retrieve());
48  ATH_CHECK(m_fieldCacheCondObjInputKey.initialize());
49 
50  return StatusCode::SUCCESS;
51  }
52 
53  std::unique_ptr<Trk::Track> MuonTrackCleaner::clean(const Trk::Track& track, const std::set<Identifier>& chamberRemovalExclusionList,
54  const EventContext& ctx) const {
55  CleaningState state;
56  state.chamberRemovalExclusionList = chamberRemovalExclusionList;
57 
58  if (!state.chamberRemovalExclusionList.empty()) {
59  ATH_MSG_DEBUG(" Cleaning with exclusion list " << state.chamberRemovalExclusionList.size());
60  }
61 
62  std::unique_ptr<Trk::Track> cleanedTrack = cleanTrack(ctx, &track, state);
63  return cleanedTrack;
64  }
65  std::unique_ptr<Trk::Track> MuonTrackCleaner::clean(const Trk::Track& track, const EventContext& ctx) const {
66  CleaningState state;
67  std::unique_ptr<Trk::Track> cleanedTrack = cleanTrack(ctx, &track, state);
68  return cleanedTrack;
69  }
70 
71  std::unique_ptr<Trk::Track> MuonTrackCleaner::cleanTrack(const EventContext& ctx, const Trk::Track* track, CleaningState& state) const {
72  ATH_MSG_DEBUG(" Perform cleaning for track ");
73  ATH_MSG_DEBUG(m_printer->print(*track));
74 
75  init(ctx, *track, state);
76 
77  ATH_MSG_DEBUG("after init, track is " << m_printer->print(*track));
78  ATH_MSG_DEBUG(" start cleaning ");
79 
80  unsigned int nstationsInitial = state.stations.size();
81 
82  // first clean up chambers
83  std::unique_ptr<Trk::Track> chamberTrack = chamberCleaning(ctx, std::make_unique<Trk::Track>(*track), state);
84  if (!chamberTrack) {
85  ATH_MSG_DEBUG(" chamber removal failed ");
86  return nullptr;
87  }
88  ATH_MSG_DEBUG("after chamber cleaning, track is " << m_printer->print(*chamberTrack));
89 
90  // fail if only station remains on the track
91  unsigned int nstationsChamberCleaning = state.stations.size();
92  if (nstationsInitial != nstationsChamberCleaning) {
93  if (!checkStations(state)) return nullptr;
94  }
95 
96  // if performed curved fit and we did not have a vertex constraint or ID hits, reject the track if inner was removed
97  if (!state.slFit && !state.hasVertexConstraint && state.nIdHits <= 0) {
98  if (!checkInnerConstraint(state)) return nullptr;
99  }
100 
101  // if performing a single station layer cleaning without ID hits, reject track if there are insufficient phi constraints
102  if (!checkPhiConstraint(state)) return nullptr;
103 
104  // clean competing ROTs
105  std::unique_ptr<Trk::Track> cleanCompTrack = cleanCompROTs(ctx, std::move(chamberTrack), state);
106  if (!cleanCompTrack) {
107  ATH_MSG_DEBUG(" CompROT cleaning failed ");
108  return nullptr;
109  }
110  ATH_MSG_DEBUG("after comp rot cleaning, track is " << m_printer->print(*cleanCompTrack));
111 
112  // recover MDTs with flipped signs
113  std::unique_ptr<Trk::Track> flippedTrack = recoverFlippedMdt(ctx, std::move(cleanCompTrack), state);
114  if (!flippedTrack) {
115  ATH_MSG_DEBUG(" MDT sign flipping failed ");
116  return nullptr;
117  }
118  ATH_MSG_DEBUG("after flipped mdt recovery, track is " << m_printer->print(*flippedTrack));
119 
120  std::unique_ptr<Trk::Track> hitTrack = hitCleaning(ctx, std::move(flippedTrack), state);
121  if (!hitTrack) {
122  ATH_MSG_DEBUG(" track lost after outlier removal ");
123  return nullptr;
124  }
125  ATH_MSG_DEBUG("after hit cleaning, track is " << m_printer->print(*hitTrack));
126 
127  // keep this clone in case outlier recovery fails but the rest of the cleaning was succesful.
128  std::unique_ptr<Trk::Track> hitTrackClone = std::make_unique<Trk::Track>(*hitTrack);
129 
130  // fail if only one station remains
131  unsigned int nstationsHitCleaning = state.stations.size();
132  if (nstationsInitial != nstationsHitCleaning) {
133  if (!checkStations(state)) return nullptr;
134  }
135 
136  // if performed curved fit and we did not have a vertex constraint or ID hits, reject the track if inner was removed
137  if (!state.slFit && !state.hasVertexConstraint && state.nIdHits <= 0) {
138  if (!checkInnerConstraint(state)) return nullptr;
139  }
140 
141  // if performing a single station layer cleaning without ID hits, reject track if there are insufficient phi constraints
142  if (!checkPhiConstraint(state)) return nullptr;
143 
144  std::unique_ptr<Trk::Track> cleanedTrack = outlierRecovery(ctx, std::move(hitTrack), state);
145  // do not discard tracks that fail outlierRecovery, check that the track is ok
146  // note that this also performs a useful check on the quality of the cleaning in general
147  if (!cleanedTrack || !state.chambersToBeRemoved.empty() || !state.largePullMeasurements.empty()) {
148  init(ctx, *hitTrackClone, state);
149  if (!state.chambersToBeRemoved.empty() || !state.largePullMeasurements.empty()) {
150  ATH_MSG_DEBUG("Outlier recovery failure unrecoverable, reject track");
151  return nullptr;
152  } else {
153  ATH_MSG_DEBUG("Outlier recovery failed but initial track is recoverable");
154  cleanedTrack = std::move(hitTrackClone);
155  }
156  }
157 
158  if (state.nhits < state.noutliers) {
159  ATH_MSG_DEBUG(" track rejected due to high outlier ratio: hits " << state.nhits << " outliers " << state.noutliers);
160  return nullptr;
161  }
162 
163  unsigned int nstationsFinal = state.stations.size();
164  if (nstationsInitial != nstationsFinal) {
165  if (!checkStations(state)) return nullptr;
166  }
167 
168  ATH_MSG_VERBOSE(" final track " << m_printer->print(*cleanedTrack));
169  ATH_MSG_VERBOSE(m_printer->printStations(*cleanedTrack));
170 
171  return cleanedTrack;
172  }
173 
174  std::unique_ptr<Trk::Track> MuonTrackCleaner::cleanCompROTs(const EventContext& ctx, std::unique_ptr<Trk::Track> track,
175  CleaningState& state) const {
176  if (!m_cleanCompROTs || state.numberOfCleanedCompROTs == 0) return track;
177 
178  const Trk::Perigee* perigee = track->perigeeParameters();
179  if (!perigee) {
180  ATH_MSG_DEBUG(" track without perigee ");
181  return nullptr;
182  }
183 
184  ATH_MSG_DEBUG(" Clean comp rots " << state.numberOfCleanedCompROTs);
185 
186  auto tsos = std::make_unique<Trk::TrackStates>();
187  tsos->reserve(state.measInfo.size());
188 
189  unsigned int nmeas = 0;
190  // loop over hits
191  InfoIt hit = state.measInfo.begin();
192  InfoIt hit_end = state.measInfo.end();
193  for (; hit != hit_end; ++hit) {
194  // hits that are flagged as outlier or hits in the chamber to be removed are added as Outlier
195  if (!hit->useInFit) {
196  ATH_MSG_DEBUG(" removing hit " << m_idHelperSvc->toString(hit->id) << " pull " << hit->resPull->pull().front());
197  if (hit->inBounds)
198  tsos->push_back(MuonTSOSHelper::cloneTSOSWithUpdate(*hit->originalState, *hit->meas, *hit->pars,
200 
201  continue;
202  } else {
203  if (hit->meas) ++nmeas;
204 
205  if (hit->cleanedCompROT) {
206  tsos->push_back(MuonTSOSHelper::cloneTSOSWithUpdate(*hit->originalState, *hit->cleanedCompROT, *hit->pars,
208  ATH_MSG_DEBUG(" replacing CompROT " << m_idHelperSvc->toString(hit->id) << " pull " << hit->resPull->pull().front());
209  } else {
210  tsos->push_back(hit->originalState->clone());
211  }
212  }
213  }
214 
215  if (nmeas < 6) {
216  ATH_MSG_DEBUG(" too few hits, cannot recover CompROTS ");
217  return nullptr;
218  }
219 
220  // create new track
221  std::unique_ptr<Trk::Track> cleanedTrack =
222  std::make_unique<Trk::Track>(track->info(), std::move(tsos), track->fitQuality() ? track->fitQuality()->uniqueClone() : nullptr);
223  printStates(cleanedTrack.get());
224 
225  // fit new track
226  std::unique_ptr<Trk::Track> newTrack = fitTrack(ctx, *cleanedTrack, track->info().particleHypothesis(), state.slFit);
227 
228  if (newTrack) {
229  init(ctx, *newTrack, state);
230  return newTrack;
231  } else
232  return nullptr;
233  }
234 
235  std::unique_ptr<Trk::Track> MuonTrackCleaner::recoverFlippedMdt(const EventContext& ctx, std::unique_ptr<Trk::Track> track,
236  CleaningState& state) const {
237  if (!m_flipMdtDriftRadii || state.numberOfFlippedMdts == 0) return track;
238 
239  const Trk::Perigee* perigee = track->perigeeParameters();
240  if (!perigee) {
241  ATH_MSG_DEBUG(" track without perigee ");
242  return nullptr;
243  }
244 
245  ATH_MSG_DEBUG(" Trying to flip MDT signs: total number of hits with wrong sign " << state.numberOfFlippedMdts);
246 
247  auto tsos = std::make_unique<Trk::TrackStates>();
248  tsos->reserve(state.measInfo.size());
249 
250  unsigned int nmeas = 0;
251  // loop over hits
252  InfoIt hit = state.measInfo.begin();
253  InfoIt hit_end = state.measInfo.end();
254  for (; hit != hit_end; ++hit) {
255  // hits that are flagged as outlier or hits in the chamber to be removed are added as Outlier
256  if (!hit->useInFit) {
257  ATH_MSG_DEBUG(" removing hit " << m_idHelperSvc->toString(hit->id) << " pull " << hit->resPull->pull().front());
258  if (hit->inBounds)
259  tsos->push_back(MuonTSOSHelper::cloneTSOSWithUpdate(*hit->originalState, *hit->meas, *hit->pars,
261 
262  continue;
263  } else {
264  if (hit->meas) ++nmeas;
265 
266  if (hit->flippedMdt) {
267  tsos->push_back(MuonTSOSHelper::cloneTSOSWithUpdate(*hit->originalState, *hit->flippedMdt, *hit->pars,
269  ATH_MSG_DEBUG(" flipping sign hit " << m_idHelperSvc->toString(hit->id) << " pull " << hit->resPull->pull().front());
270  } else {
271  tsos->push_back(hit->originalState->clone());
272  }
273  }
274  }
275 
276  if (nmeas < 6) {
277  ATH_MSG_DEBUG(" too few hits, cannot flip MDT hit sign ");
278  return nullptr;
279  }
280 
281  // create new track
282  std::unique_ptr<Trk::Track> cleanedTrack =
283  std::make_unique<Trk::Track>(track->info(), std::move(tsos), track->fitQuality() ? track->fitQuality()->uniqueClone() : nullptr);
284  printStates(cleanedTrack.get());
285 
286  // fit new track
287  std::unique_ptr<Trk::Track> newTrack = fitTrack(ctx, *cleanedTrack, track->info().particleHypothesis(), state.slFit);
288 
289  if (newTrack) {
290  init(ctx, *newTrack, state);
291  return newTrack;
292  } else
293  return nullptr;
294  }
295 
296  std::unique_ptr<Trk::Track> MuonTrackCleaner::hitCleaning(const EventContext& ctx, std::unique_ptr<Trk::Track> track,
297  CleaningState& state) const {
298  if (state.largePullMeasurements.empty()) return track;
299  ATH_MSG_DEBUG(" trying outlier removal ");
300 
301  const Trk::Perigee* perigee = track->perigeeParameters();
302  if (!perigee) {
303  ATH_MSG_DEBUG("input track without perigee ");
304  return nullptr;
305  }
306 
307  std::unique_ptr<Trk::Track> newTrack;
308 
309  for (unsigned int n = 0; n < m_ncycles; ++n) {
310  // sanity check, should not remove too many hits
311  if (state.largePullMeasurements.size() > 10) {
312  ATH_MSG_DEBUG(" Too many outliers, cannot perform cleaning ");
313  return nullptr;
314  }
315 
316  ATH_MSG_VERBOSE(" outlier removal cycle " << n);
317 
318  auto tsos = std::make_unique<Trk::TrackStates>();
319  tsos->reserve(state.measInfo.size());
320  ATH_MSG_VERBOSE("cleaning track with " << state.measInfo.size() << " hits");
321 
322  unsigned int nmeas = 0;
323  unsigned int nremovedPhi = 0;
324  bool hasSmall = false;
325  bool hasLarge = false;
326  MCTBCleaningInfo* firstPhi = nullptr;
327  MCTBCleaningInfo* lastPhi = nullptr;
328  std::map<StIndex, std::pair<bool, bool> > slCountsPerStationLayer;
329  // loop over hits
330  InfoIt hit = state.measInfo.begin();
331  InfoIt hit_end = state.measInfo.end();
332  for (; hit != hit_end; ++hit) {
333  bool remove = state.largePullMeasurements.count(hit->meas) || !hit->inBounds || hit->isNoise;
334  // hits that are flagged as outlier or hits in the chamber to be removed are added as Outlier
335  if (!hit->useInFit || remove) {
336  hit->useInFit = 0;
337 
338  // count number of phi outliers
339  if (!hit->id.is_valid() || m_idHelperSvc->measuresPhi(hit->id)) ++nremovedPhi;
340 
341  if (remove) {
342  std::string inb = hit->inBounds ? " inBounds" : " outBounds";
343  ATH_MSG_DEBUG(" removing hit " << m_idHelperSvc->toString(hit->id) << " pull " << hit->resPull->pull().front()
344  << inb);
345  }
346  if (hit->inBounds) {
347  if (hit->cleanedCompROT) {
348  tsos->push_back(MuonTSOSHelper::cloneTSOSWithUpdate(*hit->originalState, *hit->cleanedCompROT, *hit->pars,
350  } else {
351  tsos->push_back(MuonTSOSHelper::cloneTSOSWithUpdate(*hit->originalState, *hit->meas, *hit->pars,
353  }
354  }
355  continue;
356  } else {
357  if (hit->resPull)
358  ATH_MSG_DEBUG(" keeping hit " << m_idHelperSvc->toString(hit->id) << " pull " << hit->resPull->pull().front());
359 
360  if (hit->meas) {
361  ++nmeas;
362  if (!hit->id.is_valid() || m_idHelperSvc->measuresPhi(hit->id)) {
363  if (!firstPhi)
364  firstPhi = &(*hit);
365  else
366  lastPhi = &(*hit);
367  }
368 
369  if (hit->id.is_valid() && m_idHelperSvc->isMdt(hit->id)) {
370  StIndex stIndex = toStationIndex(hit->chIndex);
371  bool isSmall = m_idHelperSvc->isSmallChamber(hit->id);
372  bool isLarge = !isSmall;
373  // look for layer
374  std::map<StIndex, std::pair<bool, bool> >::iterator pos =
375  slCountsPerStationLayer.find(stIndex);
376 
377  // if not found add current
378  if (pos == slCountsPerStationLayer.end())
379  slCountsPerStationLayer[stIndex] = std::make_pair(isSmall, isLarge);
380  else {
381  // update
382  if (isSmall) slCountsPerStationLayer[stIndex].first = true;
383  if (isLarge) slCountsPerStationLayer[stIndex].second = true;
384  }
385  }
386  }
387  if (!hit->originalState) ATH_MSG_DEBUG("no original state!");
388  tsos->push_back(hit->originalState->clone());
389  }
390  }
391  // loop over sl map and count the overlaps
392  unsigned int noverlaps = 0;
393  for (auto [index, slCounts] : slCountsPerStationLayer) {
394  if (!hasSmall && slCounts.first) hasSmall = true;
395  if (!hasLarge && slCounts.second) hasLarge = true;
396  if (slCounts.first && slCounts.second) ++noverlaps;
397  }
398  // now update for the case there are small and large chambers but not in the same layer
399  if (noverlaps == 0 && hasSmall && hasLarge) ++noverlaps;
400 
401  if (nmeas < 6) {
402  ATH_MSG_DEBUG(" too few hits, cannot perform hitCleaning ");
403  return nullptr;
404  }
405 
406  ATH_MSG_DEBUG(" nremovedPhi " << nremovedPhi << " noverlaps " << noverlaps << " nid " << state.nIdHits);
407  if (firstPhi) ATH_MSG_DEBUG(" hasFirstPhi: " << m_idHelperSvc->toString(firstPhi->id));
408  if (lastPhi) ATH_MSG_DEBUG(" hasLastPhi: " << m_idHelperSvc->toString(lastPhi->id));
409 
410  // only perform check on phi constraints if any phi hits were removed
411  if (nremovedPhi > 0) {
412  bool hasPhiConstraint = false;
413 
414  if (state.nIdHits > 0)
415  hasPhiConstraint = true; // ok if ID hits
416  else if (firstPhi && noverlaps > 0)
417  hasPhiConstraint = true; // ok if one phi hit + one overlap
418  else if (noverlaps > 1)
419  hasPhiConstraint = true; // ok if two overlaps
420  else if (firstPhi && lastPhi && firstPhi->pars && lastPhi->pars) {
421  double distPhi =
422  std::abs((firstPhi->pars->position() - lastPhi->pars->position()).dot(firstPhi->pars->momentum().unit()));
423  ATH_MSG_DEBUG(" Distance between phi hits " << distPhi);
424  if (distPhi > 450.) hasPhiConstraint = true;
425  }
426  if (!hasPhiConstraint) {
427  ATH_MSG_DEBUG("Lost phi constraint during track cleaning, reject track");
428  return nullptr;
429  }
430  }
431 
432  // create new track
433  std::unique_ptr<Trk::Track> cleanedTrack =
434  std::make_unique<Trk::Track>(track->info(), std::move(tsos), track->fitQuality() ? track->fitQuality()->uniqueClone() : nullptr);
435 
436  // fit new track
437  printStates(cleanedTrack.get());
438 
439  newTrack = fitTrack(ctx, *cleanedTrack, track->info().particleHypothesis(), state.slFit);
440 
441  if (!newTrack) {
442  return nullptr;
443  } else {
444  const Trk::Perigee* perigee = newTrack->perigeeParameters();
445  if (!perigee) {
446  ATH_MSG_DEBUG(" track without perigee ");
447  return nullptr;
448  }
449  // reinitialize cleaner
450  init(ctx, *newTrack, state);
451  }
452 
453  if (state.largePullMeasurements.empty()) {
454  ATH_MSG_DEBUG(" cleaning ended successfully after cycle " << n);
455  return newTrack;
456  }
457  }
458 
459  return nullptr;
460  }
461 
462  std::unique_ptr<Trk::Track> MuonTrackCleaner::chamberCleaning(const EventContext& ctx, std::unique_ptr<Trk::Track> track,
463  CleaningState& state) const {
464  ATH_MSG_DEBUG("run chamber cleaning on track " << m_printer->print(*track));
465 
466  if (state.chambersToBeRemoved.empty() && state.chambersToBeRemovedPhi.empty()) return track;
467 
468  if (state.pullSumPerChamber.size() == 2) {
469  // loop over chambers that should be removed, if one of them is MDT or CSC don't clean
470  // as this would result in a single chamber track
471  PullChIt chit = state.chambersToBeRemoved.begin();
472  PullChIt chit_end = state.chambersToBeRemoved.end();
473  for (; chit != chit_end; ++chit) {
474  const Identifier& chid = chit->second;
475  if (m_idHelperSvc->isMdt(chid) || m_idHelperSvc->isCsc(chid)) {
476  ATH_MSG_DEBUG(" only two precision chambers, cannot remove chamber. ");
477  return nullptr;
478  }
479  }
480  }
481 
482  if (!state.chamberRemovalExclusionList.empty()) {
483  unsigned int foundChambers = 0;
484  // loop over chambers that should be removed and check if they are in the exclusion list
485  PullChIt chit = state.chambersToBeRemoved.begin();
486  PullChIt chit_end = state.chambersToBeRemoved.end();
487  for (; chit != chit_end; ++chit) {
488  const Identifier& chid = chit->second;
489  if (m_idHelperSvc->isMdt(chid) && state.chamberRemovalExclusionList.count(chid)) {
490  ATH_MSG_DEBUG(" found excluded chamber " << m_idHelperSvc->toStringChamber(chid));
491  ++foundChambers;
492  }
493  }
494  unsigned int excludedChambers = state.chamberRemovalExclusionList.size();
495  if (foundChambers > excludedChambers) {
496  ATH_MSG_WARNING(" Found more excluded chambers than in list, this should not happen ");
497  return nullptr;
498  } else if (foundChambers == excludedChambers) {
499  ATH_MSG_DEBUG(" all excluded chambers in removal list, failing cleaning ");
500  return nullptr;
501  }
502  }
503 
504  std::vector<ChamberRemovalOutput> cleaningResults;
505  cleaningResults.reserve(state.chambersToBeRemoved.size());
506 
507  // TODO first remove hits in both eta and phi
508 
509  ATH_MSG_DEBUG(" number of chambers short listed to be removed: " << state.chambersToBeRemoved.size());
510  std::stable_sort(state.chambersToBeRemoved.begin(), state.chambersToBeRemoved.end(), SortByAvePull());
511 
512  // try all combinations of removing a chamber with eta hits
513  unsigned int nchambers = state.chambersToBeRemoved.size() + state.chambersToBeRemovedPhi.size();
514  PullChIt chit = state.chambersToBeRemoved.begin();
515  PullChIt chit_end = state.chambersToBeRemoved.end();
516  for (; chit != chit_end; ++chit) {
517  ChamberRemovalOutput result = removeChamber(ctx, track, chit->second, false, true, state);
518  if (!result.track) {
519  ATH_MSG_DEBUG(" Removed eta hits of " << m_idHelperSvc->toStringChamber(chit->second) << ", track lost ");
520  continue;
521  }
522  ATH_MSG_DEBUG(" Removed eta hits of " << m_idHelperSvc->toStringChamber(chit->second));
523  ATH_MSG_DEBUG(m_printer->print(*result.track));
524 
525  // this is an optimization for the common case where there is only one chamber to be removed
526  if (nchambers > 1) unremoveHits(result);
527 
528  cleaningResults.push_back(std::move(result));
529  } // for (chit)
530 
531  ATH_MSG_DEBUG(" number of phi chambers short listed to be removed: " << state.chambersToBeRemoved.size());
532  std::stable_sort(state.chambersToBeRemovedPhi.begin(), state.chambersToBeRemovedPhi.end(), SortByAvePull());
533  // try all combinations of removing a chamber with phi hits
534  chit = state.chambersToBeRemovedPhi.begin();
535  chit_end = state.chambersToBeRemovedPhi.end();
536  for (; chit != chit_end; ++chit) {
537  ChamberRemovalOutput result = removeChamber(ctx, track, chit->second, true, false, state);
538  if (!result.track) {
539  ATH_MSG_DEBUG(" Removed phi hits of " << m_idHelperSvc->toStringChamber(chit->second) << ", track lost ");
540  continue;
541  }
542  ATH_MSG_DEBUG(" Removed phi hits of " << m_idHelperSvc->toStringChamber(chit->second));
543  ATH_MSG_DEBUG(m_printer->print(*result.track));
544 
545  // this is an optimization for the common case where there is only one chamber to be removed
546  if (nchambers > 1) unremoveHits(result);
547 
548  cleaningResults.push_back(std::move(result));
549  }
550 
551  // if no cleaned tracks return 0
552  if (cleaningResults.empty()) return nullptr;
553  std::stable_sort(cleaningResults.begin(), cleaningResults.end(), SortChamberRemovalResultByChi2Ndof());
554  ATH_MSG_DEBUG(" chamberCleaning Results nr " << cleaningResults.size());
555  for (auto& res : cleaningResults) { ATH_MSG_DEBUG(" track " << m_printer->print(*res.track)); }
556 
557  ChamberRemovalOutput& finalResult = cleaningResults.front();
558  if (nchambers > 1) {
559  // loop over removed hits and redo 'remove'
560  for (auto* hit : finalResult.removedHits) hit->useInFit = 0;
561  }
562 
563  ATH_MSG_DEBUG(" chamberCleaning: track ");
564  ATH_MSG_DEBUG(m_printer->print(*finalResult.track));
565 
566  // make clone just in case outlier recovery fails
567  std::unique_ptr<Trk::Track> finalResultTrackClone = std::make_unique<Trk::Track>(*finalResult.track);
568 
569  init(ctx, *finalResultTrackClone, state);
570 
571  // now finally check whether the removed layer now is recoverable (happens sometimes if the segment has one or more bad hits)
572  ChIndex removedChamberIndex = m_idHelperSvc->chamberIndex(finalResult.chId);
573  std::unique_ptr<Trk::Track> recoveredTrack = outlierRecovery(ctx, std::move(finalResult.track), state, &removedChamberIndex);
574  if (!recoveredTrack) return finalResultTrackClone;
575  init(ctx, *recoveredTrack, state);
576  return recoveredTrack;
577  }
578 
580  const std::unique_ptr<Trk::Track>& track, Identifier chId,
581  bool removePhi, bool removeEta, CleaningState& state) const {
582  ATH_MSG_DEBUG(" removing chamber " << m_idHelperSvc->toStringChamber(chId));
583 
584  // store result
586  result.chId = chId;
587  const Trk::Perigee* perigee = track->perigeeParameters();
588  if (!perigee) {
589  ATH_MSG_DEBUG(" track without perigee ");
590  return result;
591  }
592 
593  auto tsos = std::make_unique<Trk::TrackStates>();
594  tsos->reserve(state.measInfo.size());
595 
596  unsigned int nmeas = 0;
597  // loop over hits
598  std::set<Identifier> stations{};
599  for (MCTBCleaningInfo& hit : state.measInfo) {
600  if (hit.id.is_valid()) {
601  bool measuresPhi = m_idHelperSvc->measuresPhi(hit.id);
602  bool remove = hit.chId == chId && ((removePhi && measuresPhi) || (removeEta && !measuresPhi));
603  // hits that are flagged as outlier or hits in the chamber to be removed are added as Outlier
604  if (!hit.useInFit || remove) {
605  ATH_MSG_DEBUG(" removing hit " << m_idHelperSvc->toString(hit.id) << " pull " << hit.resPull->pull().front());
606  // add as outlier
607  if (hit.inBounds)
608  tsos->push_back(MuonTSOSHelper::cloneTSOSWithUpdate(*hit.originalState, *hit.meas, *hit.pars,
610 
611  // if removed, add hit to vector of hits
612  // but only if the hit was not already an outlier to be skipped!
613  if (remove && hit.useInFit) result.removedHits.push_back(&hit);
614  hit.useInFit = 0;
615  continue;
616  }
617  }
618  if (hit.meas) {
619  ++nmeas;
620  // Through how many detector layers went actually the track ?
621  if (m_idHelperSvc->isMdt(hit.id)) stations.insert(m_idHelperSvc->mdtIdHelper().multilayerID(hit.id));
622  // Keep it for the run 2 legacy
623  else if (m_idHelperSvc->isCsc(hit.id)) stations.insert(m_idHelperSvc->cscIdHelper().elementID(hit.id));
624  // Multilayer defines here whether the track went through the IP or HO wedge
625  else if (m_idHelperSvc->isMM(hit.id)) stations.insert(m_idHelperSvc->mmIdHelper().multilayerID(hit.id));
626  // Hits on track in the site before or after the Micromega wedges... yeah micromega sandwich
627  else if (m_idHelperSvc->issTgc(hit.id)) stations.insert(m_idHelperSvc->stgcIdHelper().multilayerID(hit.id));
628  }
629  tsos->push_back(hit.originalState->clone());
630  }
631 
632  if (nmeas < 6 || stations.size() < 2) {
633  ATH_MSG_DEBUG(" too few hits, cannot perform chamberCleaning ");
634  return result;
635  }
636 
637  // create new track
638  std::unique_ptr<Trk::Track> cleanedTrack =
639  std::make_unique<Trk::Track>(track->info(), std::move(tsos), track->fitQuality() ? track->fitQuality()->uniqueClone() : nullptr);
640 
641  // fit new track
642  printStates(cleanedTrack.get());
643 
644  if (!cleanedTrack->perigeeParameters()) { ATH_MSG_DEBUG(" track without perigee "); }
645 
646  std::unique_ptr<Trk::Track> newTrack = fitTrack(ctx, *cleanedTrack, track->info().particleHypothesis(), state.slFit);
647 
648  if (newTrack && !newTrack->perigeeParameters()) {
649  ATH_MSG_DEBUG(" fitted track without perigee " << *newTrack << " " << newTrack->perigeeParameters());
650  }
651 
652  result.track = std::move(newTrack);
653  return result;
654  }
655 
656  std::unique_ptr<Trk::Track> MuonTrackCleaner::outlierRecovery(const EventContext& ctx, std::unique_ptr<Trk::Track> track,
657  CleaningState& state,
658  const MuonStationIndex::ChIndex* currentIndex) const {
659  const Trk::Perigee* perigee = track->perigeeParameters();
660  if (!perigee) {
661  ATH_MSG_DEBUG(" track without perigee ");
662  return nullptr;
663  }
664 
665  ATH_MSG_VERBOSE(" outlierRecovery: ");
666  if (currentIndex) ATH_MSG_VERBOSE(" layer " << chName(*currentIndex));
667  ATH_MSG_VERBOSE(" printing chamber statistics ");
668 
669  std::set<ChIndex> recoverableLayers;
670  for (auto [stationIndex, layer] : state.chamberLayerStatistics) {
671  if (stationIndex == ChIndex::ChUnknown) continue;
673 
674  // skip all chamber layers except the requested one
675  if (currentIndex && *currentIndex != stationIndex) continue;
676 
677  ChamberLayerStatistics& statistics = layer;
678  unsigned int nhits = statistics.nhits;
679  unsigned int noutliers = statistics.noutliers;
680  // unsigned int ndeltas = statistics.ndeltas;
681  unsigned int nrecoverableOutliers = statistics.nrecoverableOutliers;
682  unsigned int noutBounds = statistics.noutBounds;
683 
684  if (nrecoverableOutliers > 0) {
685  if (nhits + nrecoverableOutliers > 2 &&
686  ((noutBounds == 0 && noutliers == 0) || (nrecoverableOutliers != 0 && noutliers < 2))) {
687  recoverableLayers.insert(stationIndex);
688  ATH_MSG_DEBUG(" found recoverable layer " << chName(statistics.chIndex));
689  }
690  }
691  }
692 
693  // if there is nothing to be done exit
694  if (recoverableLayers.empty() && !state.hasOfBoundsOutliers) return track;
695  bool addedHits = false;
696  unsigned int removedOutOfBoundsHits(0);
697 
698  auto tsos = std::make_unique<Trk::TrackStates>();
699  tsos->reserve(state.measInfo.size());
700 
701  // loop over hits
702  for (auto& hit : state.measInfo) {
703  if (!hit.useInFit) {
704  if (hit.inBounds) {
705  if (recoverableLayers.count(hit.chIndex)) {
706  // check whether we can savely add hits in this chamber to the track
707  bool recover = !isOutsideOnTrackCut(hit.id, hit.residual, hit.pull, m_associationScaleFactor);
708  if (recover && m_onlyUseHitErrorInRecovery && hit.pars) {
709  std::optional<const Trk::ResidualPull> resPull{
710  m_pullCalculator->residualPull(hit.meas, hit.pars, Trk::ResidualPull::HitOnly)};
711  if (!resPull) {
712  ATH_MSG_DEBUG(" calculation of residual/pull failed !!!!! ");
713  recover = false;
714  } else {
715  recover = !isOutsideOnTrackCut(hit.id, resPull->residual().front(), std::abs(resPull->pull().front()),
716 
717  m_associationScaleFactor);
718  }
719  }
720  if (recover) {
721  ATH_MSG_DEBUG(" adding outlier " << m_idHelperSvc->toString(hit.id) << " pull " << std::setw(7) << hit.pull);
722  if (hit.flippedMdt) {
723  double rDrift = hit.meas->localParameters()[Trk::locR];
724  double rDriftFlip = hit.flippedMdt->localParameters()[Trk::locR];
725  double rTrack = hit.pars->parameters()[Trk::locR];
726  ATH_MSG_DEBUG(" flipped MDT: r_orig " << rDrift << " flip " << rDriftFlip << " rTrack " << rTrack);
727  }
728  addedHits = true;
729  const Trk::MeasurementBase* newMeas = hit.flippedMdt ? hit.flippedMdt.get() : hit.meas;
730 
731  tsos->push_back(MuonTSOSHelper::cloneTSOSWithUpdate(*hit.originalState, *newMeas, *hit.pars,
733  } else {
734  tsos->push_back(hit.originalState->clone());
735  }
736  }
737  // layer not recoverable, drop the outliers: but if RPC, TGC, or CSC, expect track to go through all layers, so add a
738  // hole instead
739  if (m_idHelperSvc->isRpc(hit.id) || m_idHelperSvc->isTgc(hit.id) || m_idHelperSvc->isCsc(hit.id))
740  tsos->push_back(MuonTSOSHelper::createHoleTSOS(hit.pars->uniqueClone()));
741  } else {
742  ++removedOutOfBoundsHits;
743  // if RPC, TGC, or CSC, expect track to go through all layers: add a hole to replace lost outlier
744  if (m_idHelperSvc->isRpc(hit.id) || m_idHelperSvc->isTgc(hit.id) || m_idHelperSvc->isCsc(hit.id))
745  tsos->push_back(MuonTSOSHelper::createHoleTSOS(hit.pars->uniqueClone()));
746  ATH_MSG_DEBUG(" removing out of bounds outlier " << m_idHelperSvc->toString(hit.id) << " pull " << std::setw(7)
747  << hit.pull);
748  }
749  } else {
750  tsos->push_back(hit.originalState->clone());
751  }
752  }
753 
754  if (!addedHits && removedOutOfBoundsHits == 0) {
755  ATH_MSG_DEBUG(" track unchanged ");
756  return track;
757  }
758 
759  if (tsos->size() < 6) {
760  ATH_MSG_WARNING(" too few hits, cannot add hits. This should not happen ");
761  return nullptr;
762  }
763 
764  // create new track
765  std::unique_ptr<Trk::Track> cleanedTrack =
766  std::make_unique<Trk::Track>(track->info(), std::move(tsos), track->fitQuality() ? track->fitQuality()->uniqueClone() : nullptr);
767 
768  if (!addedHits) {
769  ATH_MSG_DEBUG(" only removed out of bound hits, returning track without new fit ");
770  return cleanedTrack;
771  }
772 
773  // fit new track
774  printStates(cleanedTrack.get());
775 
776  std::unique_ptr<Trk::Track> newTrack = fitTrack(ctx, *cleanedTrack, track->info().particleHypothesis(), state.slFit);
777 
778  if (newTrack) {
779  ATH_MSG_DEBUG("Outlier recovery successfull ");
780  init(ctx, *newTrack, state);
781  } else {
782  ATH_MSG_DEBUG("refit after outlier recovery failed ");
783  }
784 
785  return newTrack;
786  }
787 
788  void MuonTrackCleaner::init(const EventContext& ctx, const Trk::Track& track, CleaningState& state) const {
789  // Tell clang to optimize assuming that FP exceptions can trap.
790  // Otherwise, it can vectorize the division, which can lead to
791  // spurious division-by-zero traps from unused vector lanes.
793 
794  state.nscatterers = 0;
795  state.numberOfFlippedMdts = 0;
796  state.numberOfCleanedCompROTs = 0;
797  state.nhits = 0;
798  state.noutliers = 0;
799  state.pullSum = ChamberPullInfo();
800  state.pullSumPhi = ChamberPullInfo();
802  state.chambersToBeRemoved.clear();
803  state.chambersToBeRemovedPhi.clear();
804  state.pullSumPerChamber.clear();
805  state.pullSumPerChamberPhi.clear();
806  state.pullSumPerChamberEta.clear();
807  state.hitsPerChamber.clear();
808  state.outBoundsPerChamber.clear();
809  state.measInfo.clear();
810  state.largePullMeasurements.clear();
811  state.chamberLayerStatistics.clear();
812  state.stations.clear();
813  state.phiLayers.clear();
814  state.hasOfBoundsOutliers = false;
815  state.hasVertexConstraint = false;
816  state.hasSmall = false;
817  state.hasLarge = false;
818  state.nIdHits = 0;
819  state.nPseudoMeasurements = 0;
820  state.nPhiConstraints = 0;
821 
822  MagField::AtlasFieldCache fieldCache;
823  // Get field cache object
824  SG::ReadCondHandle<AtlasFieldCacheCondObj> readHandle{m_fieldCacheCondObjInputKey, ctx};
825  if (!readHandle.isValid()) {
826  ATH_MSG_ERROR("Failed to retrieve AtlasFieldCacheCondObj with key " << m_fieldCacheCondObjInputKey.key());
827  return;
828  }
829  readHandle->getInitializedCache(fieldCache);
830 
831  state.slFit = !fieldCache.toroidOn() || m_edmHelperSvc->isSLTrack(track);
832  if (m_use_slFit) state.slFit = true;
833 
834  // loop over track and calculate residuals
835  const Trk::TrackStates* states = track.trackStateOnSurfaces();
836  if (!states) {
837  ATH_MSG_WARNING(" track without states, cannot perform cleaning ");
838  return;
839  }
840 
841  ATH_MSG_DEBUG(" init: " << m_printer->print(track));
842 
843  state.measInfo.reserve(states->size());
844 
845  std::set<int> rpcLayers;
846  std::set<int> tgcLayers;
847  const Trk::MeasurementBase* mdtmeas = nullptr;
848  double largestmdtpull = -999;
849 
850  // loop over TSOSs
851  for (const Trk::TrackStateOnSurface* tsit : *states) {
852  if (tsit->type(Trk::TrackStateOnSurface::Perigee))
853  ATH_MSG_DEBUG(tsit->dumpType() << ", parameters " << *tsit->trackParameters());
854  const Trk::TrackParameters* pars = tsit->trackParameters();
855  if (!pars) {
856  state.measInfo.emplace_back(tsit);
857  continue;
858  }
859 
860  if (tsit->type(Trk::TrackStateOnSurface::Scatterer)) {
861  const Trk::MaterialEffectsBase* matEff = tsit->materialEffectsOnTrack();
862  const Trk::MaterialEffectsOnTrack* matTrk = dynamic_cast<const Trk::MaterialEffectsOnTrack*>(matEff);
863  ATH_MSG_VERBOSE(" Scatterer: r " << pars->position().perp() << " z " << pars->position().z());
864  if (matEff) ATH_MSG_VERBOSE(" X0 " << matEff->thicknessInX0());
865  if (matTrk && matTrk->scatteringAngles()) {
866  const Trk::ScatteringAngles* scatAngle = matTrk->scatteringAngles();
867  ATH_MSG_VERBOSE(" pull phi " << scatAngle->deltaPhi() / scatAngle->sigmaDeltaPhi() << " pull theta "
868  << scatAngle->deltaTheta() / scatAngle->sigmaDeltaTheta());
869  }
870  if (matTrk && matTrk->energyLoss()) {
871  const Trk::EnergyLoss* eloss = matTrk->energyLoss();
872  ATH_MSG_DEBUG(" eloss " << eloss->deltaE());
873  }
874  ++state.nscatterers;
875  state.measInfo.emplace_back(tsit);
876  continue;
877  }
878 
879  // check whether state is a measurement
880  const Trk::MeasurementBase* meas = tsit->measurementOnTrack();
881  if (!meas) {
882  state.measInfo.emplace_back(tsit);
883  continue;
884  }
885 
886  Identifier id = m_edmHelperSvc->getIdentifier(*meas);
887  bool pseudo = !id.is_valid();
888  if (pseudo) ++state.nPseudoMeasurements;
889 
890  if (!pseudo && !m_idHelperSvc->mdtIdHelper().is_muon(id)) {
891  ATH_MSG_VERBOSE(" TSOS is not a muon hit, position: r " << pars->position().perp() << " z " << pars->position().z());
892 
893  // count ID hits on track
894  if (tsit->type(Trk::TrackStateOnSurface::Measurement) && m_idHelperSvc->mdtIdHelper().is_indet(id)) { ++state.nIdHits; }
895  state.measInfo.emplace_back(tsit);
896  continue;
897  }
898 
899  // check whether there is a vertex constraint
900  if (pseudo && dynamic_cast<const Trk::PseudoMeasurementOnTrack*>(meas) && pars->associatedSurface().center().perp() < 200.) {
901  state.hasVertexConstraint = true;
902  }
903 
904  Identifier chId = pseudo ? id : m_idHelperSvc->chamberId(id);
905  bool measuresPhi = pseudo ? true : m_idHelperSvc->measuresPhi(id);
906 
907  // bound checks
908  Amg::Vector2D locPos;
909  if (!meas->associatedSurface().globalToLocal(pars->position(), pars->position(), locPos)) {
910  ATH_MSG_DEBUG(" localToGlobal failed !!!!! ");
911  continue;
912  }
913  bool inBounds = true;
914  double tol1 = 100.;
915  double tol2 = 2 * tol1;
916  if (!pseudo && m_idHelperSvc->isMdt(id)) tol1 = 5.;
917 
918  // we need a special bound check for MDTs so we cast to SL surface
919  const Trk::StraightLineSurface* slSurf = dynamic_cast<const Trk::StraightLineSurface*>(&meas->associatedSurface());
920  // we need a special bound check also for MMs to consider edge passivation
921  const MMClusterOnTrack* mmClusterOnTrack = dynamic_cast<const MMClusterOnTrack*>(meas);
922 
923  if (slSurf) {
924  // perform bound check only for second coordinate
925  inBounds = slSurf->bounds().insideLoc2(locPos, tol2);
926  } else if (mmClusterOnTrack) {
927  // for MM, perform the bound check from the detector element
928  inBounds = mmClusterOnTrack->detectorElement()->insideActiveBounds(id, locPos, tol1, tol2);
929  } else {
930  inBounds = meas->associatedSurface().insideBounds(locPos, tol1, tol2);
931  }
932 
933  ChIndex chIndex = !pseudo ? m_idHelperSvc->chamberIndex(id) : ChIndex::ChUnknown;
934 
935  // pointer to resPull: workaround because a const pointer is returned
936  std::optional<Trk::ResidualPull> resPull{m_pullCalculator->residualPull(
938  if (!resPull) {
939  ATH_MSG_DEBUG(" calculation of residual/pull failed !!!!! ");
940  continue;
941  }
942  int pullSize = resPull->pull().size();
943  double residual = resPull->residual().front();
944  double pull = std::abs(resPull->pull().front());
945 
946  // sanity check
947  if (!pseudo && pullSize != 1) {
948  ATH_MSG_WARNING(" ResidualPull vector has size " << pullSize << " for channel " << m_idHelperSvc->toString(id));
949  continue;
950  }
951 
952  bool isMDT = !pseudo ? m_idHelperSvc->isMdt(id) : false;
953  double error = pull > 0.001 ? std::abs(residual / pull) : 1000.;
954  double rDrift = isMDT ? meas->localParameters()[Trk::locR] : 0.;
955  double rTrack = isMDT ? pars->parameters()[Trk::locR] : 0.;
956  double rTrackAbs = std::abs(rTrack);
957  double flippedResidual = isMDT ? rDrift + rTrack : 1e10;
958  double flippedPull = isMDT ? std::abs(flippedResidual / error) : 1e10;
959 
960  bool isNoise = false;
961  bool isOutlier = isOutsideOnTrackCut(id, residual, pull, 1);
962  bool isRecoverable = m_recoverOutliers && !isOutlier && !isOutsideOnTrackCut(id, residual, pull, m_associationScaleFactor);
963  bool flippedIsRecoverable =
964  isMDT && flippedPull < pull - 0.1 && !isOutsideOnTrackCut(id, flippedResidual, flippedPull, m_associationScaleFactor);
965  double innerRadius = 14.6;
966  if (isMDT) {
967  const MdtDriftCircleOnTrack* mdtdc = dynamic_cast<const MdtDriftCircleOnTrack*>(meas);
968  if (mdtdc) innerRadius = mdtdc->detectorElement()->innerTubeRadius();
969  }
970 
971  bool isDelta = isOutlier && isMDT && rTrackAbs < innerRadius && rTrackAbs > std::abs(rDrift);
972 
973  // remove all outliers that are too far from the track
974  if (isOutlier) {
975  if (isMDT) {
976  if (rTrackAbs > innerRadius) inBounds = false;
977  } else if (pull > 10.) {
978  inBounds = false;
979  }
980  }
981 
982  std::unique_ptr<MdtDriftCircleOnTrack> mdtRotFlipped;
983  std::unique_ptr<const CompetingMuonClustersOnTrack> updatedCompRot;
984  bool flipSign = false;
985  if (!pseudo) {
986  const MdtDriftCircleOnTrack* mdtRot = isMDT ? dynamic_cast<const MdtDriftCircleOnTrack*>(meas) : nullptr;
987  if (mdtRot && mdtRot->prepRawData() && mdtRot->prepRawData()->adc() < m_adcCut) {
988  isNoise = true;
989  isOutlier = true;
990  isRecoverable = false;
991  flippedIsRecoverable = false;
992  isDelta = false;
993  }
994  if (flippedIsRecoverable) {
995  residual = flippedResidual;
996  pull = flippedPull;
997  flipSign = true;
998  }
999  if (!isNoise && flipSign) {
1000  if (mdtRot) {
1001  mdtRotFlipped = std::make_unique<MdtDriftCircleOnTrack>(*mdtRot);
1002  Trk::DriftCircleSide side = rDrift < 0. ? Trk::RIGHT : Trk::LEFT;
1003  m_mdtRotCreator->updateSign(*mdtRotFlipped, side);
1004  double rDriftFlip = mdtRotFlipped->localParameters()[Trk::locR];
1005  int signRot = rDrift < 0 ? -1 : 1;
1006  int signRotFlip = rDriftFlip < 0 ? -1 : 1;
1007  if (rDrift != 0. && signRot == signRotFlip) {
1008  ATH_MSG_WARNING(" failed to flip sign of MDT " << rDrift << " flip " << rDriftFlip);
1009  }
1010  } else {
1011  ATH_MSG_WARNING(" failed to dynamic_cast measurement with MDT Identifier to a MdtDriftCircleOnTrack");
1012  }
1013  } else {
1014  // if the outlier MDT is not recoverable by flipping the sign, add it as the worst outlier
1015  if (isOutlier && isMDT && pull > largestmdtpull && !tsit->type(Trk::TrackStateOnSurface::Outlier)) {
1016  largestmdtpull = pull;
1017  mdtmeas = meas;
1018  }
1019  }
1020 
1021  if (measuresPhi) {
1022  bool isRpc = m_idHelperSvc->isRpc(id);
1023  if (isRpc) {
1024  int layer = 0;
1025  StIndex stIndex = m_idHelperSvc->stationIndex(id);
1026  if (stIndex == StIndex::BM && m_idHelperSvc->rpcIdHelper().doubletR(id) == 1)
1027  layer = 1;
1028  else if (stIndex == StIndex::BO)
1029  layer = 2;
1030  rpcLayers.insert(layer);
1031  }
1032 
1033  bool isTgc = m_idHelperSvc->isTgc(id);
1034  if (isTgc) {
1035  int layer = 0;
1036  StIndex stIndex = m_idHelperSvc->stationIndex(id);
1037  if (stIndex == StIndex::EM) {
1038  std::string stName = m_idHelperSvc->chamberNameString(id);
1039  if (stName[1] == '1')
1040  layer = 1;
1041  else if (stName[1] == '2')
1042  layer = 2;
1043  else if (stName[1] == '3')
1044  layer = 3;
1045  else {
1046  ATH_MSG_WARNING("Unable to calculate TGC layer for " << m_idHelperSvc->toString(id));
1047  layer = -1;
1048  }
1049  }
1050  if (layer != -1) tgcLayers.insert(layer);
1051  }
1052  if (m_idHelperSvc->issTgc(id)) {
1053  int layer = 4;
1054  if (m_idHelperSvc->stgcIdHelper().multilayer(id) == 2) layer = 5;
1055  tgcLayers.insert(layer);
1056  ATH_MSG_VERBOSE("adding STGC phi hit " << layer << " size " << tgcLayers.size());
1057  }
1058  }
1059 
1060  if (m_cleanCompROTs) {
1061  const CompetingMuonClustersOnTrack* crot = (measuresPhi && !isMDT && m_idHelperSvc->isRpc(id))
1062  ? dynamic_cast<const CompetingMuonClustersOnTrack*>(meas)
1063  : nullptr;
1064  if (crot) {
1065  ATH_MSG_DEBUG(" CompetingMuonClustersOnTrack with rots " << crot->numberOfContainedROTs());
1066  double minpos = 0.;
1067  double minres = 0.;
1068  double maxres = 0.;
1069  double absminres = 0.;
1070  double absmaxres = 0.;
1071  for (unsigned int i = 0; i < crot->numberOfContainedROTs(); ++i) {
1072  const MuonClusterOnTrack* cluster = &crot->rioOnTrack(i);
1073  if (!cluster) continue;
1074  double residual = cluster->localParameters()[Trk::locX] - pars->parameters()[Trk::locX];
1075  double absres = residual < 0. ? -1. * residual : residual;
1076  if (i == 0) {
1077  minres = residual;
1078  maxres = residual;
1079  minpos = cluster->localParameters()[Trk::locX];
1080  absminres = absres;
1081  absmaxres = absres;
1082  } else if (absres < absminres) {
1083  minres = residual;
1084  absminres = absres;
1085  minpos = cluster->localParameters()[Trk::locX];
1086  } else if (absres > absmaxres) {
1087  maxres = residual;
1088  absmaxres = absres;
1089  }
1090  ATH_MSG_VERBOSE(" ROT " << m_idHelperSvc->toString(cluster->identify()) << " lpos "
1091  << cluster->localParameters()[Trk::locX] << " pars " << pars->parameters()[Trk::locX]
1092  << " residual " << residual);
1093  }
1094  ATH_MSG_DEBUG(" residuals: min " << minres << " max " << maxres << " diff " << maxres - minres);
1095  bool splitCompRot = false;
1096  if (std::abs(maxres - minres) > 100 && absmaxres - absminres > 20 && crot->numberOfContainedROTs() < 20) {
1097  ATH_MSG_DEBUG(" recoverable double cluster ");
1098  splitCompRot = true;
1099  }
1100  if (splitCompRot) {
1101  std::list<const Trk::PrepRawData*> prdList;
1102  ATH_MSG_DEBUG(" Splitting comp rot ");
1103  for (unsigned int i = 0; i < crot->numberOfContainedROTs(); ++i) {
1104  const MuonClusterOnTrack* cluster = &crot->rioOnTrack(i);
1105  if (!cluster) continue;
1106  double residual = cluster->localParameters()[Trk::locX] - minpos;
1107  double absres = residual < 0. ? -1. * residual : residual;
1108  if (absres < 40) {
1109  ATH_MSG_DEBUG(" NEW ROT " << m_idHelperSvc->toString(cluster->identify()) << " lpos "
1110  << cluster->localParameters()[Trk::locX] << " pars "
1111  << pars->parameters()[Trk::locX] << " residual " << residual);
1112  prdList.push_back(cluster->prepRawData());
1113  }
1114  }
1115  if (prdList.empty()) {
1116  ATH_MSG_WARNING("No clusters selected during comprot cleaning, keeping old cluster");
1117  } else {
1118  updatedCompRot=m_compRotCreator->createBroadCluster(prdList, 0.);
1119  ++state.numberOfCleanedCompROTs;
1120  }
1121  }
1122  }
1123  }
1124  }
1125 
1126  state.measInfo.emplace_back(id, chId, chIndex, inBounds, residual, pull, tsit, meas, pars, std::move(resPull), nullptr);
1127  MCTBCleaningInfo& info = state.measInfo.back();
1128  if (flipSign) { info.flippedMdt = std::move(mdtRotFlipped); }
1129  info.isNoise = isNoise;
1130  if (updatedCompRot) {
1131  ATH_MSG_DEBUG("updated competing ROT");
1132  info.cleanedCompROT = std::move(updatedCompRot);
1133  if (info.cleanedCompROT->associatedSurface() != meas->associatedSurface()) {
1134  std::unique_ptr<Trk::TrackParameters> exPars = m_extrapolator->extrapolate(ctx,
1135  *pars, info.cleanedCompROT->associatedSurface(),
1136  Trk::anyDirection, false, Trk::muon);
1137  if (!exPars) {
1138  ATH_MSG_WARNING("Update of comp rot parameters failed, keeping old ones");
1139  info.cleanedCompROT.reset();
1140  } else {
1141  info.pars = exPars.get();
1142  state.parsToBeDeleted.emplace_back(std::move(exPars));
1143  }
1144  }
1145  }
1146 
1147  ChamberLayerStatistics& chamberStatistics = state.chamberLayerStatistics[chIndex];
1148  chamberStatistics.chIndex = chIndex;
1149 
1150  if (tsit->type(Trk::TrackStateOnSurface::Outlier)) {
1151  ATH_MSG_DEBUG(" Outlier " << m_idHelperSvc->toString(id) << m_printer->print(*(info.resPull)));
1152  if (isMDT)
1153  ATH_MSG_DEBUG(" r_drift " << rDrift << " r_trk " << rTrack << " dr " << std::setw(7)
1154  << Amg::error(meas->localCovariance(), Trk::locR));
1155  if (isNoise) ATH_MSG_DEBUG(" noise ");
1156  if (!inBounds)
1157  ATH_MSG_DEBUG(" outBounds ");
1158  else {
1159  ATH_MSG_DEBUG(" inBounds ");
1160  if (flippedIsRecoverable)
1161  ATH_MSG_DEBUG(" flipped is recoverable, rFlipped " << info.flippedMdt->localParameters()[Trk::locR]);
1162  else if (isRecoverable)
1163  ATH_MSG_DEBUG(" recoverable ");
1164  else if (isDelta)
1165  ATH_MSG_DEBUG(" delta ");
1166  }
1167 
1168  if (!inBounds) {
1169  state.hasOfBoundsOutliers = true;
1170  ++chamberStatistics.noutBounds;
1171  } else if (flippedIsRecoverable || isRecoverable)
1172  ++chamberStatistics.nrecoverableOutliers;
1173  else if (isDelta)
1174  ++chamberStatistics.ndeltas;
1175  else if (pull < 10)
1176  ++chamberStatistics.noutliers;
1177 
1178  if (!pseudo) ++state.noutliers; // don't count pseudos here
1179  info.useInFit = 0;
1180  continue;
1181  }
1182 
1183  // if we get here could be as hit
1184  ++chamberStatistics.nhits;
1185  if (!pseudo) ++state.nhits; // pseudo's shouldn't count here
1186 
1187  if (flipSign) ++state.numberOfFlippedMdts;
1188 
1189  std::string idString = pseudo ? " Pseudomeasurement " : m_idHelperSvc->toString(id);
1190  std::string boundCheck = inBounds ? "inBounds" : "outBounds";
1191  ATH_MSG_VERBOSE(m_printer->print(*(info.resPull)) << " " << idString << " " << boundCheck);
1192  if (isNoise)
1193  ATH_MSG_VERBOSE(" noise");
1194  else if (isOutlier)
1195  ATH_MSG_VERBOSE(" outlier");
1196  if (isMDT) {
1197  ATH_MSG_VERBOSE(" r_drift " << std::setw(8) << rDrift << " r_trk " << std::setw(7) << rTrack << " dr " << std::setw(7)
1198  << Amg::error(meas->localCovariance(), Trk::locR));
1199  if (flipSign)
1200  ATH_MSG_VERBOSE(" flipped rDrift " << info.flippedMdt->localParameters()[Trk::locR] << " pull " << flippedPull);
1201  else if (isDelta)
1202  ATH_MSG_VERBOSE(" delta ");
1203  } else {
1204  const RpcClusterOnTrack* rpc = dynamic_cast<const RpcClusterOnTrack*>(meas);
1205  if (!rpc) {
1206  const CompetingMuonClustersOnTrack* crot = dynamic_cast<const CompetingMuonClustersOnTrack*>(meas);
1207  if (crot) { rpc = dynamic_cast<const RpcClusterOnTrack*>(crot->containedROTs().front()); }
1208  }
1209  if (rpc) ATH_MSG_DEBUG(" time " << rpc->prepRawData()->time() - rpc->globalPosition().mag() / 300.);
1210  }
1211 
1212  if (pseudo) {
1213  // pseudo measurements should not be included in chamber hit removal so stop here
1214  if (!isNoise && isOutlier) { state.largePullPseudoMeasurements.insert(meas); }
1215  continue;
1216 
1217  } else {
1218  // count hits
1219  EtaPhiHits& hits = state.hitsPerChamber[info.chId];
1220  if (measuresPhi)
1221  ++hits.nphi;
1222  else
1223  ++hits.neta;
1224 
1225  // bound checks
1226  if (!inBounds) {
1227  EtaPhiHits& outHits = state.outBoundsPerChamber[info.chId];
1228  if (measuresPhi)
1229  ++outHits.nphi;
1230  else
1231  ++outHits.neta;
1232  }
1233 
1234  // measurements with large pull
1235  if (!tsit->type(Trk::TrackStateOnSurface::Outlier) && isOutlier && !isMDT) { state.largePullMeasurements.insert(meas); }
1236 
1237  // pulls per chamber
1238  if (!m_idHelperSvc->isTrigger(info.chId)) {
1239  ChamberPullInfo& pullInfoHits = measuresPhi ? state.pullSumPhi : state.pullSum;
1240  pullInfoHits.pullSum += pull;
1241  ++pullInfoHits.nhits;
1242  if (pull > pullInfoHits.maxPull) pullInfoHits.maxPull = pull;
1243 
1244  ChamberPullInfo& pullInfoCh = measuresPhi ? state.pullSumPerChamberPhi[info.chId] : state.pullSumPerChamber[info.chId];
1245  pullInfoCh.pullSum += pull;
1246  ++pullInfoCh.nhits;
1247  if (pull > pullInfoCh.maxPull) pullInfoCh.maxPull = pull;
1248  } else {
1249  ChamberPullInfo& pullInfoTrig = measuresPhi ? state.pullSumPhi : state.pullSumTrigEta;
1250  if (!measuresPhi) state.pullSumPerChamberEta[info.chId];
1251  pullInfoTrig.pullSum += pull;
1252  ++pullInfoTrig.nhits;
1253  if (pull > pullInfoTrig.maxPull) pullInfoTrig.maxPull = pull;
1254  }
1255  }
1256  }
1257 
1258  // if there was an MDT outlier add it to the list of hits to be removed
1259  if (mdtmeas) state.largePullMeasurements.insert(mdtmeas);
1260 
1261  // check whether we have sufficient layers to savely clean the RPC/TGC comp rots
1262  unsigned int nphiLayers = rpcLayers.size() + tgcLayers.size();
1263  if (state.hasVertexConstraint) { nphiLayers += 1; }
1264  if (state.nIdHits > 0) { nphiLayers += 2; }
1265 
1266  if ((nphiLayers > 2) && state.numberOfCleanedCompROTs > 0) {
1267  ATH_MSG_DEBUG(" Sufficient constraints to clean competing ROTs: trigger layers " << nphiLayers);
1268  } else {
1269  // reset counter so no cleaning is performed
1270  state.numberOfCleanedCompROTs = 0;
1271  }
1272 
1273  // update sl fit configuration if track has ID hits or vertex constraint
1274  if (!m_use_slFit && state.slFit && (state.hasVertexConstraint || state.nIdHits > 0) && fieldCache.solenoidOn()) {
1275  state.slFit = false;
1276  }
1277 
1278  if (state.hasVertexConstraint || state.nIdHits) {
1279  if (state.hasVertexConstraint) ATH_MSG_DEBUG(" Track has vertex contraint:");
1280  if (state.nIdHits > 0) ATH_MSG_DEBUG(" Track has ID Hits: " << state.nIdHits);
1281  if (fieldCache.solenoidOn())
1282  ATH_MSG_DEBUG(" Solenoid On");
1283  else
1284  ATH_MSG_DEBUG(" Solenoid Off");
1285  if (fieldCache.toroidOn())
1286  ATH_MSG_DEBUG(" Toroid On");
1287  else
1288  ATH_MSG_DEBUG(" Toroid Off");
1289  if (state.slFit)
1290  ATH_MSG_DEBUG(" Use SL fit");
1291  else
1292  ATH_MSG_DEBUG(" Use curved fit");
1293  }
1294 
1295  std::set<Identifier> chambersToBeRemoved, chambersToBeRemovedPhi, goodEtaLayers, goodPhiLayers;
1296 
1297  // check whether there are any chambers in eta that should be removed
1298  extractChambersToBeRemoved(state, chambersToBeRemoved);
1299 
1300  // check whether there are any chambers in phi that should be removed
1301  extractChambersToBeRemoved(state, chambersToBeRemovedPhi, true);
1302 
1303  ATH_MSG_DEBUG("Chambers on track summary:");
1304 
1305  EtaPhiPerChamberIt chit = state.hitsPerChamber.begin();
1306  EtaPhiPerChamberIt chit_end = state.hitsPerChamber.end();
1307  for (; chit != chit_end; ++chit) {
1308  if (!chit->first.is_valid()) continue;
1309 
1310  bool isPrec = m_idHelperSvc->isMdt(chit->first) || m_idHelperSvc->isCsc(chit->first) || m_idHelperSvc->isMM(chit->first) ||
1311  m_idHelperSvc->issTgc(chit->first);
1312  if (isPrec) {
1313  StIndex stIndex = m_idHelperSvc->stationIndex(chit->first);
1314  state.stations.insert(stIndex);
1315  }
1316 
1317  EtaPhiHits& nhits = chit->second;
1318  EtaPhiHits& noutBounds = state.outBoundsPerChamber[chit->first];
1319  ATH_MSG_DEBUG(" chamber " << m_idHelperSvc->toStringChamber(chit->first) << " eta hits " << nhits.neta << " outBounds "
1320  << noutBounds.neta << " phi hits " << nhits.nphi << " outBounds " << noutBounds.nphi);
1321  if (nhits.neta != 0 && nhits.neta == noutBounds.neta) {
1322  ATH_MSG_DEBUG(" --> All eta hits out of bounds ");
1323  // remove eta hits for this chamber
1324  double fakePull = 1000. * nhits.neta;
1325  if (!chambersToBeRemoved.count(chit->first)) {
1326  // just add it
1327  state.chambersToBeRemoved.emplace_back(fakePull, chit->first);
1328  chambersToBeRemoved.insert(chit->first);
1329  } else {
1330  // replace existing entry if new one has larger Pull
1331  PullChIt pIt = state.chambersToBeRemoved.begin();
1332  PullChIt pIt_end = state.chambersToBeRemoved.end();
1333  for (; pIt != pIt_end; ++pIt) {
1334  if (pIt->second == chit->first && pIt->first < fakePull) {
1335  pIt->first = fakePull;
1336  break;
1337  }
1338  }
1339  }
1340  } else {
1341  if (noutBounds.neta != 0) ATH_MSG_DEBUG(" --> Some eta hits out of bounds ");
1342 
1343  if (isPrec && nhits.neta > 0) {
1344  if (m_idHelperSvc->isSmallChamber(chit->first))
1345  state.hasSmall = true;
1346  else
1347  state.hasLarge = true;
1348  }
1349  }
1350  if (nhits.nphi != 0 && nhits.nphi == noutBounds.nphi) {
1351  ATH_MSG_DEBUG(" --> All phi hits out of bounds ");
1352  // remove phi hits for this chamber
1353  double fakePull = 1000. * nhits.nphi;
1354  if (!chambersToBeRemovedPhi.count(chit->first)) {
1355  // just add it
1356  state.chambersToBeRemovedPhi.emplace_back(fakePull, chit->first);
1357  chambersToBeRemovedPhi.insert(chit->first);
1358  } else {
1359  // replace existing entry if new one has larger pull
1360  PullChIt pIt = state.chambersToBeRemovedPhi.begin();
1361  PullChIt pIt_end = state.chambersToBeRemovedPhi.end();
1362  for (; pIt != pIt_end; ++pIt) {
1363  if (pIt->second == chit->first) {
1364  pIt->first = std::max(pIt->first, fakePull);
1365  break;
1366  }
1367  }
1368  }
1369  } else {
1370  if (noutBounds.nphi != 0) ATH_MSG_DEBUG(" --> Some phi hits out of bounds ");
1371  if (nhits.nphi > 0) {
1372  state.phiLayers.insert(m_idHelperSvc->phiIndex(chit->first));
1373  }
1374  }
1375  }
1376 
1377  state.nPhiConstraints = state.phiLayers.size() + state.nPseudoMeasurements;
1378  if (state.hasLarge && state.hasSmall) ++state.nPhiConstraints;
1379  if (state.stations.size() == 1 && nphiLayers > 1) ++state.nPhiConstraints;
1380 
1381  double pull_precisionhits = -1.;
1382  if (state.pullSum.nhits != 0) { pull_precisionhits = state.pullSum.pullSum / state.pullSum.nhits; }
1383  double pull_triggerhits = -1.;
1384  if (state.pullSumTrigEta.nhits != 0) { pull_triggerhits = state.pullSumTrigEta.pullSum / state.pullSumTrigEta.nhits; }
1385  double pull_phihits = -1.;
1386  if (state.pullSumPhi.nhits != 0) { pull_phihits = state.pullSumPhi.pullSum / state.pullSumPhi.nhits; }
1387  ATH_MSG_DEBUG(" pull sum: precision hits "
1388  << pull_precisionhits << " trigger eta " << pull_triggerhits << " phi " << pull_phihits << " measurements "
1389  << state.measInfo.size() << std::endl
1390  << " precision chambers " << state.pullSumPerChamber.size() << " hits with large pull "
1391  << state.largePullMeasurements.size() << " pseudos with large pull " << state.largePullPseudoMeasurements.size()
1392  << " chambers to be removed " << state.chambersToBeRemoved.size() << " phi " << state.chambersToBeRemovedPhi.size()
1393  << " phi lay " << state.phiLayers.size() << " phi constr " << state.nPhiConstraints);
1394 
1395  if (state.pullSumPhi.nhits != 0) {
1396  double phiPull = state.pullSumPhi.pullSum / state.pullSumPhi.nhits;
1397  if (state.stations.size() == 1 && phiPull > 5.) { ATH_MSG_DEBUG(" Single station track with large phi pulls!! "); }
1398  } else
1399  ATH_MSG_DEBUG(" Track with no phi hits!! ");
1400  }
1401 
1402  bool MuonTrackCleaner::extractChambersToBeRemoved(CleaningState& state, std::set<Identifier>& chambersToBeRemovedSet,
1403  bool usePhi) const {
1404  bool doCleaning = false;
1405  PullChamberMap& pullSumPerChamber = usePhi ? state.pullSumPerChamberPhi : state.pullSumPerChamber;
1406  PullChVec& chambersToBeRemoved = usePhi ? state.chambersToBeRemovedPhi : state.chambersToBeRemoved;
1407 
1408  PullChamberCit cit = pullSumPerChamber.begin();
1409  PullChamberCit cit_end = pullSumPerChamber.end();
1410  if (msgLvl(MSG::DEBUG)) {
1411  if (!pullSumPerChamber.empty()) msg() << MSG::DEBUG << "Chamber pulls " << pullSumPerChamber.size() << ":";
1412  }
1413  int ndof = 0;
1414  double pulltot = 0.;
1415  for (; cit != cit_end; ++cit) {
1416  double avePull = cit->second.pullSum / cit->second.nhits;
1417  pulltot += cit->second.pullSum;
1418  ndof += cit->second.nhits;
1419  double avePullReduced = cit->second.nhits > 1 ? (cit->second.pullSum - cit->second.maxPull) / (cit->second.nhits - 1) : avePull;
1420  if (msgLvl(MSG::DEBUG))
1421  msg() << MSG::DEBUG << std::endl
1422  << " chamber " << m_idHelperSvc->toStringChamber(cit->first) << " pull sum " << cit->second.pullSum << " max pull "
1423  << cit->second.maxPull << " nhits " << cit->second.nhits << " ave pull " << avePull << " reduced ave pull "
1424  << avePullReduced;
1425  if (avePull > m_avePullSumPerChamberCut) {
1426  doCleaning = true;
1427  if (cit->second.nhits > 3 && avePullReduced < m_avePullSumPerChamberCut) {
1428  if (msgLvl(MSG::DEBUG)) msg() << MSG::DEBUG << " large pull sum ignored ";
1429  doCleaning = false;
1430  } else {
1431  if (msgLvl(MSG::DEBUG)) msg() << MSG::DEBUG << " large pull sum => removing";
1432  if (!chambersToBeRemovedSet.count(cit->first)) {
1433  chambersToBeRemoved.emplace_back(avePull, cit->first);
1434  chambersToBeRemovedSet.insert(cit->first);
1435  }
1436  }
1437  }
1438  }
1439  if (msgLvl(MSG::DEBUG)) msg() << endmsg;
1440  bool dropMore = false;
1441  if (dropMore && pulltot * pulltot > 2. * ndof * ndof) {
1442  doCleaning = true;
1443  if (msgLvl(MSG::DEBUG)) msg() << MSG::DEBUG << " large pull per dof " << pulltot << " ndof " << ndof << endmsg;
1444  }
1445 
1446  if (doCleaning && m_iterate) {
1447  cit = pullSumPerChamber.begin();
1448  for (; cit != cit_end; ++cit) {
1449  double avePull = cit->second.pullSum / cit->second.nhits;
1450  if (!chambersToBeRemovedSet.count(cit->first)) {
1451  chambersToBeRemoved.emplace_back(avePull, cit->first);
1452  chambersToBeRemovedSet.insert(cit->first);
1453  }
1454  }
1455  }
1456 
1457  if (dropMore && doCleaning && m_iterate) {
1458  // add trigger chambers
1459  cit = state.pullSumPerChamberEta.begin();
1460  cit_end = state.pullSumPerChamberEta.end();
1461  for (; cit != cit_end; ++cit) {
1462  double avePull = cit->second.pullSum / cit->second.nhits;
1463  if (!chambersToBeRemovedSet.count(cit->first)) {
1464  chambersToBeRemoved.emplace_back(avePull, cit->first);
1465  chambersToBeRemovedSet.insert(cit->first);
1466  }
1467  }
1468  }
1469 
1470  return doCleaning;
1471  }
1472 
1473  bool MuonTrackCleaner::isOutsideOnTrackCut(const Identifier& id, double res, double pull, double cutScaleFactor) const {
1474  bool isMdt = id.is_valid() ? m_idHelperSvc->isMdt(id) : false;
1475  bool measuresPhi = id.is_valid() ? m_idHelperSvc->measuresPhi(id) : false;
1476 
1477  // look at pulls and identify outliers
1478  double pullCut = measuresPhi ? m_pullCutPhi : m_pullCut;
1479 
1480  if (isMdt) {
1481  // if mdt residual cut is activated check whether the residual is small that 80% of the cut of
1482  if (m_useMdtResiCut) {
1483  return std::abs(res) > cutScaleFactor * m_mdtResiCut;
1484  } else {
1485  return std::abs(pull) > cutScaleFactor * pullCut;
1486  }
1487  } else {
1488  return std::abs(pull) > cutScaleFactor * pullCut;
1489  }
1490  }
1491 
1493  std::ostringstream sout;
1494 
1495  unsigned int nhits = statistics.nhits;
1496  unsigned int noutliers = statistics.noutliers;
1497  unsigned int ndeltas = statistics.ndeltas;
1498  unsigned int nrecoverableOutliers = statistics.nrecoverableOutliers;
1499  unsigned int noutBounds = statistics.noutBounds;
1500 
1501  sout << chName(statistics.chIndex) << " hits " << std::setw(6) << nhits << " outliers " << std::setw(6)
1502  << noutliers << " deltas " << std::setw(6) << ndeltas << " recoverableOutliers " << std::setw(6) << nrecoverableOutliers
1503  << " outBounds " << std::setw(6) << noutBounds;
1504 
1505  return sout.str();
1506  }
1507 
1509  unsigned int nstationsChamberCleaning = state.stations.size();
1510  ATH_MSG_DEBUG(" Cleaner removed full station from track: remaining layers " << nstationsChamberCleaning);
1511 
1512  if (nstationsChamberCleaning < 2) {
1513  ATH_MSG_DEBUG(" Cleaner removed all but one station from track!!! ");
1514  return false;
1515  }
1516  return true;
1517  }
1518 
1520  unsigned int nstations = state.stations.size();
1521  if (nstations == 1 ||
1522  (nstations == 2 && (state.stations.count(StIndex::EM) && state.stations.count(StIndex::EO)))) {
1523  ATH_MSG_DEBUG(" Momentum measurement lost, cleaning given up ");
1524  return false;
1525  }
1526  return true;
1527  }
1528 
1530  if (state.stations.size() == 1 && !state.nIdHits && state.nPhiConstraints < 2) {
1531  ATH_MSG_DEBUG(" Underconstraint fit " << state.nPhiConstraints);
1532  return false;
1533  }
1534  return true;
1535  }
1536 
1538  // loop over removed hits and 'unremove' them so they are used in the next iteration
1539  for (auto* hit : result.removedHits) hit->useInFit = 1;
1540  }
1541 
1543  const Trk::TrackStates* states = track->trackStateOnSurfaces();
1544  int nStates = 0;
1545  if (states) nStates = states->size();
1546  ATH_MSG_DEBUG("Calling fit with hits: " << nStates<<std::endl<<m_printer->printMeasurements(*track));
1547  }
1548 
1549  std::unique_ptr<Trk::Track> MuonTrackCleaner::fitTrack(const EventContext& ctx, Trk::Track& track, Trk::ParticleHypothesis pHyp,
1550  bool slFit) const {
1551  return slFit ? m_slTrackFitter->fit(ctx, track, false, pHyp) : m_trackFitter->fit(ctx, track, false, pHyp);
1552  }
1553 } // namespace Muon
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
Trk::ScatteringAngles::deltaPhi
double deltaPhi() const
returns the
Definition: ScatteringAngles.h:82
Trk::anyDirection
@ anyDirection
Definition: PropDirection.h:22
make_hlt_rep.pars
pars
Definition: make_hlt_rep.py:90
IDTPM::ndof
float ndof(const U &p)
Definition: TrackParametersHelper.h:134
Muon::MuonTrackCleaner::ChamberLayerStatistics::nrecoverableOutliers
unsigned int nrecoverableOutliers
Definition: MuonTrackCleaner.h:145
CXXUTILS_TRAPPING_FP
#define CXXUTILS_TRAPPING_FP
Definition: trapping_fp.h:24
MdtReadoutElement.h
EnergyLoss.h
Muon::MuonTrackCleaner::ChamberRemovalOutput
struct to store return values of chamber removal, contains the new track plus a list the removed hits
Definition: MuonTrackCleaner.h:100
Trk::TrackStateOnSurface::Perigee
@ Perigee
This represents a perigee, and so will contain a Perigee object only.
Definition: TrackStateOnSurface.h:117
ScatteringAngles.h
Muon::MuonTrackCleaner::CleaningState::nPseudoMeasurements
unsigned int nPseudoMeasurements
Definition: MuonTrackCleaner.h:167
Muon::MuonTrackCleaner::CleaningState::nhits
unsigned int nhits
Definition: MuonTrackCleaner.h:162
Muon::MuonTrackCleaner::CleaningState::chambersToBeRemovedPhi
PullChVec chambersToBeRemovedPhi
Definition: MuonTrackCleaner.h:189
Muon::MuonTrackCleaner::MCTBCleaningInfo::inBounds
bool inBounds
Definition: MuonTrackCleaner.h:51
Muon::MuonTrackCleaner::isOutsideOnTrackCut
bool isOutsideOnTrackCut(const Identifier &id, double res, double pull, double cutScaleFactor) const
check whether hit is an outlier
Definition: MuonTrackCleaner.cxx:1473
Trk::StraightLineSurface::bounds
virtual const SurfaceBounds & bounds() const override final
This method returns the bounds of the Surface by reference.
TRTCalib_Extractor.hits
hits
Definition: TRTCalib_Extractor.py:35
get_generator_info.result
result
Definition: get_generator_info.py:21
Muon::MuonTrackCleaner::CleaningState::hasLarge
bool hasLarge
Definition: MuonTrackCleaner.h:175
MeasurementBase.h
MuonGM::MMReadoutElement::insideActiveBounds
bool insideActiveBounds(const Identifier &id, const Amg::Vector2D &locpos, double tol1=0., double tol2=0.) const
boundary check Wrapper Trk::PlaneSurface::insideBounds() taking into account the passivated width
Definition: MMReadoutElement.h:252
Muon::MuonClusterOnTrack::globalPosition
virtual const Amg::Vector3D & globalPosition() const override
Returns global position.
Definition: MuonClusterOnTrack.cxx:93
SG::ReadCondHandle
Definition: ReadCondHandle.h:44
Muon::MdtDriftCircleOnTrack::prepRawData
virtual const MdtPrepData * prepRawData() const override final
Returns the PrepRawData used to create this corrected measurement.
Definition: MdtDriftCircleOnTrack.h:257
Trk::locX
@ locX
Definition: ParamDefs.h:37
Muon::MuonTrackCleaner::CleaningState::largePullMeasurements
MeasSet largePullMeasurements
Definition: MuonTrackCleaner.h:153
Muon::MuonTrackCleaner::CleaningState::parsToBeDeleted
std::vector< std::unique_ptr< Trk::TrackParameters > > parsToBeDeleted
Definition: MuonTrackCleaner.h:159
Surface.h
Trk::Track
The ATLAS Track class.
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/Track.h:73
MuonGM::MdtReadoutElement::innerTubeRadius
double innerTubeRadius() const
Returns the inner tube radius excluding the aluminium walls.
Muon::MuonTrackCleaner::CleaningState::pullSumTrigEta
ChamberPullInfo pullSumTrigEta
Definition: MuonTrackCleaner.h:179
Muon::MuonTrackCleaner::ChamberLayerStatistics
Definition: MuonTrackCleaner.h:140
ClusterSeg::residual
@ residual
Definition: ClusterNtuple.h:20
Trk::TrackStateOnSurface::clone
virtual TrackStateOnSurface * clone() const
Pseudo-constructor: needed to avoid excessive RTTI.
Trk::ParametersBase::position
const Amg::Vector3D & position() const
Access method for the position.
Amg::Vector2D
Eigen::Matrix< double, 2, 1 > Vector2D
Definition: GeoPrimitives.h:48
index
Definition: index.py:1
Muon::MuonStationIndex::StIndex::EM
@ EM
max
constexpr double max()
Definition: ap_fixedTest.cxx:33
Muon::MuonTrackCleaner::ChamberLayerStatistics::noutBounds
unsigned int noutBounds
Definition: MuonTrackCleaner.h:146
Muon::MuonTrackCleaner::removeChamber
ChamberRemovalOutput removeChamber(const EventContext &ctx, const std::unique_ptr< Trk::Track > &track, Identifier chId, bool removePhi, bool removeEta, CleaningState &state) const
remove chamber from track
Definition: MuonTrackCleaner.cxx:579
Muon::MuonClusterOnTrack::prepRawData
virtual const MuonCluster * prepRawData() const override=0
Returns the Trk::PrepRawData - is a MuonCluster in this scope.
Trk::ParametersT
Dummy class used to allow special convertors to be called for surfaces owned by a detector element.
Definition: EMErrorDetail.h:25
Muon::MuonTSOSHelper::createHoleTSOS
static std::unique_ptr< Trk::TrackStateOnSurface > createHoleTSOS(std::unique_ptr< Trk::TrackParameters > pars)
create a hole TSOS, takes ownership of the pointers
Definition: MuonTSOSHelper.h:92
Muon::MuonTrackCleaner::MCTBCleaningInfo
Definition: MuonTrackCleaner.h:46
EventPrimitivesHelpers.h
Muon::MuonStationIndex::stName
const std::string & stName(StIndex index)
convert StIndex into a string
Definition: MuonStationIndex.cxx:104
Trk::ResidualPull::Unbiased
@ Unbiased
RP with track state that has measurement not included.
Definition: ResidualPull.h:57
Muon::MuonTrackCleaner::checkPhiConstraint
bool checkPhiConstraint(CleaningState &state) const
Definition: MuonTrackCleaner.cxx:1529
Muon::MuonTrackCleaner::CleaningState::stations
std::set< MuonStationIndex::StIndex > stations
Definition: MuonTrackCleaner.h:191
Muon::MuonTrackCleaner::ChamberLayerStatistics::chIndex
MuonStationIndex::ChIndex chIndex
Definition: MuonTrackCleaner.h:141
Muon::MuonTrackCleaner::PullChIt
PullChVec::iterator PullChIt
Definition: MuonTrackCleaner.h:132
Muon::MuonTrackCleaner::CleaningState::phiLayers
std::set< MuonStationIndex::PhiIndex > phiLayers
Definition: MuonTrackCleaner.h:192
Muon::MuonTrackCleaner::checkStations
bool checkStations(CleaningState &state) const
Definition: MuonTrackCleaner.cxx:1508
Trk::ScatteringAngles
represents a deflection of the track caused through multiple scattering in material.
Definition: ScatteringAngles.h:26
Muon::MuonTrackCleaner::CleaningState::pullSumPhi
ChamberPullInfo pullSumPhi
Definition: MuonTrackCleaner.h:178
FitQualityOnSurface.h
Trk::MaterialEffectsBase::thicknessInX0
double thicknessInX0() const
returns the actually traversed material .
Muon::MuonTrackCleaner::MCTBCleaningInfo::originalState
const Trk::TrackStateOnSurface * originalState
Definition: MuonTrackCleaner.h:56
Muon::MuonTrackCleaner::CleaningState::slFit
bool slFit
Definition: MuonTrackCleaner.h:165
Muon::RpcClusterOnTrack
Class to represent calibrated clusters formed from RPC strips.
Definition: RpcClusterOnTrack.h:35
Trk::locR
@ locR
Definition: ParamDefs.h:44
Muon::MdtDriftCircleOnTrack::detectorElement
virtual const MuonGM::MdtReadoutElement * detectorElement() const override final
Returns the detector element, assoicated with the PRD of this class.
Definition: MdtDriftCircleOnTrack.h:268
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
Muon::CompetingMuonClustersOnTrack
Definition: CompetingMuonClustersOnTrack.h:54
Muon::MuonTrackCleaner::SortByAvePull
Definition: MuonTrackCleaner.h:134
Trk::MaterialEffectsBase
base class to integrate material effects on Trk::Track in a flexible way.
Definition: MaterialEffectsBase.h:35
Muon::MuonTrackCleaner::CleaningState::hasSmall
bool hasSmall
Definition: MuonTrackCleaner.h:174
Muon::MuonTrackCleaner::InfoIt
InfoVec::iterator InfoIt
Definition: MuonTrackCleaner.h:94
MagField::AtlasFieldCache::toroidOn
bool toroidOn() const
Muon
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.
Definition: TrackSystemController.h:45
Muon::MdtPrepData::adc
int adc() const
Returns the ADC (typically range is 0 to 250)
Definition: MdtPrepData.h:146
Muon::MuonTrackCleaner::ChamberLayerStatistics::nhits
unsigned int nhits
Definition: MuonTrackCleaner.h:142
MaterialEffectsBase.h
Identifier::is_valid
bool is_valid() const
Check if id is in a valid state.
Muon::MuonTrackCleaner::cleanTrack
std::unique_ptr< Trk::Track > cleanTrack(const EventContext &ctx, const Trk::Track *track, CleaningState &state) const
clean a track, actual implementation
Definition: MuonTrackCleaner.cxx:71
MuonTrackMakerStlTools.h
MMClusterOnTrack.h
Muon::MuonTrackCleaner::MCTBCleaningInfo::meas
const Trk::MeasurementBase * meas
Definition: MuonTrackCleaner.h:57
Muon::MuonTrackCleaner::ChamberLayerStatistics::ndeltas
unsigned int ndeltas
Definition: MuonTrackCleaner.h:144
Muon::MuonTrackCleaner::PullChVec
std::vector< std::pair< double, Identifier > > PullChVec
Definition: MuonTrackCleaner.h:131
Muon::MuonTrackCleaner::hitCleaning
std::unique_ptr< Trk::Track > hitCleaning(const EventContext &ctx, std::unique_ptr< Trk::Track > track, CleaningState &state) const
remove bad hits from track.
Definition: MuonTrackCleaner.cxx:296
Trk::TrackStateOnSurface::Outlier
@ Outlier
This TSoS contains an outlier, that is, it contains a MeasurementBase/RIO_OnTrack which was not used ...
Definition: TrackStateOnSurface.h:122
TRT::Hit::side
@ side
Definition: HitInfo.h:83
Track.h
Muon::MuonTrackCleaner::CleaningState::largePullPseudoMeasurements
MeasSet largePullPseudoMeasurements
Definition: MuonTrackCleaner.h:155
Muon::MuonTrackCleaner::CleaningState::nscatterers
unsigned int nscatterers
Definition: MuonTrackCleaner.h:161
MaterialEffectsOnTrack.h
TgcClusterOnTrack.h
Muon::MuonTrackCleaner::CleaningState::numberOfCleanedCompROTs
unsigned int numberOfCleanedCompROTs
Definition: MuonTrackCleaner.h:171
Trk::PseudoMeasurementOnTrack
Class to handle pseudo-measurements in fitters and on track objects.
Definition: PseudoMeasurementOnTrack.h:44
Muon::RpcPrepData::time
float time() const
Returns the time.
Definition: RpcPrepData.h:196
Muon::MuonTrackCleaner::CleaningState::hasVertexConstraint
bool hasVertexConstraint
Definition: MuonTrackCleaner.h:173
Muon::MuonTrackCleaner::unremoveHits
static void unremoveHits(ChamberRemovalOutput &result)
Definition: MuonTrackCleaner.cxx:1537
Muon::MuonTrackCleaner::init
void init(const EventContext &ctx, const Trk::Track &track, CleaningState &state) const
init cleaner
Definition: MuonTrackCleaner.cxx:788
PixelModuleFeMask_create_db.remove
string remove
Definition: PixelModuleFeMask_create_db.py:83
Trk::ParticleHypothesis
ParticleHypothesis
Definition: ParticleHypothesis.h:28
Muon::MuonStationIndex::toStationIndex
StIndex toStationIndex(ChIndex index)
convert ChIndex into StIndex
GeoPrimitives.h
Muon::MuonTrackCleaner::CleaningState::chambersToBeRemoved
PullChVec chambersToBeRemoved
Definition: MuonTrackCleaner.h:188
Trk::MaterialEffectsOnTrack
represents the full description of deflection and e-loss of a track in material.
Definition: MaterialEffectsOnTrack.h:40
MuonTSOSHelper.h
MMReadoutElement.h
RpcClusterOnTrack.h
Trk::ScatteringAngles::sigmaDeltaTheta
double sigmaDeltaTheta() const
returns the
Definition: ScatteringAngles.h:100
Muon::MuonTrackCleaner::ChamberRemovalOutput::removedHits
std::vector< MCTBCleaningInfo * > removedHits
Definition: MuonTrackCleaner.h:104
Muon::MuonTrackCleaner::CleaningState::nIdHits
unsigned int nIdHits
Definition: MuonTrackCleaner.h:166
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
Muon::MuonTrackCleaner::PullChamberMap
std::map< Identifier, ChamberPullInfo > PullChamberMap
Definition: MuonTrackCleaner.h:119
Muon::MuonTrackCleaner::MCTBCleaningInfo::resPull
std::optional< Trk::ResidualPull > resPull
Definition: MuonTrackCleaner.h:59
lumiFormat.i
int i
Definition: lumiFormat.py:85
Muon::MuonTrackCleaner::CleaningState::chamberLayerStatistics
std::map< MuonStationIndex::ChIndex, ChamberLayerStatistics > chamberLayerStatistics
Definition: MuonTrackCleaner.h:194
Muon::MuonTrackCleaner::EtaPhiHits::neta
int neta
Definition: MuonTrackCleaner.h:125
Muon::MuonStationIndex::chIndex
ChIndex chIndex(const std::string &index)
convert ChIndex name string to enum
Definition: MuonStationIndex.cxx:11
beamspotman.n
n
Definition: beamspotman.py:727
endmsg
#define endmsg
Definition: AnalysisConfig_Ntuple.cxx:63
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
Muon::MuonStationIndex::chName
const std::string & chName(ChIndex index)
convert ChIndex into a string
Definition: MuonStationIndex.cxx:119
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
Muon::MuonTrackCleaner::MCTBCleaningInfo::chId
Identifier chId
Definition: MuonTrackCleaner.h:48
urldecode::states
states
Definition: urldecode.h:39
TRT::Hit::layer
@ layer
Definition: HitInfo.h:79
Trk::RIGHT
@ RIGHT
the drift radius is positive (see Trk::AtaStraightLine)
Definition: DriftCircleSide.h:22
Muon::MuonTrackCleaner::EtaPhiHits
Definition: MuonTrackCleaner.h:123
Muon::MuonTrackCleaner::MCTBCleaningInfo::pars
const Trk::TrackParameters * pars
Definition: MuonTrackCleaner.h:58
res
std::pair< std::vector< unsigned int >, bool > res
Definition: JetGroupProductTest.cxx:11
Muon::MuonTrackCleaner::CleaningState::chamberRemovalExclusionList
std::set< Identifier > chamberRemovalExclusionList
Definition: MuonTrackCleaner.h:196
CscClusterOnTrack.h
Muon::MuonTrackCleaner::printStates
void printStates(Trk::Track *track) const
Definition: MuonTrackCleaner.cxx:1542
CscReadoutElement.h
Trk::EnergyLoss::deltaE
double deltaE() const
returns the
PseudoMeasurementOnTrack.h
python.StandardJetMods.pull
pull
Definition: StandardJetMods.py:309
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
Muon::MuonTrackCleaner::ChamberPullInfo
Definition: MuonTrackCleaner.h:113
Trk::ParametersBase
Definition: ParametersBase.h:55
Trk::muon
@ muon
Definition: ParticleHypothesis.h:31
Muon::MuonTSOSHelper::cloneTSOSWithUpdate
static std::unique_ptr< Trk::TrackStateOnSurface > cloneTSOSWithUpdate(const Trk::TrackStateOnSurface &tsos, const Trk::MeasurementBase &meas, const Trk::TrackParameters &pars, Trk::TrackStateOnSurface::TrackStateOnSurfaceType type)
clone input, replacing the track parameteres and the measurement base and updating the type
Definition: MuonTSOSHelper.h:34
DataVector< const Trk::TrackStateOnSurface >
Trk::ResidualPull::HitOnly
@ HitOnly
RP with biased track state, but pull from hit only.
Definition: ResidualPull.h:56
Muon::MuonTrackCleaner::outlierRecovery
std::unique_ptr< Trk::Track > outlierRecovery(const EventContext &ctx, std::unique_ptr< Trk::Track > track, CleaningState &state, const MuonStationIndex::ChIndex *currentIndex=nullptr) const
recover outliers that are within the cuts.
Definition: MuonTrackCleaner.cxx:656
Trk::SurfaceBounds::insideLoc2
virtual bool insideLoc2(const Amg::Vector2D &locpo, double tol2=0.) const =0
Extend the interface to for single inside Loc 1 / Loc2 tests.
MagField::AtlasFieldCache::solenoidOn
bool solenoidOn() const
status of the magnets
Trk::distPhi
@ distPhi
Definition: ParamDefs.h:50
MuonTrackCleaner.h
Trk::MeasurementBase::localCovariance
const Amg::MatrixX & localCovariance() const
Interface method to get the localError.
Definition: MeasurementBase.h:138
Muon::MuonStationIndex::StIndex::BO
@ BO
Muon::MuonStationIndex::StIndex
StIndex
enum to classify the different station layers in the muon spectrometer
Definition: MuonStationIndex.h:23
trapping_fp.h
Tell the compiler to optimize assuming that FP may trap.
Muon::MMClusterOnTrack
Class to represent calibrated clusters formed from TGC strips.
Definition: MMClusterOnTrack.h:26
Trk::MeasurementBase
Definition: MeasurementBase.h:58
Muon::RpcClusterOnTrack::prepRawData
virtual const RpcPrepData * prepRawData() const override final
Returns the RpcPrepData - is a TRT_DriftCircle in this scope.
Definition: RpcClusterOnTrack.h:127
Muon::CompetingMuonClustersOnTrack::numberOfContainedROTs
unsigned int numberOfContainedROTs() const
Number of RIO_OnTracks to be contained by this CompetingRIOsOnTrack.
Definition: CompetingMuonClustersOnTrack.h:178
Trk::Track::perigeeParameters
const Perigee * perigeeParameters() const
return Perigee.
Definition: Tracking/TrkEvent/TrkTrack/src/Track.cxx:163
Muon::MuonTrackCleaner::CleaningState::hasOfBoundsOutliers
bool hasOfBoundsOutliers
Definition: MuonTrackCleaner.h:172
Muon::MuonTrackCleaner::ChamberRemovalOutput::chId
Identifier chId
Definition: MuonTrackCleaner.h:103
Muon::MuonTrackCleaner::CleaningState
Definition: MuonTrackCleaner.h:151
Muon::MuonTrackCleaner::SortChamberRemovalResultByChi2Ndof
Definition: MuonTrackCleaner.h:106
Trk::TrackStateOnSurface
represents the track state (measurement, material, fit parameters and quality) at a surface.
Definition: TrackStateOnSurface.h:71
id
SG::auxid_t id
Definition: Control/AthContainers/Root/debug.cxx:239
Trk::MeasurementBase::associatedSurface
virtual const Surface & associatedSurface() const =0
Interface method to get the associated Surface.
Amg::error
double error(const Amg::MatrixX &mat, int index)
return diagonal error of the matrix caller should ensure the matrix is symmetric and the index is in ...
Definition: EventPrimitivesHelpers.h:40
Trk::EnergyLoss
This class describes energy loss material effects in the ATLAS tracking EDM.
Definition: EnergyLoss.h:34
Muon::MdtDriftCircleOnTrack
This class represents the corrected MDT measurements, where the corrections include the effects of wi...
Definition: MdtDriftCircleOnTrack.h:37
Muon::MuonTrackCleaner::PullChamberCit
PullChamberMap::const_iterator PullChamberCit
Definition: MuonTrackCleaner.h:121
Muon::MuonTrackCleaner::CleaningState::measInfo
InfoVec measInfo
Definition: MuonTrackCleaner.h:152
Muon::MuonTrackCleaner::ChamberLayerStatistics::noutliers
unsigned int noutliers
Definition: MuonTrackCleaner.h:143
Muon::MuonTrackCleaner::EtaPhiPerChamberIt
EtaPhiPerChamberMap::iterator EtaPhiPerChamberIt
Definition: MuonTrackCleaner.h:129
Muon::CompetingMuonClustersOnTrack::containedROTs
const std::vector< const MuonClusterOnTrack * > & containedROTs() const
returns the vector of SCT_ClusterOnTrack objects .
Definition: CompetingMuonClustersOnTrack.h:184
Trk::Surface::insideBounds
virtual bool insideBounds(const Amg::Vector2D &locpos, double tol1=0., double tol2=0.) const =0
virtual methods to be overwritten by the inherited surfaces
LocalParameters.h
python.PyKernel.init
def init(v_theApp, v_rootStream=None)
Definition: PyKernel.py:45
Muon::MuonTrackCleaner::ChamberPullInfo::maxPull
double maxPull
Definition: MuonTrackCleaner.h:116
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:16
Muon::MuonTrackCleaner::ChamberRemovalOutput::track
std::unique_ptr< Trk::Track > track
Definition: MuonTrackCleaner.h:102
Trk::MeasurementBase::localParameters
const LocalParameters & localParameters() const
Interface method to get the LocalParameters.
Definition: MeasurementBase.h:132
Trk::DriftCircleSide
DriftCircleSide
Enumerates the 'side' of the wire on which the tracks passed (i.e.
Definition: DriftCircleSide.h:16
Muon::MuonTrackCleaner::CleaningState::pullSumPerChamberPhi
PullChamberMap pullSumPerChamberPhi
Definition: MuonTrackCleaner.h:185
Muon::MuonTrackCleaner::MCTBCleaningInfo::useInFit
int useInFit
Definition: MuonTrackCleaner.h:50
Muon::MuonTrackCleaner::clean
std::unique_ptr< Trk::Track > clean(const Trk::Track &track, const EventContext &ctx) const override
clean a track, returns a pointer to a new track if successfull.
Definition: MuonTrackCleaner.cxx:65
Muon::MuonTrackCleaner::extractChambersToBeRemoved
bool extractChambersToBeRemoved(CleaningState &state, std::set< Identifier > &chambersToBeRemovedSet, bool usePhi=false) const
helper function to extract chambers that are to be removed
Definition: MuonTrackCleaner.cxx:1402
CylinderBounds.h
Muon::MuonTrackCleaner::CleaningState::numberOfFlippedMdts
unsigned int numberOfFlippedMdts
Definition: MuonTrackCleaner.h:170
Trk::ParametersBase::momentum
const Amg::Vector3D & momentum() const
Access method for the momentum.
Muon::CompetingMuonClustersOnTrack::rioOnTrack
const MuonClusterOnTrack & rioOnTrack(unsigned int) const
returns the RIO_OnTrack (also known as ROT) objects depending on the integer
Definition: CompetingMuonClustersOnTrack.h:190
Muon::MuonTrackCleaner::EtaPhiHits::nphi
int nphi
Definition: MuonTrackCleaner.h:126
Trk::ResidualPull::Biased
@ Biased
RP with track state including the hit.
Definition: ResidualPull.h:55
Muon::MuonTrackCleaner::initialize
StatusCode initialize() override
AlgTool initialize.
Definition: MuonTrackCleaner.cxx:37
Muon::MuonTrackCleaner::CleaningState::hitsPerChamber
EtaPhiPerChamberMap hitsPerChamber
Definition: MuonTrackCleaner.h:181
Trk::MaterialEffectsOnTrack::energyLoss
const EnergyLoss * energyLoss() const
returns the energy loss object.
Muon::MuonTrackCleaner::checkInnerConstraint
bool checkInnerConstraint(CleaningState &state) const
Definition: MuonTrackCleaner.cxx:1519
Muon::MuonTrackCleaner::CleaningState::pullSum
ChamberPullInfo pullSum
Definition: MuonTrackCleaner.h:177
Muon::MuonTrackCleaner::fitTrack
std::unique_ptr< Trk::Track > fitTrack(const EventContext &ctx, Trk::Track &track, Trk::ParticleHypothesis pHyp, bool slFit) const
Definition: MuonTrackCleaner.cxx:1549
Trk::Surface::globalToLocal
virtual bool globalToLocal(const Amg::Vector3D &glob, const Amg::Vector3D &mom, Amg::Vector2D &loc) const =0
Specified by each surface type: GlobalToLocal method without dynamic memory allocation - boolean chec...
Muon::MuonTrackCleaner::CleaningState::nPhiConstraints
unsigned int nPhiConstraints
Definition: MuonTrackCleaner.h:168
Muon::MuonTrackCleaner::MCTBCleaningInfo::id
Identifier id
Definition: MuonTrackCleaner.h:47
Muon::MuonTrackCleaner::CleaningState::pullSumPerChamberEta
PullChamberMap pullSumPerChamberEta
Definition: MuonTrackCleaner.h:186
Muon::MuonTrackCleaner::CleaningState::pullSumPerChamber
PullChamberMap pullSumPerChamber
Definition: MuonTrackCleaner.h:184
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
Trk::RIO_OnTrack::identify
Identifier identify() const
return the identifier -extends MeasurementBase
Definition: RIO_OnTrack.h:152
DEBUG
#define DEBUG
Definition: page_access.h:11
Trk::MaterialEffectsOnTrack::scatteringAngles
const ScatteringAngles * scatteringAngles() const
returns the MCS-angles object.
Muon::MuonTrackCleaner::ChamberPullInfo::nhits
int nhits
Definition: MuonTrackCleaner.h:117
MagField::AtlasFieldCache
Local cache for magnetic field (based on MagFieldServices/AtlasFieldSvcTLS.h)
Definition: AtlasFieldCache.h:43
Muon::print
std::string print(const MuPatSegment &)
Definition: MuonTrackSteering.cxx:28
Muon::MuonTrackCleaner::cleanCompROTs
std::unique_ptr< Trk::Track > cleanCompROTs(const EventContext &ctx, std::unique_ptr< Trk::Track > track, CleaningState &state) const
clean up competing ROTs that consist out of two clusters
Definition: MuonTrackCleaner.cxx:174
Trk::ScatteringAngles::sigmaDeltaPhi
double sigmaDeltaPhi() const
returns the
Definition: ScatteringAngles.h:94
Trk::TrackStateOnSurface::Scatterer
@ Scatterer
This represents a scattering point on the track, and so will contain TrackParameters and MaterialEffe...
Definition: TrackStateOnSurface.h:113
Muon::MuonStationIndex::StIndex::EO
@ EO
TgcReadoutElement.h
Trk::LEFT
@ LEFT
the drift radius is negative (see Trk::AtaStraightLine)
Definition: DriftCircleSide.h:20
Muon::MuonStationIndex::ChIndex
ChIndex
enum to classify the different chamber layers in the muon spectrometer
Definition: MuonStationIndex.h:15
xAOD::track
@ track
Definition: TrackingPrimitives.h:513
Muon::MuonTrackCleaner::ChamberPullInfo::pullSum
double pullSum
Definition: MuonTrackCleaner.h:115
Trk::ScatteringAngles::deltaTheta
double deltaTheta() const
returns the
Definition: ScatteringAngles.h:88
Muon::MuonStationIndex::ChIndex::ChUnknown
@ ChUnknown
Muon::MuonTrackCleaner::CleaningState::noutliers
unsigned int noutliers
Definition: MuonTrackCleaner.h:163
Muon::MuonStationIndex::StIndex::BM
@ BM
FitQuality.h
error
Definition: IImpactPoint3dEstimator.h:70
Muon::MMClusterOnTrack::detectorElement
virtual const MuonGM::MMReadoutElement * detectorElement() const
Returns the detector element, assoicated with the PRD of this class.
Definition: MMClusterOnTrack.h:139
python.ParticleTypeUtil.info
def info
Definition: ParticleTypeUtil.py:87
Muon::MuonTrackCleaner::CleaningState::outBoundsPerChamber
EtaPhiPerChamberMap outBoundsPerChamber
Definition: MuonTrackCleaner.h:182
python.AutoConfigFlags.msg
msg
Definition: AutoConfigFlags.py:7
Muon::MuonTrackCleaner::print
static std::string print(ChamberLayerStatistics &statistics)
Definition: MuonTrackCleaner.cxx:1492
Trk::TrackStateOnSurface::Measurement
@ Measurement
This is a measurement, and will at least contain a Trk::MeasurementBase.
Definition: TrackStateOnSurface.h:101
Muon::MuonTrackCleaner::recoverFlippedMdt
std::unique_ptr< Trk::Track > recoverFlippedMdt(const EventContext &ctx, std::unique_ptr< Trk::Track > track, CleaningState &state) const
flip signs of MDT hits with large pull if pull if the oppositely signed radius is small
Definition: MuonTrackCleaner.cxx:235
Trk::StraightLineSurface
Definition: StraightLineSurface.h:51
Muon::MuonClusterOnTrack
Base class for Muon cluster RIO_OnTracks.
Definition: MuonClusterOnTrack.h:34
Muon::MuonStationIndex::isSmall
bool isSmall(const ChIndex index)
Returns true if the chamber index is in a small sector.
Recovery.recover
def recover(listarray, ref_val)
Definition: Recovery.py:95
Muon::MuonTrackCleaner::chamberCleaning
std::unique_ptr< Trk::Track > chamberCleaning(const EventContext &ctx, std::unique_ptr< Trk::Track > track, CleaningState &state) const
remove bad chamber from track.
Definition: MuonTrackCleaner.cxx:462
RpcReadoutElement.h
Identifier
Definition: IdentifierFieldParser.cxx:14