ATLAS Offline Software
Loading...
Searching...
No Matches
MlMsTrackSeeder.cxx
Go to the documentation of this file.
5#include <algorithm>
6#include <unordered_map>
7#include <set>
8#include <tbb/blocked_range.h>
9#include <tbb/parallel_for.h>
10
11namespace MuonR4 {
12
13MlMsTrackSeeder::MlMsTrackSeeder(const std::string& msgName, Config&& cfg)
14 : AthMessaging{msgName + ".MlMsTrackSeeder"},
15 m_cfg{std::move(cfg)},
16 m_baselineSeeder{msgName + ".BaselineMsTrackSeeder", MsTrackSeeder::Config{m_cfg.baselineSeeder}} {}
17
18std::unique_ptr<MsTrackSeedContainer> MlMsTrackSeeder::findTrackSeeds(const EventContext& ctx,
19 const xAOD::MuonSegmentContainer& segments) const {
20 SG::AuxElement::ConstAccessor<std::vector<unsigned>> acc{m_cfg.candidateDecoration};
21 std::unordered_map<unsigned, std::vector<const xAOD::MuonSegment*>> groups;
22 groups.reserve(segments.size());
23
24 bool sawDecor = false;
25 for (const xAOD::MuonSegment* seg : segments) {
26 if (!seg || !acc.isAvailable(*seg)) continue;
27 sawDecor = true;
28 for (const unsigned id : acc(*seg)) groups[id].push_back(seg);
29 }
30
31 if (!sawDecor) {
32 ATH_MSG_DEBUG("MlMsTrackSeeder: no ML decoration found on any segment."
33 << (m_cfg.fallbackToBaselineIfUndecorated ? " Falling back to baseline seeder." : " Returning empty seed set."));
34 if (m_cfg.fallbackToBaselineIfUndecorated) return m_baselineSeeder.findTrackSeeds(ctx, segments);
35 return std::make_unique<MsTrackSeedContainer>();
36 }
37
38 ATH_MSG_DEBUG("MlMsTrackSeeder: " << groups.size() << " ML candidate group(s) from "
39 << segments.size() << " segment(s)");
40
41 auto out = std::make_unique<MsTrackSeedContainer>();
42
43 std::vector<unsigned> orderedIds;
44 orderedIds.reserve(groups.size());
45 for (const auto& [id, _] : groups) orderedIds.push_back(id);
46 std::sort(orderedIds.begin(), orderedIds.end());
47
48 struct CandidateResult {
49 unsigned id{0};
50 std::size_t nSegments{0};
51 std::unique_ptr<MsTrackSeedContainer> seeds{};
52 };
53
54 std::vector<CandidateResult> results(orderedIds.size());
55
56 auto runOneCandidate = [&](std::size_t idx) {
57 const unsigned id = orderedIds[idx];
58 auto& segs = groups[id];
59 std::sort(segs.begin(), segs.end());
60 segs.erase(std::unique(segs.begin(), segs.end()), segs.end());
61 results[idx].id = id;
62 results[idx].nSegments = segs.size();
63
64 if (segs.size() < m_cfg.minSegmentsPerCandidate) {
65 return;
66 }
67
69 for (const xAOD::MuonSegment* seg : segs) {
70 viewCont.push_back(seg);
71 }
72 results[idx].seeds = m_baselineSeeder.findTrackSeeds(ctx, *viewCont.asDataVector());
73 };
74
75 if (m_cfg.runCandidatesInParallel && orderedIds.size() > 1) {
76 tbb::parallel_for(tbb::blocked_range<std::size_t>(0, orderedIds.size()),
77 [&](const tbb::blocked_range<std::size_t>& range) {
78 for (std::size_t idx = range.begin(); idx != range.end(); ++idx) {
79 runOneCandidate(idx);
80 }
81 });
82 } else {
83 for (std::size_t idx = 0; idx < orderedIds.size(); ++idx) {
84 runOneCandidate(idx);
85 }
86 }
87
88 for (CandidateResult& result : results) {
89 const std::size_t nSeeds = result.seeds ? result.seeds->size() : 0;
90 ATH_MSG_DEBUG(" candidate " << result.id << ": "
91 << result.nSegments << " segment(s) -> "
92 << nSeeds << " seed(s)");
93 if (!result.seeds) continue;
94 for (MsTrackSeed& seed : *result.seeds) {
95 out->push_back(std::move(seed));
96 }
97 }
98
99 // Remove exact duplicates induced by overlapping ML candidate IDs.
100 // This is intentionally pointer-based: if two seeds contain the same segment set,
101 // they will drive the same downstream fit attempt.
102 std::set<std::vector<const xAOD::MuonSegment*>> seen;
103 MsTrackSeedContainer uniqueSeeds{};
104 for (MsTrackSeed& seed : *out) {
105 std::vector<const xAOD::MuonSegment*> key = seed.segments();
106 std::sort(key.begin(), key.end());
107 if (!seen.insert(key).second) continue;
108 uniqueSeeds.push_back(std::move(seed));
109 }
110 *out = std::move(uniqueSeeds);
111
112 ATH_MSG_DEBUG("MlMsTrackSeeder: total seeds produced = " << out->size()
113 << (out->empty() && m_cfg.fallbackToBaselineIfNoCandidates ? " — falling back to baseline seeder" : ""));
114 if (out->empty() && m_cfg.fallbackToBaselineIfNoCandidates) return m_baselineSeeder.findTrackSeeds(ctx, segments);
115 return out;
116}
117
118} // namespace MuonR4
#define ATH_MSG_DEBUG(x)
Base class for elements of a container that can have aux data.
DataVector adapter that acts like it holds const pointers.
Define macros for attributes used to control the static checker.
AthMessaging(IMessageSvc *msgSvc, const std::string &name)
Constructor.
DataVector adapter that acts like it holds const pointers.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
const DV * asDataVector() const
Return a pointer to this object, as a const DataVector.
size_type size() const noexcept
Returns the number of elements in the collection.
MlMsTrackSeeder(const std::string &msgName, Config &&cfg)
MsTrackSeeder m_baselineSeeder
const MsTrackSeeder & baselineSeeder() const
std::unique_ptr< MsTrackSeedContainer > findTrackSeeds(const EventContext &ctx, const xAOD::MuonSegmentContainer &segments) const
Helper class to group muon sgements that may belong to a muon trajectory.
This header ties the generic definitions in this package.
std::vector< MsTrackSeed > MsTrackSeedContainer
Definition MsTrackSeed.h:71
@ VIEW_ELEMENTS
this data object is a view, it does not own its elmts
STL namespace.
DataModel_detail::iterator< DVL > unique(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of unique for DataVector/List.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
MuonSegmentContainer_v1 MuonSegmentContainer
Definition of the current "MuonSegment container version".
MuonSegment_v1 MuonSegment
Reference the current persistent version: