ATLAS Offline Software
Loading...
Searching...
No Matches
MuonCombinedMuonCandidateAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7
8namespace {
9 // Temporary collection for extrapolated tracks and links with correspondent MS tracks
10 struct track_link {
11 std::unique_ptr<Trk::Track> track{};
12 unsigned int container_index{0};
13 bool extp_succeed{false};
14 track_link(std::unique_ptr<Trk::Track> trk, unsigned int idx, bool succeed) :
15 track{std::move(trk)}, container_index{idx}, extp_succeed{succeed} {}
16 };
17} // namespace
18
19
20
24 ATH_CHECK(m_msOnlyTracks.initialize());
25 ATH_CHECK(m_printer.retrieve());
26 ATH_CHECK(m_trackBuilder.retrieve(EnableTool{!m_trackBuilder.empty()}));
27 ATH_CHECK(m_trackExtrapolationTool.retrieve(EnableTool{!m_trackExtrapolationTool.empty()}));
29 ATH_CHECK(m_trackSummaryTool.retrieve());
30 ATH_CHECK(m_idHelperSvc.retrieve());
31 ATH_CHECK(m_beamSpotKey.initialize());
32
33 ATH_CHECK(m_segmentKey.initialize(!m_segmentKey.empty()));
34 ATH_CHECK(m_trackSegmentAssociationTool.retrieve(EnableTool{!m_segmentKey.empty()}));
35
36 return StatusCode::SUCCESS;
37}
38
39StatusCode MuonCombinedMuonCandidateAlg::execute(const EventContext& ctx) const {
40 // retrieve MuonSpectrometer tracks
41 const xAOD::TrackParticleContainer* muonTrackParticles{};
42 ATH_CHECK(SG::get(muonTrackParticles, m_muonTrackParticleLocation, ctx));
43
44 SG::WriteHandle muonCandidates{m_candidateCollectionName, ctx};
45 SG::WriteHandle msOnlyTracks{m_msOnlyTracks, ctx};
46
47 ATH_CHECK(muonCandidates.record(std::make_unique<MuonCandidateCollection>()));
48 ATH_CHECK(msOnlyTracks.record(std::make_unique<TrackCollection>()));
49
50 const InDet::BeamSpotData* beamSpot{nullptr};
51 ATH_CHECK(SG::get(beamSpot, m_beamSpotKey, ctx));
52
53 ATH_MSG_DEBUG("Producing MuonCandidates for " << muonTrackParticles->size());
54 unsigned int ntracks = 0;
55
56
57 ATH_MSG_DEBUG("Beamspot position bs_x=" << Amg::toString(beamSpot->beamPos()));
58
59 std::vector<track_link> trackLinks;
60
61 unsigned int index = -1;
62 // Loop over MS tracks
63 for (const xAOD::TrackParticle* track : *muonTrackParticles) {
64 ++index;
65
66 if (!track->track()) {
67 ATH_MSG_WARNING("MuonStandalone track particle without Trk::Track");
68 continue;
69 }
70 const Trk::Track& msTrack = *track->track();
71
72 ATH_MSG_VERBOSE("Re-Fitting track " << std::endl
73 << m_printer->print(msTrack) << std::endl
74 << m_printer->printStations(msTrack));
75
76 std::unique_ptr<Trk::Track> standaloneTrack;
77 if (m_extrapolationStrategy == 0u) {
78 standaloneTrack = m_trackBuilder->standaloneFit(ctx, msTrack, beamSpot->beamPos(), nullptr);
79 } else {
80 standaloneTrack = m_trackExtrapolationTool->extrapolate(msTrack, ctx);
81 }
82
83 if (standaloneTrack) {
84 // Reject the track if its fit quality is much (much much) worse than that of the non-extrapolated track
85 if (standaloneTrack->fitQuality()->doubleNumberDoF() == 0) {
86 standaloneTrack.reset();
87 ATH_MSG_DEBUG("extrapolated track has no DOF, don't use it");
88 } else {
89 double mschi2 = 2.5; // a default we should hopefully never have to use (taken from CombinedMuonTrackBuilder)
90 if (msTrack.fitQuality()->doubleNumberDoF() > 0)
91 mschi2 = msTrack.fitQuality()->chiSquared() / msTrack.fitQuality()->doubleNumberDoF();
92 // choice of 1000 is slightly arbitrary, the point is that the fit should be really be terrible
93 if (standaloneTrack->fitQuality()->chiSquared() / standaloneTrack->fitQuality()->doubleNumberDoF() > 1000 * mschi2) {
94 standaloneTrack.reset();
95 ATH_MSG_DEBUG("extrapolated track has a degraded fit, don't use it");
96 }
97 }
98 }
99 if (standaloneTrack) {
100 standaloneTrack->info().setParticleHypothesis(Trk::muon);
101 standaloneTrack->info().setPatternRecognitionInfo(Trk::TrackInfo::MuidStandAlone);
102 ATH_MSG_VERBOSE("Extrapolated track " << std::endl
103 << m_printer->print(*standaloneTrack) << std::endl
104 << m_printer->printStations(*standaloneTrack));
105 ++ntracks;
106 if (!standaloneTrack->perigeeParameters()) {
107 ATH_MSG_WARNING(" Track without perigee " << (*standaloneTrack));
108 } else if (!standaloneTrack->perigeeParameters()->covariance()) {
109 ATH_MSG_WARNING(" Track with perigee without covariance " << (*standaloneTrack));
110 }
111 trackLinks.emplace_back(std::move(standaloneTrack), index, true);
112 } else {
113 // We can create tracks from EM segments+TGC hits
114 // If these are not successfully extrapolated, they are too low quality to be useful
115 // So only make candidates from un-extrapolated tracks if they are not EM-only
116 bool skipTrack = true;
117 const Trk::MuonTrackSummary* msMuonTrackSummary = nullptr;
118 std::unique_ptr<Trk::TrackSummary> msTrackSummary;
119 // If reading from an ESD, the track will not have a track summary yet
120 if (!msTrack.trackSummary()) {
121 msTrackSummary = m_trackSummaryTool->summary(ctx, msTrack);
122 msMuonTrackSummary = msTrackSummary->muonTrackSummary();
123 } else{
124 msMuonTrackSummary = msTrack.trackSummary()->muonTrackSummary();
125 }
126 for (const auto& chs : msMuonTrackSummary->chamberHitSummary()) {
127 using namespace Muon::MuonStationIndex;
128 if ((chs.isMdt() && m_idHelperSvc->stationIndex(chs.chamberId()) != StIndex::EM) ||
129 m_idHelperSvc->isCsc(chs.chamberId())) {
130 skipTrack = false;
131 break;
132 }
133 }
134 if (!skipTrack) {
135 trackLinks.emplace_back(std::make_unique<Trk::Track>(msTrack), index, false);
136 }
137 }
138 }
140 auto extrapTracks = std::make_unique<TrackCollection>(SG::VIEW_ELEMENTS);
141 extrapTracks->reserve(trackLinks.size());
142 for (const track_link& link : trackLinks) {
143 extrapTracks->push_back(link.track.get());
144 }
145 ATH_MSG_DEBUG("Finished back-tracking, total number of successfull fits " << ntracks);
146
147 // Resolve ambiguity between extrapolated tracks (where available)
148 auto resolvedTracks(m_ambiguityProcessor->process(ctx, extrapTracks.get()));
149
150 ATH_MSG_DEBUG("Finished ambiguity solving: " << extrapTracks->size() << " track(s) in -> " << resolvedTracks->size()
151 << " track(s) out");
152
153 const Trk::SegmentCollection* segments{nullptr};
154 ATH_CHECK(SG::get(segments, m_segmentKey, ctx));
155
156 // Loop over resolved tracks and build MuonCondidate collection
157 for (const Trk::Track* track : *resolvedTracks) {
158 std::vector<track_link>::iterator tLink = std::ranges::find_if(trackLinks,
159 [&track](const track_link& link) {
160 return link.track.get() == track;
161 });
162
163 if (tLink == trackLinks.end()) {
164 ATH_MSG_WARNING("Unable to find internal link between MS and SA tracks!");
165 continue;
166 }
167
168 std::unique_ptr<MuonCombined::MuonCandidate> muon_candidate{};
169 ElementLink<xAOD::TrackParticleContainer> MS_TrkLink{*muonTrackParticles, tLink->container_index, ctx};
170 if (tLink->extp_succeed) {
171 msOnlyTracks->push_back(std::move(tLink->track));
172 ElementLink<TrackCollection> saLink(*msOnlyTracks, msOnlyTracks->size() - 1, ctx);
173 muon_candidate = std::make_unique<MuonCombined::MuonCandidate>(MS_TrkLink, saLink,
174 msOnlyTracks->size() - 1);
175 // remove track from set so it is not deleted
176 } else {
177 // in this case the extrapolation failed
178 muon_candidate = std::make_unique<MuonCombined::MuonCandidate>(MS_TrkLink);
179 }
181 if (segments) {
182 std::vector<const Muon::MuonSegment*> assoc_segs;
183 m_trackSegmentAssociationTool->associatedSegments(*muon_candidate->primaryTrack(), segments, assoc_segs);
184 muon_candidate->setSegments(std::move(assoc_segs));
185 }
186 muonCandidates->push_back(std::move(muon_candidate));
187 }
188 return StatusCode::SUCCESS;
189}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
size_type size() const noexcept
Returns the number of elements in the collection.
SG::WriteHandleKey< MuonCandidateCollection > m_candidateCollectionName
ToolHandle< Muon::IMuonTrackExtrapolationTool > m_trackExtrapolationTool
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_muonTrackParticleLocation
ToolHandle< Trk::ITrackAmbiguityProcessorTool > m_ambiguityProcessor
PublicToolHandle< MuonCombined::IMuonTrackToSegmentAssociationTool > m_trackSegmentAssociationTool
SG::ReadCondHandleKey< InDet::BeamSpotData > m_beamSpotKey
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
ToolHandle< Trk::IExtendedTrackSummaryTool > m_trackSummaryTool
StatusCode execute(const EventContext &ctx) const override
ToolHandle< Rec::ICombinedMuonTrackBuilder > m_trackBuilder
Gaudi::Property< unsigned int > m_extrapolationStrategy
SG::WriteHandleKey< TrackCollection > m_msOnlyTracks
PublicToolHandle< Muon::MuonEDMPrinterTool > m_printer
SG::ReadHandleKey< Trk::SegmentCollection > m_segmentKey
Retrieve the segment container to perform the segment association offline.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
double chiSquared() const
returns the of the overall track fit
Definition FitQuality.h:56
double doubleNumberDoF() const
returns the number of degrees of freedom of the overall track or vertex fit as double
Definition FitQuality.h:68
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
const MuonTrackSummary * muonTrackSummary() const
returns a pointer to the MuonTrackSummary if available
const Trk::TrackSummary * trackSummary() const
Returns a pointer to the const Trk::TrackSummary owned by this const track (could be nullptr).
const FitQuality * fitQuality() const
return a pointer to the fit quality const-overload
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
@ VIEW_ELEMENTS
this data object is a view, it does not own its elmts
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
DataVector< Trk::Segment > SegmentCollection
Definition index.py:1
TrackParticle_v1 TrackParticle
Reference the current persistent version:
TrackParticleContainer_v1 TrackParticleContainer
Definition of the current "TrackParticle container version".