ATLAS Offline Software
Loading...
Searching...
No Matches
MuonTrackSteering.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "MuonTrackSteering.h"
6
7#include <algorithm>
8#include <cmath>
9#include <iomanip>
10#include <set>
11#include <sstream>
12#include <string>
13#include <utility>
14
26namespace Muon {
27
28 std::string print(const MuPatSegment& /* seg */) { return ""; }
29
30 std::string print(const std::vector<MuPatSegment*>& segVec) {
31 std::ostringstream s;
32 for (const MuPatSegment* sit : segVec) { s << " " << print(*sit); }
33 return s.str();
34 }
35
36 std::string print(const MuPatTrack& track) {
37 std::ostringstream s;
38 s << "Track:" << print(track.segments());
39 return s.str();
40 }
41
42 std::string print(const std::vector<std::unique_ptr<MuPatTrack> >& tracks) {
43 std::ostringstream s;
44 for (const std::unique_ptr<MuPatTrack>& tit : tracks) s << std::endl << print(*tit);
45
46 return s.str();
47 }
48 //----------------------------------------------------------------------------------------------------------
49 using namespace MuonStationIndex;
50 MuonTrackSteering::MuonTrackSteering(const std::string& t, const std::string& n, const IInterface* p) :
51 base_class(t,n,p), m_combinedSLOverlaps(false) {
52
53 declareProperty("StrategyList", m_stringStrategies, "List of strategies to be used by the track steering");
54 declareProperty("SegSeedQCut", m_segQCut[0] = -2, "Required quality for segments to be a seed");
55 declareProperty("Seg2ndQCut", m_segQCut[1] = -2, "Required quality for segments to be the second on a track");
56 declareProperty("SegOtherQCut", m_segQCut[2] = -2, "Required quality for segments to be added to a track");
57 declareProperty("OutputSingleStationTracks", m_outputSingleStationTracks = false);
58 declareProperty("DoSummary", m_doSummary = false);
59 declareProperty("UseTightSegmentMatching", m_useTightMatching = true);
60 declareProperty("SegmentThreshold", m_segThreshold = 8);
61 declareProperty("OnlyMdtSeeding", m_onlyMDTSeeding = true);
62 }
63
65 ATH_CHECK(m_edmHelperSvc.retrieve());
66 ATH_CHECK(m_printer.retrieve());
67 ATH_CHECK(m_candidateTool.retrieve());
69 ATH_CHECK(m_trackBTool.retrieve());
70 ATH_CHECK(m_ambiTool.retrieve());
71 ATH_CHECK(m_mooBTool.retrieve());
72 ATH_CHECK(m_trackRefineTool.retrieve());
73 ATH_CHECK(m_trackSummaryTool.retrieve());
75 if (m_outputSingleStationTracks) ATH_MSG_INFO("Single station track enabled ");
76 ATH_CHECK(m_segmentFitter.retrieve(DisableTool{!m_outputSingleStationTracks}));
77 ATH_CHECK(m_muonHoleRecoverTool.retrieve(DisableTool{!m_outputSingleStationTracks}));
78 ATH_CHECK(m_trackSelector.retrieve(DisableTool{m_trackSelector.empty()}));
79 if (!m_trackSelector.empty()) ATH_MSG_INFO("Track selection enabled: " << m_trackSelector);
80
81 return StatusCode::SUCCESS;
82 }
83
84 std::unique_ptr<TrackCollection> MuonTrackSteering::find(const EventContext& ctx, const MuonSegmentCollection& coll) const {
85 GarbageContainer trash_bin{};
86 trash_bin.reserve(150);
87
88 std::unique_ptr<TrackCollection> result = std::make_unique<TrackCollection>();
89
90 ChSegCol_t chamberSegments{}; // <! Segments sorted per Chamber
91 StSegCol_t stationSegments{}; // <! Segments sorted per station
92 ChSet chambersWithSegments;
93 StSet stationsWithSegments;
94 // Extract segments into work arrays
95 if (extractSegments(ctx, coll, chamberSegments, stationSegments, chambersWithSegments, stationsWithSegments, trash_bin)) {
96 // Perform the actual track finding
97 result = findTracks(ctx, chamberSegments, stationSegments);
98 }
99 return result;
100 }
101
102 bool MuonTrackSteering::extractSegments(const EventContext& ctx, const MuonSegmentCollection& coll, ChSegCol_t& chamberSegments, StSegCol_t& stationSegments,
103 ChSet& chambersWithSegments, StSet& stationsWithSegments, GarbageContainer& trash_bin) const {
104 if (coll.empty()) return false;
105
106 ATH_MSG_DEBUG("New collection " << coll.size());
107
108 // Sort the input collection by chamber & station IDs
109 for (const MuonSegment* segment : coll) {
110 ATH_MSG_DEBUG("Adding segment ");
111 std::unique_ptr<MuPatSegment> aSeg = m_candidateTool->createSegInfo(ctx, *segment);
112 if (!aSeg) continue;
113 ATH_MSG_DEBUG(" -> MuPatSegment " << m_candidateTool->print(*aSeg));
114
115 ChIndex chIndex = aSeg->chIndex;
116 StIndex stIndex = aSeg->stIndex;
117 if (chIndex == ChIndex::ChUnknown || stIndex == StIndex::StUnknown) {
118 ATH_MSG_WARNING("Chamber or station index invalid:" << m_candidateTool->print(*aSeg));
119 continue;
120 }
121 chambersWithSegments.insert(chIndex);
122 stationsWithSegments.insert(stIndex);
123
124 std::vector<MuPatSegment*>& segments = chamberSegments[toInt(chIndex)];
125 segments.push_back(aSeg.get());
127 std::vector<MuPatSegment*>& segments2 = stationSegments[toInt(stIndex)];
128 segments2.push_back(aSeg.get());
129 }
130 trash_bin.push_back(std::move(aSeg));
131 }
132
134 combineOverlapSegments(ctx, chamberSegments[toInt(ChIndex::BIS)], chamberSegments[toInt(ChIndex::BIL)], stationSegments,
135 stationsWithSegments, trash_bin);
136 combineOverlapSegments(ctx, chamberSegments[toInt(ChIndex::BMS)], chamberSegments[toInt(ChIndex::BML)], stationSegments,
137 stationsWithSegments, trash_bin);
138 combineOverlapSegments(ctx, chamberSegments[toInt(ChIndex::BOS)], chamberSegments[toInt(ChIndex::BOL)], stationSegments,
139 stationsWithSegments, trash_bin);
140 combineOverlapSegments(ctx, chamberSegments[toInt(ChIndex::EIS)], chamberSegments[toInt(ChIndex::EIL)], stationSegments,
141 stationsWithSegments, trash_bin);
142 combineOverlapSegments(ctx, chamberSegments[toInt(ChIndex::EMS)], chamberSegments[toInt(ChIndex::EML)], stationSegments,
143 stationsWithSegments, trash_bin);
144 combineOverlapSegments(ctx, chamberSegments[toInt(ChIndex::EOS)], chamberSegments[toInt(ChIndex::EOL)], stationSegments,
145 stationsWithSegments, trash_bin);
146 combineOverlapSegments(ctx, chamberSegments[toInt(ChIndex::EES)], chamberSegments[toInt(ChIndex::EEL)], stationSegments,
147 stationsWithSegments, trash_bin);
148 combineOverlapSegments(ctx, chamberSegments[toInt(ChIndex::CSS)], chamberSegments[toInt(ChIndex::CSL)], stationSegments,
149 stationsWithSegments, trash_bin);
150 std::vector<MuPatSegment*>& segments = chamberSegments[toInt(ChIndex::BEE)];
151 if (!segments.empty()) {
152 chambersWithSegments.insert(ChIndex::BEE);
153 stationsWithSegments.insert(StIndex::BE);
154 std::vector<MuPatSegment*>& segs = stationSegments[toInt(StIndex::BE)];
155 segs.insert(segs.end(), segments.begin(), segments.end());
156 }
157 }
158 return true;
159 }
160
161 void MuonTrackSteering::combineOverlapSegments(const EventContext& ctx, std::vector<MuPatSegment*>& ch1, std::vector<MuPatSegment*>& ch2,
162 StSegCol_t& stationSegments, StSet& stationsWithSegments,
163 GarbageContainer& trash_bin) const {
165
166 // if both empty there is nothing to be done
167 if (ch1.empty() && ch2.empty()) return;
168
169 // get station index from the first segment in the first non empty vector
170 StIndex stIndex = !ch1.empty() ? ch1.front()->stIndex : ch2.front()->stIndex;
171
172 SegCol& stationVec = stationSegments[toInt(stIndex)];
173
174 // vector to flag entries in the second station that were matched
175 std::vector<bool> wasMatched2(ch2.size(), false);
176
177 // loop over all possible combinations
178 for (MuPatSegment* sit1 : ch1) {
179 // do not combine poor quality segments
180 int qualityLevel1 = ch1.size() > 5 ? 1 : 2;
181 if (sit1->quality < qualityLevel1) {
182 ATH_MSG_VERBOSE("resolveSLOverlaps::bad segment1 q: " << sit1->quality << " cut " << qualityLevel1 << std::endl
183 << m_printer->print(*sit1->segment));
184 stationVec.push_back(sit1);
185 continue;
186 }
187
188 bool wasMatched1 = false;
189
190 // apply looser cuts as we perform matching
191 int qualityLevel2 = ch2.size() > 5 ? 1 : 2;
194 int idx_ch2 = -1;
195 for (MuPatSegment* sit2 : ch2) {
196 ++idx_ch2;
197 // do not combine poor quality segments AND require at least one of the segments to have a quality beter than 1
198 if (sit2->quality < qualityLevel2) {
199 ATH_MSG_VERBOSE("resolveSLOverlaps::bad segment2: q " << sit2->quality << " cut " << qualityLevel2 << std::endl
200 << m_printer->print(*sit2->segment));
201 continue;
202 }
203 if (sit1->quality < 2 && sit2->quality < 2) {
204 ATH_MSG_VERBOSE("resolveSLOverlaps:: combination of insufficient quality " << std::endl
205 << " q1 " << sit1->quality << " q2 "
206 << sit1->quality);
207 continue;
208 }
209
210 ATH_MSG_VERBOSE(" combining entries: " << std::endl
211 << m_printer->print(*sit1->segment) << std::endl
212 << m_printer->print(*sit2->segment));
213
214 if (!m_candidateMatchingTool->match(ctx, *sit1, *sit2, false)) {
215 ATH_MSG_VERBOSE(" overlap combination rejected based on matching" << std::endl << m_printer->print(*sit2->segment));
216 continue;
217 }
218
219 // create MuonSegment
221 std::unique_ptr<MuonSegment> newseg{m_mooBTool->combineToSegment(ctx, *sit1, *sit2, emptyPhiHits)};
222 if (!newseg) {
223 ATH_MSG_DEBUG(" Combination of segments failed ");
224 continue;
225 }
226 const Trk::FitQuality* fq = newseg->fitQuality();
227 if (!fq || fq->numberDoF() == 0) {
228 ATH_MSG_WARNING(" no fit quality, dropping segment ");
229 continue;
230 }
231 if (fq->chiSquared() / fq->numberDoF() > 2.5) {
232 ATH_MSG_DEBUG("bad fit quality, dropping segment " << fq->chiSquared() / fq->numberDoF());
233 continue;
234 }
235 std::unique_ptr<MuPatSegment> segInfo = m_candidateTool->createSegInfo(ctx, *newseg);
236 // check whether segment of good quality AND that its quality is equal or better than the input segments
237 if (!segInfo || segInfo->quality < 2 || (segInfo->quality < sit1->quality || segInfo->quality < sit2->quality)) {
238 if(segInfo) ATH_MSG_VERBOSE("resolveSLOverlaps::bad segment " << std::endl << m_printer->print(*segInfo->segment));
239 else ATH_MSG_VERBOSE("Invalid segment info");
240 continue;
241 }
242 int shared_eta = 0, shared_phi = 0; // check for hits shared between segments
243
244 const MuPatSegment* const_sit1 = sit1;
245 const MuPatSegment* const_sit2 = sit2;
246 for (const MuPatHitPtr& hit_ch1 : const_sit1->hitList()) {
247 for (const MuPatHitPtr& hit_ch2 : const_sit2->hitList()) {
248 if (hit_ch1->info().id == hit_ch2->info().id) {
249 if (hit_ch1->info().measuresPhi)
250 shared_phi++;
251 else
252 shared_eta++;
253 }
254 }
255 }
256
257 if (sit1->etaHits().size() + sit2->etaHits().size() - shared_eta - segInfo->etaHits().size() > 1) {
258 ATH_MSG_VERBOSE("resolveSLOverlaps::more than one eta measurement removed, dropping track "
259 << std::endl
260 << m_printer->print(*segInfo->segment));
261 continue;
262 }
263
264 int phiHitDiff = sit1->phiHits().size() + sit2->phiHits().size() - shared_phi - segInfo->phiHits().size();
265 if (phiHitDiff > 1 || (sit1->phiHits().size() + sit2->phiHits().size() > 0 && segInfo->phiHits().empty())) {
266 ATH_MSG_VERBOSE("resolveSLOverlaps::more than one phi measurement removed, dropping track "
267 << std::endl
268 << m_printer->print(*segInfo->segment));
269 continue;
270 }
273 double cosPointingAngle = (newseg->globalPosition().x() * newseg->globalDirection().x() +
274 newseg->globalPosition().y() * newseg->globalDirection().y()) /
275 (newseg->globalPosition().perp() * newseg->globalDirection().perp());
276 if (cosPointingAngle < 0.995) {
277 ATH_MSG_VERBOSE("resolveSLOverlaps: rejected due to too large pointing angle " << std::endl
278 << m_printer->print(*segInfo->segment));
279 continue;
280 }
281 ATH_MSG_VERBOSE("created SL overlap segment: cos pointing " << cosPointingAngle << std::endl
282 << m_printer->print(*segInfo->segment));
283
284 // flag segments as matched
285 wasMatched1 = true;
286 wasMatched2[idx_ch2] = true;
287
288 // add segment
289 stationVec.push_back(segInfo.get());
290 trash_bin.push_back(std::move(newseg));
291 trash_bin.push_back(std::move(segInfo));
292
293 }
294
295 // if entry was not associated with entry in other station add it to entries
296 if (!wasMatched1) { stationVec.push_back(sit1); }
297 }
298
299 // loop over entries in second station and add unassociated entries to candidate entries
300 for (unsigned int i = 0; i < wasMatched2.size(); ++i) {
301 if (!wasMatched2[i]) { stationVec.push_back(ch2[i]); }
302 }
303
304 // add station to list of stations with segments
305 if (!stationVec.empty()) { stationsWithSegments.insert(stIndex); }
306
307 // sort segment according to their quality
308 std::stable_sort(stationVec.begin(), stationVec.end(), SortSegInfoByQuality());
309 }
310
311 //-----------------------------------------------------------------------------------------------------------
312
313 std::unique_ptr<TrackCollection> MuonTrackSteering::findTracks(const EventContext& ctx, ChSegCol_t& chamberSegments, StSegCol_t& stationSegments) const {
314 // Very basic : output all of the segments we are starting with
315 ATH_MSG_DEBUG("List of all strategies: " << m_strategies.size());
316 for (unsigned int i = 0; i < m_strategies.size(); ++i) ATH_MSG_DEBUG((*(m_strategies[i])));
317
318 std::vector<std::unique_ptr<MuPatTrack> > resultAll;
319
320 // Outermost loop over strategies!
321 for (unsigned int i = 0; i < m_strategies.size(); ++i) {
322 if (!m_strategies[i]) continue; // Check for empty strategy pointer
323
324 const MuonTrackSteeringStrategy& strategy = *m_strategies[i];
325
326 std::vector<std::unique_ptr<MuPatTrack> > result;
327
328 // Segments that will be looped over...
329 SegColVec_t mySegColVec(strategy.getAll().size());
330
331 ATH_MSG_VERBOSE("Segments to be looped on: " << mySegColVec.size());
332
333 std::set<StIndex> stations;
334 // Preprocessing : loop over layers
335 for (unsigned int lit = 0; lit < strategy.getAll().size(); ++lit) {
336 std::vector<ChIndex> chambers = strategy.getCh(lit);
337
338 // Optional : combine segments in the same station but different chambers
340 // Loop over stations in the layer
341 for (unsigned int chin = 0; chin < chambers.size(); ++chin) {
342 // get station index for the chamber
343 StIndex stIndex = toStationIndex(chambers[chin]);
344
345 // skip those that are already included
346 if (stations.count(stIndex)) continue;
347 SegCol& segments = stationSegments[toInt(stIndex)];
348 // Add all of the MuPatSegments into the list for that layer
349 // db
350
352 // SegCol filteredSegments;
353 for (unsigned int iseg = 0; iseg < segments.size(); iseg++) {
354 double thetaSeg = std::abs((*segments[iseg]).segment->globalPosition().theta());
355
356 // only select segments in barrel/endcap overlap
357 if ((0.74159 > thetaSeg && thetaSeg > 0.51159) || (2.63 > thetaSeg && thetaSeg > 2.40))
358 mySegColVec[lit].push_back(segments[iseg]);
359 }
360 } else {
361 mySegColVec[lit].insert(mySegColVec[lit].end(), segments.begin(), segments.end());
362 }
363
364 stations.insert(stIndex);
365 } // End of loop over chambers
366
367 } else {
368 // Loop over stations in the layer
369 for (unsigned int chin = 0; chin < chambers.size(); ++chin) {
370 SegCol& segments = chamberSegments[toInt(chambers[chin])];
371 // Throw all of the MuPatSegments into the list for that layer
372 mySegColVec[lit].insert(mySegColVec[lit].end(), segments.begin(), segments.end());
373 } // End of loop over chambers
374 } // End of if combine segments in a layer
375
376 } // End of loop over layers
377
378 // Preprocessing step two : sort all layers' segments by quality
379 for (unsigned int lit = 0; lit < mySegColVec.size(); ++lit) {
380 std::stable_sort(mySegColVec[lit].begin(), mySegColVec[lit].end(), SortSegInfoByQuality());
381 }
382
383 if (m_doSummary || msgLvl(MSG::DEBUG)) {
384 bool hasSegments = false;
385 for (unsigned int lit = 0; lit < mySegColVec.size(); ++lit) {
386 if (!mySegColVec[lit].empty()) {
387 hasSegments = true;
388 break;
389 }
390 }
391 if (hasSegments) {
392 msg(m_doSummary ? MSG::INFO : MSG::DEBUG) << "For strategy: " << strategy.getName() << " segments are: ";
393 for (unsigned int lit = 0; lit < mySegColVec.size(); ++lit)
394 for (unsigned int sit = 0; sit < mySegColVec[lit].size(); ++sit)
395 msg(m_doSummary ? MSG::INFO : MSG::DEBUG) << std::endl
396 << " " << m_candidateTool->print(*(mySegColVec[lit])[sit]);
397 msg(m_doSummary ? MSG::INFO : MSG::DEBUG) << endmsg;
398 }
399 }
400
401 // Hang on to whether we want to cut seeds or not
402 bool cutSeeds = strategy.option(MuonTrackSteeringStrategy::CutSeedsOnTracks);
403
404 // Now assign priority for the layers
405 std::vector<unsigned int> seeds;
406
407 // Assign seeds dynamically according to
408 if (strategy.option(MuonTrackSteeringStrategy::DynamicSeeding)) {
409 // Loop through layers and do a little sort
410 std::vector<std::pair<int, unsigned int> > occupancy; // layer , occ
411 for (unsigned int lit = 0; lit < mySegColVec.size(); ++lit) {
412 occupancy.emplace_back(mySegColVec[lit].size(), lit);
413 }
414 std::stable_sort(occupancy.begin(), occupancy.end());
415 for (unsigned int lit = 0; lit < occupancy.size(); ++lit) { seeds.push_back(occupancy[lit].second); }
416 } else {
417 seeds = strategy.seeds();
418 if (seeds.empty()) {
419 for (unsigned int j = 0; j < mySegColVec.size(); ++j) seeds.push_back(j);
420 }
421 }
422 ATH_MSG_VERBOSE("Selected seed layers " << seeds.size());
423
424 MuPatSegment* seedSeg = nullptr;
425 // Loop over seed layers
426 for (unsigned int lin = 0; lin < seeds.size(); ++lin) {
427 // Loop over segments in that layer
428 ATH_MSG_VERBOSE("New seed layer " << lin << " segments in layer " << mySegColVec[lin].size());
429
430 for (unsigned int sin = 0; sin < mySegColVec[lin].size(); sin++) {
431 seedSeg = mySegColVec[lin].operator[](sin);
432 if (!seedSeg) continue; // Check for empty poinnter
433
434 // Optionally, if the seed is on a track we skip it
435 if (cutSeeds && seedSeg->usedInFit) continue;
436
437 // See if the seed passes our quality cut
438 if (seedSeg->quality < m_segQCut[0] ||
439 (m_segQCut[0] == -99 && !(seedSeg->segQuality && seedSeg->segQuality->isStrict())))
440 continue;
441 if (m_onlyMDTSeeding && !seedSeg->isMdt) continue;
442
443 int segsInCone = 0;
444 double phiSeed = seedSeg->segment->globalPosition().phi();
445 double etaSeed = seedSeg->segment->globalPosition().eta();
446 for (unsigned int sin2 = 0; sin2 < mySegColVec[lin].size(); sin2++) {
447 if (sin == sin2) continue;
448 MuPatSegment* seg = mySegColVec[lin].operator[](sin2);
449
450 if (seg->quality < m_segQCut[0] || (m_segQCut[0] == -99 && !(seg->segQuality && seg->segQuality->isStrict())))
451 continue;
452
453 double phiSeg = seg->segment->globalPosition().phi();
454 double etaSeg = seg->segment->globalPosition().eta();
455
456 double deltaPhi = xAOD::P4Helpers::deltaPhi(phiSeed, phiSeg);
457 double deltaEta = std::abs(etaSeed - etaSeg);
458 double deltaR = std::hypot(deltaPhi, deltaEta);
459
460 if (deltaR < 0.35) segsInCone++;
461 }
462 ATH_MSG_VERBOSE("New seed " << sin << " segments in cone " << segsInCone);
463
464 if (segsInCone > m_segThreshold && seedSeg->quality < m_segQCut[0] + 1) continue;
465
466 std::vector<std::unique_ptr<MuPatTrack> > found =
467 findTrackFromSeed(ctx, *seedSeg, *(m_strategies[i]), seeds[lin], mySegColVec);
468
469 ATH_MSG_VERBOSE(" Tracks for seed: " << std::endl << " --- " << m_candidateTool->print(result));
470 if (!found.empty()) {
471 result.insert(result.end(), std::make_move_iterator(found.begin()), std::make_move_iterator(found.end()));
472 }
473 } // End of loop over segments in a layer
474 } // Done with loop over seed layers
475
476 // Post-processing : refinement
477 if (!result.empty() && strategy.option(MuonTrackSteeringStrategy::DoRefinement)) refineTracks(ctx, result);
478
479 // Post-processing : ambiguity resolution
480 if (msgLvl(MSG::DEBUG) && !result.empty()) {
481 msg(MSG::DEBUG) << "Initial track collection for strategy: " << strategy.getName() << " " << m_candidateTool->print(result)
482 << endmsg;
483 }
484
486
487 if (!result.empty())
488 resultAll.insert(resultAll.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end()));
489
490 } // Done with loop over strategies
491
492 if (!resultAll.empty()) { solveAmbiguities(resultAll); }
493
495 SegCol& emSegments = stationSegments[toInt(StIndex::EM)];
496 // loop over segments in EM stations
497 if (!emSegments.empty()) {
498 for (MuPatSegment* sit : emSegments) {
499 // skip segments that are associated to a track
500 if (!sit->tracks().empty()) continue;
501
502 // only take highest quality segments
503 if (sit->quality < 2) continue;
504
505 // fit segment and add the track if fit ok
506 std::unique_ptr<Trk::Track> segmentTrack(m_segmentFitter->fit(*sit->segment));
507 if (segmentTrack) {
508 // Try to recover hits on the track
509 std::unique_ptr<Trk::Track> recoveredTrack(m_muonHoleRecoverTool->recover(*segmentTrack, ctx));
510 if (recoveredTrack) segmentTrack.swap(recoveredTrack);
511
512 // generate a track summary for this track
513 if (m_trackSummaryTool.isEnabled()) {
514 m_trackSummaryTool->computeAndReplaceTrackSummary(ctx, *segmentTrack, false);
515 }
516
517 std::unique_ptr<MuPatTrack> can = m_candidateTool->createCandidate(*sit, segmentTrack);
518 if (can)
519 resultAll.push_back(std::move(can));
520 else
521 ATH_MSG_WARNING("Failed to create MuPatTrack");
522 }
523 }
524 }
525 }
526
527 // Output all the tracks that we are ending with
528 if (!resultAll.empty()) {
529 if (m_doSummary)
530 ATH_MSG_INFO("Final Output : " << m_candidateTool->print(resultAll) << endmsg);
531 else
532 ATH_MSG_DEBUG("Final Output : " << m_candidateTool->print(resultAll) << endmsg);
533 }
534 std::unique_ptr<TrackCollection> finalTrack = nullptr;
535 if (!resultAll.empty()) { finalTrack = selectTracks(resultAll); }
536
537 return finalTrack;
538 }
539
540 std::vector<std::unique_ptr<MuPatTrack> > MuonTrackSteering::findTrackFromSeed(const EventContext& ctx, MuPatSegment& seedSeg,
541 const MuonTrackSteeringStrategy& strat,
542 const unsigned int layer, const SegColVec_t& segs) const {
543 // the resulting vector of tracks to be returned
544 std::vector<std::unique_ptr<MuPatTrack> > result;
545 ATH_MSG_DEBUG("Working on seed: " << std::endl << " --- " << m_candidateTool->print(seedSeg));
546 const unsigned int endLayer = strat.getAll().size();
548 for (unsigned int ilayer = 0; ilayer < strat.getAll().size(); ++ilayer) {
549 if (ilayer == layer) continue; // don't include the layer of the seed
550
551 if (segs[ilayer].empty()) continue;
552
553 std::vector<MuPatSegment*> matchedSegs;
554 bool tightCuts = false;
555 //
556 if (m_useTightMatching) {
557 double phiSeed = (seedSeg.segment)->globalPosition().phi();
558 double etaSeed = (seedSeg.segment)->globalPosition().eta();
559
560 int segsInCone = 0;
561 for (unsigned int j = 0; j < segs[ilayer].size(); j++) {
562 double phiSeg = (*segs[ilayer][j]).segment->globalPosition().phi();
563 double etaSeg = (*segs[ilayer][j]).segment->globalPosition().eta();
564
565 double deltaPhi = xAOD::P4Helpers::deltaPhi(phiSeed, phiSeg);
566 double deltaEta = std::abs(etaSeed - etaSeg);
567 double deltaR = std::hypot(deltaPhi, deltaEta);
568
569 if (deltaR < 0.35) segsInCone++;
570 }
571
572 if (segsInCone > m_segThreshold) {
573 for (unsigned int j = 0; j < segs[ilayer].size(); ++j) {
574 bool isMatched = m_candidateMatchingTool->match(ctx, seedSeg, *segs[ilayer][j], true);
575
576 if (isMatched) matchedSegs.push_back(segs[ilayer][j]);
577 }
578 if (matchedSegs.empty()) continue;
579 tightCuts = true;
580 }
581 }
582
583 std::vector<std::unique_ptr<MuPatTrack> > tracks;
584
585 if (!matchedSegs.empty() && m_useTightMatching)
586 tracks = m_trackBTool->find(ctx, seedSeg, matchedSegs);
587 else
588 tracks = m_trackBTool->find(ctx, seedSeg, segs[ilayer]);
589 if (!tracks.empty()) {
590 // if we reached the end of the sequence, we should save what we have else continue to next layer
591 if (ilayer + 1 == strat.getAll().size()) {
592 result.insert(result.end(), std::make_move_iterator(tracks.begin()), std::make_move_iterator(tracks.end()));
593 break;
594 }
595
596 // loop on found tracks
597 for (std::unique_ptr<MuPatTrack>& cit : tracks) {
598 unsigned int nextLayer = ilayer + 1;
599 if (nextLayer < strat.getAll().size()) {
600 int cutLevel = tightCuts ? 1 : 0;
601 std::vector<std::unique_ptr<MuPatTrack> > nextTracks =
602 extendWithLayer(ctx, *cit, segs, nextLayer, endLayer, cutLevel);
603 if (!nextTracks.empty()) {
604 result.insert(result.end(), std::make_move_iterator(nextTracks.begin()),
605 std::make_move_iterator(nextTracks.end()));
606 } else {
607 result.push_back(std::move(cit));
608 }
609 }
610 }
611 }
612 }
613
614 ATH_MSG_DEBUG("Constructed " << result.size() << " tracks with strategy " << strat.getName());
615 return result;
616 }
617
618 std::vector<std::unique_ptr<MuPatTrack> > MuonTrackSteering::extendWithLayer(const EventContext& ctx, MuPatTrack& candidate, const SegColVec_t& segs,
619 unsigned int nextlayer, const unsigned int endlayer,
620 int cutLevel) const {
621 std::vector<std::unique_ptr<MuPatTrack> > result;
622 if (nextlayer < endlayer) {
623 for (; nextlayer != endlayer; nextlayer++) {
624 if (segs[nextlayer].empty()) continue;
625
626 std::vector<std::unique_ptr<MuPatTrack> > nextTracks = m_trackBTool->find(ctx, candidate, segs[nextlayer]);
627 if (!nextTracks.empty()) {
628 for (std::unique_ptr<MuPatTrack>& cit : nextTracks) {
629 std::vector<std::unique_ptr<MuPatTrack> > nextTracks2 =
630 extendWithLayer(ctx, *cit, segs, nextlayer + 1, endlayer, cutLevel);
631 if (!nextTracks2.empty()) {
632 result.insert(result.end(), std::make_move_iterator(nextTracks2.begin()),
633 std::make_move_iterator(nextTracks2.end()));
634 } else {
635 result.push_back(std::move(cit));
636 }
637 }
638 }
639 }
640 }
641
642 return result;
643 }
644
645 //-----------------------------------------------------------------------------------------------------------
646 std::unique_ptr<TrackCollection> MuonTrackSteering::selectTracks(std::vector<std::unique_ptr<MuPatTrack> >& candidates, bool takeOwnership) const {
647 std::unique_ptr<TrackCollection> result = takeOwnership ?std::make_unique<TrackCollection>() : std::make_unique<TrackCollection>(SG::VIEW_ELEMENTS);
648 result->reserve(candidates.size());
649 for (std::unique_ptr<MuPatTrack>& cit : candidates) {
650 auto & thisTrack = cit->track();
651 // if track selector is configured, use it and remove bad tracks
652 if (!m_trackSelector.empty() && !m_trackSelector->decision(thisTrack)) continue;
653
654 Trk::Track* track{nullptr};
655 if (takeOwnership)
656 track = new Trk::Track(thisTrack);
657 else
658 track = &thisTrack;
659 // add track summary to this track
660 if (m_trackSummaryTool.isEnabled()) { m_trackSummaryTool->computeAndReplaceTrackSummary(*track, false); }
661 result->push_back(track);
662 }
663 return result;
664 }
665
666 void MuonTrackSteering::refineTracks(const EventContext& ctx, std::vector<std::unique_ptr<MuPatTrack> >& candidates) const {
667 for (std::unique_ptr<MuPatTrack>& cit : candidates) { m_trackRefineTool->refine(ctx, *cit); }
668 }
669
670 //-----------------------------------------------------------------------------------------------------------
671
672 void MuonTrackSteering::solveAmbiguities(std::vector<std::unique_ptr<MuPatTrack> >& tracks,
673 const MuonTrackSteeringStrategy* /*strat*/) const {
674 // the resulting vector of tracks to be returned
675 std::unique_ptr<TrackCollection> trkColl(selectTracks(tracks, false));
676 if (!trkColl || trkColl->empty()) { return; }
677
678 std::unique_ptr<const TrackCollection> resolvedTracks(m_ambiTool->process(trkColl.get()));
679 if (!resolvedTracks) { return; }
680
681 ATH_MSG_DEBUG(" resolved track candidates: old size " << trkColl->size() << " new size " << resolvedTracks->size());
682
683 std::vector<std::unique_ptr<MuPatTrack> >::iterator pat = tracks.begin();
684 for (; pat != tracks.end();) {
685 bool found = false;
686 for (const Trk::Track* rtrk : *resolvedTracks) {
687 if (&(*pat)->track() == rtrk) {
688 found = true;
689 break;
690 }
691 }
692 if (!found) {
693 pat = tracks.erase(pat);
694 } else {
695 ++pat;
696 }
697 }
698
699 }
700
701 //-----------------------------------------------------------------------------------------------------------
702
703 StatusCode MuonTrackSteering::decodeStrategyVector(const std::vector<std::string>& strategy) {
704 for (unsigned int i = 0; i < strategy.size(); ++i) {
705 std::unique_ptr<const MuonTrackSteeringStrategy> holder = decodeStrategy(strategy[i]);
706 if (!holder) {
707 // complain
708 ATH_MSG_DEBUG("failed to decode strategy");
709 } else {
710 // flag whether segments should be combined
712 m_strategies.emplace_back(std::move(holder));
713 }
714 }
715 return StatusCode::SUCCESS;
716 }
717
718 //-----------------------------------------------------------------------------------------------------------
719
720 std::unique_ptr<const MuonTrackSteeringStrategy> MuonTrackSteering::decodeStrategy(const std::string& strategy) const {
721 const std::string delims(" \t[],;");
722
723 // The strategy name
724 std::string name;
725
726 // The strategy options (which should be a vector of enums, but I'll use strings now to check that I'm
727 // decoding the stragegy correctly)
728 std::vector<std::string> options;
729
730 // The strategy sequence (which should be a vector of vector of station enumbs, but again I'll use
731 // strings instead of enums to test that I've got the decoding correct)
732 typedef std::vector<std::string> ChamberGroup;
733 std::vector<ChamberGroup> sequence;
734 std::string seqStr;
735
736 bool success = false;
737 std::unique_ptr<const MuonTrackSteeringStrategy> result;
738
739 std::string::size_type length = strategy.length();
740
741 // Extract the strategy name and options
742 std::string::size_type begIdx, endIdx;
743 begIdx = strategy.find_first_not_of(delims);
744 if (std::string::npos != begIdx) {
745 endIdx = strategy.find(':', begIdx);
746 if (std::string::npos != endIdx) {
747 seqStr = strategy.substr(endIdx + 1, length - endIdx - 1);
748 std::string nameopt = strategy.substr(begIdx, endIdx - begIdx);
749 std::string::size_type bi = nameopt.find('[');
750 if (std::string::npos != bi) {
751 name = nameopt.substr(0, bi);
752
753 // Decode options
754 std::string::size_type ei = nameopt.find(']', bi);
755 if (std::string::npos == ei) { ei = nameopt.length(); }
756 std::string inputOpt = nameopt.substr(bi + 1, ei - bi - 1);
757 success = decodeList(inputOpt, options);
758 } else {
759 name = nameopt;
760 }
761 }
762 }
763 if (msgLvl(MSG::DEBUG)) {
764 ATH_MSG_DEBUG("From strat: " << strategy << " with success " << success << " end " << endIdx << " beg " << begIdx
765 << " Name: " << name << " options: ");
766 for (std::vector<std::string>::iterator oit = options.begin(); oit != options.end(); ++oit)
767 msg(MSG::DEBUG) << " " << *oit << endmsg;
768 }
769 // Name and options successfully decoded, now decode the sequence and groups
770 if (success) {
771 begIdx = endIdx + 1;
772 do {
773 endIdx = strategy.find(';', begIdx);
774 std::string::size_type lstIdx = endIdx;
775 if (std::string::npos == endIdx) { lstIdx = strategy.length(); }
776 std::string grpString = strategy.substr(begIdx, lstIdx - begIdx);
777 ChamberGroup group;
778 success = success && decodeList(grpString, group);
779 sequence.push_back(group);
780 begIdx = lstIdx + 1;
781 } while (std::string::npos != endIdx && success);
782 }
783
784 if (success) {
785 std::vector<std::vector<ChIndex> > path;
786 for (unsigned int i = 0; i < sequence.size(); ++i) {
787 std::vector<ChIndex> idxGrp;
788 for (unsigned int j = 0; j < sequence[i].size(); ++j) {
789 ChIndex idx = chIndex(sequence[i][j]);
790 if (ChIndex::ChUnknown == idx) {
791 ATH_MSG_WARNING("I am complaining: Bad station index.");
792 } else {
793 idxGrp.push_back(idx);
794 }
795 }
796 path.push_back(idxGrp);
797 }
798 result = std::make_unique<MuonTrackSteeringStrategy>(name, options, path);
799 }
800
801 return result;
802 }
803
804 //-----------------------------------------------------------------------------------------------------------
805
806 bool MuonTrackSteering::decodeList(const std::string& input, std::vector<std::string>& list) {
807 bool result = true;
808 std::string::size_type begIdx = 0;
809 std::string::size_type endIdx = 0;
810 do {
811 endIdx = input.find(',', begIdx);
812 std::string::size_type lstIdx = endIdx;
813 if (std::string::npos == endIdx) { lstIdx = input.length(); }
814 std::string item = input.substr(begIdx, lstIdx - begIdx);
815 list.push_back(item);
816 begIdx = lstIdx + 1;
817 } while (std::string::npos != endIdx);
818 return result;
819 }
820
821} // namespace Muon
Scalar perp() const
perp method - perpendicular length
Scalar deltaPhi(const MatrixBase< Derived > &vec) const
Scalar deltaR(const MatrixBase< Derived > &vec) const
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
double length(const pvec &v)
#define x
static const Attributes_t empty
std::vector< const Trk::PrepRawData * > PrepVec
const MuPatHitList & hitList() const
returns a reference to the hit list
const MeasVec & phiHits() const
return all phi hits on the entry
segment candidate object.
bool isMdt
true for MDT, false for CSC
const MuonSegment * segment
const MuonSegmentQuality * segQuality
track candidate object.
Definition MuPatTrack.h:37
bool isStrict() const
Returns true if the segment was created using strict criteria.
This is the common class for 3D segments used in the muon spectrometer.
virtual const Amg::Vector3D & globalPosition() const override final
global position
const std::vector< std::vector< MuonStationIndex::ChIndex > > & getAll() const
ToolHandle< MooTrackBuilder > m_mooBTool
std::unique_ptr< TrackCollection > selectTracks(std::vector< std::unique_ptr< MuPatTrack > > &candidates, bool takeOwnership=true) const
std::vector< MuPatSegment * > SegCol
std::unique_ptr< const MuonTrackSteeringStrategy > decodeStrategy(const std::string &strategy) const
std::array< SegCol, MuonStationIndex::toInt(MuonStationIndex::ChIndex::ChIndexMax)> ChSegCol_t
Helper container to sort the segments by chamber index.
std::set< MuonStationIndex::ChIndex > ChSet
std::unique_ptr< TrackCollection > find(const EventContext &ctx, const MuonSegmentCollection &coll) const override
find tracks starting from a MuonSegmentCollection
static bool decodeList(const std::string &input, std::vector< std::string > &list)
ToolHandle< Trk::ITrackAmbiguityProcessorTool > m_ambiTool
ToolHandle< MooCandidateMatchingTool > m_candidateMatchingTool
ToolHandle< Muon::MuonTrackSelectorTool > m_trackSelector
PublicToolHandle< MuonEDMPrinterTool > m_printer
void combineOverlapSegments(const EventContext &ctx, std::vector< MuPatSegment * > &ch1, std::vector< MuPatSegment * > &ch2, StSegCol_t &stationSegments, StSet &stationsWithSegments, GarbageContainer &trash_bin) const
bool extractSegments(const EventContext &ctx, const MuonSegmentCollection &coll, ChSegCol_t &chamberSegments, StSegCol_t &stationSegments, ChSet &chambersWithSegments, StSet &stationsWithSegments, GarbageContainer &trash_bin) const
virtual StatusCode initialize() override
initialize method, method taken from bass-class AlgTool
ToolHandle< IMuonTrackBuilder > m_trackBTool
std::array< int, 3 > m_segQCut
Required segment quality for seed, 2nd, and other segments.
ToolHandle< IMuonHoleRecoveryTool > m_muonHoleRecoverTool
StatusCode decodeStrategyVector(const std::vector< std::string > &strategy)
void refineTracks(const EventContext &ctx, std::vector< std::unique_ptr< MuPatTrack > > &candidates) const
std::vector< std::unique_ptr< MuPatTrack > > extendWithLayer(const EventContext &ctx, MuPatTrack &candidate, const SegColVec_t &segcol, unsigned int nextlayer, const unsigned int endlayer, int cutLevel=0) const
void solveAmbiguities(std::vector< std::unique_ptr< MuPatTrack > > &tracks, const MuonTrackSteeringStrategy *strat=nullptr) const
Resolve ambiguities among tracks for a single strategy This allows a strategy-specific ambiguity solv...
ServiceHandle< IMuonEDMHelperSvc > m_edmHelperSvc
ToolHandle< IMuonTrackRefiner > m_trackRefineTool
std::vector< std::unique_ptr< const MuonTrackSteeringStrategy > > m_strategies
ToolHandle< MuPatCandidateTool > m_candidateTool
MuonTrackSteering(const std::string &, const std::string &, const IInterface *)
default AlgTool constructor
std::vector< std::unique_ptr< MuPatTrack > > findTrackFromSeed(const EventContext &ctx, MuPatSegment &seedSeg, const MuonTrackSteeringStrategy &strat, const unsigned int layer, const SegColVec_t &segs) const
Find tracks starting from a good segment.
std::array< SegCol, MuonStationIndex::toInt(MuonStationIndex::StIndex::StIndexMax)> StSegCol_t
Helper container to sort the segments by station index.
std::vector< SegCol > SegColVec_t
std::unique_ptr< TrackCollection > findTracks(const EventContext &ctx, ChSegCol_t &chamberSegments, StSegCol_t &stationSegments) const
actual find method
std::vector< std::string > m_stringStrategies
ToolHandle< Trk::IExtendedTrackSummaryTool > m_trackSummaryTool
std::set< MuonStationIndex::StIndex > StSet
ToolHandle< IMuonSegmentFittingTool > m_segmentFitter
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
StIndex
enum to classify the different station layers in the muon spectrometer
ChIndex chIndex(const std::string &index)
convert ChIndex name string to enum
StIndex toStationIndex(ChIndex index)
convert ChIndex into StIndex
constexpr int toInt(const EnumType enumVal)
ChIndex
enum to classify the different chamber layers in the muon spectrometer
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.
std::shared_ptr< MuPatHit > MuPatHitPtr
Definition MuPatHit.h:25
std::string print(const MuPatSegment &)
std::vector< const Muon::MuonSegment * > MuonSegmentCollection
static const MooTrackBuilder::PrepVec emptyPhiHits
@ VIEW_ELEMENTS
this data object is a view, it does not own its elmts
void stable_sort(DataModel_detail::iterator< DVL > beg, DataModel_detail::iterator< DVL > end)
Specialization of stable_sort for DataVector/List.
double deltaPhi(double phiA, double phiB)
delta Phi in range [-pi,pi[
void push_back(std::unique_ptr< MuonSegment > seg)
MsgStream & msg
Definition testRead.cxx:32