ATLAS Offline Software
Trk2dDistanceSeeder.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 /*********************************************************************
6  Trk2dDistanceSeeder.cxx - Description in header file
7 *********************************************************************/
8 
9 //#define TRK2DDISTANCESEEDER_DEBUG
10 
12 #include "GaudiKernel/EventContext.h"
13 #include "GaudiKernel/SystemOfUnits.h"
17 #include <cmath>
18 
19 namespace {
20  inline double dist2d(const Amg::Vector3D & a, const Amg::Vector3D & b) {
21  return std::sqrt(std::pow(a.x()-b.x(),2)+std::pow(a.y()-b.y(),2));
22  }
23  inline double takenearest(const double of, const double to) {
24  if (of-to>=M_PI) return of-2*M_PI;
25  if (of-to<-M_PI) return of+2*M_PI;
26  return of;
27  }
28 
29  inline double
30  safeAtan2(const double y, const double x)
31  {
32  //This is basically what TMath::Atan2 does
33  //up until 6.24 at least.
34  if (x != 0){
35  return std::atan2(y, x);
36  }
37  //x ==0 cases
38  if (y == 0){
39  return 0;
40  }
41  if (y > 0){
42  return M_PI_2;
43  }
44  else{
45  return -M_PI_2;
46  }
47  }
48 
49  inline double
50  safeAcos(const double x)
51  {
52  // This is what TMath::Acos did up to 6.22 but not
53  // from 6.24 onwards...
54  if (x < -1.) {
55  return M_PI;
56  }
57  if (x > 1.) {
58  return 0;
59  }
60  return std::acos(x);
61  }
62 
63  inline double
64  oppositeangle(const double angle)
65  {
66  return angle > 0. ? angle - M_PI : angle + M_PI;
67  }
68  inline double
69  square(const double tosquare)
70  {
71  return std::pow(tosquare, 2);
72  }
73  inline double
74  getphipoca(const Trk::Perigee& myPerigee)
75  {
76  return myPerigee.parameters()[Trk::phi0] + M_PI / 2;
77  }
78  inline double
79  setphipoca(const double phi)
80  {
81  return phi - M_PI / 2.;
82  }
83  inline double
84  goFromPhipocaToPhi(const double phipoca)
85  {
86  return phipoca + M_PI / 2.;
87  }
88 
89  inline double
90  getRadiusOfCurvature(const Trk::Perigee& myPerigee, const double Bzfield)
91  {
92  return sin(myPerigee.parameters()[Trk::theta]) /
93  (Bzfield * myPerigee.parameters()[Trk::qOverP]);
94  }
95  inline Amg::Vector3D
96  getCenterOfCurvature(const Trk::Perigee& myPerigee,
97  const double RadiusOfCurvature,
98  const double phipoca)
99  {
100  return Amg::Vector3D(myPerigee.associatedSurface().center().x() +
101  myPerigee.parameters()[Trk::d0] * cos(phipoca) -
102  RadiusOfCurvature * cos(phipoca),
103  myPerigee.associatedSurface().center().y() +
104  myPerigee.parameters()[Trk::d0] * sin(phipoca) -
105  RadiusOfCurvature * sin(phipoca),
106  myPerigee.associatedSurface().center().z() +
107  myPerigee.parameters()[Trk::z0] +
108  RadiusOfCurvature *
109  myPerigee.parameters()[Trk::phi0] /
110  tan(myPerigee.parameters()[Trk::theta]));
111  }
112  inline Amg::Vector3D
113  getSeedPoint(const Trk::Perigee& myPerigee,
114  const Amg::Vector3D& center,
115  const double radius,
116  const double newphi)
117  {
118  // short int sgnd0=(short
119  // int)(myPerigee.parameters()[Trk::d0]/fabs(myPerigee.parameters()[Trk::d0]));
120  return Amg::Vector3D(
121  center.x() + radius * cos(newphi + M_PI / 2.),
122  center.y() + radius * sin(newphi + M_PI / 2.),
123  // eliminated sgnd0 from
124  // center.z()-radius*(newphi-sgnd0*M_PI/2.)/tan(myPerigee.parameters()[Trk::theta]));
125  center.z() - radius * newphi / tan(myPerigee.parameters()[Trk::theta]));
126  }
127  inline Amg::Vector3D
128  getSeedPoint(const Amg::Vector3D& center,
129  const double radius,
130  const double newphi)
131  {
132  // short int sgnd0=(short
133  // int)(myPerigee.parameters()[Trk::d0]/fabs(myPerigee.parameters()[Trk::d0]));
134  return Amg::Vector3D(center.x() + radius * cos(newphi + M_PI / 2.),
135  center.y() + radius * sin(newphi + M_PI / 2.),
136  0.);
137  }
138 
139 }//end anonymous namespace
140 
141 namespace Trk
142 {
143  Trk2dDistanceSeeder::Trk2dDistanceSeeder(const std::string& t, const std::string& n, const IInterface* p) :
144  AthAlgTool(t,n,p),
145  m_solveAmbiguityUsingZ(true)
146  {
147  declareProperty("SolveAmbiguityUsingZ",m_solveAmbiguityUsingZ);
148  declareInterface<Trk2dDistanceSeeder>(this);
149  }
150 
152 
154  {
157  ATH_MSG_DEBUG( "Initialize successful" );
158  return StatusCode::SUCCESS;
159  }
160 
162  {
163  ATH_MSG_DEBUG( "Finalize successful" );
164  return StatusCode::SUCCESS;
165  }
166 
167 
170  TwoPoints* twopoints /*=nullptr*/) const
171  {
172  SG::ReadCondHandle<AtlasFieldCacheCondObj> readHandle{m_fieldCacheCondObjInputKey, Gaudi::Hive::currentContext()};
173  const AtlasFieldCacheCondObj* fieldCondObj{*readHandle};
174 
175  MagField::AtlasFieldCache fieldCache;
176  fieldCondObj->getInitializedCache (fieldCache);
177 
178  const double bfield1 = getBField (mytracks.getFirstPerigee(), fieldCache);
179  const double bfield2 = getBField (mytracks.getSecondPerigee(), fieldCache);
180 
181  //phitanpoca here means not the tan to poca (which is phi0) but the direction from perigee to the center of curvature (I don't know
182  //why I chose this strange name, sorry!)
183  const double phitanpoca1=getphipoca(mytracks.getFirstPerigee());
184  const double phitanpoca2=getphipoca(mytracks.getSecondPerigee());
185 
186  //Temporary abs1 and abs2 are the signed radius quantities (later we will reduce it to unsigned quantities)
187  double abs1 = getRadiusOfCurvature(mytracks.getFirstPerigee(), bfield1);
188  double abs2 = getRadiusOfCurvature(mytracks.getSecondPerigee(),bfield2);
189 
190  const double sgnr1 = abs1>0 ? 1. : -1.;
191  const double sgnr2 = abs2>0 ? 1. : -1.;
192 
193  //component x of center of curv of first particle
194  const std::pair<Amg::Vector3D,Amg::Vector3D> centersofcurv
195  (getCenterOfCurvature(mytracks.getFirstPerigee(),abs1,phitanpoca1),
196  getCenterOfCurvature(mytracks.getSecondPerigee(),abs2,phitanpoca2));
197 
198 #ifdef TRK2DDISTANCESEEDER_DEBUG
199  ATH_MSG_DEBUG( " Center of track number 1: " << centersofcurv.first << " center of track 2 " << centersofcurv.second );
200 #endif
201 
202  const double distance2d = dist2d(centersofcurv.first,centersofcurv.second);
203 
204  abs1 = std::abs(abs1);
205  abs2 = std::abs(abs2);
206 
207 
208 #ifdef TRK2DDISTANCESEEDER_DEBUG
209  ATH_MSG_DEBUG( "abs1: " << abs1 << " abs2: " << abs2 );
210  ATH_MSG_DEBUG( "phitanpoca1: " << phitanpoca1 << " phitanpoca2: " << phitanpoca2 );
211  ATH_MSG_DEBUG( "distance2d " << distance2d );
212 #endif
213 
214  double phi1 = 0;
215  double phi2 = 0;
216 
217  // Strictly redundant with phi1 and phi2 above, but needed to get results
218  // that are rounded identically with the pre-MT version.
219  double phi1poca = 0;
220  double phi2poca = 0;
221 
222  //first case (the two circles are the one distinct from the other)
223  if (distance2d > (abs1+abs2)) {
224 
225 #ifdef TRK2DDISTANCESEEDER_DEBUG
226  ATH_MSG_DEBUG ("Distinct circles " );
227 #endif
228 
229  phi1 = safeAtan2(centersofcurv.second.y()-centersofcurv.first.y(),
230  centersofcurv.second.x()-centersofcurv.first.x());
231 
232  if (sgnr2<0) {
233  phi2=phi1;
234  } else {
235  phi2=oppositeangle(phi1);
236  }
237 
238  if (sgnr1<0) {
239  phi1=oppositeangle(phi1);
240  }
241 
242  //Now you are worried that the solution has to be the one nearest to the original phi...
243  phi1=takenearest(phi1,phitanpoca1);
244  phi2=takenearest(phi2,phitanpoca2);
245  }
246  else {
247  //second case(if distance2d<abs1+abs2 we have still two cases
248  //1) one circle inside the other (nobody is touched) (if |abs2-abs1|>d)
249  //2) two intersections (if |abs2-abs1|<d)
250  // -->(case with one intersection seems me of no physical interest)
251  if (fabs(abs2-abs1)>=distance2d) {
252 
253 #ifdef TRK2DDISTANCESEEDER_DEBUG
254  ATH_MSG_DEBUG( " one circle inside the other " );
255 #endif
256 
257  //1)
258  if (abs2<abs1) {
259 
260 #ifdef TRK2DDISTANCESEEDER_DEBUG
261  ATH_MSG_DEBUG(" second radius smaller than first " );
262 #endif
263  phi1 = safeAtan2(centersofcurv.second.y()-centersofcurv.first.y(),
264  centersofcurv.second.x()-centersofcurv.first.x());
265  phi2=phi1;
266  }
267  else {
268 
269 #ifdef TRK2DDISTANCESEEDER_DEBUG
270  ATH_MSG_DEBUG( " first radius smaller than second " );
271 #endif
272 
273 
274  phi1 = safeAtan2(-(centersofcurv.second.y()-centersofcurv.first.y()),
275  -(centersofcurv.second.x()-centersofcurv.first.x()));
276  phi2=phi1;
277  }
278 
279  //adjust the sign, taking into account possible q(1,2)<0
280  if (sgnr2<0) {
281  phi2=oppositeangle(phi2);
282  }
283 
284  if (sgnr1<0) {
285  phi1=oppositeangle(phi1);
286  }
287 
288  phi1=takenearest(setphipoca(phi1),setphipoca(phitanpoca1));
289  phi2=takenearest(setphipoca(phi2),setphipoca(phitanpoca2));
290  phi1poca = setphipoca(phi1);
291  phi2poca = setphipoca(phi2);
292  }
293  else {
294 
295  //Do it easier...
296  const double projection2=(square(abs1)-square(abs2)-square(distance2d))/2./distance2d;
297  const double cosinus2=projection2/sgnr2/abs2;
298 
299 
300 #ifdef TRK2DDISTANCESEEDER_DEBUG
301  const double projection1=(square(abs2)-square(abs1)-square(distance2d))/2./distance2d;
302  const double cosinus1=projection1/sgnr1/abs1;
303  ATH_MSG_DEBUG( "projection1: " << projection1 << " cosinus1 " << cosinus1
304  << "projection2: " << projection2 << " cosinus2 " << cosinus2 );
305 #endif
306 
307  const double phibase2 =
308  safeAtan2(centersofcurv.second.y() - centersofcurv.first.y(),
309  centersofcurv.second.x() - centersofcurv.first.x());
310 
311  const double addtophi2=
312  safeAcos(cosinus2);
313 
314 #ifdef TRK2DDISTANCESEEDER_DEBUG
315  ATH_MSG_DEBUG( " phibase2 is : " << phibase2 << " add to phi " << addtophi2 );
316 #endif
317 
318  const std::pair<double,double> possiblephiontrack2(phibase2+addtophi2,phibase2-addtophi2);
319 
320 #ifdef TRK2DDISTANCESEEDER_DEBUG
321  ATH_MSG_DEBUG( "the two phis are: " << possiblephiontrack2.first << " and " << possiblephiontrack2.second );
322 #endif
323 
324  const std::pair<double,double>
325  possiblecosphitrack1((centersofcurv.second.x()-centersofcurv.first.x()
326  +sgnr2*abs2*std::cos(possiblephiontrack2.first))/sgnr1/abs1,
327  (centersofcurv.second.x()-centersofcurv.first.x()
328  +sgnr2*abs2*std::cos(possiblephiontrack2.second))/sgnr1/abs1);
329 
330  const std::pair<double,double>
331  possiblesigntrack1(sgnr1*(centersofcurv.second.y()-centersofcurv.first.y()
332  +sgnr2*abs2*std::sin(possiblephiontrack2.first))>0?1.:-1.,
333  sgnr1*(centersofcurv.second.y()-centersofcurv.first.y()
334  +sgnr2*abs2*std::sin(possiblephiontrack2.second))>0?1.:-1.);
335 
336  const std::pair<double,double>
337  possiblephiontrack1(possiblesigntrack1.first*safeAcos(possiblecosphitrack1.first),
338  possiblesigntrack1.second*safeAcos(possiblecosphitrack1.second));
339 
340 
341  const std::pair<PointOnTrack,PointOnTrack>
342  possiblepointsontrack1(PointOnTrack(mytracks.getFirstPerigee(),
343  takenearest(setphipoca(possiblephiontrack1.first),
344  setphipoca(phitanpoca1))),
345  PointOnTrack(mytracks.getFirstPerigee(),
346  takenearest(setphipoca(possiblephiontrack1.second),
347  setphipoca(phitanpoca1))));
348 
349  const std::pair<PointOnTrack,PointOnTrack>
350  possiblepointsontrack2(PointOnTrack(mytracks.getSecondPerigee(),
351  takenearest(setphipoca(possiblephiontrack2.first),
352  setphipoca(phitanpoca2))),
353  PointOnTrack(mytracks.getSecondPerigee(),
354  takenearest(setphipoca(possiblephiontrack2.second),
355  setphipoca(phitanpoca2))));
356 
357 
358  const std::pair<Amg::Vector3D,Amg::Vector3D>
359  possiblepoints1(getSeedPoint(possiblepointsontrack1.first.getPerigee(),centersofcurv.first,
360  abs1*sgnr1,possiblepointsontrack1.first.getPhiPoint()),
361  getSeedPoint(possiblepointsontrack1.second.getPerigee(),centersofcurv.first,
362  abs1*sgnr1,possiblepointsontrack1.second.getPhiPoint()));
363 
364  const std::pair<Amg::Vector3D,Amg::Vector3D>
365  possiblepoints2(getSeedPoint(possiblepointsontrack2.first.getPerigee(),centersofcurv.second,
366  abs2*sgnr2,possiblepointsontrack2.first.getPhiPoint()),
367  getSeedPoint(possiblepointsontrack2.second.getPerigee(),centersofcurv.second,
368  abs2*sgnr2,possiblepointsontrack2.second.getPhiPoint()));
369 
370 
371 #ifdef TRK2DDISTANCESEEDER_DEBUG
372  ATH_MSG_DEBUG( "Point 1a: x " << possiblepoints1.first.x() << " y " << possiblepoints1.first.y() );
373  ATH_MSG_DEBUG( "Point 2a: x " << possiblepoints2.first.x() << " y " << possiblepoints2.first.y() );
374  ATH_MSG_DEBUG( "Point 1b: x " << possiblepoints1.second.x() << " y " << possiblepoints1.second.y() );
375  ATH_MSG_DEBUG( "Point 2b: x " << possiblepoints2.second.x() << " y " << possiblepoints2.second.y() );
376  ATH_MSG_DEBUG( "Distance between 1a and 2a:" << fabs(possiblepoints1.first.z()-possiblepoints2.first.z()) <<
377  "Distance between 1a and 2a:" << fabs(possiblepoints1.second.z()-possiblepoints2.second.z()) );
378 #endif
379 
380 
381  //now discover what couple of points are the nearest ones
383  {
384  if (fabs(possiblepoints1.first.z()-possiblepoints2.first.z())<
385  fabs(possiblepoints1.second.z()-possiblepoints2.second.z()))
386  {
387  phi1poca = possiblepointsontrack1.first.getPhiPoint();
388  phi2poca = possiblepointsontrack2.first.getPhiPoint();
389  } else {
390  phi1poca = possiblepointsontrack1.second.getPhiPoint();
391  phi2poca = possiblepointsontrack2.second.getPhiPoint();
392  }
393  }
394  else
395  {
396  if (sqrt(possiblepoints1.first.x()*possiblepoints1.first.x()+possiblepoints1.first.y()*possiblepoints1.first.y())<
397  sqrt(possiblepoints2.first.x()*possiblepoints2.first.x()+possiblepoints2.first.y()*possiblepoints2.first.y()))
398  {
399  phi1poca = possiblepointsontrack1.first.getPhiPoint();
400  phi2poca = possiblepointsontrack2.first.getPhiPoint();
401  } else {
402  phi1poca = possiblepointsontrack1.second.getPhiPoint();
403  phi2poca = possiblepointsontrack2.second.getPhiPoint();
404  }
405  }
406  phi1=goFromPhipocaToPhi(phi1poca);
407  phi2=goFromPhipocaToPhi(phi2poca);
408  }
409  }
410 
411  if (twopoints) {
412  *twopoints = TwoPoints (getSeedPoint(centersofcurv.first,
413  abs1*sgnr1,setphipoca(phi1)),
414  getSeedPoint(centersofcurv.second,
415  abs2*sgnr2,setphipoca(phi2)));
416  }
417 
418  return std::make_pair (PointOnTrack (mytracks.getFirstPerigee(), phi1poca),
419  PointOnTrack (mytracks.getSecondPerigee(),phi2poca));
420  }
421 
422 
424  {
425  double magnFieldVect[3];
426  double posXYZ[3];
427  posXYZ[0] = p.associatedSurface().center().x();
428  posXYZ[1] = p.associatedSurface().center().y();
429  posXYZ[2] = p.associatedSurface().center().z();
430 
431  cache.getField(posXYZ,magnFieldVect);
432  const double bfield = magnFieldVect[2]*299.792;//should be in GeV/mm
433  if (bfield==0. || std::isnan(bfield)) {
434  ATH_MSG_DEBUG( "Could not find a magnetic field different from zero: very very strange" );
435  return 0.60407; //Value in GeV/mm (ATLAS units)
436  }
437  ATH_MSG_DEBUG( "Magnetic field projection of z axis in the perigee position is: " << bfield << " GeV/mm " );
438 
439  return bfield;
440  }
441 
442 
443 } // namespace Trk
Trk::TwoTracks::getSecondPerigee
const Perigee & getSecondPerigee() const
Definition: TwoTracks.cxx:21
TrackParameters.h
phi
Scalar phi() const
phi method
Definition: AmgMatrixBasePlugin.h:67
SG::ReadCondHandle
Definition: ReadCondHandle.h:44
AtlasFieldCacheCondObj
Definition: AtlasFieldCacheCondObj.h:19
AthCommonDataStore< AthCommonMsg< AlgTool > >::declareProperty
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T > &t)
Definition: AthCommonDataStore.h:145
Trk::ParametersT
Dummy class used to allow special convertors to be called for surfaces owned by a detector element.
Definition: EMErrorDetail.h:25
initialize
void initialize()
Definition: run_EoverP.cxx:894
Trk::Trk2dDistanceSeeder::GetSeed
TwoPointOnTrack GetSeed(const TwoTracks &mytracks, TwoPoints *twopoints=nullptr) const
Definition: Trk2dDistanceSeeder.cxx:169
M_PI
#define M_PI
Definition: ActiveFraction.h:11
Trk::z0
@ z0
Definition: ParamDefs.h:64
Trk::TwoTracks::getFirstPerigee
const Perigee & getFirstPerigee() const
Definition: TwoTracks.cxx:17
Trk::TwoPoints
std::pair< Amg::Vector3D, Amg::Vector3D > TwoPoints
Definition: SeedFinderParamDefs.h:20
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
drawFromPickle.cos
cos
Definition: drawFromPickle.py:36
x
#define x
Trk::Trk2dDistanceSeeder::getBField
double getBField(const Perigee &p, MagField::AtlasFieldCache &cache) const
Definition: Trk2dDistanceSeeder.cxx:423
Trk::ParametersT::associatedSurface
virtual const S & associatedSurface() const override final
Access to the Surface method.
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:210
beamspotman.n
n
Definition: beamspotman.py:731
Trk2dDistanceSeeder.h
Trk::theta
@ theta
Definition: ParamDefs.h:66
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
angle
double angle(const GeoTrf::Vector2D &a, const GeoTrf::Vector2D &b)
Definition: TRTDetectorFactory_Full.cxx:73
AtlasFieldCache.h
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
Trk::Trk2dDistanceSeeder::initialize
virtual StatusCode initialize() override
Definition: Trk2dDistanceSeeder.cxx:153
drawFromPickle.tan
tan
Definition: drawFromPickle.py:36
Trk::Trk2dDistanceSeeder::m_solveAmbiguityUsingZ
bool m_solveAmbiguityUsingZ
Definition: Trk2dDistanceSeeder.h:63
Trk::Trk2dDistanceSeeder::Trk2dDistanceSeeder
Trk2dDistanceSeeder(const std::string &t, const std::string &n, const IInterface *p)
Definition: Trk2dDistanceSeeder.cxx:143
Trk::TwoPointOnTrack
std::pair< PointOnTrack, PointOnTrack > TwoPointOnTrack
Definition: SeedFinderParamDefs.h:19
Trk::Trk2dDistanceSeeder::m_fieldCacheCondObjInputKey
SG::ReadCondHandleKey< AtlasFieldCacheCondObj > m_fieldCacheCondObjInputKey
Definition: Trk2dDistanceSeeder.h:66
Trk
Ensure that the ATLAS eigen extensions are properly loaded.
Definition: FakeTrackBuilder.h:9
Trk::d0
@ d0
Definition: ParamDefs.h:63
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
SG::CondHandleKey::initialize
StatusCode initialize(bool used=true)
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
ParticleGun_SamplingFraction.radius
radius
Definition: ParticleGun_SamplingFraction.py:96
CxxUtils::to
CONT to(RANGE &&r)
Definition: ranges.h:39
Trk::PointOnTrack
Definition: PointOnTrack.h:13
a
TList * a
Definition: liststreamerinfos.cxx:10
y
#define y
Trk::Trk2dDistanceSeeder::~Trk2dDistanceSeeder
virtual ~Trk2dDistanceSeeder()
MagField::AtlasFieldCache
Local cache for magnetic field (based on MagFieldServices/AtlasFieldSvcTLS.h)
Definition: AtlasFieldCache.h:43
Trk::qOverP
@ qOverP
perigee
Definition: ParamDefs.h:67
MagField::AtlasFieldCache::getField
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,...
Definition: AtlasFieldCache.cxx:42
drawFromPickle.sin
sin
Definition: drawFromPickle.py:36
AthAlgTool
Definition: AthAlgTool.h:26
pow
constexpr int pow(int base, int exp) noexcept
Definition: ap_fixedTest.cxx:15
Trk::Trk2dDistanceSeeder::finalize
virtual StatusCode finalize() override
Definition: Trk2dDistanceSeeder.cxx:161
TwoTracks.h
Trk::phi0
@ phi0
Definition: ParamDefs.h:65
Trk::TwoTracks
Definition: TwoTracks.h:15