ATLAS Offline Software
Loading...
Searching...
No Matches
MuonR4::MsTrackSeeder Class Reference

Helper class to group muon sgements that may belong to a muon trajectory. More...

#include <MsTrackSeeder.h>

Inheritance diagram for MuonR4::MsTrackSeeder:
Collaboration diagram for MuonR4::MsTrackSeeder:

Classes

struct  Config
 Configuration object. More...

Public Types

enum class  SeedCoords : std::uint8_t { eDetSection , eSector , ePosOnCylinder }
 Abrivation of the seed coordinates. More...
using SearchTree_t = Acts::KDTree<3, const xAOD::MuonSegment*, double, std::array, 6>
 Definition of the search tree class.
using Location = MsTrackSeed::Location
 Enum toggling whether the segment is in the endcap or barrel.
using SectorProjector = ExpandedSector::SectorProjector
 Recycle the expanded sector.
using VecOpt_t = std::optional<Amg::Vector3D>
using PosMomPair_t = std::pair<Amg::Vector3D, Amg::Vector3D>

Public Member Functions

 MsTrackSeeder (const std::string &msgName, Config &&cfg)
 Standard constructor.
SearchTree_t constructTree (const xAOD::MuonSegmentContainer &segments) const
 Construct a complete search tree from a MuonSegment container.
Amg::Vector2D expressOnCylinder (const xAOD::MuonSegment &segment, const Location loc, const ExpandedSector sector) const
 Expresses the segment on the cylinder surface.
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.
double estimateQtimesP (const AtlasFieldCacheCondObj &magField, const Amg::Vector3D &planeNorm, const PosMomPair_t &p1, const PosMomPair_t &p2) const
 Estimate the charge times momentum of a muon candidate when two points are available.
double estimateQtimesP (const AtlasFieldCacheCondObj &magField, const MsTrackSeed &seed) const
 Estimate the charge times momentum of a muon track candidate from the contained segments.
bool withinBounds (const Amg::Vector2D &projPos, const Location loc) const
 Returns whether the expression on the cylinder is within the surface bounds.
std::unique_ptr< MsTrackSeedContainerfindTrackSeeds (const EventContext &ctx, const xAOD::MuonSegmentContainer &segments) const
 Constructs the MS track seeds from the segment container.
bool msgLvl (const MSG::Level lvl) const
 Test the output level.
MsgStream & msg () const
 The standard message stream.
MsgStream & msg (const MSG::Level lvl) const
 The standard message stream.
void setLevel (MSG::Level lvl)
 Change the current logging level.

Static Public Member Functions

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 arranged such that the x-axis is co-linear to the phi direction.
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 orthogonal to the plane.

Private Types

using TreeRawVec_t = SearchTree_t::vector_t
 Abbrivation of the KDTree raw data vector.

Private Member Functions

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 direction.
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 positions and directions of the trajectory.
void appendSegment (const xAOD::MuonSegment *segment, const Location loc, TreeRawVec_t &outContainer) const
 Append the to the raw data container.
std::unique_ptr< MsTrackSeedContainerresolveOverlaps (MsTrackSeedContainer &&unresolved) const
 Removes exact duplciates or partial subsets of the MsTrackSeeds.
void initMessaging () const
 Initialize our message level and MessageSvc.

Private Attributes

std::set< double > m_fieldExtpSteps {}
Config m_cfg {}
std::string m_nm
 Message source name.
boost::thread_specific_ptr< MsgStream > m_msg_tls
 MsgStream instance (a std::cout like with print-out levels).
std::atomic< IMessageSvc * > m_imsg { nullptr }
 MessageSvc pointer.
std::atomic< MSG::Level > m_lvl { MSG::NIL }
 Current logging level.
std::atomic_flag m_initialized ATLAS_THREAD_SAFE = ATOMIC_FLAG_INIT
 Messaging initialized (initMessaging).

Detailed Description

Helper class to group muon sgements that may belong to a muon trajectory.

The reconstructed muon segments are projected onto the surface of a cylinder crossing roughly the middle stations of the MS. They are then appended to a 3-dimensional search tree using the extrapolated coordinate on the cylnder, the cylinder surface index and the segment's associated sector number.

Definition at line 29 of file MsTrackSeeder.h.

