ATLAS Offline Software
Loading...
Searching...
No Matches
SegmentExtpTest.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "SegmentExtpTest.h"
6
11
12#include "Acts/Definitions/Units.hpp"
13#include "Acts/Surfaces/LineBounds.hpp"
14#include "Acts/Surfaces/PlaneSurface.hpp"
15
19
21#include "GaudiKernel/PhysicalConstants.h"
23
24#include "Acts/Visualization/ObjVisualization3D.hpp"
25#include "Acts/Visualization/GeometryView3D.hpp"
27
28#include "ActsInterop/Logger.h"
29
30using namespace Acts::UnitLiterals;
31using namespace MuonR4::SegmentFit;
32using namespace Acts::detail::LineHelper;
33
34namespace MuonValR4{
36 ATH_CHECK(m_readKey.initialize());
37 ATH_CHECK(m_geoCtxKey.initialize());
38 ATH_CHECK(m_idHelperSvc.retrieve());
40 ATH_CHECK(detStore()->retrieve(m_detMgr));
41 return StatusCode::SUCCESS;
42 }
43 StatusCode SegmentExtpTest::execute(const EventContext& ctx) const {
44 const xAOD::MuonSegmentContainer* segments{nullptr};
45 ATH_CHECK(SG::get(segments, m_readKey, ctx));
46 const ActsTrk::GeometryContext* gctx{nullptr};
47 ATH_CHECK(SG::get(gctx, m_geoCtxKey, ctx));
48 const Acts::GeometryContext tgContext{gctx->context()};
49
50 auto extrapolate = [&](const Acts::BoundTrackParameters& start,
51 const MuonR4::SpacePoint& sp) {
52 const Amg::Transform3D& trf = sp.msSector()->localToGlobalTransform(*gctx);
53 const Acts::Surface& target = xAOD::muonSurface(sp.primaryMeasurement());
54 const Amg::Vector3D n = target.normal(tgContext,
55 Amg::Vector3D::Zero(),
56 Amg::Vector3D::Zero());
57
58 auto lambda = sp.isStraw() ? Amg::intersect<3>(trf * sp.localPosition(),
59 trf.linear() * sp.sensorDirection(),
60 start.position(tgContext),
61 start.direction())
62 : Amg::intersect<3>(start.position(tgContext),
63 start.direction(), n,
64 n.dot(target.center(tgContext)));
65
66 const auto* detEl = static_cast<const ActsTrk::IDetectorElementBase*>(target.surfacePlacement());
67 ATH_MSG_VERBOSE("Propagate "<<Amg::toString(start.position(tgContext))<<" + "
68 <<Amg::toString(start.direction())<<" onto surface: "<<target.toString(tgContext)
69 <<"\n, "<<m_idHelperSvc->toString(detEl->identify())
70 << " geoId: "<<target.geometryId()<<", "<<( lambda.value_or(0.) > 0 ? "forward" : "backward"));
71
72 return m_extrapolationTool->propagate(ctx, start, target, lambda.value_or(0.) > 0
73 ? Acts::Direction::Forward()
74 : Acts::Direction::Backward(), 100._m);
75
76 };
77 StatusCode retCode = StatusCode::SUCCESS;
78
79 SeedingAux::Config cfg{};
80 cfg.parsToUse.clear();
81 SeedingAux pullCalculator{cfg, makeActsAthenaLogger(this, "PullCalculator")};
82
83 SeedingAux::Line_t line{};
84
85 for (const xAOD::MuonSegment* segment : *segments) {
86 const MuonR4::Segment* detSeg = MuonR4::detailedSegment(*segment);
87
88 line.updateParameters(localSegmentPars(*segment));
89
90
91 const MuonGMR4::SpectrometerSector* sector = m_detMgr->getSectorEnvelope(segment->chamberIndex(),
92 segment->sector(),
93 segment->etaIndex());
94 auto startPars = boundSegmentPars(*gctx, *detSeg);
95
96 Acts::ObjVisualization3D visualHelper{};
97 if (m_drawEvent) {
99 drawSegmentLine(*gctx, *segment, visualHelper,
100 Acts::ViewConfig{.color = {220, 0, 0}});
101 drawSegmentMeasurements(*gctx, *segment, visualHelper, Acts::s_viewSurface);
102 }
103
104 if (msgLvl(MSG::VERBOSE)) {
105 std::stringstream sstr{};
106 sstr<<"pos: "<<Amg::toString(segment->position())
107 <<", dir: "<<Amg::toString(segment->direction())
108 <<", chi2/nDoF: "<<segment->chiSquared() / segment->numberDoF()
109 <<", nDoF: "<<segment->numberDoF()<<", "
110 <<segment->nPrecisionHits()<<", "<<segment->nPhiLayers()<<std::endl;
111 for (const auto& meas : detSeg->measurements()) {
112 sstr<<" **** "<<(*meas)<<", chi2: "<<SeedingAux::chi2Term(line, *meas)
113 <<", sign: "<<(meas->isStraw() ?
114 (SeedingAux::strawSign(line, *meas) == 1 ? "R" : "L") : "-")
115 <<", geoId: "<<(meas->type() != xAOD::UncalibMeasType::Other ?
116 xAOD::muonSurface(meas->spacePoint()->primaryMeasurement()).geometryId()
117 : Acts::GeometryIdentifier{})
118 <<std::endl;
119 }
120 ATH_MSG_VERBOSE("Run propagation test on "<<sector->identString()<<std::endl<<sstr.str());
121 }
122 for (const auto& meas: detSeg->measurements()) {
123 if (!meas->spacePoint() ||
124 meas->fitState() != MuonR4::CalibratedSpacePoint::State::Valid) {
125 continue;
126 }
127 const auto sp = meas->spacePoint();
128 const Acts::Surface& targetSurf{xAOD::muonSurface(sp->primaryMeasurement())};
129
130 const auto& bounds = targetSurf.bounds();
131 Amg::Vector2D lPos{Amg::Vector2D::Zero()}, mPos{Amg::Vector2D::Zero()};
132 const Amg::Transform3D toSurf = targetSurf.localToGlobalTransform(tgContext).inverse() *
133 sector->surface().localToGlobalTransform(tgContext);
134 if (targetSurf.type() == Acts::Surface::SurfaceType::Plane) {
135 lPos = (toSurf * SeedingAux::extrapolateToPlane(line, *meas)).block<2,1>(0,0);
136 if (!bounds.inside(lPos, Acts::BoundaryTolerance::AbsoluteEuclidean(-2._mm))){
137 ATH_MSG_WARNING("The position "<<Amg::toString(lPos)
138 <<" is outside the trapezoid "<<bounds
139 <<" "<<m_idHelperSvc->toString(sp->identify()));
140 continue;
141 }
142 mPos = (toSurf * meas->localPosition()).block<2,1>(0,0);
143 } else if (targetSurf.type() == Acts::Surface::SurfaceType::Straw) {
144 const auto cIsect = lineIntersect<3>(meas->localPosition(), meas->sensorDirection(),
145 line.position(), line.direction());
146 const auto cIsectPos = cIsect.position();
147 const Amg::Vector3D closePos = toSurf * cIsectPos;
148 lPos[0] = Acts::copySign(closePos.perp(), SeedingAux::strawSign(line, *meas));
149 lPos[1] = closePos.z();
150 mPos[0] = Acts::copySign(meas->driftRadius(), lPos[0]);
151 if (meas->measuresPhi()) {
152 mPos[1] = meas->localPosition().x();
153 }
154 const auto& lBounds = static_cast<const Acts::LineBounds&>(bounds);
155 if (std::abs(closePos.z()) > lBounds.get(Acts::LineBounds::eHalfLengthZ) - 2._cm ||
156 closePos.perp() >lBounds.get(Acts::LineBounds::eR) - 0.2_mm) {
157 ATH_MSG_WARNING("The line does not cross tube "
158 <<m_idHelperSvc->toString(sp->identify())
159 <<" "<<Amg::toString(lPos)<<" vs. "<<bounds<<".");
160 continue;
161 }
162 }
163 auto extpPars = extrapolate(startPars, *sp);
164 if (!extpPars.ok()) {
165 ATH_MSG_FATAL("Failed to propagate to "<<(*meas)
166 <<",\n lPos: "<<Amg::toString(toSurf * meas->localPosition())
167 <<", expected: "<<Amg::toString(lPos)<<", "<<targetSurf.bounds());
168 retCode = StatusCode::FAILURE;
169 continue;
170 }
171 if (m_drawEvent) {
173 drawBoundParameters(*gctx, *extpPars, visualHelper,
174 Acts::ViewConfig{.color = {0, 0, 220}}, 6._cm);
175 }
176
177 if (targetSurf.type() == Acts::Surface::SurfaceType::Plane) {
178 ATH_MSG_DEBUG("Position on "<<m_idHelperSvc->toString(sp->identify())
179 <<" plane "<<Amg::toString(lPos)<<" vs. "
180 <<Amg::toString((*extpPars).localPosition()));
181 const Amg::Vector2D dPos = (*extpPars).localPosition() - lPos;
182 if (dPos.mag() > 0.1_mm) {
183 ATH_MSG_FATAL("Too large deviation on "<<m_idHelperSvc->toString(sp->identify())
184 <<", "<<Amg::toString(dPos));
185 retCode = StatusCode::FAILURE;
186 }
187 } else if (targetSurf.type() == Acts::Surface::SurfaceType::Straw) {
188 const double dist = lPos[0];
189 const double extDist = (*extpPars).parameters()[Acts::eBoundLoc0];
190 const double extLocZ = (*extpPars).parameters()[Acts::eBoundLoc1];
191 const double cov = meas->covariance()[Acts::toUnderlying(AxisDefs::etaCov)];
192 ATH_MSG_DEBUG("Distance on surface "<<m_idHelperSvc->toString(sp->identify())
193 <<" straight: "<<dist<<", extrapolated: "<<extDist
194 <<"--> "<<(extDist - dist ) / std::sqrt(cov)
195 <<", along the tube: "<<lPos[1]<<", extrapolated: "<<extLocZ);
196 if (std::abs(dist - extDist) / std::sqrt(cov) > 0.05 ||
197 std::abs(lPos[1] - extLocZ) > 0.1_mm) {
198 ATH_MSG_FATAL("Too large deviation on "<<m_idHelperSvc->toString(sp->identify())
199 <<", "<<Amg::toString(lPos)<<" vs. ("<<extDist<<", "<<extLocZ<<")"
200 <<", deviate R: "<<(std::abs(dist -extDist) / std::sqrt(cov))
201 <<", deviate Z: "<<std::abs(lPos[1] - extLocZ));
202 retCode = StatusCode::FAILURE;
203 }
204 }
205
206 pullCalculator.updateSpatialResidual(line, *meas);
207 const Amg::Vector2D res = mPos - lPos;
208 AmgSymMatrix(2) cov{AmgSymMatrix(2)::Identity()};
209 cov(0,0) = 1./meas->covariance()[1];
210 cov(1,1) = 1./meas->covariance()[0];
211 ATH_MSG_DEBUG("Analyze residual for "<<m_idHelperSvc->toString(sp->identify())
212 <<" / "<<targetSurf.geometryId()<<" --- measurement: "<<Amg::toString(mPos)<<", extraploated: "
213 <<Amg::toString(lPos)<<" --> residual: "<<Amg::toString(res)<<" vs. "
214 <<Amg::toString(pullCalculator.residual())<<", chi2: "<<pullCalculator.chi2Term(line, *meas)
215 <<" vs. "<<res.dot(cov*res));
216 }
217 if (m_drawEvent) {
218 visualHelper.write(std::format("ExtTpTest_{:}_{:}_{:}.obj",
219 ctx.eventID().event_number(), segment->index(),
220 MuonR4::printID(*segment)));
221 }
222 }
223
224 return retCode;
225 }
226
227}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_FATAL(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define AmgSymMatrix(dim)
std::pair< std::vector< unsigned int >, bool > res
static Double_t sp
Handle class for reading from StoreGate.
std::unique_ptr< const Acts::Logger > makeActsAthenaLogger(IMessageSvc *svc, const std::string &name, int level, std::optional< std::string > parent_name)
Acts::GeometryContext context() const
base class interface providing the bare minimal interface extension.
const ServiceHandle< StoreGateSvc > & detStore() const
bool msgLvl(const MSG::Level lvl) const
A spectrometer sector forms the envelope of all chambers that are placed in the same MS sector & laye...
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.
Placeholder for what will later be the muon segment EDM representation.
const MeasVec & measurements() const
Returns the associated measurements.
The muon space point is the combination of two uncalibrated measurements one of them measures the eta...
SG::ReadHandleKey< ActsTrk::GeometryContext > m_geoCtxKey
Dependency on the geometry alignment.
Gaudi::Property< bool > m_drawEvent
Option to draw every extrapolation asan obj file.
virtual StatusCode execute(const EventContext &ctx) const override final
const MuonGMR4::MuonDetectorManager * m_detMgr
Detector manager to fetch the sector surfaces.
ToolHandle< ActsTrk::IExtrapolationTool > m_extrapolationTool
Track extrapolation tool.
SG::ReadHandleKey< xAOD::MuonSegmentContainer > m_readKey
Declare the data dependency on the standard Mdt+Rpc+Tgc segment container.
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
IdHelperSvc to decode the Identifiers.
virtual StatusCode initialize() override final
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::Affine3d Transform3D
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
SpacePoint::SeedingAux SeedingAux
Abrivation of the CompSpacePointAuxiliaries.
Parameters localSegmentPars(const xAOD::MuonSegment &seg)
Returns the localSegPars decoration from a xAODMuon::Segment.
Acts::BoundTrackParameters boundSegmentPars(const MuonGMR4::MuonDetectorManager &detMgr, const xAOD::MuonSegment &segment, std::optional< Acts::BoundMatrix > cov=std::nullopt, Acts::ParticleHypothesis hypot=Acts::ParticleHypothesis::muon())
Returns the segment parameters as boundTrackParameters.
std::string printID(const xAOD::MuonSegment &seg)
Print the chamber ID of a segment, e.g.
const Segment * detailedSegment(const xAOD::MuonSegment &seg)
Helper function to navigate from the xAOD::MuonSegment to the MuonR4::Segment.
Lightweight algorithm to read xAOD MDT sim hits and (fast-digitised) drift circles from SG and fill a...
void drawBoundParameters(const ActsTrk::GeometryContext &gctx, const Acts::BoundTrackParameters &pars, Acts::ObjVisualization3D &visualHelper, const Acts::ViewConfig &viewConfig=Acts::s_viewLine, const double standardLength=3.*Gaudi::Units::cm)
Draw a line representing the bound track parameters.
void drawSegmentMeasurements(const ActsTrk::GeometryContext &gctx, const xAOD::MuonSegment &segment, Acts::ObjVisualization3D &visualHelper, const Acts::ViewConfig &viewConfig=Acts::s_viewSensitive)
Draw all uncalibrated measurements associated to the segment.
void drawSegmentLine(const ActsTrk::GeometryContext &gctx, const xAOD::MuonSegment &segment, Acts::ObjVisualization3D &visualHelper, const Acts::ViewConfig &viewConfig=Acts::s_viewLine, const double standardLength=1.*Gaudi::Units::m)
Draw a segment line inside the obj file.
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
MuonSegmentContainer_v1 MuonSegmentContainer
Definition of the current "MuonSegment container version".
MuonSegment_v1 MuonSegment
Reference the current persistent version:
const Acts::Surface & muonSurface(const UncalibratedMeasurement *meas)
Returns the associated Acts surface to the measurement.