ATLAS Offline Software
Loading...
Searching...
No Matches
ImpactPoint3dEstimator.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 ImpactPoint3dEstimator.cxx - Description in header file
7*********************************************************************/
8
14
15// #define IMPACTPOINT3DESTIMATOR_DEBUG
16
17//added for cuts in case of displaced vertex
20
21#include <cmath>
22
23namespace Trk
24{
25
26 ImpactPoint3dEstimator::ImpactPoint3dEstimator(const std::string& t, const std::string& n, const IInterface* p) :
27 base_class(t,n,p),
30 m_precision(1e-10)//DeltaPhi
31 {
32 declareProperty("Extrapolator",m_extrapolator);
33 declareProperty("MaxIterations",m_maxiterations);
34 declareProperty("Precision",m_precision);
35 }
36
38
40 {
41 if (!m_extrapolator.empty()) {
42 ATH_CHECK( m_extrapolator.retrieve() );
43 } else {
44 m_extrapolator.disable();
45 }
47
48 ATH_MSG_DEBUG( "Initialize successful" );
49 return StatusCode::SUCCESS;
50 }
51
53 {
54 ATH_MSG_DEBUG( "Finalize successful" );
55 return StatusCode::SUCCESS;
56 }
57
58
59 template<typename T>
60 std::unique_ptr<PlaneSurface>
62 const Amg::Vector3D* theVertex,
63 double& distance) const
64 {
65 const Amg::Vector3D momentumUnit = thePerigee->momentum().unit();
66 double pathLength = ( *theVertex - thePerigee->position() ).dot( momentumUnit )
67 / ( momentumUnit.dot( momentumUnit )) ;
68 //first vector at 3d impact point
69
70
71 Amg::Vector3D POCA = thePerigee->position() + pathLength * momentumUnit;// Position of closest approach
72 Amg::Vector3D DeltaR = *theVertex - POCA;
73 distance=DeltaR.mag();
74 DeltaR=DeltaR.unit();
75
76
77 //correct DeltaR from small deviations from orthogonality to DeltaR -- DeltaR.dot(momentumUnit) should equal 0 if the above is correct
78
79 Amg::Vector3D DeltaRcorrected=DeltaR-(DeltaR.dot(momentumUnit))*momentumUnit;
80
81 if ((DeltaR-DeltaRcorrected).mag()>1e-4)
82 {
83 ATH_MSG_WARNING( " DeltaR and MomentumDir are not orthogonal " );
84 ATH_MSG_DEBUG( std::setprecision(10) << " DeltaR-DeltaRcorrected: " << (DeltaR-DeltaRcorrected).mag() );
85 }
86
87 Amg::Vector3D YDir=momentumUnit.cross(DeltaRcorrected);
88
89 ATH_MSG_VERBOSE( "final minimal distance is: " << distance);
90 ATH_MSG_DEBUG( "POCA in 3D is: " << POCA );
91
92 //store the plane...
93 ATH_MSG_VERBOSE( "plane to which to extrapolate X " << DeltaRcorrected << " Y " << YDir << " Z " << momentumUnit);
94
95 Amg::Transform3D thePlane(DeltaRcorrected, YDir, momentumUnit, *theVertex);
96
97#ifdef IMPACTPOINT3DESTIMATOR_DEBUG
98 std::cout << "the translation is, directly from Transform3d: " << thePlane->getTranslation() << endmsg;
99#endif
100
101 return std::make_unique<PlaneSurface>(thePlane);
102
103 }
104
105 std::unique_ptr<PlaneSurface>
106 ImpactPoint3dEstimator::Estimate3dIP(const EventContext& /*ctx*/,
107 const NeutralParameters* neutralPerigee,
108 const Amg::Vector3D* theVertex,
109 double& distance) const
110 {
111 ATH_MSG_DEBUG("Neutral particle -- propagate like a straight line");
112 return Estimate3dIPNoCurvature(neutralPerigee, theVertex, distance);
113 }
114
115 std::unique_ptr<PlaneSurface>
117 const TrackParameters* trackPerigee,
118 const Amg::Vector3D* theVertex,
119 double& distance) const
120 {
122 const AtlasFieldCacheCondObj* fieldCondObj{*readHandle};
123 if (!fieldCondObj)[[unlikely]]{
124 ATH_MSG_ERROR("fieldCondObj is nullptr");
125 return nullptr;
126 }
127 MagField::AtlasFieldCache fieldCache;
128 fieldCondObj->getInitializedCache (fieldCache);
129
130 double magnFieldVect[3];
131 fieldCache.getField(trackPerigee->associatedSurface().center().data(),magnFieldVect);
132 if(magnFieldVect[2] == 0 ){
133 ATH_MSG_DEBUG("Magnetic field in the Z direction is 0 -- propagate like a straight line");
134 return Estimate3dIPNoCurvature(trackPerigee, theVertex, distance);
135 }
136
137 const Trk::Perigee* thePerigee=dynamic_cast<const Trk::Perigee*>(trackPerigee);
138 if (thePerigee==nullptr)
139 {
141 " ImpactPoint3dEstimator didn't get a Perigee* as ParametersBase*: "
142 "cast not possible. Need to EXTRAPOLATE...");
143 Trk::PerigeeSurface perigeeSurface(*theVertex);
144 std::unique_ptr<const Trk::TrackParameters> tmp =
145 m_extrapolator->extrapolateDirectly(
146 ctx, *trackPerigee, perigeeSurface);
147 if (tmp && tmp->associatedSurface().type() == Trk::SurfaceType::Perigee) {
148 thePerigee = static_cast<const Trk::Perigee*>(tmp.release());
149 }
150 if (thePerigee == nullptr){
151 return nullptr;
152 }
153 }
154
155 ATH_MSG_VERBOSE( " Now running ImpactPoint3dEstimator::Estimate3dIP" );
156 double phi0=thePerigee->parameters()[Trk::phi0];
157 double dCosPhi0=-std::sin(phi0);
158 double dSinPhi0=std::cos(phi0);
159 double theta=thePerigee->parameters()[Trk::theta];
160 double cotTheta=1./std::tan(thePerigee->parameters()[Trk::theta]);
161 double d0=thePerigee->parameters()[Trk::d0];
162
163 //I need the radius (magnetic field...)
164 double Bz=magnFieldVect[2]*299.792;
165 double Rt=std::sin(theta)/(Bz*thePerigee->parameters()[Trk::qOverP]);
166
167 double x0=thePerigee->associatedSurface().center().x()+(d0-Rt)*dCosPhi0;
168 double y0=thePerigee->associatedSurface().center().y()+(d0-Rt)*dSinPhi0;
169 double z0=thePerigee->associatedSurface().center().z()+thePerigee->parameters()[Trk::z0]+Rt*phi0*cotTheta;
170
171 if (thePerigee!=trackPerigee) {
172 delete thePerigee;
173 thePerigee=nullptr;
174 }
175
176 double xc=theVertex->x();
177 double yc=theVertex->y();
178 double zc=theVertex->z();
179
180 double phiActual=phi0;
181 double dCosPhiActual=-std::sin(phiActual);
182 double dSinPhiActual=std::cos(phiActual);
183
184 double secderivative=0.;
185 double derivative=0.;
186
187 int ncycle=0;
188 bool isok=false;
189
190 double deltaphi=0.;
191
192#ifdef IMPACTPOINT3DESTIMATOR_DEBUG
193 std::cout << std::setprecision(25) << "actual distance before cycle is: " << std::hypot(x0-xc+Rt*dCosPhiActual,
194 y0-yc+Rt*dSinPhiActual,
195 z0-zc-Rt*cotTheta*phiActual) << std::endl;
196#endif
197
198 do {
199
200#ifdef IMPACTPOINT3DESTIMATOR_DEBUG
201 ATH_MSG_VERBOSE( "Cycle number: " << ncycle << " old phi: " << phiActual );
202#endif
203
204
205 derivative=(x0-xc)*(-Rt*dSinPhiActual)+(y0-yc)*Rt*dCosPhiActual+(z0-zc-Rt*phiActual*cotTheta)*(-Rt*cotTheta);
206 secderivative=Rt*(-(x0-xc)*dCosPhiActual-(y0-yc)*dSinPhiActual+Rt*cotTheta*cotTheta);
207#ifdef IMPACTPOINT3DESTIMATOR_DEBUG
208 ATH_MSG_VERBOSE( "derivative is: " << derivative << " sec derivative is: " << secderivative );
209#endif
210
211 deltaphi=-derivative/secderivative;
212
213#ifdef IMPACTPOINT3DESTIMATOR_DEBUG
214 std::cout << std::setprecision(25) << "deltaphi: " << deltaphi << std::endl;
215#endif
216
217 phiActual+=deltaphi;
218 dCosPhiActual=-std::sin(phiActual);
219 dSinPhiActual=std::cos(phiActual);
220
221#ifdef IMPACTPOINT3DESTIMATOR_DEBUG
222 ATH_MSG_VERBOSE( "derivative is: " << derivative << " sec derivative is: " << secderivative );
223 std::cout << std::setprecision(25) << std::hypot(x0-xc+Rt*dCosPhiActual, y0-yc+Rt*dSinPhiActual,
224 z0-zc-Rt*cotTheta*phiActual) << std::endl;
225 ATH_MSG_VERBOSE( "actual distance is: " << std::hypot(x0-xc+Rt*dCosPhiActual,
226 y0-yc+Rt*dSinPhiActual,
227 z0-zc-Rt*cotTheta*phiActual));
228#endif
229
230 if (secderivative<0) throw error::ImpactPoint3dEstimatorProblem("Second derivative is negative");
231
232 if (ncycle>m_maxiterations) throw error::ImpactPoint3dEstimatorProblem("Too many loops: could not find minimum distance to vertex");
233
234 ncycle+=1;
235 if (ncycle>m_maxiterations||std::abs(deltaphi)<m_precision) {
236#ifdef IMPACTPOINT3DESTIMATOR_DEBUG
237 ATH_MSG_VERBOSE( "found minimum at: " << phiActual );
238#endif
239 isok=true;
240 }
241
242 } while (!isok);
243
244 //now you have to construct the plane with PlaneSurface
245 //first vector at 3d impact point
246 Amg::Vector3D MomentumDir(std::cos(phiActual)*std::sin(theta),std::sin(phiActual)*std::sin(theta),std::cos(theta));
247 Amg::Vector3D DeltaR(x0-xc+Rt*dCosPhiActual,y0-yc+Rt*dSinPhiActual,z0-zc-Rt*cotTheta*phiActual);
248 distance=DeltaR.mag();
249 if (distance==0.){
250 ATH_MSG_WARNING("DeltaR is zero in ImpactPoint3dEstimator::Estimate3dIP, returning nullptr");
251 return nullptr;
252 }
253 DeltaR=DeltaR.unit();
254
255
256 //correct DeltaR from small deviations from orthogonality to DeltaR
257
258 Amg::Vector3D DeltaRcorrected=DeltaR-(DeltaR.dot(MomentumDir))*MomentumDir;
259
260 if ((DeltaR-DeltaRcorrected).mag()>1e-4)
261 {
262 ATH_MSG_WARNING( " DeltaR and MomentumDir are not orthogonal " );
263 ATH_MSG_DEBUG( std::setprecision(10) << " DeltaR-DeltaRcorrected: " << (DeltaR-DeltaRcorrected).mag() );
264 }
265
266 Amg::Vector3D YDir=MomentumDir.cross(DeltaRcorrected);
267
268 //store the impact 3d point
269 Amg::Vector3D vertex(x0+Rt*dCosPhiActual,y0+Rt*dSinPhiActual,z0-Rt*cotTheta*phiActual);
270
271 ATH_MSG_VERBOSE( "final minimal distance is: " << std::hypot(x0-xc+Rt*dCosPhiActual,
272 y0-yc+Rt*dSinPhiActual,
273 z0-zc-Rt*cotTheta*phiActual));
274
275 ATH_MSG_DEBUG( "POCA in 3D is: " << vertex );
276
277
278 //store the plane...
279 ATH_MSG_VERBOSE( "plane to which to extrapolate X " << DeltaRcorrected << " Y " << YDir << " Z " << MomentumDir );
280
281 Amg::Transform3D thePlane(DeltaRcorrected, YDir, MomentumDir, *theVertex);
282
283#ifdef IMPACTPOINT3DESTIMATOR_DEBUG
284 std::cout << "the translation is, directly from Transform3d: " << thePlane.getTranslation() << endmsg;
285#endif
286 return std::make_unique<PlaneSurface>(thePlane);
287 }//end of estimate 3dIP method
288
289 bool
290 ImpactPoint3dEstimator::addIP3dAtaPlane(const EventContext& ctx, VxTrackAtVertex & vtxTrack,const Amg::Vector3D & vertex) const
291 {
292 if (vtxTrack.initialPerigee()) {
293 const AtaPlane* myPlane=IP3dAtaPlane(ctx,vtxTrack,vertex);
294 if (myPlane)
295 {
296 vtxTrack.setImpactPoint3dAtaPlane(myPlane);
297 return true;
298 }
299 } else { //for neutrals
301 if (myPlane) {
302 ATH_MSG_VERBOSE ("Adding plane: " << myPlane->associatedSurface() );
303 vtxTrack.setImpactPoint3dNeutralAtaPlane(myPlane);
304 return true;
305 }
306 }
307 return false;
308 }
309
310
311 const Trk::AtaPlane *
312 ImpactPoint3dEstimator::IP3dAtaPlane(const EventContext& ctx,VxTrackAtVertex & vtxTrack,const Amg::Vector3D & vertex) const
313 {
314 if (!vtxTrack.initialPerigee() && vtxTrack.initialNeutralPerigee())
315 ATH_MSG_WARNING( "Calling ImpactPoint3dEstimator::IP3dAtaPlane cannot return NeutralAtaPlane" );
316 std::unique_ptr<PlaneSurface> theSurfaceAtIP;
317 try
318 {
319 double distance = 0;
320 theSurfaceAtIP = Estimate3dIP(ctx,vtxTrack.initialPerigee(),&vertex,distance);
321 }
323 {
324 ATH_MSG_WARNING( " ImpactPoint3dEstimator failed to find minimum distance between track and vertex seed: " << err.p );
325 return nullptr;
326 }
327 if(!theSurfaceAtIP){
328 ATH_MSG_WARNING( " ImpactPoint3dEstimator failed to find minimum distance and returned 0 " );
329 return nullptr;
330 }
331#ifdef ImpactPoint3dAtaPlaneFactory_DEBUG
332 ATH_MSG_VERBOSE( "Original perigee was: " << *(vtxTrack.initialPerigee()) );
333 ATH_MSG_VERBOSE( "The resulting surface is: " << *theSurfaceAtIP );
334#endif
335 const auto* pTrackPar = m_extrapolator->extrapolate(
336 ctx,
337 *(vtxTrack.initialPerigee()),
338 *theSurfaceAtIP).release();
339 if (const Trk::AtaPlane* res = dynamic_cast<const Trk::AtaPlane *>(pTrackPar); res){
340 return res;
341 }
342 ATH_MSG_DEBUG("TrackParameters ptr returned from extrapolate could not be cast to Trk::AtaPlane* in IP3dAtaPlane(..)");
343 return nullptr;
344 }
345
346
348 ImpactPoint3dEstimator::IP3dNeutralAtaPlane(const EventContext& ctx,const NeutralParameters * initNeutPerigee,const Amg::Vector3D & vertex) const
349 {
350 std::unique_ptr<PlaneSurface> theSurfaceAtIP;
351
352 try
353 {
354 double distance = 0;
355 theSurfaceAtIP = Estimate3dIP(ctx,initNeutPerigee,&vertex,distance);
356 }
358 {
359 ATH_MSG_WARNING( " ImpactPoint3dEstimator failed to find minimum distance between track and vertex seed: " << err.p );
360 return nullptr;
361 }
362 if(!theSurfaceAtIP){
363 ATH_MSG_WARNING( " ImpactPoint3dEstimator failed to find minimum distance and returned 0 " );
364 return nullptr;
365 }
366#ifdef ImpactPoint3dAtaPlaneFactory_DEBUG
367 ATH_MSG_VERBOSE( "Original neutral perigee was: " << *initNeutPerigee );
368 ATH_MSG_VERBOSE( "The resulting surface is: " << *theSurfaceAtIP );
369#endif
370
371 const Trk::NeutralAtaPlane* res = nullptr;
372 std::unique_ptr<const Trk::NeutralParameters> tmp = m_extrapolator->extrapolate(*initNeutPerigee,*theSurfaceAtIP);
373 if(dynamic_cast<const Trk::NeutralAtaPlane*> (tmp.get())){
374 res = static_cast<const Trk::NeutralAtaPlane*> (tmp.release());
375 }
376 return res;
377 }
378
379
380}
Scalar mag() const
mag method
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
std::pair< std::vector< unsigned int >, bool > res
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,...
virtual StatusCode finalize() override
virtual bool addIP3dAtaPlane(const EventContext &ctx, VxTrackAtVertex &, const Amg::Vector3D &vertex) const override
Actual estimate method, changing the state of Trk::VxTrackAtVertex.
virtual const Trk::NeutralAtaPlane * IP3dNeutralAtaPlane(const EventContext &ctx, const NeutralParameters *initNeutPerigee, const Amg::Vector3D &vertex) const override
virtual StatusCode initialize() override
virtual std::unique_ptr< PlaneSurface > Estimate3dIP(const EventContext &ctx, const Trk::TrackParameters *trackPerigee, const Amg::Vector3D *theVertex, double &distance) const override
SG::ReadCondHandleKey< AtlasFieldCacheCondObj > m_fieldCacheCondObjInputKey
virtual const Trk::AtaPlane * IP3dAtaPlane(const EventContext &ctx, VxTrackAtVertex &vtxTrack, const Amg::Vector3D &vertex) const override
This method creates the ImpactPoint3dAtaPlane as the parameters of the track at the point of closest ...
std::unique_ptr< PlaneSurface > Estimate3dIPNoCurvature(const T *, const Amg::Vector3D *theVertex, double &distance) const
ImpactPoint3dEstimator(const std::string &t, const std::string &n, const IInterface *p)
Default constructor due to Athena interface.
ToolHandle< Trk::IExtrapolator > m_extrapolator
virtual const Surface & associatedSurface() const override=0
Access to the Surface associated to the Parameters.
virtual const S & associatedSurface() const override final
Access to the Surface method.
Class describing the Line to which the Perigee refers to.
const Amg::Vector3D & center() const
Returns the center position of the Surface.
The VxTrackAtVertex is a common class for all present TrkVertexFitters The VxTrackAtVertex is designe...
void setImpactPoint3dAtaPlane(const AtaPlane *myIP3dAtaPlane)
Set method for ImpactPoint3dAtaPlane.
const NeutralParameters * initialNeutralPerigee(void) const
Access to the initial perigee parameters of trajectory.
const TrackParameters * initialPerigee(void) const
Access to the initial perigee parameters of trajectory.
void setImpactPoint3dNeutralAtaPlane(const NeutralAtaPlane *myIP3dNeutralAtaPlane)
Set method for ImpactPoint3dNeutralAtaPlane.
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
Ensure that the ATLAS eigen extensions are properly loaded.
ParametersT< TrackParametersDim, Charged, PerigeeSurface > Perigee
ParametersBase< NeutralParametersDim, Neutral > NeutralParameters
@ 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
ParametersT< NeutralParametersDim, Neutral, PlaneSurface > NeutralAtaPlane
ParametersBase< TrackParametersDim, Charged > TrackParameters
ParametersT< TrackParametersDim, Charged, PlaneSurface > AtaPlane
#define unlikely(x)