Member Typedef Documentation

◆ Location

Enum toggling whether the segment is in the endcap or barrel.

Definition at line 56 of file MsTrackSeeder.h.

◆ PosMomPair_t

Definition at line 102 of file MsTrackSeeder.h.

◆ SearchTree_t

using MuonR4::MsTrackSeeder::SearchTree_t = Acts::KDTree<3, const xAOD::MuonSegment*, double, std::array, 6>

Definition of the search tree class.

Definition at line 54 of file MsTrackSeeder.h.

◆ SectorProjector

Recycle the expanded sector.

Definition at line 58 of file MsTrackSeeder.h.

◆ TreeRawVec_t

using MuonR4::MsTrackSeeder::TreeRawVec_t = SearchTree_t::vector_t
private

Abbrivation of the KDTree raw data vector.

Definition at line 171 of file MsTrackSeeder.h.

◆ VecOpt_t

Definition at line 59 of file MsTrackSeeder.h.

Member Enumeration Documentation

◆ SeedCoords

enum class MuonR4::MsTrackSeeder::SeedCoords : std::uint8_t
strong

Abrivation of the seed coordinates.

Enumerator
eDetSection 

Encode the seed location (-1,1 -> endcaps, 0 -> barrel.

eSector 

Sector of the associated spectrometer sector.

ePosOnCylinder 

Extrapolation position along the cylinder surface.

Definition at line 61 of file MsTrackSeeder.h.

61 : std::uint8_t{
63 eDetSection,
65 eSector,
67 ePosOnCylinder
68 };

Constructor & Destructor Documentation

◆ MsTrackSeeder()

MuonR4::MsTrackSeeder::MsTrackSeeder ( const std::string & msgName,
Config && cfg )

Standard constructor.

Parameters
msgNameName of the seeder's msgStream
cfgConfigured cylinder dimensions, cuts & selection tool

Initialize the field extraction steps

Definition at line 35 of file MsTrackSeeder.cxx.

35 :
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 }
AthMessaging(IMessageSvc *msgSvc, const std::string &name)
Constructor.
std::set< double > m_fieldExtpSteps

Member Function Documentation

◆ appendSegment()

void MuonR4::MsTrackSeeder::appendSegment ( const xAOD::MuonSegment * segment,
const Location loc,
TreeRawVec_t & outContainer ) const
private

Append the to the raw data container.

If the projection onto the barrel cylinder / endcap discs exceeds the bounds, the segment is not added. Segments in sector 1/16 are mirrored into sector 0/17 to complete the search range

Parameters
segmentPointer to the segment to add
locSwitch whether the segment shall be projected onto barrel/endcap
outContainerRaw KDTree data vector where the segment is appended

Check whether the segment belongs to the left or right sector as well

Blow-up the number of sectors by a factor of 2. The even numbers represent the segments expressed @ the sector centre. The odd numbers represent the overlap region between two adjacent sectors. For sector 16, the right overlap region is mapped to 1

Enumeration to indicate whether the segment is expressed on the negative endcap (-1), the barrel (0) or the positive endcap

Coordinate on the cylinder

Definition at line 300 of file MsTrackSeeder.cxx.

302 {
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 }
#define ATH_MSG_VERBOSE(x)
bool withinBounds(const Amg::Vector2D &projPos, const Location loc) const
Returns whether the expression on the cylinder is within the surface bounds.
Amg::Vector2D expressOnCylinder(const xAOD::MuonSegment &segment, const Location loc, const ExpandedSector sector) const
Expresses the segment on the cylinder surface.
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.
Amg::Vector3D position() const
Returns the position as Amg::Vector.
int nPhiLayers() const
Returns the number of phi layers.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Matrix< double, 2, 1 > Vector2D
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.

◆ constructTree()

SearchTree_t MuonR4::MsTrackSeeder::constructTree ( const xAOD::MuonSegmentContainer & segments) const

Construct a complete search tree from a MuonSegment container.

Parameters
segmentsReference to the segment container to construct.

Definition at line 334 of file MsTrackSeeder.cxx.

