ATLAS Offline Software
Loading...
Searching...
No Matches
MuonLayerAmbiguitySolverTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
6
10
11namespace Muon {
12 using namespace MuonStationIndex;
13 MuonLayerAmbiguitySolverTool::MuonLayerAmbiguitySolverTool(const std::string& type, const std::string& name, const IInterface* parent) :
14 AthAlgTool(type, name, parent) {
15 declareInterface<IMuonLayerAmbiguitySolverTool>(this);
16 }
17
19 ATH_CHECK(m_segmentSelector.retrieve());
21 ATH_CHECK(m_muonTrackBuilder.retrieve());
22 ATH_CHECK(m_printer.retrieve());
23
24 return StatusCode::SUCCESS;
25 }
26
27 void MuonLayerAmbiguitySolverTool::resolveOverlaps(const EventContext& ctx, const std::vector<MuonLayerRecoData>& allLayers,
28 std::vector<MuonCandidate>& resolvedCandidates) const {
29 // re-organise data to allow hash based access, resolve small large overlaps
30 std::vector<std::vector<MuonLayerIntersection> > muonLayerDataHashVec;
31 buildLayerVec(ctx, allLayers, muonLayerDataHashVec);
32
33 // build candidate by selecting seeds and extending them
34 unsigned int nseeds = 0; // counter for number of seeds up to now
35 std::set<const MuonSegment*> usedSegments; // keep track of the segments already used
36 std::vector<StIndex> inverseSeedLayerOrder = {StIndex::BO, StIndex::BI, StIndex::BM,
37 StIndex::EO, StIndex::EE, StIndex::EI, StIndex::EM};
38 while (nseeds < m_maxSeeds) {
39 // first get a seed
40 MuonLayerIntersection layerIntersection;
41 if (!getNextSeed(muonLayerDataHashVec, usedSegments, inverseSeedLayerOrder, layerIntersection)) {
42 ATH_MSG_VERBOSE("No more seeds, total used seeds " << nseeds);
43 break;
44 }
45
46 // create first candidate from seed and extend it
47 std::vector<MuonLayerIntersection> layerIntersections = {layerIntersection};
48 std::vector<MuonCandidate> candidates = {MuonCandidate(std::move(layerIntersections))};
49 if (extendCandidatesWithLayers(ctx, candidates, muonLayerDataHashVec, inverseSeedLayerOrder)) {
50 // add candidates to output list
51 ATH_MSG_DEBUG(" Completed seed extension " << candidates.size());
52 if (msgLvl(MSG::VERBOSE)) {
53 for (const auto& candidate : candidates) {
54 msg(MSG::VERBOSE) << " Candidate with layers " << candidate.layerIntersections.size();
55 for (const auto& entry : candidate.layerIntersections) {
56 msg(MSG::VERBOSE) << std::endl << " " << m_printer->print(*entry.segment);
57 }
58 }
59 msg(MSG::VERBOSE) << endmsg;
60 }
61
62 // add all segments on the candidates to the exlusion list
63 for (const auto& candidate : candidates) {
64 for (const auto& layer : candidate.layerIntersections) { usedSegments.insert(layer.segment.get()); }
65 }
66 resolvedCandidates.insert(resolvedCandidates.end(), std::make_move_iterator(candidates.begin()),
67 std::make_move_iterator(candidates.end()));
68 }
69 ++nseeds;
70 }
71
72 ATH_MSG_DEBUG("Completed ambiguity solving using " << nseeds << " seeds, resulting in " << resolvedCandidates.size()
73 << " track candidates ");
74 }
75
77 const EventContext& ctx, std::vector<MuonCandidate>& candidates,
78 const std::vector<std::vector<MuonLayerIntersection> >& muonLayerDataHashVec,
79 const std::vector<MuonStationIndex::StIndex>& inverseSeedLayerOrder) const {
80 // break recursive call chain once we processed all layers
81 if (inverseSeedLayerOrder.empty()) return true;
82
83 ATH_MSG_VERBOSE("extendCandidates " << candidates.size() << " remaining layers " << inverseSeedLayerOrder.size());
84
85 // get data in current layer
86 MuonStationIndex::StIndex currentStIndex = inverseSeedLayerOrder.back();
87 const std::vector<MuonLayerIntersection>& layerIntersections = muonLayerDataHashVec[toInt(currentStIndex)];
88 if (!layerIntersections.empty()) {
89 // store new MuonCandidates
90 std::vector<MuonCandidate> newCandidates;
91
92 // loop over candidates
93 for (MuonCandidate& candidate : candidates) {
94 // if more than one segment is selected in the layer, create a new candidate
95 unsigned int selectedSegmentsInLayer = 0;
96 // loop over data in layer
97 for (const MuonLayerIntersection& layerIntersection : layerIntersections) {
98 // match segment to candidate. Segment pairs with the same identifier are
99 // excluded from the beginning
100 if (match(ctx, candidate, layerIntersection)) {
101 // if first add to existing candidate, else create a new candidate
102 if (selectedSegmentsInLayer == 0) {
103 candidate.layerIntersections.push_back(layerIntersection);
104 } else {
105 MuonCandidate newCandidate = candidate;
107 newCandidate.layerIntersections.back() = layerIntersection;
108 newCandidates.emplace_back(std::move(newCandidate));
109 }
110 ++selectedSegmentsInLayer;
111 }
112 }
113 }
114 // add new candidates to list
115 if (!newCandidates.empty()) {
116 ATH_MSG_VERBOSE("Found multiple solutions, add new candidates " << newCandidates.size());
117 candidates.insert(candidates.end(), std::make_move_iterator(newCandidates.begin()),
118 std::make_move_iterator(newCandidates.end()));
119 }
120 }
121
122 // remove the current layer and call extendCandidatesWithLayers for the next layer
123 std::vector<MuonStationIndex::StIndex> newInverseSeedLayerOrder = inverseSeedLayerOrder;
124 newInverseSeedLayerOrder.pop_back();
125 return extendCandidatesWithLayers(ctx, candidates, muonLayerDataHashVec, newInverseSeedLayerOrder);
126 }
127
128 bool MuonLayerAmbiguitySolverTool::match(const EventContext& ctx, const MuonCandidate& candidate,
129 const MuonLayerIntersection& layerIntersection) const {
130 // loop over layers and match each segment to the new one, if any fails, fail the combination
131 for (const Muon::MuonLayerIntersection& layer : candidate.layerIntersections) {
132 if (!m_segmentMatchingTool->match(ctx, *layer.segment, *layerIntersection.segment)) return false;
133 }
134 return true;
135 }
136
137 bool MuonLayerAmbiguitySolverTool::getNextSeed(const std::vector<std::vector<MuonLayerIntersection> >& muonLayerDataHashVec,
138 std::set<const MuonSegment*>& usedSegments,
139 std::vector<MuonStationIndex::StIndex>& inverseSeedLayerOrder,
140 MuonLayerIntersection& layerIntersection) const {
141 ATH_MSG_VERBOSE("getNextSeed, remaining layers " << inverseSeedLayerOrder.size());
142 // loop over the inverse seed layers
143 std::vector<MuonStationIndex::StIndex>::const_reverse_iterator rit = inverseSeedLayerOrder.rbegin();
144 std::vector<MuonStationIndex::StIndex>::const_reverse_iterator rit_end = inverseSeedLayerOrder.rend();
145 for (; rit != rit_end; ++rit) {
146 // loop over segments and find the next 'good' one that was not used yet
147 for (const MuonLayerIntersection& muonLayerIntersection : muonLayerDataHashVec[toInt(*rit)]) {
149 if (muonLayerIntersection.quality < m_seedQualityThreshold) continue;
150 // only consider once
151 const MuonSegment* segment = muonLayerIntersection.segment.get();
152 if (usedSegments.count(segment)) continue;
153 usedSegments.insert(segment);
154
155 // return result
156 layerIntersection = muonLayerIntersection;
157 ATH_MSG_VERBOSE("Selected seed " << m_printer->print(*segment));
158 return true;
159 }
160 // if we get here, we processed all the possible seeds in the layer so we can remove it from the list
161 inverseSeedLayerOrder.pop_back();
162 }
163 return false;
164 }
165
166 void MuonLayerAmbiguitySolverTool::buildLayerVec(const EventContext& ctx, const std::vector<MuonLayerRecoData>& allLayers,
167 std::vector<std::vector<MuonLayerIntersection> >& muonLayerDataHashVec) const {
168 // clear and resize hash vector, initialize with null_ptr
169 muonLayerDataHashVec.clear();
170 muonLayerDataHashVec.resize(toInt(StIndex::StIndexMax));
171
172 // loop over layers
173 for (const MuonLayerRecoData& layer : allLayers) {
174 const MuonLayerSurface& layerSurface = layer.intersection.layerSurface;
176
177 // create layer intersections
178 std::vector<MuonLayerIntersection> layerIntersections;
179 layerIntersections.reserve(layer.segments.size());
180 for (const std::shared_ptr<const MuonSegment>& segment : layer.segments) {
181 // get quality and skip bad ones
182 int quality = m_segmentSelector->quality(*segment);
183 if (quality < m_minSegmentQuality) continue;
184 layerIntersections.emplace_back(layer.intersection, segment, quality);
185 }
186
187 // if there are no segments yet in the layer, directly add them
188 if (muonLayerDataHashVec[toInt(stIndex)].empty()) {
189 muonLayerDataHashVec[toInt(stIndex)] = std::move(layerIntersections);
190 } else {
191 // there are already segment, try resolving small/large overlaps
192 resolveSmallLargeOverlaps(ctx, muonLayerDataHashVec[toInt(stIndex)], layerIntersections);
193 }
194
195 // finally sort the segments
196 std::ranges::stable_sort(muonLayerDataHashVec[toInt(stIndex)],
197 [](const Muon::MuonLayerIntersection& a, const Muon::MuonLayerIntersection& b) { return a.quality > b.quality; });
198 }
199
200 if (msgLvl(MSG::DEBUG)) {
201 msg(MSG::DEBUG) << " Done building segment vector ";
202 for (const auto& vec : muonLayerDataHashVec) {
203 for (const auto& entry : vec) { msg(MSG::DEBUG) << std::endl << " " << m_printer->print(*entry.segment); }
204 }
205 msg(MSG::DEBUG) << endmsg;
206 }
207 }
208
210 std::vector<MuonLayerIntersection>& existingLayerIntersections,
211 std::vector<MuonLayerIntersection>& newLayerIntersections) const {
212 ATH_MSG_VERBOSE(" resolveSmallLargeOverlaps: existing " << existingLayerIntersections.size() << " new "
213 << newLayerIntersections.size());
214
215 // keep track of segments that have been merged
216 std::set<const MuonSegment*> combinedSegments;
217 std::vector<MuonLayerIntersection> combinedIntersections;
218
219 // loop over all permutations
220 for (const MuonLayerIntersection& layerIntersection1 : existingLayerIntersections) {
221 // get quality and skip bad ones
222 if (layerIntersection1.quality < m_minSegmentQuality) continue;
223 for (const MuonLayerIntersection& layerIntersection2 : newLayerIntersections) {
224 // get quality and skip bad ones
225 if (layerIntersection2.quality < m_minSegmentQuality) continue;
226
227 // require at least one of the segments to be above seeding threshold
228 if (layerIntersection1.quality < m_seedQualityThreshold && layerIntersection2.quality < m_seedQualityThreshold) continue;
229
230 // match segments
231 if (!m_segmentMatchingTool->match(ctx, *layerIntersection1.segment, *layerIntersection2.segment)) continue;
232
233 // build new segment
234 static const IMuonSegmentTrackBuilder::PrepVec emptyVec{};
235 std::shared_ptr<const MuonSegment> newseg{
236 m_muonTrackBuilder->combineToSegment(ctx, *layerIntersection1.segment, *layerIntersection2.segment, emptyVec)};
237 if (!newseg) {
238 ATH_MSG_DEBUG(" Fit of combination of segments failed ");
239 continue;
240 }
241
242 // check fit quality
243 const Trk::FitQuality* fq = newseg->fitQuality();
244 if (!fq || fq->numberDoF() == 0) {
245 ATH_MSG_WARNING(" No fit quality, dropping segment ");
246 continue;
247 }
248 if (fq->chiSquared() / fq->numberDoF() > 2.5) {
249 ATH_MSG_DEBUG("Bad fit quality, dropping segment " << fq->chiSquared() / fq->numberDoF());
250 continue;
251 }
252
253 // check that quality of the combined segment is not worse that the original ones
254 int qualitynew = m_segmentSelector->quality(*newseg);
255 if (qualitynew < layerIntersection1.quality || qualitynew < layerIntersection2.quality) {
256 ATH_MSG_DEBUG("Quality got worse after combination: new " << qualitynew << " q1 " << layerIntersection1.quality
257 << " q2 " << layerIntersection2.quality);
258 continue;
259 }
260
261 // select intersection closest to the IP and create new MuonLayerIntersection
262 // get line from combined segment to the IP
263 Amg::Vector3D direction = newseg->globalPosition().unit();
264 // lambda to project the intersection positions on the line, treats the case where pointer is null
265 auto getDistance = [](const MuonLayerIntersection& layerIntersection, const Amg::Vector3D& direction) {
266 if (!layerIntersection.intersection.trackParameters) return 1e9;
267 return layerIntersection.intersection.trackParameters->position().dot(direction);
268 };
269 double dist1 = getDistance(layerIntersection1, direction);
270 double dist2 = getDistance(layerIntersection2, direction);
271 if (dist1 < dist2)
272 combinedIntersections.emplace_back(layerIntersection1.intersection, newseg, qualitynew);
273 else
274 combinedIntersections.emplace_back(layerIntersection2.intersection, newseg, qualitynew);
275
276 ATH_MSG_DEBUG(" Combined segments " << std::endl
277 << " first " << m_printer->print(*layerIntersection1.segment) << std::endl
278 << " second " << m_printer->print(*layerIntersection2.segment) << std::endl
279 << " combined " << m_printer->print(*newseg));
280
281 // add segments to exclusion list
282 combinedSegments.insert(layerIntersection1.segment.get());
283 combinedSegments.insert(layerIntersection2.segment.get());
284 }
285 }
286
287 // lambda to loop over the input intersections and add them to the new list
288 auto insert_intersection = [&combinedSegments](const Muon::MuonLayerIntersection& inter_sect) {
289 return !combinedSegments.count(inter_sect.segment.get());
290 };
291 // do the insertion and swap the new vector with the existingLayerIntersections
292 combinedIntersections.reserve(existingLayerIntersections.size() + newLayerIntersections.size());
293 std::copy_if(std::make_move_iterator(existingLayerIntersections.begin()), std::make_move_iterator(existingLayerIntersections.end()),
294 std::back_inserter(combinedIntersections), insert_intersection);
295 std::copy_if(std::make_move_iterator(newLayerIntersections.begin()), std::make_move_iterator(newLayerIntersections.end()),
296 std::back_inserter(combinedIntersections), insert_intersection);
297 existingLayerIntersections = std::move(combinedIntersections);
298 }
299} // namespace Muon
#define endmsg
#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)
std::vector< size_t > vec
static Double_t a
static const Attributes_t empty
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
bool msgLvl(const MSG::Level lvl) const
MsgStream & msg() const
std::vector< const Trk::PrepRawData * > PrepVec
Gaudi::Property< unsigned int > m_maxSeeds
ToolHandle< IMuonSegmentTrackBuilder > m_muonTrackBuilder
virtual void resolveOverlaps(const EventContext &ctx, const std::vector< Muon::MuonLayerRecoData > &allLayers, std::vector< MuonCandidate > &resolvedCandidates) const override
IMuonLayerAmbiguitySolverTool interface: find.
bool match(const EventContext &ctx, const MuonCandidate &candidate, const MuonLayerIntersection &layerIntersection) const
MuonLayerAmbiguitySolverTool(const std::string &type, const std::string &name, const IInterface *parent)
Default AlgTool functions.
void buildLayerVec(const EventContext &ctx, const std::vector< MuonLayerRecoData > &allLayers, std::vector< std::vector< MuonLayerIntersection > > &muonLayerDataHashVec) const
void resolveSmallLargeOverlaps(const EventContext &ctx, std::vector< MuonLayerIntersection > &existingLayerIntersections, std::vector< MuonLayerIntersection > &newLayerIntersections) const
ToolHandle< IMuonSegmentSelectionTool > m_segmentSelector
bool getNextSeed(const std::vector< std::vector< MuonLayerIntersection > > &muonLayerDataHashVec, std::set< const MuonSegment * > &usedSegments, std::vector< MuonStationIndex::StIndex > &inverseSeedLayerOrder, MuonLayerIntersection &layerIntersection) const
ToolHandle< IMuonSegmentMatchingTool > m_segmentMatchingTool
PublicToolHandle< MuonEDMPrinterTool > m_printer
bool extendCandidatesWithLayers(const EventContext &ctx, std::vector< MuonCandidate > &candidates, const std::vector< std::vector< MuonLayerIntersection > > &muonLayerRecoDataHashVec, const std::vector< MuonStationIndex::StIndex > &inverseSeedLayerOrder) const
This is the common class for 3D segments used in the muon spectrometer.
Class to represent and store fit qualities from track reconstruction in terms of and number of degre...
Definition FitQuality.h:97
int numberDoF() const
returns the number of degrees of freedom of the overall track or vertex fit as integer
Definition FitQuality.h:60
double chiSquared() const
returns the of the overall track fit
Definition FitQuality.h:56
Eigen::Matrix< double, 3, 1 > Vector3D
StIndex
enum to classify the different station layers in the muon spectrometer
StIndex toStationIndex(ChIndex index)
convert ChIndex into StIndex
constexpr int toInt(const EnumType enumVal)
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.
std::shared_ptr< const MuonSegment > segment
segment
MuonSystemExtension::Intersection intersection
intersection with layer
std::shared_ptr< const Trk::TrackParameters > trackParameters