ATLAS Offline Software
Loading...
Searching...
No Matches
TruthTrackSeederTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
5
14
15#include "Acts/Surfaces/PlaneSurface.hpp"
16#include "Acts/Definitions/Units.hpp"
17
18
19#include "TruthUtils/AtlasPID.h"
20
21using namespace Acts::UnitLiterals;
22
23namespace {
25 std::uint8_t countHits(const xAOD::MuonSegment& s) {
26 return s.nPrecisionHits() + s.nTrigEtaLayers() + s.nPhiLayers() +
27 s.nPrecisionOutliers() + s.nTriggerEtaOutliers() + s.nTriggerPhiOutliers();
28 }
29}
30
31namespace MuonR4 {
33 ATH_CHECK(m_segmentKey.initialize());
34 ATH_CHECK(m_truthLinkKey.initialize());
35 ATH_CHECK(detStore()->retrieve(m_detMgr));
36 ATH_CHECK(m_ctxProvider.initialize());
37 return StatusCode::SUCCESS;
38 }
39 StatusCode TruthTrackSeederTool::findTrackSeeds(const EventContext& ctx,
40 std::vector<MsTrackSeed>& outSeeds) const {
41 const xAOD::MuonSegmentContainer* segments{nullptr};
42 ATH_CHECK(SG::get(segments, m_segmentKey, ctx));
43 std::unordered_map<const xAOD::TruthParticle*, std::vector<const xAOD::MuonSegment*>> truthSeeds{};
45 for (const xAOD::MuonSegment* seg : *segments) {
46 const xAOD::TruthParticle* truthPart = getTruthMatchedParticle(*seg);
47 if (truthPart && truthPart->isMuon()) {
48 truthSeeds[truthPart].push_back(seg);
49 }
50 }
51 for (auto& [truthPart, assocSegs] : truthSeeds) {
52 std::ranges::sort(assocSegs, [](const xAOD::MuonSegment* a, const xAOD::MuonSegment* b){
53 if (a->chamberIndex() != b->chamberIndex()) {
54 return a->chamberIndex() < b->chamberIndex();
55 }
56 return countHits(*a) > countHits(*b);
57 });
59 auto [begin, end] = std::ranges::unique(assocSegs, [](const xAOD::MuonSegment* a, const xAOD::MuonSegment* b){
60 return a->chamberIndex() == b->chamberIndex();
61 });
62 assocSegs.erase(begin,end);
63 if (assocSegs.size() < 2) {
64 continue;
65 }
66 MsTrackSeed& seed = outSeeds.emplace_back(MsTrackSeed::Location::Barrel,
67 ExpandedSector{truthPart->phi()});
68 std::ranges::for_each(assocSegs, [&seed](const xAOD::MuonSegment* seg) {
69 seed.addSegment(seg);
70 });
71 }
72
73 return StatusCode::SUCCESS;
74 }
75
76 Acts::Result<Acts::BoundTrackParameters>
78 const MsTrackSeed& seed) const {
79
80 const Acts::GeometryContext tgContext{m_ctxProvider.getGeometryContext(ctx)};
82 const xAOD::MuonSegment* firstSeg = seed.segments().front();
83 const xAOD::MuonSegment* secondSeg = seed.segments()[1];
84 // If both segments are on the same station (BI) check whether the order needs to be swapped
87 const xAOD::MuonSegment* truthSeg = getMatchedTruthSegment(*firstSeg);
88 if (!truthSeg) {
89 ATH_MSG_WARNING(__func__<<"() "<<__LINE__<<" - No truth segment found");
90 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
91 }
92 const Acts::Surface& firstSurf{xAOD::muonSurface(firstMeasurement(*firstSeg, false))};
93 const Acts::Surface& secondSurf{xAOD::muonSurface(firstMeasurement(*secondSeg, false))};
94 const double distA = firstSurf.intersect(tgContext, truthSeg->position(), truthSeg->direction()).closest().pathLength();
95 const double distB = secondSurf.intersect(tgContext, truthSeg->position(), truthSeg->direction()).closest().pathLength();
96 ATH_MSG_VERBOSE(__func__<<" "<<__LINE__<<" - Detected segments in sector overlap "
97 <<printID(*firstSeg)<<" & "<<printID(*secondSeg)
98 <<". Check whether they need to be swapped "<<distA<<" vs. "<<distB);
99 if (distA> distB) {
100 std::swap(firstSeg, secondSeg);
101 }
102 }
103 const xAOD::MuonSegment* truthSeg = getMatchedTruthSegment(*firstSeg);
104 if (!truthSeg) {
105 ATH_MSG_WARNING(__func__<<"() "<<__LINE__<<" - No truth segment found");
106 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
107 }
108 const xAOD::TruthParticle* truthPart = getTruthMatchedParticle(*truthSeg);
109 if (!truthPart) {
110 ATH_MSG_WARNING(__func__<<"() "<<__LINE__<<" - No truth particle found");
111 return Acts::Result<Acts::BoundTrackParameters>::failure(std::make_error_code(std::errc::invalid_argument));
112 }
113 const MuonGMR4::SpectrometerSector* msSector{m_detMgr->getSectorEnvelope(truthSeg->chamberIndex(),
114 truthSeg->sector(),
115 truthSeg->etaIndex())};
116 const Acts::Surface& sectorSurf{msSector->surface()};
117 const Amg::Vector3D firstPos{atFirstSurface(tgContext, *firstSeg, false)};
118 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - First measurement "
119 <<msSector->idHelperSvc()->toString(xAOD::identify(firstMeasurement(*firstSeg, false)))
120 <<", position: "<<Amg::toString(firstPos));
121
122 const auto& oldTrf = sectorSurf.localToGlobalTransform(tgContext);
123 const Amg::Vector3D segDir = truthSeg->direction();
124 const Amg::Vector3D locDir = oldTrf.inverse().linear() * segDir;
125 const double pathLength = std::abs((truthSeg->position() - firstPos).dot(segDir)) + 10._cm;
126
127 const Amg::Isometry3D newTrf = oldTrf * Amg::getTranslate3D(-pathLength * locDir);
128 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Create new surface in front of "<<msSector->identString()
129 <<", "<<Amg::toString(newTrf));
130 auto shiftedSurf = Acts::Surface::makeShared<Acts::PlaneSurface>(newTrf);
131
132 Acts::BoundVector locPars = SegmentFit::boundSegmentPars(tgContext, *m_detMgr, *truthSeg).parameters();
133 static const SG::ConstAccessor<float> acc_pt{"pt"};
134 locPars[Acts::eBoundQOverP] = truthPart->charge() / ActsTrk::energyToActs(acc_pt(*truthSeg) * std::cosh(truthPart->eta()));
135 Acts::BoundTrackParameters result{shiftedSurf, locPars,
136 Acts::BoundMatrix::Identity(),
137 Acts::ParticleHypothesis::muon()};
138 using namespace Acts::detail::LineHelper;
139 if (msgLvl(MSG::VERBOSE)) {
140 std::stringstream outStream{};
141 outStream<<"Start parameters:\n"<<result<<",\n"
142 <<result.referenceSurface().toString(tgContext)
143 <<"absolute momentum: "
144 <<result.absoluteMomentum()<<"/"<<ActsTrk::energyToActs(truthPart->pt()* std::cosh(truthPart->eta()))
145 <<", start point closure: "<<(result.position(tgContext) + pathLength * segDir - truthSeg->position()).mag()
146 <<", angle closure: "<<Amg::angle(result.direction(), segDir) / 1._degree
147 <<"\n\ndump measurements:\n";
148
149 for (const xAOD::MuonSegment* segment : seed.segments()) {
150 outStream<<" - Segment "<<printID(*segment)<<" @ "<<Amg::toString(segment->position())<<"+"
151 <<Amg::toString(segment->direction())<<std::endl;
152 for (unsigned int m = 0; m < nMeasurements(*segment); ++m) {
153 const xAOD::UncalibratedMeasurement* meas = getMeasurement(*segment, m);
154 if (meas->type() == xAOD::UncalibMeasType::Other) {
155 continue;
156 }
157 const auto* mMeas = static_cast<const xAOD::MuonMeasurement*>(meas);
158 const Acts::Surface& surf{xAOD::muonSurface(meas)};
159 const double dist{surf.intersect(tgContext, result.position(tgContext), segDir,
160 Acts::BoundaryTolerance::Infinite()).closest().pathLength()};
161 outStream<<" *** "<<m_detMgr->idHelperSvc()->toString(mMeas->identify())
162 <<" @ "<<Amg::toString(surf.localToGlobalTransform(tgContext) * mMeas->localMeasurementPos())
163 <<", center: "<<Amg::toString(surf.center(tgContext))
164 <<", travelled distance: "<<dist<<std::endl;
165 }
166 }
167 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Created start parameters:\n"<<outStream.str());
168 }
169 return result;
170 }
171}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
static Double_t a
Handle class for reading from StoreGate.
A spectrometer sector forms the envelope of all chambers that are placed in the same MS sector & laye...
const Muon::IMuonIdHelperSvc * idHelperSvc() const
Returns the IdHelpeSvc.
std::string identString() const
Returns a string encoding the chamber index & the sector of the MS sector.
const Acts::PlaneSurface & surface() const
Returns the associated surface.
ActsTrk::ContextUtility m_ctxProvider
Context utility to retrieve the geometry context.
SG::ReadHandleKey< xAOD::MuonSegmentContainer > m_segmentKey
Declare the data dependency on the standard Mdt+Rpc+Tgc segment container & on the NSW segment contai...
virtual Acts::Result< Acts::BoundTrackParameters > estimateStartParameters(const EventContext &ctx, const MsTrackSeed &seed) const override final
Estimate the start track parameters for a given track seed.
virtual StatusCode initialize() override final
virtual StatusCode findTrackSeeds(const EventContext &ctx, std::vector< MsTrackSeed > &outSeeds) const override final
Retrieves the segment container from StoreGate and constructs TrackSeeds from them.
SG::ReadDecorHandleKey< xAOD::MuonSegmentContainer > m_truthLinkKey
Dependency on the truth particle link.
MuonGMR4::MuonDetectorManager * m_detMgr
Instance to the muon detector manager.
virtual std::string toString(const Identifier &id) const =0
print all fields to string
Helper class to provide constant type-safe access to aux data.
Amg::Vector3D direction() const
Returns the direction as Amg::Vector.
::Muon::MuonStationIndex::ChIndex chamberIndex() const
Returns the chamber index.
Amg::Vector3D position() const
Returns the position as Amg::Vector.
int etaIndex() const
Returns the eta index, which corresponds to stationEta in the offline identifiers (and the ).
virtual double pt() const override final
The transverse momentum ( ) of the particle.
double charge() const
Physical charge.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
bool isMuon() const
Whether the particle is a muon (or antimuon).
virtual xAOD::UncalibMeasType type() const =0
Returns the type of the measurement type as a simple enumeration.
constexpr double energyToActs(const double athenaE)
Converts an energy scalar from Athena to Acts units.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Isometry3d Isometry3D
double angle(const Amg::Vector3D &v1, const Amg::Vector3D &v2)
calculates the opening angle between two vectors
Amg::Isometry3D getTranslate3D(const double X, const double Y, const double Z)
: Returns a shift transformation along an arbitrary axis
Eigen::Matrix< double, 3, 1 > Vector3D
Acts::BoundTrackParameters boundSegmentPars(const ActsTrk::GeometryContext &gctx, const MuonGMR4::MuonDetectorManager &detMgr, const xAOD::MuonSegment &segment, const Acts::ParticleHypothesis hypot=Acts::ParticleHypothesis::muon())
Returns the segment parameters as boundTrackParameters.
This header ties the generic definitions in this package.
const xAOD::TruthParticle * getTruthMatchedParticle(const xAOD::MuonSegment &segment)
Returns the particle truth-matched to the segment.
std::string printID(const xAOD::MuonSegment &seg)
Print the chamber ID of a segment, e.g.
const xAOD::UncalibratedMeasurement * getMeasurement(const xAOD::MuonSegment &segment, const std::size_t n)
Returns the n-th uncalibrated measurement.
std::size_t nMeasurements(const xAOD::MuonSegment &segment)
Returns the number of associated Uncalibrated measurements.
const xAOD::UncalibratedMeasurement * firstMeasurement(const xAOD::MuonSegment &segment, const bool skipOutlier=true)
Retrieves the first measurement associated with the segment.
const xAOD::MuonSegment * getMatchedTruthSegment(const xAOD::MuonSegment &segment)
Returns the truth-matched segment.
Amg::Vector3D atFirstSurface(const Acts::GeometryContext &gctx, const xAOD::MuonSegment &segment, const bool skipOutlier=true)
Expresses the segment position on the surface of the first measurement.
StIndex toStationIndex(ChIndex index)
convert ChIndex into StIndex
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
void swap(ElementLinkVector< DOBJ > &lhs, ElementLinkVector< DOBJ > &rhs)
UncalibratedMeasurement_v1 UncalibratedMeasurement
Define the version of the uncalibrated measurement class.
MuonSegmentContainer_v1 MuonSegmentContainer
Definition of the current "MuonSegment container version".
MuonMeasurement_v1 MuonMeasurement
TruthParticle_v1 TruthParticle
Typedef to implementation.
const Identifier & identify(const UncalibratedMeasurement *meas)
Returns the associated identifier from the muon measurement.
MuonSegment_v1 MuonSegment
Reference the current persistent version:
const Acts::Surface & muonSurface(const UncalibratedMeasurement *meas)
Returns the associated Acts surface to the measurement.