334 {
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 }
size_type size() const noexcept
Returns the number of elements in the collection.
SearchTree_t::vector_t TreeRawVec_t
Abbrivation of the KDTree raw data vector.
Acts::KDTree< 3, const xAOD::MuonSegment *, double, std::array, 6 > SearchTree_t
Definition of the search tree class.
void appendSegment(const xAOD::MuonSegment *segment, const Location loc, TreeRawVec_t &outContainer) const
Append the to the raw data container.
MuonSegment_v1 MuonSegment
Reference the current persistent version:

◆ estimateQtimesP() [1/3]

double MuonR4::MsTrackSeeder::estimateQtimesP ( const AtlasFieldCacheCondObj & magField,
const Amg::Vector3D & planeNorm,
const PosMomPair_t & p1,
const PosMomPair_t & p2 ) const

Estimate the charge times momentum of a muon candidate when two points are available.

The position and direction of each point need to be projected onto the given phi plane, and the muon trajectory is approximated as 2D trajectory within this plane.

Parameters
magFieldMagnetic field
planeNormNormal of the bending plane containing the muon trajectory in this simplified approach
seg1First segment
seg2Second segment
Returns
: Estimated Q*P value

Definition at line 175 of file MsTrackSeeder.cxx.

178 {
179 MagField::AtlasFieldCache fieldCache{};
180 magField.getInitializedCache(fieldCache);
181
182 return getPtimesQ(forceIntegration(p1, p2, planeNorm, fieldCache),
183 p2.second - p1.second);
184 }
void getInitializedCache(MagField::AtlasFieldCache &cache) const
get B field cache for evaluation as a function of 2-d or 3-d position.
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...
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...

◆ estimateQtimesP() [2/3]

double MuonR4::MsTrackSeeder::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.

The given position and direction of each point need to be projected onto the given phi plane, and the muon trajectory is approximated as 2D trajectory within this plane.

Parameters
magFieldMagnetic field
planeNormNormal of the bending plane containing the muon trajectory in this simplified approach
seg1First segment
seg2Second segment
seg3Third segment
Returns
: Estimated Q*P value

Definition at line 104 of file MsTrackSeeder.cxx.

108 {
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 }
const PlainObject unit() const
This is a plugin that makes Eigen look like CLHEP & defines some convenience methods.
double charge(const T &p)
Definition AtlasPID.h:997
bool msgLvl(const MSG::Level lvl) const
Test the output level.
Eigen::Matrix< double, 3, 1 > Vector3D
float j(const xAOD::IParticle &, const xAOD::TrackMeasurementValidation &hit, const Eigen::Matrix3d &jab_inv)

◆ estimateQtimesP() [3/3]

double MuonR4::MsTrackSeeder::estimateQtimesP ( const AtlasFieldCacheCondObj & magField,
const MsTrackSeed & seed ) const

Estimate the charge times momentum of a muon track candidate from the contained segments.

The position and direction of the segments are projected onto a given phi plane, defined by the segments with phi information or the sector plane.
The muon trajectory is approximated as 2D trajectory within this plane to avoid side effects from (non)-present phi measurements.

Parameters
magFielReference to the magnetic field holder
seedReference to the seed of interest.

Calculate the averaged phi from the segments

If less than 3 segments are found check whether the track crosses the BEE or EE chamber and use that segment as the third one.

Definition at line 219 of file MsTrackSeeder.cxx.

