ATLAS Offline Software
Loading...
Searching...
No Matches
MsTrackSeeder.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
7
8#include "Acts/Utilities/Helpers.hpp"
9#include "Acts/Definitions/Tolerance.hpp"
10#include "Acts/Definitions/Units.hpp"
11
13namespace {
14 using namespace Acts::UnitLiterals;
16 constexpr bool chargeAgree(double PtimesQ1, double PtimesQ2) {
17 return PtimesQ1 * PtimesQ2 > 0;
18 };
20 double momentumDev(double PtimesQ1, double PtimesQ2) {
21 const double denom {std::max(std::abs(PtimesQ1) + std::abs(PtimesQ2), Acts::s_epsilon)};
22 return std::abs(PtimesQ1 - PtimesQ2) / denom;
23 };
24 float reducedChi2(const xAOD::MuonSegment& seg) {
25 return seg.chiSquared() / std::max(1.f, seg.numberDoF());
26 }
27 std::string print(const xAOD::MuonSegment& seg) {
28 return std::format("{:}, nPrecHits: {:}, nPhiHits: {:}", MuonR4::printID(seg),
29 seg.nPrecisionHits(), seg.nPhiLayers());
30 }
31}
32
33namespace MuonR4{
35 MsTrackSeeder::MsTrackSeeder(const std::string& msgName, Config&& cfg):
36 AthMessaging{msgName},
37 m_cfg{std::move(cfg)}{
38
40 const double stepSize {1. / static_cast<double>(m_cfg.nFieldSteps)};
41 for (std::size_t i = 0; i < m_cfg.nFieldSteps; ++i) {
42 m_fieldExtpSteps.insert((static_cast<double>(i) + 0.5) * stepSize);
43 }
44 }
46 const int Sector,
47 const Amg::Vector3D& posToProject) {
48 // Find the sensor direction
49 Amg::Vector3D projDir {
50 ExpandedSector{static_cast<unsigned>(Sector),
52 return Acts::PlanarHelper::intersectPlane(
53 posToProject, projDir, planeNorm, Amg::Vector3D::Zero()).position();
54 }
56 const Amg::Vector3D& dirToProject) {
57 return (dirToProject - dirToProject.dot(planeNorm) * planeNorm).unit();
58 }
60 const Location loc,
61 const ExpandedSector sector) const {
64 sector.normalDir(), segment.sector(), segment.position())};
65 const Amg::Vector3D dir{segment.direction()};
66
67 const Amg::Vector2D projPos{pos.perp(), pos.z()};
68 const Amg::Vector2D projDir{dir.perp(), dir.z()};
69
70 ATH_MSG_VERBOSE( "segment position:" << Amg::toString(segment.position())<< ", direction: " << Amg::toString(segment.direction()) );
71 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Express segment in @"<<Amg::toString(pos)
72 <<", direction: "<<Amg::toString(dir)<< " sector projector: " << sector
73 << " location: " << Acts::toUnderlying(loc));
74 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Projected position onto sector: "<<Amg::toString(projPos)
75 <<", projected direction: "<<Amg::toString(projDir));
76
77 double lambda{0.};
78 if (Location::Barrel == loc) {
79 lambda = Amg::intersect<2>(projPos, projDir, Amg::Vector2D::UnitX(),
80 m_cfg.barrelRadius).value_or(10. * Gaudi::Units::km);
81 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Intersect with barrel at radius: "<<m_cfg.barrelRadius<<" --> "<<Amg::toString(projPos + lambda * projDir));
82 } else {
83 lambda = Amg::intersect<2>(projPos, projDir, Amg::Vector2D::UnitY(),
84 Acts::copySign(m_cfg.endcapDiscZ, projPos[1])).value_or(10. * Gaudi::Units::km);
85 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Intersect with endcap at z: "<<Acts::copySign(m_cfg.endcapDiscZ, projPos[1])<<" --> "<<Amg::toString(projPos + lambda * projDir));
86 }
87 return projPos + lambda * projDir;
88 }
90 const Location loc) const {
91 using enum Location;
92 if (loc == Barrel && std::abs(projPos[1]) > std::min(m_cfg.endcapDiscZ, m_cfg.barrelLength)) {
93 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Position "<<Amg::toString(projPos)<<
94 " exceeds cylinder boundaries ("<<m_cfg.barrelRadius<<", "
95 <<std::min(m_cfg.endcapDiscZ, m_cfg.barrelLength)<<")");
96 return false;
97 } else if (loc == Endcap && (0 > projPos[0] || projPos[0] > m_cfg.endcapDiscRadius)) {
98 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Position "<<Amg::toString(projPos)<<
99 " exceeds endcap boundaries ("<<m_cfg.endcapDiscRadius<<", "<<Acts::copySign(m_cfg.endcapDiscZ, projPos[1])<<")");
100 return false;
101 }
102 return true;
103 }
105 const Amg::Vector3D& planeNorm,
106 const PosMomPair_t& p1,
107 const PosMomPair_t& p2,
108 const PosMomPair_t& p3) const {
109 // When 3 points are available, we can use each pair of segments to estimate
110 // the momentum and charge, and then combine the estimates. To make the
111 // combination, we define a struct to hold each PtimesQ estimate
112 struct Estimate {
113 double PtimesQ{0.};
114 // Weighting factor based on the magnitude of the integrated force.
115 double weight{0.};
116 // Scores as a combination of charge agreement and momentum deviation.
117 double score{0.};
118 };
119
120 MagField::AtlasFieldCache fieldCache{};
121 magField.getInitializedCache(fieldCache);
122
123 const Amg::Vector3D force12 {forceIntegration(p1, p2, planeNorm, fieldCache)};
124 const Amg::Vector3D force23 {forceIntegration(p2, p3, planeNorm, fieldCache)};
125 const Amg::Vector3D force13 {force12 + force23};
126
127 std::vector<Estimate> estimates{};
128 const double weightNorm {force12.mag() + force23.mag()};
129 // Pairwise momentum estimates: 12 and 23
130 estimates.emplace_back(getPtimesQ(force12, p2.second - p1.second), force12.mag()/weightNorm, 0.);
131 estimates.emplace_back(getPtimesQ(force23, p3.second - p2.second), force23.mag()/weightNorm, 0.);
132 // Two estimates for pair 13: using segment directions and using position differences
133 const double weight13 {force13.mag()/weightNorm};
134 estimates.emplace_back(getPtimesQ(force13, p3.second - p1.second), weight13, 0.);
135 const Amg::Vector3D t12 {(p2.first - p1.first).unit()};
136 const Amg::Vector3D t23 {(p3.first - p2.first).unit()};
137 estimates.emplace_back(getPtimesQ(force13, t23 - t12), weight13, 0.);
138
139 for (std::size_t i {0}; i < estimates.size(); ++i) {
140 Estimate& est1 {estimates[i]};
141 for (std::size_t j {i+1}; j < estimates.size(); ++j) {
142 Estimate& est2 {estimates[j]};
143 // Compute the charge agreement score & momentum deviation
144 double w {std::min(est1.weight, est2.weight)};
145 double chargeScore {chargeAgree(est1.PtimesQ, est2.PtimesQ) ? 1. : -1.};
146 double pDevPenalty {momentumDev(est1.PtimesQ, est2.PtimesQ)};
147 // Update the scores
148 est1.score += w * (chargeScore - pDevPenalty);
149 est2.score += w * (chargeScore - pDevPenalty);
150 }
151 }
152 if (msgLvl(MSG::VERBOSE)) {
153 std::vector<std::string> names {"Pair01", "Pair12", "Pair02Seg", "Pair02Pos"};
154 for (const auto& [i, est] : Acts::enumerate(estimates)) {
155 ATH_MSG_VERBOSE(__func__<<"() Estimate "<<names[i]<<": PtimesQ: "<<est.PtimesQ*1e-3
156 <<", weight: "<<est.weight<<", score: "<<est.score);
157 }
158 }
159 // Find the best charge estimate and estimate the final momentum as a weighted average of the
160 // estimates that agree with the best charge
161 const Estimate& bestEstimate {*std::ranges::max_element(estimates,
162 std::ranges::less{}, &Estimate::score)};
163 const double charge {std::copysign(1., bestEstimate.PtimesQ)};
164
165 double totalSum {0.}, totalWeight {0.};
166 for (const Estimate& est : estimates) {
167 if (chargeAgree(est.PtimesQ, charge)) {
168 totalSum += est.PtimesQ * est.weight;
169 totalWeight += est.weight;
170 }
171 }
172 assert(totalWeight > Acts::s_epsilon);
173 return totalSum / totalWeight;
174 }
176 const Amg::Vector3D& planeNorm,
177 const PosMomPair_t& p1,
178 const PosMomPair_t& p2) const {
179 MagField::AtlasFieldCache fieldCache{};
180 magField.getInitializedCache(fieldCache);
181
182 return getPtimesQ(forceIntegration(p1, p2, planeNorm, fieldCache),
183 p2.second - p1.second);
184 }
186 const PosMomPair_t& point2,
187 const Amg::Vector3D& planeNorm,
188 MagField::AtlasFieldCache& fieldCache) const {
189 const auto& [pos1, dir1] = point1;
190 const auto& [pos2, dir2] = point2;
191
192 Amg::Vector3D locField{Amg::Vector3D::Zero()};
193 Amg::Vector3D accumForce{Amg::Vector3D::Zero()};
194 for (double fieldStep : m_fieldExtpSteps) {
195 const Amg::Vector3D extPos {(1. - fieldStep) * pos1 + fieldStep * pos2};
196 const Amg::Vector3D extDir {((1. - fieldStep) * dir1 + fieldStep * dir2).unit()};
197
198 fieldCache.getField(extPos.data(), locField.data());
199 const Amg::Vector3D locForce {locField.dot(planeNorm) * extDir.cross(planeNorm)};
200 accumForce += locForce;
201
202 ATH_MSG_VERBOSE(__func__<<"() step: "<<fieldStep
203 <<", pos: "<<Amg::toString(extPos)<<", dir: "<<Amg::toString(extDir)
204 <<" --> local |B|: "<<locField.mag()*1e3 << " [T]"<<", |Bnorm|: "<<locField.dot(planeNorm)*1e3
205 <<" [T], local |v x Bnorm|: "<<locForce.mag()*1e3<<" [T].");
206 }
207 const double dS {(pos2 - pos1).mag() / static_cast<double>(m_fieldExtpSteps.size())};
208 return accumForce * dS;
209 }
210 double MsTrackSeeder::getPtimesQ(const Amg::Vector3D& forceIntegral,
211 const Amg::Vector3D& deltaDir) const {
212 const double PtimesQ {0.3 * Gaudi::Units::GeV * forceIntegral.mag2() / deltaDir.dot(forceIntegral)};
213
214 ATH_MSG_VERBOSE("estimateQtimesP() force integral: "<<forceIntegral.mag()<<" [T*m], deltaDir: "
215 <<deltaDir.mag()<<", cos: "<<deltaDir.dot(forceIntegral)/ (deltaDir.mag() * forceIntegral.mag())
216 <<", PtimesQ: "<<PtimesQ/Gaudi::Units::GeV <<" [GeV].");
217 return PtimesQ;
218 }
220 const MsTrackSeed& seed) const {
221 using namespace Muon::MuonStationIndex;
222 MagField::AtlasFieldCache fieldCache{};
223 magField.getInitializedCache(fieldCache);
224
226 double deltaPhiAcc {0.};
227 std::optional<double> centralPhi {};
228 unsigned nSegsWithPhi{0};
229 for (const xAOD::MuonSegment* segment : seed.segments()) {
230 if (segment->nPhiLayers() > 0) {
231 if (!centralPhi) centralPhi = segment->position().phi();
232 deltaPhiAcc += P4Helpers::deltaPhi(*centralPhi, segment->position().phi());
233 ++nSegsWithPhi;
234 }
235 }
236 const double circPhi {nSegsWithPhi > 0
237 ? P4Helpers::deltaPhi(*centralPhi + deltaPhiAcc / nSegsWithPhi, 0.)
238 : seed.sector().phi()};
239
240 std::array<const xAOD::MuonSegment*, 3> segmentsToUse{};
241 // Try first to find segments in the inner, middle and outer layers. If both a barrel
242 // and endcap segments are present in the same layer, the barrel segment is preferred.
243 for (const xAOD::MuonSegment* segment : seed.segments()) {
244 ChIndex chIndex {segment->chamberIndex()};
245 switch(toLayerIndex(chIndex)) {
247 if (!segmentsToUse[0] || isBarrel(chIndex)) {
248 segmentsToUse[0] = segment;
249 }
250 break;
252 if (!segmentsToUse[1] || isBarrel(chIndex)) {
253 segmentsToUse[1] = segment;
254 }
255 break;
257 if (!segmentsToUse[2] || isBarrel(chIndex)) {
258 segmentsToUse[2] = segment;
259 }
260 break;
261 default:
262 break;
263 }
264 }
265 unsigned nSegments = std::ranges::count_if(segmentsToUse,
266 [](const xAOD::MuonSegment* seg) { return seg != nullptr; });
267
269 if (nSegments < 3) {
270 auto missingSeg = std::ranges::find(segmentsToUse, nullptr);
271 for (const xAOD::MuonSegment* segment : seed.segments()) {
272 LayerIndex layIndex {toLayerIndex(segment->chamberIndex())};
273 if (layIndex != LayerIndex::Extended && layIndex != LayerIndex::BarrelExtended) {
274 continue;
275 }
276 assert(missingSeg != segmentsToUse.end());
277 *missingSeg = segment;
278 nSegments++;
279 if (nSegments == 3) {
280 break;
281 }
282 missingSeg = std::ranges::find(segmentsToUse, nullptr);
283 }
284 std::ranges::sort(segmentsToUse, [](const xAOD::MuonSegment* seg1, const xAOD::MuonSegment* seg2) {
285 if (!seg1 || !seg2) {
286 return seg1 != nullptr;
287 }
288 return seg1->position().perp() < seg2->position().perp();
289 });
290 }
291 const Amg::Vector3D planeNorm {Acts::makeDirectionFromPhiTheta(circPhi + 90._degree, 90._degree)};
292 auto point = [&planeNorm](const xAOD::MuonSegment* seg) {
293 return std::make_pair(segPosOntoPhiPlane(planeNorm, seg->sector(), seg->position()),
294 segDirOntoPhiPlane(planeNorm, seg->direction()));
295 };
296 return nSegments == 3
297 ? estimateQtimesP(magField, planeNorm, point(segmentsToUse[0]), point(segmentsToUse[1]), point(segmentsToUse[2]))
298 : estimateQtimesP(magField, planeNorm, point(segmentsToUse[0]), point(segmentsToUse[1]));
299 }
301 const Location loc,
302 TreeRawVec_t& outContainer) const {
303
304 const unsigned segSector = segment->sector();
305 for (const auto proj : {SectorProjector::leftOverlap, SectorProjector::center, SectorProjector::rightOverlap}) {
307 const ExpandedSector projSector{segSector, proj};
308 if (segment->nPhiLayers() > 0 && projSector != ExpandedSector{segment->position().phi()}) {
309 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Segment @"<<Amg::toString(segment->position())
310 <<" is not in sector "<<projSector);
311 continue;
312 }
313 const Amg::Vector2D refPoint{expressOnCylinder(*segment, loc, projSector)};
314 if (!withinBounds(refPoint, loc)) {
315 continue;
316 }
317 using enum SeedCoords;
318 std::array<double, 3> coords{};
322 coords[Acts::toUnderlying(eSector)] = projSector.sector();
325 coords[Acts::toUnderlying(eDetSection)] = Acts::copySign(Acts::toUnderlying(loc), refPoint[1]);
327 coords[Acts::toUnderlying(ePosOnCylinder)] = refPoint[Location::Barrel == loc];
328 ATH_MSG_VERBOSE("Add segment "<<print(*segment)<<", seed quality: "
329 <<m_cfg.selector->passSeedingQuality(Gaudi::Hive::currentContext(), *detailedSegment(*segment))
330 <<" with "<<coords<<" to the search tree");
331 outContainer.emplace_back(std::move(coords), segment);
332 }
333 }
335 TreeRawVec_t rawData{};
336 rawData.reserve(3*segments.size());
337 for (const xAOD::MuonSegment* segment : segments){
338 appendSegment(segment, Location::Barrel, rawData);
339 appendSegment(segment, Location::Endcap, rawData);
340 }
341 ATH_MSG_VERBOSE("Create a new tree with "<<rawData.size()<<" entries. ");
342 return SearchTree_t{std::move(rawData)};
343 }
344 std::unique_ptr<MsTrackSeedContainer> MsTrackSeeder::findTrackSeeds(const EventContext& ctx,
345 const xAOD::MuonSegmentContainer& segments) const {
346 SearchTree_t orderedSegs{constructTree(segments)};
347 MsTrackSeedContainer trackSeeds{};
348 using enum SeedCoords;
349 for (const auto& [coords, seedCandidate] : orderedSegs) {
352 const Segment* recoSeedCandidate = detailedSegment(*seedCandidate);
353 if (!m_cfg.selector->passSeedingQuality(ctx, *recoSeedCandidate)){
354 ATH_MSG_VERBOSE("Segment "<<print(*seedCandidate)<<" does not pass the seeding quality.");
355 continue;
356 }
358 SearchTree_t::range_t selectRange{};
361 selectRange[Acts::toUnderlying(eDetSection)].shrink(coords[Acts::toUnderlying(eDetSection)] - 0.1,
362 coords[Acts::toUnderlying(eDetSection)] + 0.1);
364 selectRange[Acts::toUnderlying(ePosOnCylinder)].shrink(coords[Acts::toUnderlying(ePosOnCylinder)] - m_cfg.seedHalfLength,
365 coords[Acts::toUnderlying(ePosOnCylinder)] + m_cfg.seedHalfLength);
367 selectRange[Acts::toUnderlying(eSector)].shrink(coords[Acts::toUnderlying(eSector)] -0.25,
368 coords[Acts::toUnderlying(eSector)] +0.25);
369
370 MsTrackSeed newSeed{static_cast<Location>(std::abs(coords[Acts::toUnderlying(eDetSection)])),
371 ExpandedSector{static_cast<std::int8_t>(coords[Acts::toUnderlying(eSector)])}};
373 ATH_MSG_VERBOSE("Search for compatible segments to "<<print(*seedCandidate)<<".");
374 orderedSegs.rangeSearchMapDiscard(selectRange, [&](
375 const SearchTree_t::coordinate_t& /*coords*/,
376 const xAOD::MuonSegment* extendWithMe) {
378 const Segment* extendCandidate = detailedSegment(*extendWithMe);
379 if (!m_cfg.selector->compatibleForTrack(ctx, *recoSeedCandidate, *extendCandidate)) {
380 ATH_MSG_VERBOSE("Segment "<<print(*extendWithMe)<<" is not compatible.");
381 return;
382 }
383 auto itr = std::ranges::find_if(newSeed.segments(), [extendWithMe](const xAOD::MuonSegment* onSeed){
384 return extendWithMe->chamberIndex() == onSeed->chamberIndex();
385 });
386 if (itr == newSeed.segments().end()){
387 ATH_MSG_VERBOSE("Add segment "<<print(*extendWithMe)<<" to seed.");
388 newSeed.addSegment(extendWithMe);
389 }
390 else if (reducedChi2(**itr) > reducedChi2(*extendWithMe) &&
391 (*itr)->nPhiLayers() <= extendWithMe->nPhiLayers()) {
392
393 ATH_MSG_VERBOSE("Replace segment "<<print(**itr)<<" with "<<print(*extendWithMe)
394 <<" on seed due to better chi2.");
395 newSeed.replaceSegment(*itr, extendWithMe);
396 }
397 });
399 if (newSeed.segments().empty()) {
400 continue;
401 }
402
403 newSeed.addSegment(seedCandidate);
404
405 // Let's check if we build a single station seed and if yes reject it.
406 using namespace Muon::MuonStationIndex;
407 if(toLayerIndex(newSeed.segments().front()->chamberIndex()) == toLayerIndex(newSeed.segments().back()->chamberIndex())){
408 ATH_MSG_VERBOSE("Reject seed with segments in the same station.");
409 continue;
410 }
411
412 //Check if we have multiple segments from the same station, if so split the seed and create duplicate seeds
413
415 const double r = newSeed.location() == Location::Barrel ? m_cfg.barrelRadius
416 : coords[Acts::toUnderlying(ePosOnCylinder)];
417 const double z = newSeed.location() == Location::Barrel ? coords[Acts::toUnderlying(ePosOnCylinder)]
418 : coords[Acts::toUnderlying(eDetSection)]* m_cfg.endcapDiscZ;
419
420 Amg::Vector3D pos = r * newSeed.sector().radialDir()
421 + z * Amg::Vector3D::UnitZ();
422
423 newSeed.setPosition(std::move(pos));
424 ATH_MSG_VERBOSE("Add new seed "<<newSeed);
425 trackSeeds.emplace_back(std::move(newSeed));
426 }
427 ATH_MSG_VERBOSE("Found in total "<<trackSeeds.size()<<" before overlap removal");
428 return resolveOverlaps(std::move(trackSeeds));
429 }
430 std::unique_ptr<MsTrackSeedContainer>
432
434 std::ranges::sort(unresolved, [](const MsTrackSeed& a, const MsTrackSeed&b) {
435 return a.segments().size() > b.segments().size();
436 });
437 auto outputSeeds = std::make_unique<MsTrackSeedContainer>();
438 outputSeeds->reserve(unresolved.size());
439 std::ranges::copy_if(std::move(unresolved), std::back_inserter(*outputSeeds),
440 [&outputSeeds](const MsTrackSeed& testMe) {
441 for (const MsTrackSeed& good : *outputSeeds){
442 if (!testMe.sector().isNeighbour(good.sector())) {
443 continue;
444 }
445 const std::size_t sharedSegs = std::ranges::count_if(testMe.segments(),
446 [&good](const xAOD::MuonSegment* segInTest){
447 return std::ranges::find(good.segments(), segInTest) !=
448 good.segments().end();
449 });
450 if (sharedSegs == testMe.segments().size()) {
451 return false;
452 }
453 }
454 return true;
455 });
456
457 ATH_MSG_VERBOSE("Found in total "<<outputSeeds->size()<<" after overlap removal");
458 return outputSeeds;
459 }
460}
Scalar mag() const
mag method
const PlainObject unit() const
This is a plugin that makes Eigen look like CLHEP & defines some convenience methods.
#define ATH_MSG_VERBOSE(x)
double charge(const T &p)
Definition AtlasPID.h:997
static Double_t a
void print(char *figname, TCanvas *c1)
#define z
bool msgLvl(const MSG::Level lvl) const
Test the output level.
AthMessaging(IMessageSvc *msgSvc, const std::string &name)
Constructor.
void getInitializedCache(MagField::AtlasFieldCache &cache) const
get B field cache for evaluation as a function of 2-d or 3-d position.
size_type size() const noexcept
Returns the number of elements in the collection.
Local cache for magnetic field (based on MagFieldServices/AtlasFieldSvcTLS.h).
void getField(const double *ATH_RESTRICT xyz, double *ATH_RESTRICT bxyz, double *ATH_RESTRICT deriv=nullptr)
get B field value at given position xyz[3] is in mm, bxyz[3] is in kT if deriv[9] is given,...
Amg::Vector3D normalDir() const
Returns the vector that is normal to the plane spanned by the expanded sector.
@ center
Project the segment onto the overlap with the previous sector.
std::int8_t sector() const
Returns the expanded sector number.
bool isNeighbour(const ExpandedSector &other) const
Amg::Vector3D radialDir() const
Returns the vector pointing radially along the sector plane.
void addSegment(const xAOD::MuonSegment *seg)
Append a segment to the seed.
Location location() const
Returns the location of the seed.
ExpandedSector sector() const
Returns the seed's sector.
Definition MsTrackSeed.h:63
const std::vector< const xAOD::MuonSegment * > & segments() const
Returns the vector of associated segments.
void replaceSegment(const xAOD::MuonSegment *exist, const xAOD::MuonSegment *updated)
Replaces an already added segment in the seed with a better suited one.
void setPosition(Amg::Vector3D &&pos)
set the seed's position
bool withinBounds(const Amg::Vector2D &projPos, const Location loc) const
Returns whether the expression on the cylinder is within the surface bounds.
double estimateQtimesP(const AtlasFieldCacheCondObj &magField, const Amg::Vector3D &planeNorm, const PosMomPair_t &p1, const PosMomPair_t &p2, const PosMomPair_t &p3) const
Estimate the charge times momentum of a muon candidate when three points are available.
SearchTree_t::vector_t TreeRawVec_t
Abbrivation of the KDTree raw data vector.
std::unique_ptr< MsTrackSeedContainer > resolveOverlaps(MsTrackSeedContainer &&unresolved) const
Removes exact duplciates or partial subsets of the MsTrackSeeds.
std::pair< Amg::Vector3D, Amg::Vector3D > PosMomPair_t
static Amg::Vector3D segPosOntoPhiPlane(const Amg::Vector3D &planeNorm, const int Sector, const Amg::Vector3D &posToProject)
Projects the segment position onto the plane with global phi = x The local coordinate system is arran...
Acts::KDTree< 3, const xAOD::MuonSegment *, double, std::array, 6 > SearchTree_t
Definition of the search tree class.
static Amg::Vector3D segDirOntoPhiPlane(const Amg::Vector3D &planeNorm, const Amg::Vector3D &dirToProject)
Projects the segment direction onto the plane with global phi = x by removing the component orthogona...
void appendSegment(const xAOD::MuonSegment *segment, const Location loc, TreeRawVec_t &outContainer) const
Append the to the raw data container.
MsTrackSeeder(const std::string &msgName, Config &&cfg)
Standard constructor.
Amg::Vector2D expressOnCylinder(const xAOD::MuonSegment &segment, const Location loc, const ExpandedSector sector) const
Expresses the segment on the cylinder surface.
double getPtimesQ(const Amg::Vector3D &forceIntegral, const Amg::Vector3D &deltaDir) const
Compute the charge times momentum from the integral of lorentz force and the total change in directio...
MsTrackSeed::Location Location
Enum toggling whether the segment is in the endcap or barrel.
std::set< double > m_fieldExtpSteps
SeedCoords
Abrivation of the seed coordinates.
@ eSector
Sector of the associated spectrometer sector.
@ ePosOnCylinder
Extrapolation position along the cylinder surface.
@ eDetSection
Encode the seed location (-1,1 -> endcaps, 0 -> barrel.
SearchTree_t constructTree(const xAOD::MuonSegmentContainer &segments) const
Construct a complete search tree from a MuonSegment container.
Amg::Vector3D forceIntegration(const PosMomPair_t &point1, const PosMomPair_t &point2, const Amg::Vector3D &planeNorm, MagField::AtlasFieldCache &fieldCache) const
Compute the integral of magnetic force (v x B ) dS along a trajectory, given the initial and final po...
std::unique_ptr< MsTrackSeedContainer > findTrackSeeds(const EventContext &ctx, const xAOD::MuonSegmentContainer &segments) const
Constructs the MS track seeds from the segment container.
Placeholder for what will later be the muon segment EDM representation.
float numberDoF() const
Returns the numberDoF.
int nPrecisionHits() const
Amg::Vector3D direction() const
Returns the direction as Amg::Vector.
float chiSquared() const
Amg::Vector3D position() const
Returns the position as Amg::Vector.
int nPhiLayers() const
Returns the number of phi layers.
int r
Definition globals.cxx:22
std::optional< double > intersect(const AmgVector(N)&posA, const AmgVector(N)&dirA, const AmgVector(N)&posB, const AmgVector(N)&dirB)
Calculates the point B' along the line B that's closest to a second line A.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
This header ties the generic definitions in this package.
std::vector< MsTrackSeed > MsTrackSeedContainer
Definition MsTrackSeed.h:71
std::string printID(const xAOD::MuonSegment &seg)
Print the chamber ID of a segment, e.g.
MsTrackSeeder::SearchTree_t SearchTree_t
std::string print(const cont_t &container)
Print a space point container to string.
const Segment * detailedSegment(const xAOD::MuonSegment &seg)
Helper function to navigate from the xAOD::MuonSegment to the MuonR4::Segment.
ChIndex chIndex(const std::string &index)
convert ChIndex name string to enum
bool isBarrel(const ChIndex index)
Returns true if the chamber index points to a barrel chamber.
LayerIndex
enum to classify the different layers in the muon spectrometer
LayerIndex toLayerIndex(ChIndex index)
convert ChIndex into LayerIndex
ChIndex
enum to classify the different chamber layers in the muon spectrometer
double deltaPhi(double phiA, double phiB)
delta Phi in range [-pi,pi[
Definition P4Helpers.h:34
STL namespace.
MuonSegmentContainer_v1 MuonSegmentContainer
Definition of the current "MuonSegment container version".
MuonSegment_v1 MuonSegment
Reference the current persistent version:
Configuration object.