ATLAS Offline Software
Loading...
Searching...
No Matches
NewtonTrkDistanceFinder.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/*********************************************************************
6 NewtonTrkDistanceFinder.cxx - Description in header file
7*********************************************************************/
8
9//#define TrkDistance_DEBUG
10
11#include "GaudiKernel/EventContext.h"
12
15
17
19#include <cmath>
20
21
22
23namespace {
24 inline double getRadiusOfCurvature(const Trk::Perigee & myPerigee,const double Bzfield) {
25 return sin(myPerigee.parameters()[Trk::theta])/(Bzfield*myPerigee.parameters()[Trk::qOverP]);
26 }
27}
28
29namespace Trk
30{
31 NewtonTrkDistanceFinder::NewtonTrkDistanceFinder(const std::string& t, const std::string& n, const IInterface* p) :
32 AthAlgTool(t,n,p),
33 m_precision(1e-8),
35 {
36 declareProperty("Precision",m_precision);
38 declareInterface<NewtonTrkDistanceFinder>(this);
39 }
40
42
44 {
45 ATH_CHECK( AlgTool::initialize() );
47 ATH_MSG_DEBUG( "Initialize successful" );
48 return StatusCode::SUCCESS;
49 }
51 {
52 ATH_MSG_DEBUG( "Finalize successful" );
53 return StatusCode::SUCCESS;
54 }
55
56std::variant<TwoPoints, std::string>
58 const PointOnTrack & secondtrack) const
59{
60 //Now the direction of momentum at point of closest approach (but only direction, not versus)
61 const double a_phi0 = firsttrack.getPerigee().parameters()[Trk::phi0];
62 const double a_cosphi0 = -sin(a_phi0);//do i need it?
63 const double a_sinphi0 = cos(a_phi0);//~?
64
65 //Now initialize the variable you need to go on
66 const double a_x0=firsttrack.getPerigee().associatedSurface().center().x() +
67 firsttrack.getPerigee().parameters()[Trk::d0]*a_cosphi0;
68 const double a_y0=firsttrack.getPerigee().associatedSurface().center().y() +
69 firsttrack.getPerigee().parameters()[Trk::d0]*a_sinphi0;
70 const double a_z0=firsttrack.getPerigee().associatedSurface().center().z() +
71 firsttrack.getPerigee().parameters()[Trk::z0];
72
73#ifdef TrkDistance_DEBUG
74 ATH_MSG_DEBUG( "a_x0 " << a_x0 << " a_y0 " << a_y0 << " a_z0 " << a_z0 );
75 ATH_MSG_DEBUG( "m_a_phi0 " << a_phi0 );
76#endif
77
78 // Setup magnetic field retrieval
79 SG::ReadCondHandle<AtlasFieldCacheCondObj> readHandle{m_fieldCacheCondObjInputKey, Gaudi::Hive::currentContext()};
80 const AtlasFieldCacheCondObj* fieldCondObj{*readHandle};
81 if (!fieldCondObj){
82 ATH_MSG_ERROR("GetClosestPoints: fieldCondObj is nullptr.");
83 return "fieldCondObj is nullptr";
84 }
86 fieldCondObj->getInitializedCache (fieldCache);
87
88 double magnFieldVect[3];
89 double posXYZ[3];
90 posXYZ[0] = firsttrack.getPerigee().associatedSurface().center().x();
91 posXYZ[1] = firsttrack.getPerigee().associatedSurface().center().y();
92 posXYZ[2] = firsttrack.getPerigee().associatedSurface().center().z();
93 fieldCache.getField(posXYZ,magnFieldVect);
94
95
96 //Magnetic field at (x0,y0,z0)
97 const double a_Bz=magnFieldVect[2]*299.792;//B field in Gev/mm
98 //EvaluateMagneticField(a_x0,b_y0,b_z0);
99
100 const double a_Rt = getRadiusOfCurvature(firsttrack.getPerigee(),a_Bz);
101 const double a_cotantheta = 1./tan(firsttrack.getPerigee().parameters()[Trk::theta]);
102
103#ifdef TrkDistance_DEBUG
104 ATH_MSG_DEBUG( "a_Rt" << a_Rt << " a_cotantheta " << a_cotantheta );
105 ATH_MSG_DEBUG( "Magnetic field at perigee is " << a_Bz << "GeV/mm " );
106#endif
107
108 //Now the direction of momentum at point of closest approach (but only direction, not versus)
109 const double b_phi0 = secondtrack.getPerigee().parameters()[Trk::phi0];
110 const double b_cosphi0 = -sin(b_phi0);//do i need it?
111 const double b_sinphi0 = cos(b_phi0);//~?
112
113 //Now initialize the variable you need to go on
114 const double b_x0=secondtrack.getPerigee().associatedSurface().center().x() +
115 secondtrack.getPerigee().parameters()[Trk::d0]*b_cosphi0;
116 const double b_y0=secondtrack.getPerigee().associatedSurface().center().y() +
117 secondtrack.getPerigee().parameters()[Trk::d0]*b_sinphi0;
118 const double b_z0=secondtrack.getPerigee().associatedSurface().center().z() +
119 secondtrack.getPerigee().parameters()[Trk::z0];
120
121#ifdef TrkDistance_DEBUG
122 ATH_MSG_DEBUG( "b_x0 " << b_x0 << " b_y0 " << b_y0 << " b_z0 " << b_z0 );
123 ATH_MSG_DEBUG( "b_phi0 " << b_phi0 );
124#endif
125
126
127 posXYZ[0] = secondtrack.getPerigee().associatedSurface().center().x();
128 posXYZ[1] = secondtrack.getPerigee().associatedSurface().center().y();
129 posXYZ[2] = secondtrack.getPerigee().associatedSurface().center().z();
130 fieldCache.getField(posXYZ,magnFieldVect);
131
132 //Magnetic field at (x0,y0,z0)
133 const double b_Bz = magnFieldVect[2]*299.792;//B field in Gev/mm - for the moment use a constant field offline
134 //use the right value expressed in GeV
135 //EvaluateMagneticField(b_x0,b_y0,b_z0);
136
137 const double b_Rt = getRadiusOfCurvature(secondtrack.getPerigee(),b_Bz);
138 const double b_cotantheta = 1./tan(secondtrack.getPerigee().parameters()[Trk::theta]);
139
140#ifdef TrkDistance_DEBUG
141 ATH_MSG_DEBUG( "b_Rt" << b_Rt << " b_cotantheta " << b_cotantheta );
142 ATH_MSG_DEBUG( "Magnetic field at perigee is " << b_Bz << " GeV/mm " );
143#endif
144
145
146 //Now prepare some more elaborate pieces for later
147 const double ab_Dx0 = a_x0-b_x0-a_Rt*a_cosphi0+b_Rt*b_cosphi0;
148 const double ab_Dy0 = a_y0-b_y0-a_Rt*a_sinphi0+b_Rt*b_sinphi0;
149 const double ab_Dz0 = a_z0-b_z0+a_Rt*a_cotantheta*a_phi0-b_Rt*b_cotantheta*b_phi0;
150
151#ifdef TrkDistance_DEBUG
152 ATH_MSG_DEBUG( "ab_Dx0 " << ab_Dx0 << " ab_Dy0 " << ab_Dy0 << " ab_Dz0 " << ab_Dz0 );
153#endif
154
155
156 //Prepare the initial point that can be different from point of closest approach
157 //If you don't specify any point the default will be the point of closest approach!!
158 //Another subroutine will be implemented if you want to use
159 //a certain seed
160 double a_phi = firsttrack.getPhiPoint();//this has to be corrected as soon as you adjust the Trk2dDistanceSeeder...
161 double b_phi = secondtrack.getPhiPoint();
162
163 //store cos and sin of phi
164 double a_cosphi = -sin(a_phi);
165 double a_sinphi = cos(a_phi);
166 double b_cosphi = -sin(b_phi);
167 double b_sinphi = cos(b_phi);
168
169
170#ifdef TrkDistance_DEBUG
171 ATH_MSG_DEBUG( "Beginning phi is a_phi: " << a_phi << " b_phi " << b_phi );
172 ATH_MSG_DEBUG( "LOOP number 0" );
173#endif
174
175
176 int loopsnumber = 0;
177
178 bool isok=false;
179
180 while (!isok) {
181
182#ifdef TrkDistance_DEBUG
183 ATH_MSG_DEBUG( "Entered LOOP number: " << loopsnumber );
184 ATH_MSG_DEBUG( "actual value of a_phi: " << a_phi << " of b_phi " << b_phi );
185#endif
186
187
188 //count the loop number
189 ++loopsnumber;
190
191
192#ifdef TrkDistance_DEBUG
193 ATH_MSG_DEBUG( "First point x: " << GetClosestPoints().first.x()
194 << "y: " << GetClosestPoints().first.y()
195 << "z: " << GetClosestPoints().first.z() );
196 ATH_MSG_DEBUG( << "Second point x: " << GetClosestPoints().second.x()
197 << "y: " << GetClosestPoints().second.y()
198 << "z: " << GetClosestPoints().second.z() );
199
200 ATH_MSG_DEBUG( "ActualDistance: " << GetDistance() );
201 ATH_MSG_DEBUG( "real Dx0 " << ab_Dx0+a_Rt*a_cosphi-b_Rt*b_cosphi );
202 ATH_MSG_DEBUG( "real Dy0 " << ab_Dy0+a_Rt*a_sinphi-b_Rt*b_sinphi );
203#endif
204
205 //I remove the factor two from the formula
206 const double d1da_phi =
207 (ab_Dx0-b_Rt*b_cosphi)*(-a_Rt*a_sinphi)+
208 (ab_Dy0-b_Rt*b_sinphi)*a_cosphi*a_Rt+
209 (ab_Dz0-a_Rt*a_cotantheta*a_phi+b_Rt*b_cotantheta*b_phi)*(-a_Rt*a_cotantheta);
210
211
212 //same for second deriv respective to phi
213 const double d1db_phi =
214 (ab_Dx0+a_Rt*a_cosphi)*b_Rt*b_sinphi-//attention!MINUS here
215 (ab_Dy0+a_Rt*a_sinphi)*b_cosphi*b_Rt+
216 (ab_Dz0-a_Rt*a_cotantheta*a_phi+b_Rt*b_cotantheta*b_phi)*(+b_Rt*b_cotantheta);
217
218 //second derivatives (d^2/d^2(a) d^2/d^2(b) d^2/d(a)d(b) )
219
220 const double d2da_phi2 =
221 (ab_Dx0-b_Rt*b_cosphi)*(-a_Rt*a_cosphi)+
222 (ab_Dy0-b_Rt*b_sinphi)*(-a_Rt*a_sinphi)+
223 +a_Rt*a_Rt*(a_cotantheta*a_cotantheta);
224
225 const double d2db_phi2 =
226 (ab_Dx0+a_Rt*a_cosphi)*(+b_Rt*b_cosphi)+
227 (ab_Dy0+a_Rt*a_sinphi)*(+b_Rt*b_sinphi)+
228 +b_Rt*b_Rt*(b_cotantheta*b_cotantheta);
229
230
231 const double d2da_phib_phi = -a_Rt*b_Rt*(a_sinphi*b_sinphi+a_cosphi*b_cosphi+a_cotantheta*b_cotantheta);
232
233 //Calculate the determinant of the Jacobian
234
235 const double det = d2da_phi2*d2db_phi2-d2da_phib_phi*d2da_phib_phi;
236
237
238#ifdef TrkDistance_DEBUG
239 ATH_MSG_DEBUG( "d1da_phi " << d1da_phi << " d1db_phi " << d1db_phi << " d2da_phi2 " << d2da_phi2 << " d2db_phi2 " << d2db_phi2
240 << " d2da_phib_phi " << d2da_phib_phi << " det " << det );
241#endif
242
243 //if the quadratic form is defined negative or is semidefined, throw the event
244 //(you are in a maximum or in a saddle point)
245 if (det<0) {
246 ATH_MSG_DEBUG( "Hessian is negative: saddle point" );
247 return "Hessian is negative";
248 }
249 if (det>0&&d2da_phi2<0) {
250 ATH_MSG_DEBUG( "Hessian indicates a maximum: derivative will be zero but result incorrect" );
251 return "Maximum point found";
252 }
253 if (det == 0.) [[unlikely]]{
254 ATH_MSG_DEBUG( "Hessian is zero" );
255 return "Hessian is zero";
256 }
257 //Now apply the Newton formula in more than one dimension
258 const double deltaa_phi = -(d2db_phi2*d1da_phi-d2da_phib_phi*d1db_phi)/det;
259 const double deltab_phi = -(-d2da_phib_phi*d1da_phi+d2da_phi2*d1db_phi)/det;
260
261#ifdef TrkDistance_DEBUG
262 ATH_MSG_DEBUG( "deltaa_phi: " << deltaa_phi );
263 ATH_MSG_DEBUG( "deltab_phi: " << deltab_phi );
264#endif
265
266
267 a_phi += deltaa_phi;
268 b_phi += deltab_phi;
269
270 //store cos and sin of phi
271 a_cosphi = -sin(a_phi);
272 a_sinphi = cos(a_phi);
273 b_cosphi = -sin(b_phi);
274 b_sinphi = cos(b_phi);
275
276 if (std::sqrt(std::pow(deltaa_phi,2)+std::pow(deltab_phi,2))<m_precision ||
277 loopsnumber>m_maxloopnumber) isok=true;
278
279 }
280
281 if (loopsnumber>m_maxloopnumber) {
282 return "Could not find minimum distance: max loops number reached"; //now return error, see how to do it...
283 }
284
285
286 return TwoPoints(Amg::Vector3D(a_x0+a_Rt*(a_cosphi-a_cosphi0),
287 a_y0+a_Rt*(a_sinphi-a_sinphi0),
288 a_z0-a_Rt*(a_phi-a_phi0)*a_cotantheta),
289 Amg::Vector3D(b_x0+b_Rt*(b_cosphi-b_cosphi0),
290 b_y0+b_Rt*(b_sinphi-b_sinphi0),
291 b_z0-b_Rt*(b_phi-b_phi0)*b_cotantheta));
292}
293
294
295} // namespace Trk
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_DEBUG(x)
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
void getInitializedCache(MagField::AtlasFieldCache &cache) const
get B field cache for evaluation as a function of 2-d or 3-d position.
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,...
std::variant< TwoPoints, std::string > GetClosestPoints(const Perigee &a, const Perigee &b) const
SG::ReadCondHandleKey< AtlasFieldCacheCondObj > m_fieldCacheCondObjInputKey
virtual StatusCode initialize() override
virtual StatusCode finalize() override
NewtonTrkDistanceFinder(const std::string &t, const std::string &n, const IInterface *p)
virtual const S & associatedSurface() const override final
Access to the Surface method.
double getPhiPoint() const
const Perigee & getPerigee() const
const Amg::Vector3D & center() const
Returns the center position of the Surface.
Eigen::Matrix< double, 3, 1 > Vector3D
Ensure that the ATLAS eigen extensions are properly loaded.
ParametersT< TrackParametersDim, Charged, PerigeeSurface > Perigee
@ phi0
Definition ParamDefs.h:65
@ theta
Definition ParamDefs.h:66
@ qOverP
perigee
Definition ParamDefs.h:67
@ d0
Definition ParamDefs.h:63
@ z0
Definition ParamDefs.h:64
std::pair< Amg::Vector3D, Amg::Vector3D > TwoPoints
#define unlikely(x)