220 {
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)) {
246 case LayerIndex::Inner:
247 if (!segmentsToUse[0] || isBarrel(chIndex)) {
248 segmentsToUse[0] = segment;
249 }
250 break;
251 case LayerIndex::Middle:
252 if (!segmentsToUse[1] || isBarrel(chIndex)) {
253 segmentsToUse[1] = segment;
254 }
255 break;
256 case LayerIndex::Outer:
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 }
Scalar phi() const
phi method
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.
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...
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...
Amg::Vector3D direction() const
Returns the direction as Amg::Vector.
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
double deltaPhi(double phiA, double phiB)
delta Phi in range [-pi,pi[
Definition P4Helpers.h:34

◆ expressOnCylinder()

Amg::Vector2D MuonR4::MsTrackSeeder::expressOnCylinder ( const xAOD::MuonSegment & segment,
const Location loc,
const ExpandedSector sector ) const

Expresses the segment on the cylinder surface.

Parameters
segmentReference to the segment of consideration
locSurface location: [barrel/endcap]
expandedSectorThe expanded sector number taking the overlap regions between large and small sectors into account [0;32]

extrapolated position

Definition at line 59 of file MsTrackSeeder.cxx.

61 {
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 }
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.

◆ findTrackSeeds()

std::unique_ptr< MsTrackSeedContainer > MuonR4::MsTrackSeeder::findTrackSeeds ( const EventContext & ctx,
const xAOD::MuonSegmentContainer & segments ) const

Constructs the MS track seeds from the segment container.

Parameters
ctxEventContext to access conditions / event data
segmentsRefrence to the overall event's segment container

Bad segment not suitable for track seeding or the segment coordinates are just mirrored at the overlap between sector 1 -> 16

Define the search range.

Ensure that only endcap / barrel seeds are considered. The values are integers -> add tiny margin

Move 25 cm along the projected plane

Include the neighbouring sectors

Using the cube above, let the tree search for all compatible segments

Ensure that the sector overlap and momentum vectors are compatible with a MS trajectory

No segments were combined

Calculate the seed's position

Definition at line 344 of file MsTrackSeeder.cxx.

345 {
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 std::optional<LayerIndex> layerIndex{std::nullopt};
408 bool foundSingleStationSeed{true};
409
410 for(const xAOD::MuonSegment* seg : newSeed.segments()) {
411 if (!layerIndex) {
412 layerIndex = toLayerIndex(seg->chamberIndex());
413 ATH_MSG_DEBUG("First segment is in layer "<<*layerIndex);
414 } else if ( (*layerIndex) != toLayerIndex(seg->chamberIndex())) {
415 ATH_MSG_DEBUG("Found segment in layer "<<toLayerIndex(seg->chamberIndex())<<" which is different from the first segment in layer "<<*layerIndex);
416 foundSingleStationSeed = false;
417 break;
418 }
419 }
420 if(foundSingleStationSeed) {
421 continue;
422 }
423
424 //Check if we have multiple segments from the same station, if so split the seed and create duplicate seeds
425
427 const double r = newSeed.location() == Location::Barrel ? m_cfg.barrelRadius
428 : coords[Acts::toUnderlying(ePosOnCylinder)];
429 const double z = newSeed.location() == Location::Barrel ? coords[Acts::toUnderlying(ePosOnCylinder)]
430 : coords[Acts::toUnderlying(eDetSection)]* m_cfg.endcapDiscZ;
431
432 Amg::Vector3D pos = r * newSeed.sector().radialDir()
433 + z * Amg::Vector3D::UnitZ();
434
435 newSeed.setPosition(std::move(pos));
436 ATH_MSG_VERBOSE("Add new seed "<<newSeed);
437 trackSeeds.emplace_back(std::move(newSeed));
438 }
439 ATH_MSG_VERBOSE("Found in total "<<trackSeeds.size()<<" before overlap removal");
440 return resolveOverlaps(std::move(trackSeeds));
441 }
#define ATH_MSG_DEBUG(x)
#define z
std::unique_ptr< MsTrackSeedContainer > resolveOverlaps(MsTrackSeedContainer &&unresolved) const
Removes exact duplciates or partial subsets of the MsTrackSeeds.
MsTrackSeed::Location Location
Enum toggling whether the segment is in the endcap or barrel.
SearchTree_t constructTree(const xAOD::MuonSegmentContainer &segments) const
Construct a complete search tree from a MuonSegment container.
int r
Definition globals.cxx:22
std::vector< MsTrackSeed > MsTrackSeedContainer
Definition MsTrackSeed.h:71

◆ forceIntegration()

Amg::Vector3D MuonR4::MsTrackSeeder::forceIntegration ( const PosMomPair_t & point1,
const PosMomPair_t & point2,
const Amg::Vector3D & planeNorm,
MagField::AtlasFieldCache & fieldCache ) const
private

Compute the integral of magnetic force (v x B ) dS along a trajectory, given the initial and final positions and directions of the trajectory.

The trajectory is approximated as a straight line between the two positions, and the magnetic field is evaluated at several points along this line.

Parameters
point1Initial position and direction
point2Final position and direction
planeNormNormal vector of the bending plane used for the momentum estimation, used to extract the orthogonal component to the field
fieldCacheMagnetic field cache
Returns
: Integral of magnetic force

Definition at line 185 of file MsTrackSeeder.cxx.

188 {
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 }
Scalar mag() const
mag method
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,...

◆ getPtimesQ()

double MuonR4::MsTrackSeeder::getPtimesQ ( const Amg::Vector3D & forceIntegral,
const Amg::Vector3D & deltaDir ) const
private

Compute the charge times momentum from the integral of lorentz force and the total change in direction.

Parameters
forceIntegralCumulative lorentz force
deltaDirChange in direction
Returns
: Estimated Q*P value

Definition at line 210 of file MsTrackSeeder.cxx.

211 {
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 }

◆ initMessaging()

void AthMessaging::initMessaging ( ) const
privateinherited

Initialize our message level and MessageSvc.

This method should only be called once.

Definition at line 39 of file AthMessaging.cxx.

40{
42 // If user did not set an explicit level, set a default
43 if (m_lvl == MSG::NIL) {
44 m_lvl = m_imsg ?
45 static_cast<MSG::Level>( m_imsg.load()->outputLevel(m_nm) ) :
46 MSG::INFO;
47 }
48}
std::string m_nm
Message source name.
std::atomic< IMessageSvc * > m_imsg
MessageSvc pointer.
std::atomic< MSG::Level > m_lvl
Current logging level.
IMessageSvc * getMessageSvc(bool quiet=false)

◆ msg() [1/2]

MsgStream & AthMessaging::msg ( ) const
inlineinherited

The standard message stream.

Returns a reference to the default message stream May not be invoked before sysInitialize() has been invoked.

Definition at line 167 of file AthMessaging.h.

168{
169 MsgStream* ms = m_msg_tls.get();
170 if (!ms) {
171 if (!m_initialized.test_and_set()) initMessaging();
172 ms = new MsgStream(m_imsg,m_nm);
173 m_msg_tls.reset( ms );
174 }
175
176 ms->setLevel (m_lvl);
177 return *ms;
178}
boost::thread_specific_ptr< MsgStream > m_msg_tls
MsgStream instance (a std::cout like with print-out levels).
void initMessaging() const
Initialize our message level and MessageSvc.

◆ msg() [2/2]

MsgStream & AthMessaging::msg ( const MSG::Level lvl) const
inlineinherited

The standard message stream.

Returns a reference to the default message stream May not be invoked before sysInitialize() has been invoked.

Definition at line 182 of file AthMessaging.h.

183{ return msg() << lvl; }
MsgStream & msg() const
The standard message stream.

◆ msgLvl()

bool AthMessaging::msgLvl ( const MSG::Level lvl) const
inlineinherited

Test the output level.

Parameters
lvlThe message level to test against
Returns
boolean Indicating if messages at given level will be printed
Return values
trueMessages at level "lvl" will be printed

Definition at line 151 of file AthMessaging.h.

152{
153 // If user did not set explicit message level we have to initialize
154 // the messaging and retrieve the default via the MessageSvc.
155 if (m_lvl==MSG::NIL && !m_initialized.test_and_set()) initMessaging();
156
157 if (m_lvl <= lvl) {
158 msg() << lvl;
159 return true;
160 } else {
161 return false;
162 }
163}

◆ resolveOverlaps()

std::unique_ptr< MsTrackSeedContainer > MuonR4::MsTrackSeeder::resolveOverlaps ( MsTrackSeedContainer && unresolved) const
private

Removes exact duplciates or partial subsets of the MsTrackSeeds.

Parameters
unresolvedInput MsTrackSeedContainer with duplicates

Resort the seeds starting from the ones with the most segments to the lowest

Definition at line 443 of file MsTrackSeeder.cxx.

443 {
444
446 std::ranges::sort(unresolved, [](const MsTrackSeed& a, const MsTrackSeed&b) {
447 return a.segments().size() > b.segments().size();
448 });
449 auto outputSeeds = std::make_unique<MsTrackSeedContainer>();
450 outputSeeds->reserve(unresolved.size());
451 std::ranges::copy_if(std::move(unresolved), std::back_inserter(*outputSeeds),
452 [&outputSeeds](const MsTrackSeed& testMe) {
453 for (const MsTrackSeed& good : *outputSeeds){
454 if (!testMe.sector().isNeighbour(good.sector())) {
455 continue;
456 }
457 const std::size_t sharedSegs = std::ranges::count_if(testMe.segments(),
458 [&good](const xAOD::MuonSegment* segInTest){
459 return std::ranges::find(good.segments(), segInTest) !=
460 good.segments().end();
461 });
462 if (sharedSegs == testMe.segments().size()) {
463 return false;
464 }
465 }
466 return true;
467 });
468
469 ATH_MSG_VERBOSE("Found in total "<<outputSeeds->size()<<" after overlap removal");
470 return outputSeeds;
471 }
static Double_t a

◆ segDirOntoPhiPlane()

Amg::Vector3D MuonR4::MsTrackSeeder::segDirOntoPhiPlane ( const Amg::Vector3D & planeNorm,
const Amg::Vector3D & dirToProject )
static

Projects the segment direction onto the plane with global phi = x by removing the component orthogonal to the plane.

Parameters
planeNormNormal of the phi plane onto which the segment is projected
dirToProjectDirection to project

Definition at line 55 of file MsTrackSeeder.cxx.

56 {
57 return (dirToProject - dirToProject.dot(planeNorm) * planeNorm).unit();
58 }

◆ segPosOntoPhiPlane()

Amg::Vector3D MuonR4::MsTrackSeeder::segPosOntoPhiPlane ( const Amg::Vector3D & planeNorm,
const int Sector,
const Amg::Vector3D & posToProject )
static

Projects the segment position onto the plane with global phi = x The local coordinate system is arranged such that the x-axis is co-linear to the phi direction.

The segment is moved along the MDT's wire direction in that sector.

Parameters
planeNormNormal of the phi plane onto which the segment is projected
SectorSector of the segment to be projected, needed to find the wire direction
posToProjectPosition to project

Definition at line 45 of file MsTrackSeeder.cxx.

47 {
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 }
@ center
Project the segment onto the overlap with the previous sector.

◆ setLevel()

void AthMessaging::setLevel ( MSG::Level lvl)
inherited

Change the current logging level.

Use this rather than msg().setLevel() for proper operation with MT.

Definition at line 28 of file AthMessaging.cxx.

29{
30 m_lvl = lvl;
31}

◆ withinBounds()

bool MuonR4::MsTrackSeeder::withinBounds ( const Amg::Vector2D & projPos,
const Location loc ) const

Returns whether the expression on the cylinder is within the surface bounds.

Parameters
projPosProjected position on the cylinder
locSurface location: [barrel/endcap]

Definition at line 89 of file MsTrackSeeder.cxx.

90 {
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 }

Member Data Documentation

◆ ATLAS_THREAD_SAFE

std::atomic_flag m_initialized AthMessaging::ATLAS_THREAD_SAFE = ATOMIC_FLAG_INIT
mutableprivateinherited

Messaging initialized (initMessaging).

Definition at line 141 of file AthMessaging.h.

◆ m_cfg

Config MuonR4::MsTrackSeeder::m_cfg {}
private

Definition at line 186 of file MsTrackSeeder.h.

186{};

◆ m_fieldExtpSteps

std::set<double> MuonR4::MsTrackSeeder::m_fieldExtpSteps {}
private

Definition at line 185 of file MsTrackSeeder.h.

185{};

◆ m_imsg

std::atomic<IMessageSvc*> AthMessaging::m_imsg { nullptr }
mutableprivateinherited

MessageSvc pointer.

Definition at line 135 of file AthMessaging.h.

135{ nullptr };

◆ m_lvl

std::atomic<MSG::Level> AthMessaging::m_lvl { MSG::NIL }
mutableprivateinherited

Current logging level.

Definition at line 138 of file AthMessaging.h.

138{ MSG::NIL };

◆ m_msg_tls

boost::thread_specific_ptr<MsgStream> AthMessaging::m_msg_tls
mutableprivateinherited

MsgStream instance (a std::cout like with print-out levels).

Definition at line 132 of file AthMessaging.h.

◆ m_nm

std::string AthMessaging::m_nm
privateinherited

Message source name.

Definition at line 129 of file AthMessaging.h.


The documentation for this class was generated from the following files: