ATLAS Offline Software
Loading...
Searching...
No Matches
SolenoidalIntersector.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6// SolenoidalIntersector.cxx, (c) ATLAS Detector software
8
9#include "GaudiKernel/SystemOfUnits.h"
17#include "TrkSurfaces/Surface.h"
18
19namespace Trk
20{
21
23 const TrackSurfaceIntersection& trackTrackSurfaceIntersection,
24 const double qOverP)
25 : m_sinTheta (trackTrackSurfaceIntersection.direction().perp()),
27 m_cotTheta (trackTrackSurfaceIntersection.direction().z() * m_oneOverSinTheta),
29 m_solPar (solpar),
30 m_lastPosition (trackTrackSurfaceIntersection.position()),
31 m_solParams (solpar,
32 trackTrackSurfaceIntersection.position().perp(),
33 trackTrackSurfaceIntersection.position().z(),
35{
36}
37
39 const std::string& name,
40 const IInterface* parent)
41 : base_class(type, name, parent) {}
42
43StatusCode
45{
48 return StatusCode::SUCCESS;
49}
50
51StatusCode
53{
54 ATH_MSG_DEBUG( "finalized after " << m_countExtrapolations << " extrapolations with "
55 << m_countRKSwitches << " switches to RK integration");
56
57 return StatusCode::SUCCESS;
58}
59
60
62std::optional<Trk::TrackSurfaceIntersection>
64 const TrackSurfaceIntersection& trackIntersection,
65 const double qOverP) const
66{
67
68 const auto surfaceType = surface.type();
69 if (surfaceType == Trk::SurfaceType::Plane) {
70 return intersectPlaneSurface(static_cast<const PlaneSurface&>(surface),
71 trackIntersection, qOverP);
72 }
73 if (surfaceType == Trk::SurfaceType::Line) {
74 return m_rungeKuttaIntersector->approachStraightLineSurface(
75 static_cast<const StraightLineSurface&>(surface), trackIntersection,
76 qOverP);
77 }
78 if (surfaceType == Trk::SurfaceType::Cylinder) {
80 static_cast<const CylinderSurface&>(surface), trackIntersection,
81 qOverP);
82 }
83 if (surfaceType == Trk::SurfaceType::Disc) {
84 return intersectDiscSurface(static_cast<const DiscSurface&>(surface),
85 trackIntersection, qOverP);
86 }
87 if (surfaceType == Trk::SurfaceType::Perigee) {
88 return m_rungeKuttaIntersector->approachPerigeeSurface(
89 static_cast<const PerigeeSurface&>(surface), trackIntersection,
90 qOverP);
91 }
92
93 ATH_MSG_WARNING( " unrecognized Surface" );
94 return std::nullopt;
95}
96
98std::optional<Trk::TrackSurfaceIntersection>
100 const TrackSurfaceIntersection& trackIntersection,
101 const double qOverP) const
102{ return m_rungeKuttaIntersector->approachPerigeeSurface(surface, trackIntersection, qOverP); }
103
105std::optional<Trk::TrackSurfaceIntersection>
107 const TrackSurfaceIntersection& trackIntersection,
108 const double qOverP) const
109{ return m_rungeKuttaIntersector->approachStraightLineSurface(surface, trackIntersection, qOverP); }
110
112std::optional<Trk::TrackSurfaceIntersection>
114 const TrackSurfaceIntersection& trackIntersection,
115 const double qOverP) const
116{
117 const SolenoidParametrization* solenoidParametrization =
119
120 double endRadius = surface.globalReferencePoint().perp();
121 if (!solenoidParametrization || endRadius > solenoidParametrization->maximumR())
122 return m_rungeKuttaIntersector->intersectCylinderSurface(surface, trackIntersection, qOverP);
123
124 Constants* com = nullptr;
125 std::optional<TrackSurfaceIntersection> isect = newIntersection(
126 trackIntersection, *solenoidParametrization, qOverP, com);
128
129 double radius2 = isect->position().perp2();
130 if (std::abs(endRadius - sqrt(radius2)) > m_surfaceTolerance
131 && ! extrapolateToR(*isect, radius2, *com, endRadius)) return std::nullopt;
132
133 return intersection(std::move(*isect), *com, surface);
134}
135
137std::optional<Trk::TrackSurfaceIntersection>
139 const TrackSurfaceIntersection& trackIntersection,
140 const double qOverP) const
141{
142 const SolenoidParametrization* solenoidParametrization =
144
145 double endZ = surface.center().z();
146 if (!solenoidParametrization || std::abs(endZ) > solenoidParametrization->maximumZ())
147 return m_rungeKuttaIntersector->intersectDiscSurface(surface, trackIntersection, qOverP);
148
149 Constants* com = nullptr;
150 std::optional<TrackSurfaceIntersection> isect =
151 newIntersection (trackIntersection,
152 *solenoidParametrization,
153 qOverP,
154 com);
155
157
158 if (std::abs(endZ -trackIntersection.position().z()) > m_surfaceTolerance
159 && ! extrapolateToZ(*isect, *com, endZ))
160 {
161 return std::nullopt;
162 }
163
164 return intersection(std::move(*isect), *com, surface);
165}
166
168std::optional<Trk::TrackSurfaceIntersection>
170 const TrackSurfaceIntersection& trackIntersection,
171 const double qOverP) const
172{
173 const SolenoidParametrization* solenoidParametrization =
175
176 if (!solenoidParametrization ||
177 std::abs(surface.center().z()) > solenoidParametrization->maximumZ()
178 || surface.center().perp() > solenoidParametrization->maximumR())
179 return m_rungeKuttaIntersector->intersectPlaneSurface(surface, trackIntersection, qOverP);
180
181 Constants* com = nullptr;
182 std::optional<TrackSurfaceIntersection> isect =
183 newIntersection (trackIntersection,
184 *solenoidParametrization,
185 qOverP,
186 com);
187 Amg::Vector3D& pos = isect->position();
188 Amg::Vector3D& dir = isect->direction();
190 double radius2 = pos.perp2();
191
192 // step until sufficiently near to plane surface
193 // this gives wrong answer!
194 // DistanceSolution solution = surface.straightLineDistanceEstimate(pos,dir);
195 // if (! solution.signedDistance()) return 0;
196 // double distance = solution.currentDistance(true);
197
198 int numberSteps = 0;
199 double dot = surface.normal().dot(dir);
200 double offset = surface.normal().dot(surface.center() - pos);
201
202 while (std::abs(offset) > m_surfaceTolerance * std::abs(dot)) {
203 // take care if grazing incidence - quit if looper
204 if (std::abs(dot) < 0.0001)
205 return std::nullopt;
206 double distance = offset / dot;
207
208 // extrapolate
209 if (com->m_sinTheta < 0.9) {
210 if (!extrapolateToZ(*isect, *com, pos.z() + distance * dir.z()))
211 return std::nullopt;
212 radius2 = pos.perp2();
213 } else {
214 if (!extrapolateToR(*isect, radius2, *com,
215 (pos + distance * dir).perp()))
216 return std::nullopt;
217 }
218
219 // check we are getting closer to the plane, switch to RK in case of
220 // difficulty
221 dot = surface.normal().dot(dir);
222 offset = surface.normal().dot(surface.center() - pos);
223 if (std::abs(offset) > m_surfaceTolerance * std::abs(dot) &&
224 (++numberSteps > 5 ||
225 std::abs(offset) > 0.5 * std::abs(distance * dot))) {
227 ATH_MSG_DEBUG(" switch to RK after "
228 << numberSteps << " steps at offset " << offset
229 << " dot " << surface.normal().dot(dir));
230
231 return m_rungeKuttaIntersector->intersectPlaneSurface(
232 surface, trackIntersection, qOverP);
233 }
234 };
235
236 return intersection(std::move(*isect), *com, surface);
237}
238
240bool
242 Amg::Vector3D endPosition) const
243{
244 const SolenoidParametrization* solenoidParametrization =
246
247 // check cylinder bounds for valid parametrization
248 return solenoidParametrization &&
249
250 std::abs(endPosition.z()) < solenoidParametrization->maximumZ()
251
252 && endPosition.perp() < solenoidParametrization->maximumR()
253
254 && getSolenoidParametrization()->validOrigin(startPosition);
255}
256
257// private methods
258
259
260bool
262 double& radius2,
263 Constants& com,
264 const double endR) const
265{
266 Amg::Vector3D& pos = isect.position();
267 Amg::Vector3D& dir = isect.direction();
268
269 double fieldComponent =
270 com.m_solPar.fieldComponent(pos.z(), com.m_solParams);
271 double curvature = fieldComponent * com.m_qOverPt;
272 double arcLength = linearArcLength(isect, com, radius2, endR);
273 if (std::abs(arcLength * curvature) > m_deltaPhiTolerance) {
274 double radiusOfCurvature = 1. / curvature;
275 double xCentre =
276 pos.x() - radiusOfCurvature * dir.y() * com.m_oneOverSinTheta;
277 double yCentre =
278 pos.y() + radiusOfCurvature * dir.x() * com.m_oneOverSinTheta;
279 double cosPhi;
280 double sinPhi;
281 arcLength =
282 circularArcLength(endR, radiusOfCurvature, xCentre, yCentre,
283 dir.x() * com.m_oneOverSinTheta,
284 dir.y() * com.m_oneOverSinTheta, cosPhi, sinPhi);
285 if (std::abs(arcLength * com.m_cotTheta) < m_surfaceTolerance) {
286 pos.x() = xCentre + radiusOfCurvature * sinPhi;
287 pos.y() = yCentre - radiusOfCurvature * cosPhi;
288 pos.z() += arcLength * com.m_cotTheta;
289 radius2 = endR * endR;
290 dir.x() = cosPhi * com.m_sinTheta;
291 dir.y() = sinPhi * com.m_sinTheta;
292 isect.pathlength() += arcLength * com.m_oneOverSinTheta;
293 arcLength = 0.;
294 }
295 }
296
297 double deltaZ = arcLength * com.m_cotTheta;
298 if (std::abs(deltaZ) < m_surfaceTolerance) // avoid FPE with constant
299 // curvature parabolic approx
300 {
301 double cosPhi = dir.x() * com.m_oneOverSinTheta;
302 double sinPhi = dir.y() * com.m_oneOverSinTheta;
303 if (std::abs(arcLength) > m_surfaceTolerance) {
304 double sinDPhi = 0.5 * arcLength * curvature;
305 double cosDPhi =
306 1. - 0.5 * sinDPhi * sinDPhi * (1.0 + 0.25 * sinDPhi * sinDPhi);
307 double temp = cosPhi;
308 cosPhi = temp * cosDPhi - sinPhi * sinDPhi;
309 sinPhi = temp * sinDPhi + sinPhi * cosDPhi;
310 dir.x() = (cosPhi * cosDPhi - sinPhi * sinDPhi) * com.m_sinTheta;
311 dir.y() = (sinPhi * cosDPhi + cosPhi * sinDPhi) * com.m_sinTheta;
312 }
313
314 pos.x() += arcLength * cosPhi;
315 pos.y() += arcLength * sinPhi;
316 pos.z() += arcLength * com.m_cotTheta;
317 radius2 = endR * endR;
318 isect.pathlength() += arcLength * com.m_oneOverSinTheta;
319 } else {
320 extrapolateToZ(isect, com, pos.z() + deltaZ);
321 radius2 = pos.perp2();
322 if (std::abs(endR - std::sqrt(radius2)) > m_surfaceTolerance) {
323 deltaZ = linearArcLength(isect, com, radius2, endR) * com.m_cotTheta;
324 extrapolateToZ(isect, com, pos.z() + deltaZ);
325 radius2 = pos.perp2();
326 }
327 }
328
329 return true;
330}
331
332bool
334 Constants& com,
335 const double endZ)
336{
337 Amg::Vector3D& pos = isect.position();
338 Amg::Vector3D& dir = isect.direction();
339
340 double firstIntegral = 0.;
341 double secondIntegral = 0.;
342 com.m_solPar.fieldIntegrals(firstIntegral, secondIntegral, pos.z(), endZ,
343 com.m_solParams);
344 double DFiMax = 0.1;
345 double cosPhi = dir.x() * com.m_oneOverSinTheta;
346 double sinPhi = dir.y() * com.m_oneOverSinTheta;
347 double cosBeta;
348 double sinBeta;
349 double deltaPhi2 =
350 secondIntegral * com.m_qOverPt / std::abs(com.m_cotTheta);
351 if (std::abs(deltaPhi2) < DFiMax) {
352 double deltaPhi2Squared = deltaPhi2 * deltaPhi2;
353 sinBeta = 1. - 0.166667 * deltaPhi2Squared;
354 cosBeta = -0.5 * deltaPhi2 * (1. - 0.083333 * deltaPhi2Squared);
355 } else if (2. * std::abs(deltaPhi2) < M_PI) {
356 sinBeta = std::sin(deltaPhi2) / deltaPhi2;
357 cosBeta = (std::cos(deltaPhi2) - 1.) / deltaPhi2;
358 } else {
359 return false;
360 }
361
362 double radialDistance = (endZ - pos.z()) / com.m_cotTheta;
363 pos.x() += radialDistance * (sinPhi * cosBeta + cosPhi * sinBeta);
364 pos.y() += radialDistance * (sinPhi * sinBeta - cosPhi * cosBeta);
365 pos.z() = endZ;
366 isect.pathlength() += radialDistance * com.m_oneOverSinTheta;
367
368 double cosAlpha;
369 double sinAlpha;
370 double deltaPhi1 = firstIntegral * com.m_qOverPt / std::abs(com.m_cotTheta);
371 if (std::abs(deltaPhi1) < DFiMax) {
372 double deltaPhi1Squared = deltaPhi1 * deltaPhi1;
373 sinAlpha = deltaPhi1 * (1. - 0.166667 * deltaPhi1Squared);
374 cosAlpha =
375 1. - 0.5 * deltaPhi1Squared * (1. - 0.083333 * deltaPhi1Squared);
376 } else {
377 sinAlpha = std::sin(deltaPhi1);
378 cosAlpha = std::cos(deltaPhi1);
379 }
380 dir.x() = (cosPhi * cosAlpha - sinPhi * sinAlpha) * com.m_sinTheta;
381 dir.y() = (sinPhi * cosAlpha + cosPhi * sinAlpha) * com.m_sinTheta;
382 return true;
383}
384
385std::optional<TrackSurfaceIntersection>
387 const SolenoidParametrization& solpar,
388 const double qOverP,
389 Constants*& com)
390{
391 const TrackSurfaceIntersection::IIntersectionCache* oldCache = isect.cache();
392 std::unique_ptr<Constants> cache;
393 Amg::Vector3D lastPosition;
394 lastPosition.setZero();
395
396 if (oldCache) {
397 assert(typeid(*oldCache) == typeid(Constants));
398 cache =
399 std::make_unique<Constants>(*static_cast<const Constants*>(oldCache));
400 lastPosition = cache->m_lastPosition;
401 } else {
402 cache = std::make_unique<Constants>(solpar, isect, qOverP);
403 }
404
405 com = cache.get();
406 auto newIsect =
407 std::make_optional<TrackSurfaceIntersection>(isect, std::move(cache));
408 if (oldCache) {
409 newIsect->position() = lastPosition;
410 }
411 return newIsect;
412}
413
415 std::stringstream msg;
416 msg << "Invalid read handle for SolenoidParametrization " << m_solenoidParametrizationKey.key();
417 throw std::logic_error(msg.str());
418}
419
420} // end of namespace
#define M_PI
Scalar perp() const
perp method - perpendicular length
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Class for a CylinderSurface in the ATLAS detector.
virtual const Amg::Vector3D & globalReferencePoint() const override final
Returns a global reference point: For the Cylinder this is Where denotes the averagePhi() of the cy...
Class for a DiscSurface in the ATLAS detector.
Definition DiscSurface.h:54
Class describing the Line to which the Perigee refers to.
Class for a planaer rectangular or trapezoidal surface in the ATLAS detector.
bool validOrigin(const Amg::Vector3D &origin) const
void fieldIntegrals(double &firstIntegral, double &secondIntegral, double zBegin, double zEnd, Parameters &parms) const
double fieldComponent(double z, const Parameters &parms) const
SG::ReadCondHandleKey< SolenoidParametrization > m_solenoidParametrizationKey
virtual std::optional< TrackSurfaceIntersection > intersectDiscSurface(const DiscSurface &surface, const TrackSurfaceIntersection &trackTrackSurfaceIntersection, const double qOverP) const override
IIntersector interface method for specific Surface type : DiscSurface.
std::optional< TrackSurfaceIntersection > intersection(TrackSurfaceIntersection &&isect, Constants &com, const Surface &surface) const
virtual std::optional< TrackSurfaceIntersection > approachPerigeeSurface(const PerigeeSurface &surface, const TrackSurfaceIntersection &trackTrackSurfaceIntersection, const double qOverP) const override
IIntersector interface method for specific Surface type : PerigeeSurface.
ToolHandle< IIntersector > m_rungeKuttaIntersector
static bool extrapolateToZ(TrackSurfaceIntersection &isect, Constants &com, const double endZ)
static constexpr double m_deltaPhiTolerance
virtual StatusCode finalize() override
virtual std::optional< TrackSurfaceIntersection > intersectSurface(const Surface &surface, const TrackSurfaceIntersection &trackTrackSurfaceIntersection, const double qOverP) const override
IIntersector interface method for general Surface type.
virtual bool isValid(Amg::Vector3D startPosition, Amg::Vector3D endPosition) const override
IIntersector interface method to check validity of parametrization within extrapolation range.
static std::optional< TrackSurfaceIntersection > newIntersection(const TrackSurfaceIntersection &oldIsect, const SolenoidParametrization &solpar, const double qOverP, Constants *&com)
virtual std::optional< TrackSurfaceIntersection > intersectPlaneSurface(const PlaneSurface &surface, const TrackSurfaceIntersection &trackTrackSurfaceIntersection, const double qOverP) const override
IIntersector interface method for specific Surface type : PlaneSurface.
virtual StatusCode initialize() override
bool extrapolateToR(TrackSurfaceIntersection &isect, double &radius2, Constants &com, const double endRadius) const
virtual std::optional< TrackSurfaceIntersection > approachStraightLineSurface(const StraightLineSurface &surface, const TrackSurfaceIntersection &trackTrackSurfaceIntersection, const double qOverP) const override
IIntersector interface method for specific Surface type : StraightLineSurface.
double linearArcLength(const TrackSurfaceIntersection &isect, const Constants &com, const double radius2, const double endRadius) const
std::atomic< unsigned long long > m_countExtrapolations
virtual std::optional< TrackSurfaceIntersection > intersectCylinderSurface(const CylinderSurface &surface, const TrackSurfaceIntersection &trackTrackSurfaceIntersection, const double qOverP) const override
IIntersector interface method for specific Surface type : CylinderSurface.
const SolenoidParametrization * getSolenoidParametrization() const
double circularArcLength(double, double, double, double, double, double, double &, double &) const
std::atomic< unsigned long long > m_countRKSwitches
SolenoidalIntersector(const std::string &type, const std::string &name, const IInterface *parent)
Class for a StraightLineSurface in the ATLAS detector to describe dirft tube and straw like detectors...
Abstract Base Class for tracking surfaces.
virtual const Amg::Vector3D & normal() const
Returns the normal vector of the Surface (i.e.
virtual constexpr SurfaceType type() const =0
Returns the Surface type to avoid dynamic casts.
const Amg::Vector3D & center() const
Returns the center position of the Surface.
An intersection with a Surface is given by.
const IIntersectionCache * cache() const
Retrieve the associated cache block, if it exists.
const Amg::Vector3D & direction() const
Method to retrieve the direction at the Intersection.
const Amg::Vector3D & position() const
Method to retrieve the position of the Intersection.
double pathlength() const
Method to retrieve the pathlength propagated till the Intersection.
Eigen::Matrix< double, 3, 1 > Vector3D
Ensure that the ATLAS eigen extensions are properly loaded.
@ z
global position (cartesian)
Definition ParamDefs.h:57
@ qOverP
perigee
Definition ParamDefs.h:67
Definition dot.py:1
Constants of motion and other cached values.
Constants(const SolenoidParametrization &solpar, const TrackSurfaceIntersection &trackTrackSurfaceIntersection, const double qOverP)
const SolenoidParametrization & m_solPar
SolenoidParametrization::Parameters m_solParams
MsgStream & msg
Definition testRead.cxx:32