]> git.uio.no Git - u/mrichter/AliRoot.git/blob - STEER/STEERBase/AliExternalTrackParam.cxx
Merge remote-tracking branch 'remotes/origin/master' into TPCdev
[u/mrichter/AliRoot.git] / STEER / STEERBase / AliExternalTrackParam.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17
18 ///////////////////////////////////////////////////////////////////////////////
19 //                                                                           //
20 // Implementation of the external track parameterisation class.              //
21 //                                                                           //
22 // This parameterisation is used to exchange tracks between the detectors.   //
23 // A set of functions returning the position and the momentum of tracks      //
24 // in the global coordinate system as well as the track impact parameters    //
25 // are implemented.
26 // Origin: I.Belikov, CERN, Jouri.Belikov@cern.ch                            //
27 ///////////////////////////////////////////////////////////////////////////////
28 #include <cassert>
29
30 #include <TVectorD.h>
31 #include <TMatrixDSym.h>
32 #include <TPolyMarker3D.h>
33 #include <TVector3.h>
34 #include <TMatrixD.h>
35
36 #include "AliExternalTrackParam.h"
37 #include "AliVVertex.h"
38 #include "AliLog.h"
39
40 ClassImp(AliExternalTrackParam)
41
42 Double32_t AliExternalTrackParam::fgMostProbablePt=kMostProbablePt;
43 Bool_t AliExternalTrackParam::fgUseLogTermMS = kFALSE;; 
44 //_____________________________________________________________________________
45 AliExternalTrackParam::AliExternalTrackParam() :
46   AliVTrack(),
47   fX(0),
48   fAlpha(0)
49 {
50   //
51   // default constructor
52   //
53   for (Int_t i = 0; i < 5; i++) fP[i] = 0;
54   for (Int_t i = 0; i < 15; i++) fC[i] = 0;
55 }
56
57 //_____________________________________________________________________________
58 AliExternalTrackParam::AliExternalTrackParam(const AliExternalTrackParam &track):
59   AliVTrack(track),
60   fX(track.fX),
61   fAlpha(track.fAlpha)
62 {
63   //
64   // copy constructor
65   //
66   for (Int_t i = 0; i < 5; i++) fP[i] = track.fP[i];
67   for (Int_t i = 0; i < 15; i++) fC[i] = track.fC[i];
68   CheckCovariance();
69 }
70
71 //_____________________________________________________________________________
72 AliExternalTrackParam& AliExternalTrackParam::operator=(const AliExternalTrackParam &trkPar)
73 {
74   //
75   // assignment operator
76   //
77   
78   if (this!=&trkPar) {
79     AliVTrack::operator=(trkPar);
80     fX = trkPar.fX;
81     fAlpha = trkPar.fAlpha;
82
83     for (Int_t i = 0; i < 5; i++) fP[i] = trkPar.fP[i];
84     for (Int_t i = 0; i < 15; i++) fC[i] = trkPar.fC[i];
85     CheckCovariance();
86   }
87
88   return *this;
89 }
90
91 //_____________________________________________________________________________
92 AliExternalTrackParam::AliExternalTrackParam(Double_t x, Double_t alpha, 
93                                              const Double_t param[5], 
94                                              const Double_t covar[15]) :
95   AliVTrack(),
96   fX(x),
97   fAlpha(alpha)
98 {
99   //
100   // create external track parameters from given arguments
101   //
102   for (Int_t i = 0; i < 5; i++)  fP[i] = param[i];
103   for (Int_t i = 0; i < 15; i++) fC[i] = covar[i];
104   CheckCovariance();
105 }
106
107 //_____________________________________________________________________________
108 void AliExternalTrackParam::CopyFromVTrack(const AliVTrack *vTrack)
109 {
110   //
111   // Recreate TrackParams from VTrack
112   // This is not a copy contructor !
113   //
114   if (!vTrack) {
115     AliError("Source VTrack is NULL");
116     return;
117   }
118   if (this==vTrack) {
119     AliError("Copy of itself is requested");
120     return;
121   }
122   //
123   if (vTrack->InheritsFrom(AliExternalTrackParam::Class())) {
124     AliDebug(1,"Source itself is AliExternalTrackParam, using assignment operator");
125     *this = *(AliExternalTrackParam*)vTrack;
126     return;
127   }
128   //
129   AliVTrack::operator=( *vTrack );
130   //
131   Double_t xyz[3],pxpypz[3],cv[21];
132   vTrack->GetXYZ(xyz);
133   pxpypz[0]=vTrack->Px();
134   pxpypz[1]=vTrack->Py();
135   pxpypz[2]=vTrack->Pz();
136   vTrack->GetCovarianceXYZPxPyPz(cv);
137   Short_t sign = (Short_t)vTrack->Charge();
138   Set(xyz,pxpypz,cv,sign);
139 }
140
141 //_____________________________________________________________________________
142 AliExternalTrackParam::AliExternalTrackParam(const AliVTrack *vTrack) :
143   AliVTrack(),
144   fX(0.),
145   fAlpha(0.)
146 {
147   //
148   // Constructor from virtual track,
149   // This is not a copy contructor !
150   //
151
152   if (vTrack->InheritsFrom("AliExternalTrackParam")) {
153      AliError("This is not a copy constructor. Use AliExternalTrackParam(const AliExternalTrackParam &) !");
154      AliWarning("Calling the default constructor...");
155      AliExternalTrackParam();
156      return;
157   }
158
159   Double_t xyz[3],pxpypz[3],cv[21];
160   vTrack->GetXYZ(xyz);
161   pxpypz[0]=vTrack->Px();
162   pxpypz[1]=vTrack->Py();
163   pxpypz[2]=vTrack->Pz();
164   vTrack->GetCovarianceXYZPxPyPz(cv);
165   Short_t sign = (Short_t)vTrack->Charge();
166
167   Set(xyz,pxpypz,cv,sign);
168 }
169
170 //_____________________________________________________________________________
171 AliExternalTrackParam::AliExternalTrackParam(Double_t xyz[3],Double_t pxpypz[3],
172                                              Double_t cv[21],Short_t sign) :
173   AliVTrack(),
174   fX(0.),
175   fAlpha(0.)
176 {
177   //
178   // constructor from the global parameters
179   //
180
181   Set(xyz,pxpypz,cv,sign);
182 }
183
184 /*
185 //_____________________________________________________________________________
186 void AliExternalTrackParam::Set(Double_t xyz[3],Double_t pxpypz[3],
187                                 Double_t cv[21],Short_t sign) 
188 {
189   //
190   // create external track parameters from the global parameters
191   // x,y,z,px,py,pz and their 6x6 covariance matrix
192   // A.Dainese 10.10.08
193
194   // Calculate alpha: the rotation angle of the corresponding local system.
195   //
196   // For global radial position inside the beam pipe, alpha is the
197   // azimuthal angle of the momentum projected on (x,y).
198   //
199   // For global radial position outside the ITS, alpha is the
200   // azimuthal angle of the centre of the TPC sector in which the point
201   // xyz lies
202   //
203   const double kSafe = 1e-5;
204   Double_t radPos2 = xyz[0]*xyz[0]+xyz[1]*xyz[1];  
205   Double_t radMax  = 45.; // approximately ITS outer radius
206   if (radPos2 < radMax*radMax) { // inside the ITS     
207      fAlpha = TMath::ATan2(pxpypz[1],pxpypz[0]);
208   } else { // outside the ITS
209      Float_t phiPos = TMath::Pi()+TMath::ATan2(-xyz[1], -xyz[0]);
210      fAlpha = 
211      TMath::DegToRad()*(20*((((Int_t)(phiPos*TMath::RadToDeg()))/20))+10);
212   }
213   //
214   Double_t cs=TMath::Cos(fAlpha), sn=TMath::Sin(fAlpha);
215   // protection:  avoid alpha being too close to 0 or +-pi/2
216   if (TMath::Abs(sn)<2*kSafe) {
217     if (fAlpha>0) fAlpha += fAlpha< TMath::Pi()/2. ?  2*kSafe : -2*kSafe;
218     else          fAlpha += fAlpha>-TMath::Pi()/2. ? -2*kSafe :  2*kSafe;
219     cs=TMath::Cos(fAlpha);
220     sn=TMath::Sin(fAlpha);
221   }
222   else if (TMath::Abs(cs)<2*kSafe) {
223     if (fAlpha>0) fAlpha += fAlpha> TMath::Pi()/2. ? 2*kSafe : -2*kSafe;
224     else          fAlpha += fAlpha>-TMath::Pi()/2. ? 2*kSafe : -2*kSafe;
225     cs=TMath::Cos(fAlpha);
226     sn=TMath::Sin(fAlpha);
227   }
228   // Get the vertex of origin and the momentum
229   TVector3 ver(xyz[0],xyz[1],xyz[2]);
230   TVector3 mom(pxpypz[0],pxpypz[1],pxpypz[2]);
231   //
232   // avoid momenta along axis
233   if (TMath::Abs(mom[0])<kSafe) mom[0] = TMath::Sign(kSafe*TMath::Abs(mom[1]), mom[0]);
234   if (TMath::Abs(mom[1])<kSafe) mom[1] = TMath::Sign(kSafe*TMath::Abs(mom[0]), mom[1]);
235
236   // Rotate to the local coordinate system
237   ver.RotateZ(-fAlpha);
238   mom.RotateZ(-fAlpha);
239
240   //
241   // x of the reference plane
242   fX = ver.X();
243
244   Double_t charge = (Double_t)sign;
245
246   fP[0] = ver.Y();
247   fP[1] = ver.Z();
248   fP[2] = TMath::Sin(mom.Phi());
249   fP[3] = mom.Pz()/mom.Pt();
250   fP[4] = TMath::Sign(1/mom.Pt(),charge);
251   //
252   if      (TMath::Abs( 1-fP[2]) < 3*kSafe) fP[2] = 1.- 3*kSafe; //Protection
253   else if (TMath::Abs(-1-fP[2]) < 3*kSafe) fP[2] =-1.+ 3*kSafe; //Protection
254   //
255   // Covariance matrix (formulas to be simplified)
256   Double_t pt=1./TMath::Abs(fP[4]);
257   // avoid alpha+phi being to close to +-pi/2 in the cov.matrix evaluation
258   double fp2 = fP[2];
259   Double_t r=TMath::Sqrt((1.-fp2)*(1.+fp2));
260   //
261   Double_t m00=-sn;// m10=cs;
262   Double_t m23=-pt*(sn + fp2*cs/r), m43=-pt*pt*(r*cs - fp2*sn);
263   Double_t m24= pt*(cs - fp2*sn/r), m44=-pt*pt*(r*sn + fp2*cs);
264   Double_t m35=pt, m45=-pt*pt*fP[3];
265
266   m43*=GetSign();
267   m44*=GetSign();
268   m45*=GetSign();
269
270   Double_t cv34 = TMath::Sqrt(cv[3 ]*cv[3 ]+cv[4 ]*cv[4 ]);
271   Double_t a1=cv[13]-cv[9]*(m23*m44+m43*m24)/m23/m43;
272   Double_t a2=m23*m24-m23*(m23*m44+m43*m24)/m43;
273   Double_t a3=m43*m44-m43*(m23*m44+m43*m24)/m23;
274   Double_t a4=cv[14]+2.*cv[9]; //cv[14]-2.*cv[9]*m24*m44/m23/m43;
275   Double_t a5=m24*m24-2.*m24*m44*m23/m43;
276   Double_t a6=m44*m44-2.*m24*m44*m43/m23;
277
278   fC[0 ] = cv[0 ]+cv[2 ];  
279   fC[1 ] = TMath::Sign(cv34,cv[3 ]/m00); 
280   fC[2 ] = cv[5 ]; 
281   fC[3 ] = (cv[10]*m43-cv[6]*m44)/(m24*m43-m23*m44)/m00; 
282   fC[10] = (cv[6]/m00-fC[3 ]*m23)/m43; 
283   fC[6 ] = (cv[15]/m00-fC[10]*m45)/m35; 
284   fC[4 ] = (cv[12]*m43-cv[8]*m44)/(m24*m43-m23*m44); 
285   fC[11] = (cv[8]-fC[4]*m23)/m43; 
286   fC[7 ] = cv[17]/m35-fC[11]*m45/m35; 
287   fC[5 ] = TMath::Abs((a4*a3-a6*a1)/(a5*a3-a6*a2));
288   fC[14] = TMath::Abs((a1-a2*fC[5])/a3);
289   fC[12] = (cv[9]-fC[5]*m23*m23-fC[14]*m43*m43)/m23/m43;
290   Double_t b1=cv[18]-fC[12]*m23*m45-fC[14]*m43*m45;
291   Double_t b2=m23*m35;
292   Double_t b3=m43*m35;
293   Double_t b4=cv[19]-fC[12]*m24*m45-fC[14]*m44*m45;
294   Double_t b5=m24*m35;
295   Double_t b6=m44*m35;
296   fC[8 ] = (b4-b6*b1/b3)/(b5-b6*b2/b3);
297   fC[13] = b1/b3-b2*fC[8]/b3;
298   fC[9 ] = TMath::Abs((cv[20]-fC[14]*(m45*m45)-fC[13]*2.*m35*m45)/(m35*m35));
299
300   CheckCovariance();
301
302   return;
303 }
304 */
305
306 //_____________________________________________________________________________
307 void AliExternalTrackParam::Set(Double_t xyz[3],Double_t pxpypz[3],
308                                 Double_t cv[21],Short_t sign) 
309 {
310   //
311   // create external track parameters from the global parameters
312   // x,y,z,px,py,pz and their 6x6 covariance matrix
313   // A.Dainese 10.10.08
314
315   // Calculate alpha: the rotation angle of the corresponding local system.
316   //
317   // For global radial position inside the beam pipe, alpha is the
318   // azimuthal angle of the momentum projected on (x,y).
319   //
320   // For global radial position outside the ITS, alpha is the
321   // azimuthal angle of the centre of the TPC sector in which the point
322   // xyz lies
323   //
324   const double kSafe = 1e-5;
325   Double_t radPos2 = xyz[0]*xyz[0]+xyz[1]*xyz[1];  
326   Double_t radMax  = 45.; // approximately ITS outer radius
327   if (radPos2 < radMax*radMax) { // inside the ITS     
328      fAlpha = TMath::ATan2(pxpypz[1],pxpypz[0]);
329   } else { // outside the ITS
330      Float_t phiPos = TMath::Pi()+TMath::ATan2(-xyz[1], -xyz[0]);
331      fAlpha = 
332      TMath::DegToRad()*(20*((((Int_t)(phiPos*TMath::RadToDeg()))/20))+10);
333   }
334   //
335   Double_t cs=TMath::Cos(fAlpha), sn=TMath::Sin(fAlpha);
336   // protection:  avoid alpha being too close to 0 or +-pi/2
337   if (TMath::Abs(sn)<2*kSafe) {
338     if (fAlpha>0) fAlpha += fAlpha< TMath::Pi()/2. ?  2*kSafe : -2*kSafe;
339     else          fAlpha += fAlpha>-TMath::Pi()/2. ? -2*kSafe :  2*kSafe;
340     cs=TMath::Cos(fAlpha);
341     sn=TMath::Sin(fAlpha);
342   }
343   else if (TMath::Abs(cs)<2*kSafe) {
344     if (fAlpha>0) fAlpha += fAlpha> TMath::Pi()/2. ? 2*kSafe : -2*kSafe;
345     else          fAlpha += fAlpha>-TMath::Pi()/2. ? 2*kSafe : -2*kSafe;
346     cs=TMath::Cos(fAlpha);
347     sn=TMath::Sin(fAlpha);
348   }
349   // Get the vertex of origin and the momentum
350   TVector3 ver(xyz[0],xyz[1],xyz[2]);
351   TVector3 mom(pxpypz[0],pxpypz[1],pxpypz[2]);
352   //
353   // Rotate to the local coordinate system
354   ver.RotateZ(-fAlpha);
355   mom.RotateZ(-fAlpha);
356
357   //
358   // x of the reference plane
359   fX = ver.X();
360
361   Double_t charge = (Double_t)sign;
362
363   fP[0] = ver.Y();
364   fP[1] = ver.Z();
365   fP[2] = TMath::Sin(mom.Phi());
366   fP[3] = mom.Pz()/mom.Pt();
367   fP[4] = TMath::Sign(1/mom.Pt(),charge);
368   //
369   if      (TMath::Abs( 1-fP[2]) < kSafe) fP[2] = 1.- kSafe; //Protection
370   else if (TMath::Abs(-1-fP[2]) < kSafe) fP[2] =-1.+ kSafe; //Protection
371   //
372   // Covariance matrix (formulas to be simplified)
373   Double_t pt=1./TMath::Abs(fP[4]);
374   Double_t r=TMath::Sqrt((1.-fP[2])*(1.+fP[2]));
375   //
376   Double_t cv34 = TMath::Sqrt(cv[3 ]*cv[3 ]+cv[4 ]*cv[4 ]);
377   //
378   Int_t special = 0;
379   double sgcheck = r*sn + fP[2]*cs;
380   if (TMath::Abs(sgcheck)>=1-kSafe) { // special case: lab phi is +-pi/2
381     special = 1;
382     sgcheck = TMath::Sign(1.0,sgcheck);
383   }
384   else if (TMath::Abs(sgcheck)<kSafe) {
385     sgcheck = TMath::Sign(1.0,cs);
386     special = 2;   // special case: lab phi is 0
387   }
388   //
389   fC[0 ] = cv[0 ]+cv[2 ];  
390   fC[1 ] = TMath::Sign(cv34,-cv[3 ]*sn); 
391   fC[2 ] = cv[5 ]; 
392   //
393   if (special==1) {
394     double pti = 1./pt;
395     double pti2 = pti*pti;
396     int q = GetSign();
397     fC[3 ] = cv[6]*pti;
398     fC[4 ] = -sgcheck*cv[8]*r*pti;
399     fC[5 ] = TMath::Abs(cv[9]*r*r*pti2);
400     fC[6 ] = (cv[10]*fP[3]-sgcheck*cv[15])*pti/r;
401     fC[7 ] = (cv[17]-sgcheck*cv[12]*fP[3])*pti;
402     fC[8 ] = (-sgcheck*cv[18]+cv[13]*fP[3])*r*pti2;
403     fC[9 ] = TMath::Abs( cv[20]-2*sgcheck*cv[19]*fP[3]+cv[14]*fP[3]*fP[3])*pti2;
404     fC[10] = cv[10]*pti2/r*q;
405     fC[11] = -sgcheck*cv[12]*pti2*q;
406     fC[12] = cv[13]*r*pti*pti2*q;
407     fC[13] = (-sgcheck*cv[19]+cv[14]*fP[3])*r*pti2*pti;
408     fC[14] = TMath::Abs(cv[14]*pti2*pti2);
409   } else if (special==2) {
410     double pti = 1./pt;
411     double pti2 = pti*pti;
412     int q = GetSign();
413     fC[3 ] = -cv[10]*pti*cs/sn;
414     fC[4 ] = cv[12]*cs*pti;
415     fC[5 ] = TMath::Abs(cv[14]*cs*cs*pti2);
416     fC[6 ] = (sgcheck*cv[6]*fP[3]-cv[15])*pti/sn;
417     fC[7 ] = (cv[17]-sgcheck*cv[8]*fP[3])*pti;
418     fC[8 ] = (cv[19]-sgcheck*cv[13]*fP[3])*cs*pti2;
419     fC[9 ] = TMath::Abs( cv[20]-2*sgcheck*cv[18]*fP[3]+cv[9]*fP[3]*fP[3])*pti2;
420     fC[10] = sgcheck*cv[6]*pti2/sn*q;
421     fC[11] = -sgcheck*cv[8]*pti2*q;
422     fC[12] = -sgcheck*cv[13]*cs*pti*pti2*q;
423     fC[13] = (-sgcheck*cv[18]+cv[9]*fP[3])*pti2*pti*q;
424     fC[14] = TMath::Abs(cv[9]*pti2*pti2);
425   }
426   else {
427     Double_t m00=-sn;// m10=cs;
428     Double_t m23=-pt*(sn + fP[2]*cs/r), m43=-pt*pt*(r*cs - fP[2]*sn);
429     Double_t m24= pt*(cs - fP[2]*sn/r), m44=-pt*pt*(r*sn + fP[2]*cs);
430     Double_t m35=pt, m45=-pt*pt*fP[3];
431     //
432     m43*=GetSign();
433     m44*=GetSign();
434     m45*=GetSign();
435     //
436     Double_t a1=cv[13]-cv[9]*(m23*m44+m43*m24)/m23/m43;
437     Double_t a2=m23*m24-m23*(m23*m44+m43*m24)/m43;
438     Double_t a3=m43*m44-m43*(m23*m44+m43*m24)/m23;
439     Double_t a4=cv[14]+2.*cv[9]; //cv[14]-2.*cv[9]*m24*m44/m23/m43;
440     Double_t a5=m24*m24-2.*m24*m44*m23/m43;
441     Double_t a6=m44*m44-2.*m24*m44*m43/m23;
442     //    
443     fC[3 ] = (cv[10]*m43-cv[6]*m44)/(m24*m43-m23*m44)/m00; 
444     fC[10] = (cv[6]/m00-fC[3 ]*m23)/m43; 
445     fC[6 ] = (cv[15]/m00-fC[10]*m45)/m35; 
446     fC[4 ] = (cv[12]*m43-cv[8]*m44)/(m24*m43-m23*m44); 
447     fC[11] = (cv[8]-fC[4]*m23)/m43; 
448     fC[7 ] = cv[17]/m35-fC[11]*m45/m35; 
449     fC[5 ] = TMath::Abs((a4*a3-a6*a1)/(a5*a3-a6*a2));
450     fC[14] = TMath::Abs((a1-a2*fC[5])/a3);
451     fC[12] = (cv[9]-fC[5]*m23*m23-fC[14]*m43*m43)/m23/m43;
452     Double_t b1=cv[18]-fC[12]*m23*m45-fC[14]*m43*m45;
453     Double_t b2=m23*m35;
454     Double_t b3=m43*m35;
455     Double_t b4=cv[19]-fC[12]*m24*m45-fC[14]*m44*m45;
456     Double_t b5=m24*m35;
457     Double_t b6=m44*m35;
458     fC[8 ] = (b4-b6*b1/b3)/(b5-b6*b2/b3);
459     fC[13] = b1/b3-b2*fC[8]/b3;
460     fC[9 ] = TMath::Abs((cv[20]-fC[14]*(m45*m45)-fC[13]*2.*m35*m45)/(m35*m35));
461   }
462   CheckCovariance();
463
464   return;
465 }
466
467 //_____________________________________________________________________________
468 void AliExternalTrackParam::Reset() {
469   //
470   // Resets all the parameters to 0 
471   //
472   fX=fAlpha=0.;
473   for (Int_t i = 0; i < 5; i++) fP[i] = 0;
474   for (Int_t i = 0; i < 15; i++) fC[i] = 0;
475 }
476
477 //_____________________________________________________________________________
478 void AliExternalTrackParam::AddCovariance(const Double_t c[15]) {
479   //
480   // Add "something" to the track covarince matrix.
481   // May be needed to account for unknown mis-calibration/mis-alignment
482   //
483     fC[0] +=c[0];
484     fC[1] +=c[1];  fC[2] +=c[2];
485     fC[3] +=c[3];  fC[4] +=c[4];  fC[5] +=c[5];
486     fC[6] +=c[6];  fC[7] +=c[7];  fC[8] +=c[8];  fC[9] +=c[9];
487     fC[10]+=c[10]; fC[11]+=c[11]; fC[12]+=c[12]; fC[13]+=c[13]; fC[14]+=c[14];
488     CheckCovariance();
489 }
490
491
492 Double_t AliExternalTrackParam::GetP() const {
493   //---------------------------------------------------------------------
494   // This function returns the track momentum
495   // Results for (nearly) straight tracks are meaningless !
496   //---------------------------------------------------------------------
497   if (TMath::Abs(fP[4])<=kAlmost0) return kVeryBig;
498   return TMath::Sqrt(1.+ fP[3]*fP[3])/TMath::Abs(fP[4]);
499 }
500
501 Double_t AliExternalTrackParam::Get1P() const {
502   //---------------------------------------------------------------------
503   // This function returns the 1/(track momentum)
504   //---------------------------------------------------------------------
505   return TMath::Abs(fP[4])/TMath::Sqrt(1.+ fP[3]*fP[3]);
506 }
507
508 //_______________________________________________________________________
509 Double_t AliExternalTrackParam::GetD(Double_t x,Double_t y,Double_t b) const {
510   //------------------------------------------------------------------
511   // This function calculates the transverse impact parameter
512   // with respect to a point with global coordinates (x,y)
513   // in the magnetic field "b" (kG)
514   //------------------------------------------------------------------
515   if (TMath::Abs(b) < kAlmost0Field) return GetLinearD(x,y);
516   Double_t rp4=GetC(b);
517
518   Double_t xt=fX, yt=fP[0];
519
520   Double_t sn=TMath::Sin(fAlpha), cs=TMath::Cos(fAlpha);
521   Double_t a = x*cs + y*sn;
522   y = -x*sn + y*cs; x=a;
523   xt-=x; yt-=y;
524
525   sn=rp4*xt - fP[2]; cs=rp4*yt + TMath::Sqrt((1.- fP[2])*(1.+fP[2]));
526   a=2*(xt*fP[2] - yt*TMath::Sqrt((1.-fP[2])*(1.+fP[2])))-rp4*(xt*xt + yt*yt);
527   return  -a/(1 + TMath::Sqrt(sn*sn + cs*cs));
528 }
529
530 //_______________________________________________________________________
531 void AliExternalTrackParam::
532 GetDZ(Double_t x, Double_t y, Double_t z, Double_t b, Float_t dz[2]) const {
533   //------------------------------------------------------------------
534   // This function calculates the transverse and longitudinal impact parameters
535   // with respect to a point with global coordinates (x,y)
536   // in the magnetic field "b" (kG)
537   //------------------------------------------------------------------
538   Double_t f1 = fP[2], r1 = TMath::Sqrt((1.-f1)*(1.+f1));
539   Double_t xt=fX, yt=fP[0];
540   Double_t sn=TMath::Sin(fAlpha), cs=TMath::Cos(fAlpha);
541   Double_t a = x*cs + y*sn;
542   y = -x*sn + y*cs; x=a;
543   xt-=x; yt-=y;
544
545   Double_t rp4=GetC(b);
546   if ((TMath::Abs(b) < kAlmost0Field) || (TMath::Abs(rp4) < kAlmost0)) {
547      dz[0] = -(xt*f1 - yt*r1);
548      dz[1] = fP[1] + (dz[0]*f1 - xt)/r1*fP[3] - z;
549      return;
550   }
551
552   sn=rp4*xt - f1; cs=rp4*yt + r1;
553   a=2*(xt*f1 - yt*r1)-rp4*(xt*xt + yt*yt);
554   Double_t rr=TMath::Sqrt(sn*sn + cs*cs);
555   dz[0] = -a/(1 + rr);
556   Double_t f2 = -sn/rr, r2 = TMath::Sqrt((1.-f2)*(1.+f2));
557   dz[1] = fP[1] + fP[3]/rp4*TMath::ASin(f2*r1 - f1*r2) - z;
558 }
559
560 //_______________________________________________________________________
561 Double_t AliExternalTrackParam::GetLinearD(Double_t xv,Double_t yv) const {
562   //------------------------------------------------------------------
563   // This function calculates the transverse impact parameter
564   // with respect to a point with global coordinates (xv,yv)
565   // neglecting the track curvature.
566   //------------------------------------------------------------------
567   Double_t sn=TMath::Sin(fAlpha), cs=TMath::Cos(fAlpha);
568   Double_t x= xv*cs + yv*sn;
569   Double_t y=-xv*sn + yv*cs;
570
571   Double_t d = (fX-x)*fP[2] - (fP[0]-y)*TMath::Sqrt((1.-fP[2])*(1.+fP[2]));
572
573   return -d;
574 }
575
576 Bool_t AliExternalTrackParam::CorrectForMeanMaterialdEdx
577 (Double_t xOverX0,  Double_t xTimesRho, Double_t mass, 
578  Double_t dEdx,
579  Bool_t anglecorr) {
580   //------------------------------------------------------------------
581   // This function corrects the track parameters for the crossed material.
582   // "xOverX0"   - X/X0, the thickness in units of the radiation length.
583   // "xTimesRho" - is the product length*density (g/cm^2).
584   //     It should be passed as negative when propagating tracks 
585   //     from the intreaction point to the outside of the central barrel. 
586   // "mass" - the mass of this particle (GeV/c^2). Negative mass means charge=2 particle
587   // "dEdx" - mean enery loss (GeV/(g/cm^2)
588   // "anglecorr" - switch for the angular correction
589   //------------------------------------------------------------------
590   Double_t &fP2=fP[2];
591   Double_t &fP3=fP[3];
592   Double_t &fP4=fP[4];
593
594   Double_t &fC22=fC[5];
595   Double_t &fC33=fC[9];
596   Double_t &fC43=fC[13];
597   Double_t &fC44=fC[14];
598
599   //Apply angle correction, if requested
600   if(anglecorr) {
601     Double_t angle=TMath::Sqrt((1.+ fP3*fP3)/((1-fP2)*(1.+fP2)));
602     xOverX0 *=angle;
603     xTimesRho *=angle;
604   } 
605
606   Double_t p=GetP();
607   if (mass<0) p += p; // q=2 particle 
608   Double_t p2=p*p;
609   Double_t beta2=p2/(p2 + mass*mass);
610
611   //Calculating the multiple scattering corrections******************
612   Double_t cC22 = 0.;
613   Double_t cC33 = 0.;
614   Double_t cC43 = 0.;
615   Double_t cC44 = 0.;
616   if (xOverX0 != 0) {
617     //Double_t theta2=1.0259e-6*14*14/28/(beta2*p2)*TMath::Abs(d)*9.36*2.33;
618     Double_t theta2=0.0136*0.0136/(beta2*p2)*TMath::Abs(xOverX0);
619     if (GetUseLogTermMS()) {
620       double lt = 1+0.038*TMath::Log(TMath::Abs(xOverX0));
621       if (lt>0) theta2 *= lt*lt;
622     }
623     if (mass<0) theta2 *= 4; // q=2 particle
624     if(theta2>TMath::Pi()*TMath::Pi()) return kFALSE;
625     cC22 = theta2*((1.-fP2)*(1.+fP2))*(1. + fP3*fP3);
626     cC33 = theta2*(1. + fP3*fP3)*(1. + fP3*fP3);
627     cC43 = theta2*fP3*fP4*(1. + fP3*fP3);
628     cC44 = theta2*fP3*fP4*fP3*fP4;
629   }
630
631   //Calculating the energy loss corrections************************
632   Double_t cP4=1.;
633   if ((xTimesRho != 0.) && (beta2 < 1.)) {
634      Double_t dE=dEdx*xTimesRho;
635      Double_t e=TMath::Sqrt(p2 + mass*mass);
636      if ( TMath::Abs(dE) > 0.3*e ) return kFALSE; //30% energy loss is too much!
637      if ( (1.+ dE/p2*(dE + 2*e)) < 0. ) return kFALSE;
638      cP4 = 1./TMath::Sqrt(1.+ dE/p2*(dE + 2*e));  //A precise formula by Ruben !
639      if (TMath::Abs(fP4*cP4)>100.) return kFALSE; //Do not track below 10 MeV/c
640
641
642      // Approximate energy loss fluctuation (M.Ivanov)
643      const Double_t knst=0.07; // To be tuned.  
644      Double_t sigmadE=knst*TMath::Sqrt(TMath::Abs(dE)); 
645      cC44 += ((sigmadE*e/p2*fP4)*(sigmadE*e/p2*fP4)); 
646  
647   }
648
649   //Applying the corrections*****************************
650   fC22 += cC22;
651   fC33 += cC33;
652   fC43 += cC43;
653   fC44 += cC44;
654   fP4  *= cP4;
655
656   CheckCovariance();
657
658   return kTRUE;
659 }
660
661 Bool_t AliExternalTrackParam::CorrectForMeanMaterial
662 (Double_t xOverX0,  Double_t xTimesRho, Double_t mass, 
663  Bool_t anglecorr,
664  Double_t (*Bethe)(Double_t)) {
665   //------------------------------------------------------------------
666   // This function corrects the track parameters for the crossed material.
667   // "xOverX0"   - X/X0, the thickness in units of the radiation length.
668   // "xTimesRho" - is the product length*density (g/cm^2). 
669   //     It should be passed as negative when propagating tracks 
670   //     from the intreaction point to the outside of the central barrel. 
671   // "mass" - the mass of this particle (GeV/c^2). mass<0 means charge=2
672   // "anglecorr" - switch for the angular correction
673   // "Bethe" - function calculating the energy loss (GeV/(g/cm^2)) 
674   //------------------------------------------------------------------
675
676   Double_t bg=GetP()/mass;
677   if (mass<0) {
678     if (mass<-990) {
679       AliDebug(2,Form("Mass %f corresponds to unknown PID particle",mass));
680       return kFALSE;
681     }
682     bg = -2*bg;
683   }
684   Double_t dEdx=Bethe(bg);
685   if (mass<0) dEdx *= 4;
686
687   return CorrectForMeanMaterialdEdx(xOverX0,xTimesRho,mass,dEdx,anglecorr);
688 }
689
690 Bool_t AliExternalTrackParam::CorrectForMeanMaterialZA
691 (Double_t xOverX0, Double_t xTimesRho, Double_t mass,
692  Double_t zOverA,
693  Double_t density,
694  Double_t exEnergy,
695  Double_t jp1,
696  Double_t jp2,
697  Bool_t anglecorr) {
698   //------------------------------------------------------------------
699   // This function corrects the track parameters for the crossed material
700   // using the full Geant-like Bethe-Bloch formula parameterization
701   // "xOverX0"   - X/X0, the thickness in units of the radiation length.
702   // "xTimesRho" - is the product length*density (g/cm^2). 
703   //     It should be passed as negative when propagating tracks 
704   //     from the intreaction point to the outside of the central barrel. 
705   // "mass" - the mass of this particle (GeV/c^2). mass<0 means charge=2 particle
706   // "density"  - mean density (g/cm^3)
707   // "zOverA"   - mean Z/A
708   // "exEnergy" - mean exitation energy (GeV)
709   // "jp1"      - density effect first junction point
710   // "jp2"      - density effect second junction point
711   // "anglecorr" - switch for the angular correction
712   //
713   //  The default values of the parameters are for silicon 
714   //
715   //------------------------------------------------------------------
716
717   Double_t bg=GetP()/mass;
718   if (mass<0) {
719     if (mass<-990) {
720       AliDebug(2,Form("Mass %f corresponds to unknown PID particle",mass));
721       return kFALSE;
722     }
723     bg = -2*bg;
724   }
725   Double_t dEdx=BetheBlochGeant(bg,density,jp1,jp2,exEnergy,zOverA);
726
727   if (mass<0) dEdx *= 4;
728   return CorrectForMeanMaterialdEdx(xOverX0,xTimesRho,mass,dEdx,anglecorr);
729 }
730
731
732
733 Bool_t AliExternalTrackParam::CorrectForMaterial
734 (Double_t d,  Double_t x0, Double_t mass, Double_t (*Bethe)(Double_t)) {
735   //------------------------------------------------------------------
736   //                    Deprecated function !   
737   //       Better use CorrectForMeanMaterial instead of it.
738   //
739   // This function corrects the track parameters for the crossed material
740   // "d"    - the thickness (fraction of the radiation length)
741   //     It should be passed as negative when propagating tracks 
742   //     from the intreaction point to the outside of the central barrel. 
743   // "x0"   - the radiation length (g/cm^2) 
744   // "mass" - the mass of this particle (GeV/c^2)
745   //------------------------------------------------------------------
746
747   return CorrectForMeanMaterial(d,x0*d,mass,kTRUE,Bethe);
748
749 }
750
751 Double_t AliExternalTrackParam::BetheBlochAleph(Double_t bg,
752          Double_t kp1,
753          Double_t kp2,
754          Double_t kp3,
755          Double_t kp4,
756          Double_t kp5) {
757   //
758   // This is the empirical ALEPH parameterization of the Bethe-Bloch formula.
759   // It is normalized to 1 at the minimum.
760   //
761   // bg - beta*gamma
762   // 
763   // The default values for the kp* parameters are for ALICE TPC.
764   // The returned value is in MIP units
765   //
766
767   Double_t beta = bg/TMath::Sqrt(1.+ bg*bg);
768
769   Double_t aa = TMath::Power(beta,kp4);
770   Double_t bb = TMath::Power(1./bg,kp5);
771
772   bb=TMath::Log(kp3+bb);
773   
774   return (kp2-aa-bb)*kp1/aa;
775 }
776
777 Double_t AliExternalTrackParam::BetheBlochGeant(Double_t bg,
778          Double_t kp0,
779          Double_t kp1,
780          Double_t kp2,
781          Double_t kp3,
782          Double_t kp4) {
783   //
784   // This is the parameterization of the Bethe-Bloch formula inspired by Geant.
785   //
786   // bg  - beta*gamma
787   // kp0 - density [g/cm^3]
788   // kp1 - density effect first junction point
789   // kp2 - density effect second junction point
790   // kp3 - mean excitation energy [GeV]
791   // kp4 - mean Z/A
792   //
793   // The default values for the kp* parameters are for silicon. 
794   // The returned value is in [GeV/(g/cm^2)].
795   // 
796
797   const Double_t mK  = 0.307075e-3; // [GeV*cm^2/g]
798   const Double_t me  = 0.511e-3;    // [GeV/c^2]
799   const Double_t rho = kp0;
800   const Double_t x0  = kp1*2.303;
801   const Double_t x1  = kp2*2.303;
802   const Double_t mI  = kp3;
803   const Double_t mZA = kp4;
804   const Double_t bg2 = bg*bg;
805   const Double_t maxT= 2*me*bg2;    // neglecting the electron mass
806   
807   //*** Density effect
808   Double_t d2=0.; 
809   const Double_t x=TMath::Log(bg);
810   const Double_t lhwI=TMath::Log(28.816*1e-9*TMath::Sqrt(rho*mZA)/mI);
811   if (x > x1) {
812     d2 = lhwI + x - 0.5;
813   } else if (x > x0) {
814     const Double_t r=(x1-x)/(x1-x0);
815     d2 = lhwI + x - 0.5 + (0.5 - lhwI - x0)*r*r*r;
816   }
817
818   return mK*mZA*(1+bg2)/bg2*
819          (0.5*TMath::Log(2*me*bg2*maxT/(mI*mI)) - bg2/(1+bg2) - d2);
820 }
821
822 Double_t AliExternalTrackParam::BetheBlochSolid(Double_t bg) {
823   //------------------------------------------------------------------
824   // This is an approximation of the Bethe-Bloch formula, 
825   // reasonable for solid materials. 
826   // All the parameters are, in fact, for Si.
827   // The returned value is in [GeV/(g/cm^2)]
828   //------------------------------------------------------------------
829
830   return BetheBlochGeant(bg);
831 }
832
833 Double_t AliExternalTrackParam::BetheBlochGas(Double_t bg) {
834   //------------------------------------------------------------------
835   // This is an approximation of the Bethe-Bloch formula, 
836   // reasonable for gas materials.
837   // All the parameters are, in fact, for Ne.
838   // The returned value is in [GeV/(g/cm^2)]
839   //------------------------------------------------------------------
840
841   const Double_t rho = 0.9e-3;
842   const Double_t x0  = 2.;
843   const Double_t x1  = 4.;
844   const Double_t mI  = 140.e-9;
845   const Double_t mZA = 0.49555;
846
847   return BetheBlochGeant(bg,rho,x0,x1,mI,mZA);
848 }
849
850 Bool_t AliExternalTrackParam::Rotate(Double_t alpha) {
851   //------------------------------------------------------------------
852   // Transform this track to the local coord. system rotated
853   // by angle "alpha" (rad) with respect to the global coord. system. 
854   //------------------------------------------------------------------
855   if (TMath::Abs(fP[2]) >= kAlmost1) {
856      AliError(Form("Precondition is not satisfied: |sin(phi)|>1 ! %f",fP[2])); 
857      return kFALSE;
858   }
859  
860   if      (alpha < -TMath::Pi()) alpha += 2*TMath::Pi();
861   else if (alpha >= TMath::Pi()) alpha -= 2*TMath::Pi();
862
863   Double_t &fP0=fP[0];
864   Double_t &fP2=fP[2];
865   Double_t &fC00=fC[0];
866   Double_t &fC10=fC[1];
867   Double_t &fC20=fC[3];
868   Double_t &fC21=fC[4];
869   Double_t &fC22=fC[5];
870   Double_t &fC30=fC[6];
871   Double_t &fC32=fC[8];
872   Double_t &fC40=fC[10];
873   Double_t &fC42=fC[12];
874
875   Double_t x=fX;
876   Double_t ca=TMath::Cos(alpha-fAlpha), sa=TMath::Sin(alpha-fAlpha);
877   Double_t sf=fP2, cf=TMath::Sqrt((1.- fP2)*(1.+fP2)); // Improve precision
878   // RS: check if rotation does no invalidate track model (cos(local_phi)>=0, i.e. particle
879   // direction in local frame is along the X axis
880   if ((cf*ca+sf*sa)<0) {
881     AliDebug(1,Form("Rotation failed: local cos(phi) would become %.2f",cf*ca+sf*sa));
882     return kFALSE;
883   }
884   //
885   Double_t tmp=sf*ca - cf*sa;
886
887   if (TMath::Abs(tmp) >= kAlmost1) {
888      if (TMath::Abs(tmp) > 1.+ Double_t(FLT_EPSILON))  
889         AliWarning(Form("Rotation failed ! %.10e",tmp));
890      return kFALSE;
891   }
892   fAlpha = alpha;
893   fX =  x*ca + fP0*sa;
894   fP0= -x*sa + fP0*ca;
895   fP2=  tmp;
896
897   if (TMath::Abs(cf)<kAlmost0) {
898     AliError(Form("Too small cosine value %f",cf)); 
899     cf = kAlmost0;
900   } 
901
902   Double_t rr=(ca+sf/cf*sa);  
903
904   fC00 *= (ca*ca);
905   fC10 *= ca;
906   fC20 *= ca*rr;
907   fC21 *= rr;
908   fC22 *= rr*rr;
909   fC30 *= ca;
910   fC32 *= rr;
911   fC40 *= ca;
912   fC42 *= rr;
913
914   CheckCovariance();
915
916   return kTRUE;
917 }
918
919 //______________________________________________________
920 Bool_t AliExternalTrackParam::RotateParamOnly(Double_t alpha)
921 {
922   // rotate to new frame, ignore covariance
923   if (TMath::Abs(fP[2]) >= kAlmost1) {
924     AliError(Form("Precondition is not satisfied: |sin(phi)|>1 ! %f",fP[2])); 
925     return kFALSE;
926   }
927   //
928   if      (alpha < -TMath::Pi()) alpha += 2*TMath::Pi();
929   else if (alpha >= TMath::Pi()) alpha -= 2*TMath::Pi();
930   //
931   Double_t &fP0=fP[0];
932   Double_t &fP2=fP[2];
933   //
934   Double_t x=fX;
935   Double_t ca=TMath::Cos(alpha-fAlpha), sa=TMath::Sin(alpha-fAlpha);
936   Double_t sf=fP2, cf=TMath::Sqrt((1.- fP2)*(1.+fP2)); // Improve precision
937   // RS: check if rotation does no invalidate track model (cos(local_phi)>=0, i.e. particle
938   // direction in local frame is along the X axis
939   if ((cf*ca+sf*sa)<0) {
940     AliDebug(1,Form("Rotation failed: local cos(phi) would become %.2f",cf*ca+sf*sa));
941     return kFALSE;
942   }
943   //
944   Double_t tmp=sf*ca - cf*sa;
945
946   if (TMath::Abs(tmp) >= kAlmost1) {
947      if (TMath::Abs(tmp) > 1.+ Double_t(FLT_EPSILON))  
948         AliWarning(Form("Rotation failed ! %.10e",tmp));
949      return kFALSE;
950   }
951   fAlpha = alpha;
952   fX =  x*ca + fP0*sa;
953   fP0= -x*sa + fP0*ca;
954   fP2=  tmp;
955   return kTRUE;
956 }
957
958 Bool_t AliExternalTrackParam::Invert() {
959   //------------------------------------------------------------------
960   // Transform this track to the local coord. system rotated by 180 deg. 
961   //------------------------------------------------------------------
962   fX = -fX;
963   fAlpha += TMath::Pi();
964   while (fAlpha < -TMath::Pi()) fAlpha += 2*TMath::Pi();
965   while (fAlpha >= TMath::Pi()) fAlpha -= 2*TMath::Pi();
966   //
967   fP[0] = -fP[0];
968   //fP[2] = -fP[2];
969   fP[3] = -fP[3];
970   fP[4] = -fP[4];
971   //
972   fC[1] = -fC[1]; // since the fP1 and fP2 are not inverted, their covariances with others change sign
973   fC[3] = -fC[3];
974   fC[7] = -fC[7];
975   fC[8] = -fC[8]; 
976   fC[11] = -fC[11]; 
977   fC[12] = -fC[12]; 
978   //
979   return kTRUE;
980 }
981
982 Bool_t AliExternalTrackParam::PropagateTo(Double_t xk, Double_t b) {
983   //----------------------------------------------------------------
984   // Propagate this track to the plane X=xk (cm) in the field "b" (kG)
985   //----------------------------------------------------------------
986   Double_t dx=xk-fX;
987   if (TMath::Abs(dx)<=kAlmost0)  return kTRUE;
988
989   Double_t crv=GetC(b);
990   if (TMath::Abs(b) < kAlmost0Field) crv=0.;
991
992   Double_t x2r = crv*dx;
993   Double_t f1=fP[2], f2=f1 + x2r;
994   if (TMath::Abs(f1) >= kAlmost1) return kFALSE;
995   if (TMath::Abs(f2) >= kAlmost1) return kFALSE;
996   if (TMath::Abs(fP[4])< kAlmost0) return kFALSE;
997
998   Double_t &fP0=fP[0], &fP1=fP[1], &fP2=fP[2], &fP3=fP[3], &fP4=fP[4];
999   Double_t 
1000   &fC00=fC[0],
1001   &fC10=fC[1],   &fC11=fC[2],  
1002   &fC20=fC[3],   &fC21=fC[4],   &fC22=fC[5],
1003   &fC30=fC[6],   &fC31=fC[7],   &fC32=fC[8],   &fC33=fC[9],  
1004   &fC40=fC[10],  &fC41=fC[11],  &fC42=fC[12],  &fC43=fC[13], &fC44=fC[14];
1005
1006   Double_t r1=TMath::Sqrt((1.-f1)*(1.+f1)), r2=TMath::Sqrt((1.-f2)*(1.+f2));
1007   if (TMath::Abs(r1)<kAlmost0)  return kFALSE;
1008   if (TMath::Abs(r2)<kAlmost0)  return kFALSE;
1009
1010   fX=xk;
1011   double dy2dx = (f1+f2)/(r1+r2);
1012   fP0 += dx*dy2dx;
1013   fP2 += x2r;
1014   if (TMath::Abs(x2r)<0.05) fP1 += dx*(r2 + f2*dy2dx)*fP3;  // Many thanks to P.Hristov !
1015   else { 
1016     // for small dx/R the linear apporximation of the arc by the segment is OK,
1017     // but at large dx/R the error is very large and leads to incorrect Z propagation
1018     // angle traversed delta = 2*asin(dist_start_end / R / 2), hence the arc is: R*deltaPhi
1019     // The dist_start_end is obtained from sqrt(dx^2+dy^2) = x/(r1+r2)*sqrt(2+f1*f2+r1*r2)
1020     //    double chord = dx*TMath::Sqrt(1+dy2dx*dy2dx);   // distance from old position to new one
1021     //    double rot = 2*TMath::ASin(0.5*chord*crv); // angular difference seen from the circle center
1022     //    fP1 += rot/crv*fP3;
1023     // 
1024     fP1 += fP3/crv*TMath::ASin(r1*f2 - r2*f1); // more economic version from Yura.
1025   }
1026
1027   //f = F - 1
1028   /*
1029   Double_t f02=    dx/(r1*r1*r1);            Double_t cc=crv/fP4;
1030   Double_t f04=0.5*dx*dx/(r1*r1*r1);         f04*=cc;
1031   Double_t f12=    dx*fP3*f1/(r1*r1*r1);
1032   Double_t f14=0.5*dx*dx*fP3*f1/(r1*r1*r1);  f14*=cc;
1033   Double_t f13=    dx/r1;
1034   Double_t f24=    dx;                       f24*=cc;
1035   */
1036   Double_t rinv = 1./r1;
1037   Double_t r3inv = rinv*rinv*rinv;
1038   Double_t f24=    x2r/fP4;
1039   Double_t f02=    dx*r3inv;
1040   Double_t f04=0.5*f24*f02;
1041   Double_t f12=    f02*fP3*f1;
1042   Double_t f14=0.5*f24*f02*fP3*f1;
1043   Double_t f13=    dx*rinv;
1044
1045   //b = C*ft
1046   Double_t b00=f02*fC20 + f04*fC40, b01=f12*fC20 + f14*fC40 + f13*fC30;
1047   Double_t b02=f24*fC40;
1048   Double_t b10=f02*fC21 + f04*fC41, b11=f12*fC21 + f14*fC41 + f13*fC31;
1049   Double_t b12=f24*fC41;
1050   Double_t b20=f02*fC22 + f04*fC42, b21=f12*fC22 + f14*fC42 + f13*fC32;
1051   Double_t b22=f24*fC42;
1052   Double_t b40=f02*fC42 + f04*fC44, b41=f12*fC42 + f14*fC44 + f13*fC43;
1053   Double_t b42=f24*fC44;
1054   Double_t b30=f02*fC32 + f04*fC43, b31=f12*fC32 + f14*fC43 + f13*fC33;
1055   Double_t b32=f24*fC43;
1056   
1057   //a = f*b = f*C*ft
1058   Double_t a00=f02*b20+f04*b40,a01=f02*b21+f04*b41,a02=f02*b22+f04*b42;
1059   Double_t a11=f12*b21+f14*b41+f13*b31,a12=f12*b22+f14*b42+f13*b32;
1060   Double_t a22=f24*b42;
1061
1062   //F*C*Ft = C + (b + bt + a)
1063   fC00 += b00 + b00 + a00;
1064   fC10 += b10 + b01 + a01; 
1065   fC20 += b20 + b02 + a02;
1066   fC30 += b30;
1067   fC40 += b40;
1068   fC11 += b11 + b11 + a11;
1069   fC21 += b21 + b12 + a12;
1070   fC31 += b31; 
1071   fC41 += b41;
1072   fC22 += b22 + b22 + a22;
1073   fC32 += b32;
1074   fC42 += b42;
1075
1076   CheckCovariance();
1077
1078   return kTRUE;
1079 }
1080
1081 Bool_t AliExternalTrackParam::PropagateParamOnlyTo(Double_t xk, Double_t b) {
1082   //----------------------------------------------------------------
1083   // Propagate this track to the plane X=xk (cm) in the field "b" (kG)
1084   // Only parameters are propagated, not the matrix. To be used for small 
1085   // distances only (<mm, i.e. misalignment)
1086   //----------------------------------------------------------------
1087   Double_t dx=xk-fX;
1088   if (TMath::Abs(dx)<=kAlmost0)  return kTRUE;
1089
1090   Double_t crv=GetC(b);
1091   if (TMath::Abs(b) < kAlmost0Field) crv=0.;
1092
1093   Double_t x2r = crv*dx;
1094   Double_t f1=fP[2], f2=f1 + x2r;
1095   if (TMath::Abs(f1) >= kAlmost1) return kFALSE;
1096   if (TMath::Abs(f2) >= kAlmost1) return kFALSE;
1097   if (TMath::Abs(fP[4])< kAlmost0) return kFALSE;
1098
1099   Double_t r1=TMath::Sqrt((1.-f1)*(1.+f1)), r2=TMath::Sqrt((1.-f2)*(1.+f2));
1100   if (TMath::Abs(r1)<kAlmost0)  return kFALSE;
1101   if (TMath::Abs(r2)<kAlmost0)  return kFALSE;
1102
1103   fX=xk;
1104   double dy2dx = (f1+f2)/(r1+r2);
1105   fP[0] += dx*dy2dx;
1106   fP[1] += dx*(r2 + f2*dy2dx)*fP[3];  // Many thanks to P.Hristov !
1107   fP[2] += x2r;
1108
1109   return kTRUE;
1110 }
1111
1112 Bool_t 
1113 AliExternalTrackParam::Propagate(Double_t alpha, Double_t x, Double_t b) {
1114   //------------------------------------------------------------------
1115   // Transform this track to the local coord. system rotated
1116   // by angle "alpha" (rad) with respect to the global coord. system, 
1117   // and propagate this track to the plane X=xk (cm) in the field "b" (kG)
1118   //------------------------------------------------------------------
1119   
1120   //Save the parameters
1121   Double_t as=fAlpha;
1122   Double_t xs=fX;
1123   Double_t ps[5], cs[15];
1124   for (Int_t i=0; i<5;  i++) ps[i]=fP[i]; 
1125   for (Int_t i=0; i<15; i++) cs[i]=fC[i]; 
1126
1127   if (Rotate(alpha))
1128      if (PropagateTo(x,b)) return kTRUE;
1129
1130   //Restore the parameters, if the operation failed
1131   fAlpha=as;
1132   fX=xs;
1133   for (Int_t i=0; i<5;  i++) fP[i]=ps[i]; 
1134   for (Int_t i=0; i<15; i++) fC[i]=cs[i]; 
1135   return kFALSE;
1136 }
1137
1138 Bool_t AliExternalTrackParam::PropagateBxByBz
1139 (Double_t alpha, Double_t x, Double_t b[3]) {
1140   //------------------------------------------------------------------
1141   // Transform this track to the local coord. system rotated
1142   // by angle "alpha" (rad) with respect to the global coord. system, 
1143   // and propagate this track to the plane X=xk (cm),
1144   // taking into account all three components of the B field, "b[3]" (kG)
1145   //------------------------------------------------------------------
1146   
1147   //Save the parameters
1148   Double_t as=fAlpha;
1149   Double_t xs=fX;
1150   Double_t ps[5], cs[15];
1151   for (Int_t i=0; i<5;  i++) ps[i]=fP[i]; 
1152   for (Int_t i=0; i<15; i++) cs[i]=fC[i]; 
1153
1154   if (Rotate(alpha))
1155      if (PropagateToBxByBz(x,b)) return kTRUE;
1156
1157   //Restore the parameters, if the operation failed
1158   fAlpha=as;
1159   fX=xs;
1160   for (Int_t i=0; i<5;  i++) fP[i]=ps[i]; 
1161   for (Int_t i=0; i<15; i++) fC[i]=cs[i]; 
1162   return kFALSE;
1163 }
1164
1165
1166 void AliExternalTrackParam::Propagate(Double_t len, Double_t x[3],
1167 Double_t p[3], Double_t bz) const {
1168   //+++++++++++++++++++++++++++++++++++++++++    
1169   // Origin: K. Shileev (Kirill.Shileev@cern.ch)
1170   // Extrapolate track along simple helix in magnetic field
1171   // Arguments: len -distance alogn helix, [cm]
1172   //            bz  - mag field, [kGaus]   
1173   // Returns: x and p contain extrapolated positon and momentum  
1174   // The momentum returned for straight-line tracks is meaningless !
1175   //+++++++++++++++++++++++++++++++++++++++++    
1176   GetXYZ(x);
1177     
1178   if (OneOverPt() < kAlmost0 || TMath::Abs(bz) < kAlmost0Field || GetC(bz) < kAlmost0){ //straight-line tracks
1179      Double_t unit[3]; GetDirection(unit);
1180      x[0]+=unit[0]*len;   
1181      x[1]+=unit[1]*len;   
1182      x[2]+=unit[2]*len;
1183
1184      p[0]=unit[0]/kAlmost0;   
1185      p[1]=unit[1]/kAlmost0;   
1186      p[2]=unit[2]/kAlmost0;   
1187   } else {
1188      GetPxPyPz(p);
1189      Double_t pp=GetP();
1190      Double_t a = -kB2C*bz*GetSign();
1191      Double_t rho = a/pp;
1192      x[0] += p[0]*TMath::Sin(rho*len)/a - p[1]*(1-TMath::Cos(rho*len))/a;
1193      x[1] += p[1]*TMath::Sin(rho*len)/a + p[0]*(1-TMath::Cos(rho*len))/a;
1194      x[2] += p[2]*len/pp;
1195
1196      Double_t p0=p[0];
1197      p[0] = p0  *TMath::Cos(rho*len) - p[1]*TMath::Sin(rho*len);
1198      p[1] = p[1]*TMath::Cos(rho*len) + p0  *TMath::Sin(rho*len);
1199   }
1200 }
1201
1202 Bool_t AliExternalTrackParam::Intersect(Double_t pnt[3], Double_t norm[3],
1203 Double_t bz) const {
1204   //+++++++++++++++++++++++++++++++++++++++++    
1205   // Origin: K. Shileev (Kirill.Shileev@cern.ch)
1206   // Finds point of intersection (if exists) of the helix with the plane. 
1207   // Stores result in fX and fP.   
1208   // Arguments: planePoint,planeNorm - the plane defined by any plane's point 
1209   // and vector, normal to the plane
1210   // Returns: kTrue if helix intersects the plane, kFALSE otherwise.
1211   //+++++++++++++++++++++++++++++++++++++++++    
1212   Double_t x0[3]; GetXYZ(x0); //get track position in MARS
1213   
1214   //estimates initial helix length up to plane
1215   Double_t s=
1216     (pnt[0]-x0[0])*norm[0] + (pnt[1]-x0[1])*norm[1] + (pnt[2]-x0[2])*norm[2];
1217   Double_t dist=99999,distPrev=dist;
1218   Double_t x[3],p[3]; 
1219   while(TMath::Abs(dist)>0.00001){
1220     //calculates helix at the distance s from x0 ALONG the helix
1221     Propagate(s,x,p,bz);
1222
1223     //distance between current helix position and plane
1224     dist=(x[0]-pnt[0])*norm[0]+(x[1]-pnt[1])*norm[1]+(x[2]-pnt[2])*norm[2];
1225
1226     if(TMath::Abs(dist) >= TMath::Abs(distPrev)) {return kFALSE;}
1227     distPrev=dist;
1228     s-=dist;
1229   }
1230   //on exit pnt is intersection point,norm is track vector at that point, 
1231   //all in MARS
1232   for (Int_t i=0; i<3; i++) {pnt[i]=x[i]; norm[i]=p[i];}
1233   return kTRUE;
1234 }
1235
1236 Double_t 
1237 AliExternalTrackParam::GetPredictedChi2(Double_t p[2],Double_t cov[3]) const {
1238   //----------------------------------------------------------------
1239   // Estimate the chi2 of the space point "p" with the cov. matrix "cov"
1240   //----------------------------------------------------------------
1241   Double_t sdd = fC[0] + cov[0]; 
1242   Double_t sdz = fC[1] + cov[1];
1243   Double_t szz = fC[2] + cov[2];
1244   Double_t det = sdd*szz - sdz*sdz;
1245
1246   if (TMath::Abs(det) < kAlmost0) return kVeryBig;
1247
1248   Double_t d = fP[0] - p[0];
1249   Double_t z = fP[1] - p[1];
1250
1251   return (d*szz*d - 2*d*sdz*z + z*sdd*z)/det;
1252 }
1253
1254 Double_t AliExternalTrackParam::
1255 GetPredictedChi2(Double_t p[3],Double_t covyz[3],Double_t covxyz[3]) const {
1256   //----------------------------------------------------------------
1257   // Estimate the chi2 of the 3D space point "p" and
1258   // the full covariance matrix "covyz" and "covxyz"
1259   //
1260   // Cov(x,x) ... :   covxyz[0]
1261   // Cov(y,x) ... :   covxyz[1]  covyz[0]
1262   // Cov(z,x) ... :   covxyz[2]  covyz[1]  covyz[2]
1263   //----------------------------------------------------------------
1264
1265   Double_t res[3] = {
1266     GetX() - p[0],
1267     GetY() - p[1],
1268     GetZ() - p[2]
1269   };
1270
1271   Double_t f=GetSnp();
1272   if (TMath::Abs(f) >= kAlmost1) return kVeryBig;
1273   Double_t r=TMath::Sqrt((1.-f)*(1.+f));
1274   Double_t a=f/r, b=GetTgl()/r;
1275
1276   Double_t s2=333.*333.;  //something reasonably big (cm^2)
1277  
1278   TMatrixDSym v(3);
1279   v(0,0)=  s2;  v(0,1)=  a*s2;                 v(0,2)=  b*s2;;
1280   v(1,0)=a*s2;  v(1,1)=a*a*s2 + GetSigmaY2();  v(1,2)=a*b*s2 + GetSigmaZY();
1281   v(2,0)=b*s2;  v(2,1)=a*b*s2 + GetSigmaZY();  v(2,2)=b*b*s2 + GetSigmaZ2();
1282
1283   v(0,0)+=covxyz[0]; v(0,1)+=covxyz[1]; v(0,2)+=covxyz[2];
1284   v(1,0)+=covxyz[1]; v(1,1)+=covyz[0];  v(1,2)+=covyz[1];
1285   v(2,0)+=covxyz[2]; v(2,1)+=covyz[1];  v(2,2)+=covyz[2];
1286
1287   v.Invert();
1288   if (!v.IsValid()) return kVeryBig;
1289
1290   Double_t chi2=0.;
1291   for (Int_t i = 0; i < 3; i++)
1292     for (Int_t j = 0; j < 3; j++) chi2 += res[i]*res[j]*v(i,j);
1293
1294   return chi2;  
1295 }
1296
1297 Double_t AliExternalTrackParam::
1298 GetPredictedChi2(const AliExternalTrackParam *t) const {
1299   //----------------------------------------------------------------
1300   // Estimate the chi2 (5 dof) of this track with respect to the track
1301   // given by the argument.
1302   // The two tracks must be in the same reference system 
1303   // and estimated at the same reference plane.
1304   //----------------------------------------------------------------
1305
1306   if (TMath::Abs(1. - t->GetAlpha()/GetAlpha()) > FLT_EPSILON) {
1307       AliError("The reference systems of the tracks differ !");
1308       return kVeryBig;
1309   }
1310   if (TMath::Abs(1. - t->GetX()/GetX()) > FLT_EPSILON) {
1311       AliError("The reference of the tracks planes differ !");
1312       return kVeryBig;
1313   }
1314
1315   TMatrixDSym c(5);
1316     c(0,0)=GetSigmaY2(); 
1317     c(1,0)=GetSigmaZY();   c(1,1)=GetSigmaZ2();
1318     c(2,0)=GetSigmaSnpY(); c(2,1)=GetSigmaSnpZ(); c(2,2)=GetSigmaSnp2();
1319     c(3,0)=GetSigmaTglY(); c(3,1)=GetSigmaTglZ(); c(3,2)=GetSigmaTglSnp(); c(3,3)=GetSigmaTgl2();
1320     c(4,0)=GetSigma1PtY(); c(4,1)=GetSigma1PtZ(); c(4,2)=GetSigma1PtSnp(); c(4,3)=GetSigma1PtTgl(); c(4,4)=GetSigma1Pt2();
1321
1322     c(0,0)+=t->GetSigmaY2(); 
1323     c(1,0)+=t->GetSigmaZY();  c(1,1)+=t->GetSigmaZ2();
1324     c(2,0)+=t->GetSigmaSnpY();c(2,1)+=t->GetSigmaSnpZ();c(2,2)+=t->GetSigmaSnp2();
1325     c(3,0)+=t->GetSigmaTglY();c(3,1)+=t->GetSigmaTglZ();c(3,2)+=t->GetSigmaTglSnp();c(3,3)+=t->GetSigmaTgl2();
1326     c(4,0)+=t->GetSigma1PtY();c(4,1)+=t->GetSigma1PtZ();c(4,2)+=t->GetSigma1PtSnp();c(4,3)+=t->GetSigma1PtTgl();c(4,4)+=t->GetSigma1Pt2();
1327     c(0,1)=c(1,0);
1328     c(0,2)=c(2,0); c(1,2)=c(2,1);
1329     c(0,3)=c(3,0); c(1,3)=c(3,1); c(2,3)=c(3,2);
1330     c(0,4)=c(4,0); c(1,4)=c(4,1); c(2,4)=c(4,2); c(3,4)=c(4,3);
1331
1332   c.Invert();
1333   if (!c.IsValid()) return kVeryBig;
1334
1335
1336   Double_t res[5] = {
1337     GetY()   - t->GetY(),
1338     GetZ()   - t->GetZ(),
1339     GetSnp() - t->GetSnp(),
1340     GetTgl() - t->GetTgl(),
1341     GetSigned1Pt() - t->GetSigned1Pt()
1342   };
1343
1344   Double_t chi2=0.;
1345   for (Int_t i = 0; i < 5; i++)
1346     for (Int_t j = 0; j < 5; j++) chi2 += res[i]*res[j]*c(i,j);
1347
1348   return chi2;  
1349 }
1350
1351 Bool_t AliExternalTrackParam::
1352 PropagateTo(Double_t p[3],Double_t covyz[3],Double_t covxyz[3],Double_t bz) {
1353   //----------------------------------------------------------------
1354   // Propagate this track to the plane 
1355   // the 3D space point "p" (with the covariance matrix "covyz" and "covxyz")
1356   // belongs to.
1357   // The magnetic field is "bz" (kG)
1358   //
1359   // The track curvature and the change of the covariance matrix
1360   // of the track parameters are negleted !
1361   // (So the "step" should be small compared with 1/curvature)
1362   //----------------------------------------------------------------
1363
1364   Double_t f=GetSnp();
1365   if (TMath::Abs(f) >= kAlmost1) return kFALSE;
1366   Double_t r=TMath::Sqrt((1.-f)*(1.+f));
1367   Double_t a=f/r, b=GetTgl()/r;
1368
1369   Double_t s2=333.*333.;  //something reasonably big (cm^2)
1370  
1371   TMatrixDSym tV(3);
1372   tV(0,0)=  s2;  tV(0,1)=  a*s2;  tV(0,2)=  b*s2;
1373   tV(1,0)=a*s2;  tV(1,1)=a*a*s2;  tV(1,2)=a*b*s2;
1374   tV(2,0)=b*s2;  tV(2,1)=a*b*s2;  tV(2,2)=b*b*s2;
1375
1376   TMatrixDSym pV(3);
1377   pV(0,0)=covxyz[0]; pV(0,1)=covxyz[1]; pV(0,2)=covxyz[2];
1378   pV(1,0)=covxyz[1]; pV(1,1)=covyz[0];  pV(1,2)=covyz[1];
1379   pV(2,0)=covxyz[2]; pV(2,1)=covyz[1];  pV(2,2)=covyz[2];
1380
1381   TMatrixDSym tpV(tV);
1382   tpV+=pV;
1383   tpV.Invert();
1384   if (!tpV.IsValid()) return kFALSE;
1385
1386   TMatrixDSym pW(3),tW(3);
1387   for (Int_t i=0; i<3; i++)
1388     for (Int_t j=0; j<3; j++) {
1389       pW(i,j)=tW(i,j)=0.;
1390       for (Int_t k=0; k<3; k++) {
1391         pW(i,j) += tV(i,k)*tpV(k,j);
1392         tW(i,j) += pV(i,k)*tpV(k,j);
1393       }
1394     }
1395
1396   Double_t t[3] = {GetX(), GetY(), GetZ()};
1397
1398   Double_t x=0.;
1399   for (Int_t i=0; i<3; i++) x += (tW(0,i)*t[i] + pW(0,i)*p[i]);  
1400   Double_t crv=GetC(bz);
1401   if (TMath::Abs(b) < kAlmost0Field) crv=0.;
1402   f += crv*(x-fX);
1403   if (TMath::Abs(f) >= kAlmost1) return kFALSE;
1404   fX=x;  
1405
1406   fP[0]=0.;
1407   for (Int_t i=0; i<3; i++) fP[0] += (tW(1,i)*t[i] + pW(1,i)*p[i]);  
1408   fP[1]=0.;
1409   for (Int_t i=0; i<3; i++) fP[1] += (tW(2,i)*t[i] + pW(2,i)*p[i]);  
1410
1411   return kTRUE;  
1412 }
1413
1414 Double_t *AliExternalTrackParam::GetResiduals(
1415 Double_t *p,Double_t *cov,Bool_t updated) const {
1416   //------------------------------------------------------------------
1417   // Returns the track residuals with the space point "p" having
1418   // the covariance matrix "cov".
1419   // If "updated" is kTRUE, the track parameters expected to be updated,
1420   // otherwise they must be predicted.  
1421   //------------------------------------------------------------------
1422   static Double_t res[2];
1423
1424   Double_t r00=cov[0], r01=cov[1], r11=cov[2];
1425   if (updated) {
1426      r00-=fC[0]; r01-=fC[1]; r11-=fC[2];
1427   } else {
1428      r00+=fC[0]; r01+=fC[1]; r11+=fC[2];
1429   }
1430   Double_t det=r00*r11 - r01*r01;
1431
1432   if (TMath::Abs(det) < kAlmost0) return 0;
1433
1434   Double_t tmp=r00; r00=r11/det; r11=tmp/det;
1435
1436   if (r00 < 0.) return 0;
1437   if (r11 < 0.) return 0;
1438
1439   Double_t dy = fP[0] - p[0];
1440   Double_t dz = fP[1] - p[1];
1441
1442   res[0]=dy*TMath::Sqrt(r00);
1443   res[1]=dz*TMath::Sqrt(r11);
1444
1445   return res;
1446 }
1447
1448 Bool_t AliExternalTrackParam::Update(Double_t p[2], Double_t cov[3]) {
1449   //------------------------------------------------------------------
1450   // Update the track parameters with the space point "p" having
1451   // the covariance matrix "cov"
1452   //------------------------------------------------------------------
1453   Double_t &fP0=fP[0], &fP1=fP[1], &fP2=fP[2], &fP3=fP[3], &fP4=fP[4];
1454   Double_t 
1455   &fC00=fC[0],
1456   &fC10=fC[1],   &fC11=fC[2],  
1457   &fC20=fC[3],   &fC21=fC[4],   &fC22=fC[5],
1458   &fC30=fC[6],   &fC31=fC[7],   &fC32=fC[8],   &fC33=fC[9],  
1459   &fC40=fC[10],  &fC41=fC[11],  &fC42=fC[12],  &fC43=fC[13], &fC44=fC[14];
1460
1461   Double_t r00=cov[0], r01=cov[1], r11=cov[2];
1462   r00+=fC00; r01+=fC10; r11+=fC11;
1463   Double_t det=r00*r11 - r01*r01;
1464
1465   if (TMath::Abs(det) < kAlmost0) return kFALSE;
1466
1467
1468   Double_t tmp=r00; r00=r11/det; r11=tmp/det; r01=-r01/det;
1469  
1470   Double_t k00=fC00*r00+fC10*r01, k01=fC00*r01+fC10*r11;
1471   Double_t k10=fC10*r00+fC11*r01, k11=fC10*r01+fC11*r11;
1472   Double_t k20=fC20*r00+fC21*r01, k21=fC20*r01+fC21*r11;
1473   Double_t k30=fC30*r00+fC31*r01, k31=fC30*r01+fC31*r11;
1474   Double_t k40=fC40*r00+fC41*r01, k41=fC40*r01+fC41*r11;
1475
1476   Double_t dy=p[0] - fP0, dz=p[1] - fP1;
1477   Double_t sf=fP2 + k20*dy + k21*dz;
1478   if (TMath::Abs(sf) > kAlmost1) return kFALSE;  
1479   
1480   fP0 += k00*dy + k01*dz;
1481   fP1 += k10*dy + k11*dz;
1482   fP2  = sf;
1483   fP3 += k30*dy + k31*dz;
1484   fP4 += k40*dy + k41*dz;
1485   
1486   Double_t c01=fC10, c02=fC20, c03=fC30, c04=fC40;
1487   Double_t c12=fC21, c13=fC31, c14=fC41;
1488
1489   fC00-=k00*fC00+k01*fC10; fC10-=k00*c01+k01*fC11;
1490   fC20-=k00*c02+k01*c12;   fC30-=k00*c03+k01*c13;
1491   fC40-=k00*c04+k01*c14; 
1492
1493   fC11-=k10*c01+k11*fC11;
1494   fC21-=k10*c02+k11*c12;   fC31-=k10*c03+k11*c13;
1495   fC41-=k10*c04+k11*c14; 
1496
1497   fC22-=k20*c02+k21*c12;   fC32-=k20*c03+k21*c13;
1498   fC42-=k20*c04+k21*c14; 
1499
1500   fC33-=k30*c03+k31*c13;
1501   fC43-=k30*c04+k31*c14; 
1502   
1503   fC44-=k40*c04+k41*c14; 
1504
1505   CheckCovariance();
1506
1507   return kTRUE;
1508 }
1509
1510 void 
1511 AliExternalTrackParam::GetHelixParameters(Double_t hlx[6], Double_t b) const {
1512   //--------------------------------------------------------------------
1513   // External track parameters -> helix parameters 
1514   // "b" - magnetic field (kG)
1515   //--------------------------------------------------------------------
1516   Double_t cs=TMath::Cos(fAlpha), sn=TMath::Sin(fAlpha);
1517   
1518   hlx[0]=fP[0]; hlx[1]=fP[1]; hlx[2]=fP[2]; hlx[3]=fP[3];
1519
1520   hlx[5]=fX*cs - hlx[0]*sn;               // x0
1521   hlx[0]=fX*sn + hlx[0]*cs;               // y0
1522 //hlx[1]=                                 // z0
1523   hlx[2]=TMath::ASin(hlx[2]) + fAlpha;    // phi0
1524 //hlx[3]=                                 // tgl
1525   hlx[4]=GetC(b);                         // C
1526 }
1527
1528
1529 static void Evaluate(const Double_t *h, Double_t t,
1530                      Double_t r[3],  //radius vector
1531                      Double_t g[3],  //first defivatives
1532                      Double_t gg[3]) //second derivatives
1533 {
1534   //--------------------------------------------------------------------
1535   // Calculate position of a point on a track and some derivatives
1536   //--------------------------------------------------------------------
1537   Double_t phase=h[4]*t+h[2];
1538   Double_t sn=TMath::Sin(phase), cs=TMath::Cos(phase);
1539
1540   r[0] = h[5];
1541   r[1] = h[0];
1542   if (TMath::Abs(h[4])>kAlmost0) {
1543      r[0] += (sn - h[6])/h[4];
1544      r[1] -= (cs - h[7])/h[4];  
1545   }
1546   r[2] = h[1] + h[3]*t;
1547
1548   g[0] = cs; g[1]=sn; g[2]=h[3];
1549   
1550   gg[0]=-h[4]*sn; gg[1]=h[4]*cs; gg[2]=0.;
1551 }
1552
1553 Double_t AliExternalTrackParam::GetDCA(const AliExternalTrackParam *p, 
1554 Double_t b, Double_t &xthis, Double_t &xp) const {
1555   //------------------------------------------------------------
1556   // Returns the (weighed !) distance of closest approach between 
1557   // this track and the track "p".
1558   // Other returned values:
1559   //   xthis, xt - coordinates of tracks' reference planes at the DCA 
1560   //-----------------------------------------------------------
1561   Double_t dy2=GetSigmaY2() + p->GetSigmaY2();
1562   Double_t dz2=GetSigmaZ2() + p->GetSigmaZ2();
1563   Double_t dx2=dy2; 
1564
1565   Double_t p1[8]; GetHelixParameters(p1,b);
1566   p1[6]=TMath::Sin(p1[2]); p1[7]=TMath::Cos(p1[2]);
1567   Double_t p2[8]; p->GetHelixParameters(p2,b);
1568   p2[6]=TMath::Sin(p2[2]); p2[7]=TMath::Cos(p2[2]);
1569
1570
1571   Double_t r1[3],g1[3],gg1[3]; Double_t t1=0.;
1572   Evaluate(p1,t1,r1,g1,gg1);
1573   Double_t r2[3],g2[3],gg2[3]; Double_t t2=0.;
1574   Evaluate(p2,t2,r2,g2,gg2);
1575
1576   Double_t dx=r2[0]-r1[0], dy=r2[1]-r1[1], dz=r2[2]-r1[2];
1577   Double_t dm=dx*dx/dx2 + dy*dy/dy2 + dz*dz/dz2;
1578
1579   Int_t max=27;
1580   while (max--) {
1581      Double_t gt1=-(dx*g1[0]/dx2 + dy*g1[1]/dy2 + dz*g1[2]/dz2);
1582      Double_t gt2=+(dx*g2[0]/dx2 + dy*g2[1]/dy2 + dz*g2[2]/dz2);
1583      Double_t h11=(g1[0]*g1[0] - dx*gg1[0])/dx2 + 
1584                   (g1[1]*g1[1] - dy*gg1[1])/dy2 +
1585                   (g1[2]*g1[2] - dz*gg1[2])/dz2;
1586      Double_t h22=(g2[0]*g2[0] + dx*gg2[0])/dx2 + 
1587                   (g2[1]*g2[1] + dy*gg2[1])/dy2 +
1588                   (g2[2]*g2[2] + dz*gg2[2])/dz2;
1589      Double_t h12=-(g1[0]*g2[0]/dx2 + g1[1]*g2[1]/dy2 + g1[2]*g2[2]/dz2);
1590
1591      Double_t det=h11*h22-h12*h12;
1592
1593      Double_t dt1,dt2;
1594      if (TMath::Abs(det)<1.e-33) {
1595         //(quasi)singular Hessian
1596         dt1=-gt1; dt2=-gt2;
1597      } else {
1598         dt1=-(gt1*h22 - gt2*h12)/det; 
1599         dt2=-(h11*gt2 - h12*gt1)/det;
1600      }
1601
1602      if ((dt1*gt1+dt2*gt2)>0) {dt1=-dt1; dt2=-dt2;}
1603
1604      //check delta(phase1) ?
1605      //check delta(phase2) ?
1606
1607      if (TMath::Abs(dt1)/(TMath::Abs(t1)+1.e-3) < 1.e-4)
1608      if (TMath::Abs(dt2)/(TMath::Abs(t2)+1.e-3) < 1.e-4) {
1609         if ((gt1*gt1+gt2*gt2) > 1.e-4/dy2/dy2) 
1610           AliDebug(1," stopped at not a stationary point !");
1611         Double_t lmb=h11+h22; lmb=lmb-TMath::Sqrt(lmb*lmb-4*det);
1612         if (lmb < 0.) 
1613           AliDebug(1," stopped at not a minimum !");
1614         break;
1615      }
1616
1617      Double_t dd=dm;
1618      for (Int_t div=1 ; ; div*=2) {
1619         Evaluate(p1,t1+dt1,r1,g1,gg1);
1620         Evaluate(p2,t2+dt2,r2,g2,gg2);
1621         dx=r2[0]-r1[0]; dy=r2[1]-r1[1]; dz=r2[2]-r1[2];
1622         dd=dx*dx/dx2 + dy*dy/dy2 + dz*dz/dz2;
1623         if (dd<dm) break;
1624         dt1*=0.5; dt2*=0.5;
1625         if (div>512) {
1626           AliDebug(1," overshoot !"); break;
1627         }   
1628      }
1629      dm=dd;
1630
1631      t1+=dt1;
1632      t2+=dt2;
1633
1634   }
1635
1636   if (max<=0) AliDebug(1," too many iterations !");
1637
1638   Double_t cs=TMath::Cos(GetAlpha());
1639   Double_t sn=TMath::Sin(GetAlpha());
1640   xthis=r1[0]*cs + r1[1]*sn;
1641
1642   cs=TMath::Cos(p->GetAlpha());
1643   sn=TMath::Sin(p->GetAlpha());
1644   xp=r2[0]*cs + r2[1]*sn;
1645
1646   return TMath::Sqrt(dm*TMath::Sqrt(dy2*dz2));
1647 }
1648  
1649 Double_t AliExternalTrackParam::
1650 PropagateToDCA(AliExternalTrackParam *p, Double_t b) {
1651   //--------------------------------------------------------------
1652   // Propagates this track and the argument track to the position of the
1653   // distance of closest approach.
1654   // Returns the (weighed !) distance of closest approach.
1655   //--------------------------------------------------------------
1656   Double_t xthis,xp;
1657   Double_t dca=GetDCA(p,b,xthis,xp);
1658
1659   if (!PropagateTo(xthis,b)) {
1660     //AliWarning(" propagation failed !");
1661     return 1e+33;
1662   }
1663
1664   if (!p->PropagateTo(xp,b)) {
1665     //AliWarning(" propagation failed !";
1666     return 1e+33;
1667   }
1668
1669   return dca;
1670 }
1671
1672
1673 Bool_t AliExternalTrackParam::PropagateToDCA(const AliVVertex *vtx, 
1674 Double_t b, Double_t maxd, Double_t dz[2], Double_t covar[3]) {
1675   //
1676   // Propagate this track to the DCA to vertex "vtx", 
1677   // if the (rough) transverse impact parameter is not bigger then "maxd". 
1678   //            Magnetic field is "b" (kG).
1679   //
1680   // a) The track gets extapolated to the DCA to the vertex.
1681   // b) The impact parameters and their covariance matrix are calculated.
1682   //
1683   //    In the case of success, the returned value is kTRUE
1684   //    (otherwise, it's kFALSE)
1685   //  
1686   Double_t alpha=GetAlpha();
1687   Double_t sn=TMath::Sin(alpha), cs=TMath::Cos(alpha);
1688   Double_t x=GetX(), y=GetParameter()[0], snp=GetParameter()[2];
1689   Double_t xv= vtx->GetX()*cs + vtx->GetY()*sn;
1690   Double_t yv=-vtx->GetX()*sn + vtx->GetY()*cs, zv=vtx->GetZ();
1691   x-=xv; y-=yv;
1692
1693   //Estimate the impact parameter neglecting the track curvature
1694   Double_t d=TMath::Abs(x*snp - y*TMath::Sqrt((1.-snp)*(1.+snp)));
1695   if (d > maxd) return kFALSE; 
1696
1697   //Propagate to the DCA
1698   Double_t crv=GetC(b);
1699   if (TMath::Abs(b) < kAlmost0Field) crv=0.;
1700
1701   Double_t tgfv=-(crv*x - snp)/(crv*y + TMath::Sqrt((1.-snp)*(1.+snp)));
1702   sn=tgfv/TMath::Sqrt(1.+ tgfv*tgfv); cs=TMath::Sqrt((1.-sn)*(1.+sn));
1703   if (TMath::Abs(tgfv)>0.) cs = sn/tgfv;
1704   else cs=1.;
1705
1706   x = xv*cs + yv*sn;
1707   yv=-xv*sn + yv*cs; xv=x;
1708
1709   if (!Propagate(alpha+TMath::ASin(sn),xv,b)) return kFALSE;
1710
1711   if (dz==0) return kTRUE;
1712   dz[0] = GetParameter()[0] - yv;
1713   dz[1] = GetParameter()[1] - zv;
1714   
1715   if (covar==0) return kTRUE;
1716   Double_t cov[6]; vtx->GetCovarianceMatrix(cov);
1717
1718   //***** Improvements by A.Dainese
1719   alpha=GetAlpha(); sn=TMath::Sin(alpha); cs=TMath::Cos(alpha);
1720   Double_t s2ylocvtx = cov[0]*sn*sn + cov[2]*cs*cs - 2.*cov[1]*cs*sn;
1721   covar[0] = GetCovariance()[0] + s2ylocvtx;   // neglecting correlations
1722   covar[1] = GetCovariance()[1];               // between (x,y) and z
1723   covar[2] = GetCovariance()[2] + cov[5];      // in vertex's covariance matrix
1724   //*****
1725
1726   return kTRUE;
1727 }
1728
1729 Bool_t AliExternalTrackParam::PropagateToDCABxByBz(const AliVVertex *vtx, 
1730 Double_t b[3], Double_t maxd, Double_t dz[2], Double_t covar[3]) {
1731   //
1732   // Propagate this track to the DCA to vertex "vtx", 
1733   // if the (rough) transverse impact parameter is not bigger then "maxd". 
1734   //
1735   // This function takes into account all three components of the magnetic
1736   // field given by the b[3] arument (kG)
1737   //
1738   // a) The track gets extapolated to the DCA to the vertex.
1739   // b) The impact parameters and their covariance matrix are calculated.
1740   //
1741   //    In the case of success, the returned value is kTRUE
1742   //    (otherwise, it's kFALSE)
1743   //  
1744   Double_t alpha=GetAlpha();
1745   Double_t sn=TMath::Sin(alpha), cs=TMath::Cos(alpha);
1746   Double_t x=GetX(), y=GetParameter()[0], snp=GetParameter()[2];
1747   Double_t xv= vtx->GetX()*cs + vtx->GetY()*sn;
1748   Double_t yv=-vtx->GetX()*sn + vtx->GetY()*cs, zv=vtx->GetZ();
1749   x-=xv; y-=yv;
1750
1751   //Estimate the impact parameter neglecting the track curvature
1752   Double_t d=TMath::Abs(x*snp - y*TMath::Sqrt((1.-snp)*(1.+snp)));
1753   if (d > maxd) return kFALSE; 
1754
1755   //Propagate to the DCA
1756   Double_t crv=GetC(b[2]);
1757   if (TMath::Abs(b[2]) < kAlmost0Field) crv=0.;
1758
1759   Double_t tgfv=-(crv*x - snp)/(crv*y + TMath::Sqrt((1.-snp)*(1.+snp)));
1760   sn=tgfv/TMath::Sqrt(1.+ tgfv*tgfv); cs=TMath::Sqrt((1.-sn)*(1.+sn));
1761   if (TMath::Abs(tgfv)>0.) cs = sn/tgfv;
1762   else cs=1.;
1763
1764   x = xv*cs + yv*sn;
1765   yv=-xv*sn + yv*cs; xv=x;
1766
1767   if (!PropagateBxByBz(alpha+TMath::ASin(sn),xv,b)) return kFALSE;
1768
1769   if (dz==0) return kTRUE;
1770   dz[0] = GetParameter()[0] - yv;
1771   dz[1] = GetParameter()[1] - zv;
1772   
1773   if (covar==0) return kTRUE;
1774   Double_t cov[6]; vtx->GetCovarianceMatrix(cov);
1775
1776   //***** Improvements by A.Dainese
1777   alpha=GetAlpha(); sn=TMath::Sin(alpha); cs=TMath::Cos(alpha);
1778   Double_t s2ylocvtx = cov[0]*sn*sn + cov[2]*cs*cs - 2.*cov[1]*cs*sn;
1779   covar[0] = GetCovariance()[0] + s2ylocvtx;   // neglecting correlations
1780   covar[1] = GetCovariance()[1];               // between (x,y) and z
1781   covar[2] = GetCovariance()[2] + cov[5];      // in vertex's covariance matrix
1782   //*****
1783
1784   return kTRUE;
1785 }
1786
1787 void AliExternalTrackParam::GetDirection(Double_t d[3]) const {
1788   //----------------------------------------------------------------
1789   // This function returns a unit vector along the track direction
1790   // in the global coordinate system.
1791   //----------------------------------------------------------------
1792   Double_t cs=TMath::Cos(fAlpha), sn=TMath::Sin(fAlpha);
1793   Double_t snp=fP[2];
1794   Double_t csp =TMath::Sqrt((1.-snp)*(1.+snp));
1795   Double_t norm=TMath::Sqrt(1.+ fP[3]*fP[3]);
1796   d[0]=(csp*cs - snp*sn)/norm; 
1797   d[1]=(snp*cs + csp*sn)/norm; 
1798   d[2]=fP[3]/norm;
1799 }
1800
1801 Bool_t AliExternalTrackParam::GetPxPyPz(Double_t p[3]) const {
1802   //---------------------------------------------------------------------
1803   // This function returns the global track momentum components
1804   // Results for (nearly) straight tracks are meaningless !
1805   //---------------------------------------------------------------------
1806   p[0]=fP[4]; p[1]=fP[2]; p[2]=fP[3];
1807   return Local2GlobalMomentum(p,fAlpha);
1808 }
1809
1810 Double_t AliExternalTrackParam::Px() const {
1811   //---------------------------------------------------------------------
1812   // Returns x-component of momentum
1813   // Result for (nearly) straight tracks is meaningless !
1814   //---------------------------------------------------------------------
1815
1816   Double_t p[3]={kVeryBig,kVeryBig,kVeryBig};
1817   GetPxPyPz(p);
1818
1819   return p[0];
1820 }
1821
1822 Double_t AliExternalTrackParam::Py() const {
1823   //---------------------------------------------------------------------
1824   // Returns y-component of momentum
1825   // Result for (nearly) straight tracks is meaningless !
1826   //---------------------------------------------------------------------
1827
1828   Double_t p[3]={kVeryBig,kVeryBig,kVeryBig};
1829   GetPxPyPz(p);
1830
1831   return p[1];
1832 }
1833
1834 Double_t AliExternalTrackParam::Xv() const {
1835   //---------------------------------------------------------------------
1836   // Returns x-component of first track point
1837   //---------------------------------------------------------------------
1838
1839   Double_t r[3]={0.,0.,0.};
1840   GetXYZ(r);
1841
1842   return r[0];
1843 }
1844
1845 Double_t AliExternalTrackParam::Yv() const {
1846   //---------------------------------------------------------------------
1847   // Returns y-component of first track point
1848   //---------------------------------------------------------------------
1849
1850   Double_t r[3]={0.,0.,0.};
1851   GetXYZ(r);
1852
1853   return r[1];
1854 }
1855
1856 Double_t AliExternalTrackParam::Theta() const {
1857   // return theta angle of momentum
1858
1859   return 0.5*TMath::Pi() - TMath::ATan(fP[3]);
1860 }
1861
1862 Double_t AliExternalTrackParam::Phi() const {
1863   //---------------------------------------------------------------------
1864   // Returns the azimuthal angle of momentum
1865   // 0 <= phi < 2*pi
1866   //---------------------------------------------------------------------
1867
1868   Double_t phi=TMath::ASin(fP[2]) + fAlpha;
1869   if (phi<0.) phi+=2.*TMath::Pi();
1870   else if (phi>=2.*TMath::Pi()) phi-=2.*TMath::Pi();
1871  
1872   return phi;
1873 }
1874
1875 Double_t AliExternalTrackParam::M() const {
1876   // return particle mass
1877
1878   // No mass information available so far.
1879   // Redifine in derived class!
1880
1881   return -999.;
1882 }
1883
1884 Double_t AliExternalTrackParam::E() const {
1885   // return particle energy
1886
1887   // No PID information available so far.
1888   // Redifine in derived class!
1889
1890   return -999.;
1891 }
1892
1893 Double_t AliExternalTrackParam::Eta() const { 
1894   // return pseudorapidity
1895
1896   return -TMath::Log(TMath::Tan(0.5 * Theta())); 
1897 }
1898
1899 Double_t AliExternalTrackParam::Y() const {
1900   // return rapidity
1901
1902   // No PID information available so far.
1903   // Redifine in derived class!
1904
1905   return -999.;
1906 }
1907
1908 Bool_t AliExternalTrackParam::GetXYZ(Double_t *r) const {
1909   //---------------------------------------------------------------------
1910   // This function returns the global track position
1911   //---------------------------------------------------------------------
1912   r[0]=fX; r[1]=fP[0]; r[2]=fP[1];
1913   return Local2GlobalPosition(r,fAlpha);
1914 }
1915
1916 Bool_t AliExternalTrackParam::GetCovarianceXYZPxPyPz(Double_t cv[21]) const {
1917   //---------------------------------------------------------------------
1918   // This function returns the global covariance matrix of the track params
1919   // 
1920   // Cov(x,x) ... :   cv[0]
1921   // Cov(y,x) ... :   cv[1]  cv[2]
1922   // Cov(z,x) ... :   cv[3]  cv[4]  cv[5]
1923   // Cov(px,x)... :   cv[6]  cv[7]  cv[8]  cv[9]
1924   // Cov(py,x)... :   cv[10] cv[11] cv[12] cv[13] cv[14]
1925   // Cov(pz,x)... :   cv[15] cv[16] cv[17] cv[18] cv[19] cv[20]
1926   //
1927   // Results for (nearly) straight tracks are meaningless !
1928   //---------------------------------------------------------------------
1929   if (TMath::Abs(fP[4])<=kAlmost0) {
1930      for (Int_t i=0; i<21; i++) cv[i]=0.;
1931      return kFALSE;
1932   }
1933   if (TMath::Abs(fP[2]) > kAlmost1) {
1934      for (Int_t i=0; i<21; i++) cv[i]=0.;
1935      return kFALSE;
1936   }
1937   Double_t pt=1./TMath::Abs(fP[4]);
1938   Double_t cs=TMath::Cos(fAlpha), sn=TMath::Sin(fAlpha);
1939   Double_t r=TMath::Sqrt((1.-fP[2])*(1.+fP[2]));
1940
1941   Double_t m00=-sn, m10=cs;
1942   Double_t m23=-pt*(sn + fP[2]*cs/r), m43=-pt*pt*(r*cs - fP[2]*sn);
1943   Double_t m24= pt*(cs - fP[2]*sn/r), m44=-pt*pt*(r*sn + fP[2]*cs);
1944   Double_t m35=pt, m45=-pt*pt*fP[3];
1945
1946   m43*=GetSign();
1947   m44*=GetSign();
1948   m45*=GetSign();
1949
1950   cv[0 ] = fC[0]*m00*m00;
1951   cv[1 ] = fC[0]*m00*m10; 
1952   cv[2 ] = fC[0]*m10*m10;
1953   cv[3 ] = fC[1]*m00; 
1954   cv[4 ] = fC[1]*m10; 
1955   cv[5 ] = fC[2];
1956   cv[6 ] = m00*(fC[3]*m23 + fC[10]*m43); 
1957   cv[7 ] = m10*(fC[3]*m23 + fC[10]*m43); 
1958   cv[8 ] = fC[4]*m23 + fC[11]*m43; 
1959   cv[9 ] = m23*(fC[5]*m23 + fC[12]*m43)  +  m43*(fC[12]*m23 + fC[14]*m43);
1960   cv[10] = m00*(fC[3]*m24 + fC[10]*m44); 
1961   cv[11] = m10*(fC[3]*m24 + fC[10]*m44); 
1962   cv[12] = fC[4]*m24 + fC[11]*m44; 
1963   cv[13] = m23*(fC[5]*m24 + fC[12]*m44)  +  m43*(fC[12]*m24 + fC[14]*m44);
1964   cv[14] = m24*(fC[5]*m24 + fC[12]*m44)  +  m44*(fC[12]*m24 + fC[14]*m44);
1965   cv[15] = m00*(fC[6]*m35 + fC[10]*m45); 
1966   cv[16] = m10*(fC[6]*m35 + fC[10]*m45); 
1967   cv[17] = fC[7]*m35 + fC[11]*m45; 
1968   cv[18] = m23*(fC[8]*m35 + fC[12]*m45)  +  m43*(fC[13]*m35 + fC[14]*m45);
1969   cv[19] = m24*(fC[8]*m35 + fC[12]*m45)  +  m44*(fC[13]*m35 + fC[14]*m45); 
1970   cv[20] = m35*(fC[9]*m35 + fC[13]*m45)  +  m45*(fC[13]*m35 + fC[14]*m45);
1971
1972   return kTRUE;
1973 }
1974
1975
1976 Bool_t 
1977 AliExternalTrackParam::GetPxPyPzAt(Double_t x, Double_t b, Double_t *p) const {
1978   //---------------------------------------------------------------------
1979   // This function returns the global track momentum extrapolated to
1980   // the radial position "x" (cm) in the magnetic field "b" (kG)
1981   //---------------------------------------------------------------------
1982   p[0]=fP[4]; 
1983   p[1]=fP[2]+(x-fX)*GetC(b); 
1984   p[2]=fP[3];
1985   return Local2GlobalMomentum(p,fAlpha);
1986 }
1987
1988 Bool_t 
1989 AliExternalTrackParam::GetYAt(Double_t x, Double_t b, Double_t &y) const {
1990   //---------------------------------------------------------------------
1991   // This function returns the local Y-coordinate of the intersection 
1992   // point between this track and the reference plane "x" (cm). 
1993   // Magnetic field "b" (kG)
1994   //---------------------------------------------------------------------
1995   Double_t dx=x-fX;
1996   if(TMath::Abs(dx)<=kAlmost0) {y=fP[0]; return kTRUE;}
1997
1998   Double_t f1=fP[2], f2=f1 + dx*GetC(b);
1999
2000   if (TMath::Abs(f1) >= kAlmost1) return kFALSE;
2001   if (TMath::Abs(f2) >= kAlmost1) return kFALSE;
2002   
2003   Double_t r1=TMath::Sqrt((1.-f1)*(1.+f1)), r2=TMath::Sqrt((1.-f2)*(1.+f2));
2004   y = fP[0] + dx*(f1+f2)/(r1+r2);
2005   return kTRUE;
2006 }
2007
2008 Bool_t 
2009 AliExternalTrackParam::GetZAt(Double_t x, Double_t b, Double_t &z) const {
2010   //---------------------------------------------------------------------
2011   // This function returns the local Z-coordinate of the intersection 
2012   // point between this track and the reference plane "x" (cm). 
2013   // Magnetic field "b" (kG)
2014   //---------------------------------------------------------------------
2015   Double_t dx=x-fX;
2016   if(TMath::Abs(dx)<=kAlmost0) {z=fP[1]; return kTRUE;}
2017
2018   Double_t crv=GetC(b);
2019   Double_t x2r = crv*dx;
2020   Double_t f1=fP[2], f2=f1 + x2r;
2021
2022   if (TMath::Abs(f1) >= kAlmost1) return kFALSE;
2023   if (TMath::Abs(f2) >= kAlmost1) return kFALSE;
2024   
2025   Double_t r1=sqrt((1.-f1)*(1.+f1)), r2=sqrt((1.-f2)*(1.+f2));
2026   double dy2dx = (f1+f2)/(r1+r2);
2027   if (TMath::Abs(x2r)<0.05) {
2028     z = fP[1] + dx*(r2 + f2*dy2dx)*fP[3]; // Many thanks to P.Hristov !    
2029   }
2030   else {
2031     // for small dx/R the linear apporximation of the arc by the segment is OK,
2032     // but at large dx/R the error is very large and leads to incorrect Z propagation
2033     // angle traversed delta = 2*asin(dist_start_end / R / 2), hence the arc is: R*deltaPhi
2034     // The dist_start_end is obtained from sqrt(dx^2+dy^2) = x/(r1+r2)*sqrt(2+f1*f2+r1*r2)
2035     // Similarly, the rotation angle in linear in dx only for dx<<R
2036     double chord = dx*TMath::Sqrt(1+dy2dx*dy2dx);   // distance from old position to new one
2037     double rot = 2*TMath::ASin(0.5*chord*crv); // angular difference seen from the circle center
2038     z = fP[1] + rot/crv*fP[3];    
2039   }
2040   return kTRUE;
2041 }
2042
2043 Bool_t 
2044 AliExternalTrackParam::GetXYZAt(Double_t x, Double_t b, Double_t *r) const {
2045   //---------------------------------------------------------------------
2046   // This function returns the global track position extrapolated to
2047   // the radial position "x" (cm) in the magnetic field "b" (kG)
2048   //---------------------------------------------------------------------
2049   Double_t dx=x-fX;
2050   if(TMath::Abs(dx)<=kAlmost0) return GetXYZ(r);
2051
2052   Double_t crv=GetC(b);
2053   Double_t x2r = crv*dx;
2054   Double_t f1=fP[2], f2=f1 + dx*crv;
2055
2056   if (TMath::Abs(f1) >= kAlmost1) return kFALSE;
2057   if (TMath::Abs(f2) >= kAlmost1) return kFALSE;
2058   
2059   Double_t r1=TMath::Sqrt((1.-f1)*(1.+f1)), r2=TMath::Sqrt((1.-f2)*(1.+f2));
2060   double dy2dx = (f1+f2)/(r1+r2);
2061   r[0] = x;
2062   r[1] = fP[0] + dx*dy2dx;
2063   if (TMath::Abs(x2r)<0.05) {
2064     r[2] = fP[1] + dx*(r2 + f2*dy2dx)*fP[3];//Thanks to Andrea & Peter
2065   }
2066   else {
2067     // for small dx/R the linear apporximation of the arc by the segment is OK,
2068     // but at large dx/R the error is very large and leads to incorrect Z propagation
2069     // angle traversed delta = 2*asin(dist_start_end / R / 2), hence the arc is: R*deltaPhi
2070     // The dist_start_end is obtained from sqrt(dx^2+dy^2) = x/(r1+r2)*sqrt(2+f1*f2+r1*r2)
2071     // Similarly, the rotation angle in linear in dx only for dx<<R
2072     double chord = dx*TMath::Sqrt(1+dy2dx*dy2dx);   // distance from old position to new one
2073     double rot = 2*TMath::ASin(0.5*chord*crv); // angular difference seen from the circle center
2074     r[2] = fP[1] + rot/crv*fP[3];
2075   }
2076
2077   return Local2GlobalPosition(r,fAlpha);
2078 }
2079
2080 //_____________________________________________________________________________
2081 void AliExternalTrackParam::Print(Option_t* /*option*/) const
2082 {
2083 // print the parameters and the covariance matrix
2084
2085   printf("AliExternalTrackParam: x = %-12g  alpha = %-12g\n", fX, fAlpha);
2086   printf("  parameters: %12g %12g %12g %12g %12g\n",
2087          fP[0], fP[1], fP[2], fP[3], fP[4]);
2088   printf("  covariance: %12g\n", fC[0]);
2089   printf("              %12g %12g\n", fC[1], fC[2]);
2090   printf("              %12g %12g %12g\n", fC[3], fC[4], fC[5]);
2091   printf("              %12g %12g %12g %12g\n", 
2092          fC[6], fC[7], fC[8], fC[9]);
2093   printf("              %12g %12g %12g %12g %12g\n", 
2094          fC[10], fC[11], fC[12], fC[13], fC[14]);
2095 }
2096
2097 Double_t AliExternalTrackParam::GetSnpAt(Double_t x,Double_t b) const {
2098   //
2099   // Get sinus at given x
2100   //
2101   Double_t crv=GetC(b);
2102   if (TMath::Abs(b) < kAlmost0Field) crv=0.;
2103   Double_t dx = x-fX;
2104   Double_t res = fP[2]+dx*crv;
2105   return res;
2106 }
2107
2108 Bool_t AliExternalTrackParam::GetDistance(AliExternalTrackParam *param2, Double_t x, Double_t dist[3], Double_t bz){
2109   //------------------------------------------------------------------------
2110   // Get the distance between two tracks at the local position x 
2111   // working in the local frame of this track.
2112   // Origin :   Marian.Ivanov@cern.ch
2113   //-----------------------------------------------------------------------
2114   Double_t xyz[3];
2115   Double_t xyz2[3];
2116   xyz[0]=x;
2117   if (!GetYAt(x,bz,xyz[1])) return kFALSE;
2118   if (!GetZAt(x,bz,xyz[2])) return kFALSE;
2119   //  
2120   //
2121   if (TMath::Abs(GetAlpha()-param2->GetAlpha())<kAlmost0){
2122     xyz2[0]=x;
2123     if (!param2->GetYAt(x,bz,xyz2[1])) return kFALSE;
2124     if (!param2->GetZAt(x,bz,xyz2[2])) return kFALSE;
2125   }else{
2126     //
2127     Double_t xyz1[3];
2128     Double_t dfi = param2->GetAlpha()-GetAlpha();
2129     Double_t ca = TMath::Cos(dfi), sa = TMath::Sin(dfi);
2130     xyz2[0] =  xyz[0]*ca+xyz[1]*sa;
2131     xyz2[1] = -xyz[0]*sa+xyz[1]*ca;
2132     //
2133     xyz1[0]=xyz2[0];
2134     if (!param2->GetYAt(xyz2[0],bz,xyz1[1])) return kFALSE;
2135     if (!param2->GetZAt(xyz2[0],bz,xyz1[2])) return kFALSE;
2136     //
2137     xyz2[0] =  xyz1[0]*ca-xyz1[1]*sa;
2138     xyz2[1] = +xyz1[0]*sa+xyz1[1]*ca;
2139     xyz2[2] = xyz1[2];
2140   }
2141   dist[0] = xyz[0]-xyz2[0];
2142   dist[1] = xyz[1]-xyz2[1];
2143   dist[2] = xyz[2]-xyz2[2];
2144
2145   return kTRUE;
2146 }
2147
2148
2149 //
2150 // Draw functionality.
2151 // Origin: Marian Ivanov, Marian.Ivanov@cern.ch
2152 //
2153
2154 void  AliExternalTrackParam::DrawTrack(Float_t magf, Float_t minR, Float_t maxR, Float_t stepR){
2155   //
2156   // Draw track line
2157   //
2158   if (minR>maxR) return ;
2159   if (stepR<=0) return ;
2160   Int_t npoints = TMath::Nint((maxR-minR)/stepR)+1;
2161   if (npoints<1) return;
2162   TPolyMarker3D *polymarker = new TPolyMarker3D(npoints);
2163   FillPolymarker(polymarker, magf,minR,maxR,stepR);
2164   polymarker->Draw();
2165 }
2166
2167 //
2168 void AliExternalTrackParam::FillPolymarker(TPolyMarker3D *pol, Float_t magF, Float_t minR, Float_t maxR, Float_t stepR){
2169   //
2170   // Fill points in the polymarker
2171   //
2172   Int_t counter=0;
2173   for (Double_t r=minR; r<maxR; r+=stepR){
2174     Double_t point[3];
2175     GetXYZAt(r,magF,point);
2176     pol->SetPoint(counter,point[0],point[1], point[2]);
2177     //    printf("xyz\t%f\t%f\t%f\n",point[0], point[1],point[2]);
2178     counter++;
2179   }
2180 }
2181
2182 Int_t AliExternalTrackParam::GetIndex(Int_t i, Int_t j) const {
2183   //
2184   Int_t min = TMath::Min(i,j);
2185   Int_t max = TMath::Max(i,j);
2186
2187   return min+(max+1)*max/2;
2188 }
2189
2190
2191 void AliExternalTrackParam::g3helx3(Double_t qfield, 
2192                                     Double_t step,
2193                                     Double_t vect[7]) {
2194 /******************************************************************
2195  *                                                                *
2196  *       GEANT3 tracking routine in a constant field oriented     *
2197  *       along axis 3                                             *
2198  *       Tracking is performed with a conventional                *
2199  *       helix step method                                        *
2200  *                                                                *
2201  *       Authors    R.Brun, M.Hansroul  *********                 *
2202  *       Rewritten  V.Perevoztchikov                              *
2203  *                                                                *
2204  *       Rewritten in C++ by I.Belikov                            *
2205  *                                                                *
2206  *  qfield (kG)       - particle charge times magnetic field      *
2207  *  step   (cm)       - step length along the helix               *
2208  *  vect[7](cm,GeV/c) - input/output x, y, z, px/p, py/p ,pz/p, p *
2209  *                                                                *
2210  ******************************************************************/
2211   const Int_t ix=0, iy=1, iz=2, ipx=3, ipy=4, ipz=5, ipp=6;
2212   const Double_t kOvSqSix=TMath::Sqrt(1./6.);
2213
2214   Double_t cosx=vect[ipx], cosy=vect[ipy], cosz=vect[ipz];
2215
2216   Double_t rho = qfield*kB2C/vect[ipp]; 
2217   Double_t tet = rho*step;
2218
2219   Double_t tsint, sintt, sint, cos1t; 
2220   if (TMath::Abs(tet) > 0.03) {
2221      sint  = TMath::Sin(tet);
2222      sintt = sint/tet;
2223      tsint = (tet - sint)/tet;
2224      Double_t t=TMath::Sin(0.5*tet);
2225      cos1t = 2*t*t/tet;
2226   } else {
2227      tsint = tet*tet/6.;
2228      sintt = (1.-tet*kOvSqSix)*(1.+tet*kOvSqSix); // 1.- tsint;
2229      sint  = tet*sintt;
2230      cos1t = 0.5*tet; 
2231   }
2232
2233   Double_t f1 = step*sintt;
2234   Double_t f2 = step*cos1t;
2235   Double_t f3 = step*tsint*cosz;
2236   Double_t f4 = -tet*cos1t;
2237   Double_t f5 = sint;
2238
2239   vect[ix]  += f1*cosx - f2*cosy;
2240   vect[iy]  += f1*cosy + f2*cosx;
2241   vect[iz]  += f1*cosz + f3;
2242
2243   vect[ipx] += f4*cosx - f5*cosy;
2244   vect[ipy] += f4*cosy + f5*cosx;  
2245
2246 }
2247
2248 Bool_t AliExternalTrackParam::PropagateToBxByBz(Double_t xk, const Double_t b[3]) {
2249   //----------------------------------------------------------------
2250   // Extrapolate this track to the plane X=xk in the field b[].
2251   //
2252   // X [cm] is in the "tracking coordinate system" of this track.
2253   // b[]={Bx,By,Bz} [kG] is in the Global coordidate system.
2254   //----------------------------------------------------------------
2255
2256   Double_t dx=xk-fX;
2257   if (TMath::Abs(dx)<=kAlmost0)  return kTRUE;
2258   if (TMath::Abs(fP[4])<=kAlmost0) return kFALSE;
2259   // Do not propagate tracks outside the ALICE detector
2260   if (TMath::Abs(dx)>1e5 ||
2261       TMath::Abs(GetY())>1e5 ||
2262       TMath::Abs(GetZ())>1e5) {
2263     AliWarning(Form("Anomalous track, target X:%f",xk));
2264     Print();
2265     return kFALSE;
2266   }
2267
2268   Double_t crv=GetC(b[2]);
2269   if (TMath::Abs(b[2]) < kAlmost0Field) crv=0.;
2270
2271   Double_t x2r = crv*dx;
2272   Double_t f1=fP[2], f2=f1 + x2r;
2273   if (TMath::Abs(f1) >= kAlmost1) return kFALSE;
2274   if (TMath::Abs(f2) >= kAlmost1) return kFALSE;
2275
2276
2277   // Estimate the covariance matrix  
2278   Double_t &fP3=fP[3], &fP4=fP[4];
2279   Double_t 
2280   &fC00=fC[0],
2281   &fC10=fC[1],   &fC11=fC[2],  
2282   &fC20=fC[3],   &fC21=fC[4],   &fC22=fC[5],
2283   &fC30=fC[6],   &fC31=fC[7],   &fC32=fC[8],   &fC33=fC[9],  
2284   &fC40=fC[10],  &fC41=fC[11],  &fC42=fC[12],  &fC43=fC[13], &fC44=fC[14];
2285
2286   Double_t r1=TMath::Sqrt((1.-f1)*(1.+f1)), r2=TMath::Sqrt((1.-f2)*(1.+f2));
2287
2288   //f = F - 1
2289   /*
2290   Double_t f02=    dx/(r1*r1*r1);            Double_t cc=crv/fP4;
2291   Double_t f04=0.5*dx*dx/(r1*r1*r1);         f04*=cc;
2292   Double_t f12=    dx*fP3*f1/(r1*r1*r1);
2293   Double_t f14=0.5*dx*dx*fP3*f1/(r1*r1*r1);  f14*=cc;
2294   Double_t f13=    dx/r1;
2295   Double_t f24=    dx;                       f24*=cc;
2296   */
2297   Double_t rinv = 1./r1;
2298   Double_t r3inv = rinv*rinv*rinv;
2299   Double_t f24=    x2r/fP4;
2300   Double_t f02=    dx*r3inv;
2301   Double_t f04=0.5*f24*f02;
2302   Double_t f12=    f02*fP3*f1;
2303   Double_t f14=0.5*f24*f02*fP3*f1;
2304   Double_t f13=    dx*rinv;
2305  
2306   //b = C*ft
2307   Double_t b00=f02*fC20 + f04*fC40, b01=f12*fC20 + f14*fC40 + f13*fC30;
2308   Double_t b02=f24*fC40;
2309   Double_t b10=f02*fC21 + f04*fC41, b11=f12*fC21 + f14*fC41 + f13*fC31;
2310   Double_t b12=f24*fC41;
2311   Double_t b20=f02*fC22 + f04*fC42, b21=f12*fC22 + f14*fC42 + f13*fC32;
2312   Double_t b22=f24*fC42;
2313   Double_t b40=f02*fC42 + f04*fC44, b41=f12*fC42 + f14*fC44 + f13*fC43;
2314   Double_t b42=f24*fC44;
2315   Double_t b30=f02*fC32 + f04*fC43, b31=f12*fC32 + f14*fC43 + f13*fC33;
2316   Double_t b32=f24*fC43;
2317   
2318   //a = f*b = f*C*ft
2319   Double_t a00=f02*b20+f04*b40,a01=f02*b21+f04*b41,a02=f02*b22+f04*b42;
2320   Double_t a11=f12*b21+f14*b41+f13*b31,a12=f12*b22+f14*b42+f13*b32;
2321   Double_t a22=f24*b42;
2322
2323   //F*C*Ft = C + (b + bt + a)
2324   fC00 += b00 + b00 + a00;
2325   fC10 += b10 + b01 + a01; 
2326   fC20 += b20 + b02 + a02;
2327   fC30 += b30;
2328   fC40 += b40;
2329   fC11 += b11 + b11 + a11;
2330   fC21 += b21 + b12 + a12;
2331   fC31 += b31; 
2332   fC41 += b41;
2333   fC22 += b22 + b22 + a22;
2334   fC32 += b32;
2335   fC42 += b42;
2336
2337   CheckCovariance();
2338   
2339   // Appoximate step length
2340   double dy2dx = (f1+f2)/(r1+r2);
2341   Double_t step = (TMath::Abs(x2r)<0.05) ? dx*TMath::Abs(r2 + f2*dy2dx)  // chord
2342     : 2.*TMath::ASin(0.5*dx*TMath::Sqrt(1.+dy2dx*dy2dx)*crv)/crv;        // arc
2343   step *= TMath::Sqrt(1.+ GetTgl()*GetTgl());
2344
2345   // Get the track's (x,y,z) and (px,py,pz) in the Global System
2346   Double_t r[3]; GetXYZ(r);
2347   Double_t p[3]; GetPxPyPz(p);
2348   Double_t pp=GetP();
2349   p[0] /= pp;
2350   p[1] /= pp;
2351   p[2] /= pp;
2352
2353
2354   // Rotate to the system where Bx=By=0.
2355   Double_t bt=TMath::Sqrt(b[0]*b[0] + b[1]*b[1]);
2356   Double_t cosphi=1., sinphi=0.;
2357   if (bt > kAlmost0) {cosphi=b[0]/bt; sinphi=b[1]/bt;}
2358   Double_t bb=TMath::Sqrt(b[0]*b[0] + b[1]*b[1] + b[2]*b[2]);
2359   Double_t costet=1., sintet=0.;
2360   if (bb > kAlmost0) {costet=b[2]/bb; sintet=bt/bb;}
2361   Double_t vect[7];
2362
2363   vect[0] = costet*cosphi*r[0] + costet*sinphi*r[1] - sintet*r[2];
2364   vect[1] = -sinphi*r[0] + cosphi*r[1];
2365   vect[2] = sintet*cosphi*r[0] + sintet*sinphi*r[1] + costet*r[2];
2366
2367   vect[3] = costet*cosphi*p[0] + costet*sinphi*p[1] - sintet*p[2];
2368   vect[4] = -sinphi*p[0] + cosphi*p[1];
2369   vect[5] = sintet*cosphi*p[0] + sintet*sinphi*p[1] + costet*p[2];
2370
2371   vect[6] = pp;
2372
2373
2374   // Do the helix step
2375   g3helx3(GetSign()*bb,step,vect);
2376
2377
2378   // Rotate back to the Global System
2379   r[0] = cosphi*costet*vect[0] - sinphi*vect[1] + cosphi*sintet*vect[2];
2380   r[1] = sinphi*costet*vect[0] + cosphi*vect[1] + sinphi*sintet*vect[2];
2381   r[2] = -sintet*vect[0] + costet*vect[2];
2382
2383   p[0] = cosphi*costet*vect[3] - sinphi*vect[4] + cosphi*sintet*vect[5];
2384   p[1] = sinphi*costet*vect[3] + cosphi*vect[4] + sinphi*sintet*vect[5];
2385   p[2] = -sintet*vect[3] + costet*vect[5];
2386
2387
2388   // Rotate back to the Tracking System
2389   Double_t cosalp = TMath::Cos(fAlpha);
2390   Double_t sinalp =-TMath::Sin(fAlpha);
2391
2392   Double_t 
2393   t    = cosalp*r[0] - sinalp*r[1];
2394   r[1] = sinalp*r[0] + cosalp*r[1];  
2395   r[0] = t;
2396
2397   t    = cosalp*p[0] - sinalp*p[1]; 
2398   p[1] = sinalp*p[0] + cosalp*p[1];
2399   p[0] = t; 
2400
2401
2402   // Do the final correcting step to the target plane (linear approximation)
2403   Double_t x=r[0], y=r[1], z=r[2];
2404   if (TMath::Abs(dx) > kAlmost0) {
2405      if (TMath::Abs(p[0]) < kAlmost0) return kFALSE;
2406      dx = xk - r[0];
2407      x += dx;
2408      y += p[1]/p[0]*dx;
2409      z += p[2]/p[0]*dx;  
2410   }
2411
2412
2413   // Calculate the track parameters
2414   t=TMath::Sqrt(p[0]*p[0] + p[1]*p[1]);
2415   fX    = x;
2416   fP[0] = y;
2417   fP[1] = z;
2418   fP[2] = p[1]/t;
2419   fP[3] = p[2]/t; 
2420   fP[4] = GetSign()/(t*pp);
2421
2422   return kTRUE;
2423 }
2424
2425 Bool_t AliExternalTrackParam::PropagateParamOnlyBxByBzTo(Double_t xk, const Double_t b[3]) {
2426   //----------------------------------------------------------------
2427   // Extrapolate this track params (w/o cov matrix) to the plane X=xk in the field b[].
2428   //
2429   // X [cm] is in the "tracking coordinate system" of this track.
2430   // b[]={Bx,By,Bz} [kG] is in the Global coordidate system.
2431   //----------------------------------------------------------------
2432
2433   Double_t dx=xk-fX;
2434   if (TMath::Abs(dx)<=kAlmost0)  return kTRUE;
2435   if (TMath::Abs(fP[4])<=kAlmost0) return kFALSE;
2436   // Do not propagate tracks outside the ALICE detector
2437   if (TMath::Abs(dx)>1e5 ||
2438       TMath::Abs(GetY())>1e5 ||
2439       TMath::Abs(GetZ())>1e5) {
2440     AliWarning(Form("Anomalous track, target X:%f",xk));
2441     Print();
2442     return kFALSE;
2443   }
2444
2445   Double_t crv=GetC(b[2]);
2446   if (TMath::Abs(b[2]) < kAlmost0Field) crv=0.;
2447
2448   Double_t x2r = crv*dx;
2449   Double_t f1=fP[2], f2=f1 + x2r;
2450   if (TMath::Abs(f1) >= kAlmost1) return kFALSE;
2451   if (TMath::Abs(f2) >= kAlmost1) return kFALSE;
2452   //
2453   Double_t r1=TMath::Sqrt((1.-f1)*(1.+f1)), r2=TMath::Sqrt((1.-f2)*(1.+f2));
2454   //
2455   // Appoximate step length
2456   double dy2dx = (f1+f2)/(r1+r2);
2457   Double_t step = (TMath::Abs(x2r)<0.05) ? dx*TMath::Abs(r2 + f2*dy2dx)  // chord
2458     : 2.*TMath::ASin(0.5*dx*TMath::Sqrt(1.+dy2dx*dy2dx)*crv)/crv;        // arc
2459   step *= TMath::Sqrt(1.+ GetTgl()*GetTgl());
2460   
2461   // Get the track's (x,y,z) and (px,py,pz) in the Global System
2462   Double_t r[3]; GetXYZ(r);
2463   Double_t p[3]; GetPxPyPz(p);
2464   Double_t pp=GetP();
2465   p[0] /= pp;
2466   p[1] /= pp;
2467   p[2] /= pp;
2468
2469   // Rotate to the system where Bx=By=0.
2470   Double_t bt=TMath::Sqrt(b[0]*b[0] + b[1]*b[1]);
2471   Double_t cosphi=1., sinphi=0.;
2472   if (bt > kAlmost0) {cosphi=b[0]/bt; sinphi=b[1]/bt;}
2473   Double_t bb=TMath::Sqrt(b[0]*b[0] + b[1]*b[1] + b[2]*b[2]);
2474   Double_t costet=1., sintet=0.;
2475   if (bb > kAlmost0) {costet=b[2]/bb; sintet=bt/bb;}
2476   Double_t vect[7];
2477
2478   vect[0] = costet*cosphi*r[0] + costet*sinphi*r[1] - sintet*r[2];
2479   vect[1] = -sinphi*r[0] + cosphi*r[1];
2480   vect[2] = sintet*cosphi*r[0] + sintet*sinphi*r[1] + costet*r[2];
2481
2482   vect[3] = costet*cosphi*p[0] + costet*sinphi*p[1] - sintet*p[2];
2483   vect[4] = -sinphi*p[0] + cosphi*p[1];
2484   vect[5] = sintet*cosphi*p[0] + sintet*sinphi*p[1] + costet*p[2];
2485
2486   vect[6] = pp;
2487
2488   // Do the helix step
2489   g3helx3(GetSign()*bb,step,vect);
2490
2491   // Rotate back to the Global System
2492   r[0] = cosphi*costet*vect[0] - sinphi*vect[1] + cosphi*sintet*vect[2];
2493   r[1] = sinphi*costet*vect[0] + cosphi*vect[1] + sinphi*sintet*vect[2];
2494   r[2] = -sintet*vect[0] + costet*vect[2];
2495
2496   p[0] = cosphi*costet*vect[3] - sinphi*vect[4] + cosphi*sintet*vect[5];
2497   p[1] = sinphi*costet*vect[3] + cosphi*vect[4] + sinphi*sintet*vect[5];
2498   p[2] = -sintet*vect[3] + costet*vect[5];
2499
2500   // Rotate back to the Tracking System
2501   Double_t cosalp = TMath::Cos(fAlpha);
2502   Double_t sinalp =-TMath::Sin(fAlpha);
2503
2504   Double_t 
2505   t    = cosalp*r[0] - sinalp*r[1];
2506   r[1] = sinalp*r[0] + cosalp*r[1];  
2507   r[0] = t;
2508
2509   t    = cosalp*p[0] - sinalp*p[1]; 
2510   p[1] = sinalp*p[0] + cosalp*p[1];
2511   p[0] = t; 
2512
2513   // Do the final correcting step to the target plane (linear approximation)
2514   Double_t x=r[0], y=r[1], z=r[2];
2515   if (TMath::Abs(dx) > kAlmost0) {
2516      if (TMath::Abs(p[0]) < kAlmost0) return kFALSE;
2517      dx = xk - r[0];
2518      x += dx;
2519      y += p[1]/p[0]*dx;
2520      z += p[2]/p[0]*dx;  
2521   }
2522
2523
2524   // Calculate the track parameters
2525   t=TMath::Sqrt(p[0]*p[0] + p[1]*p[1]);
2526   fX    = x;
2527   fP[0] = y;
2528   fP[1] = z;
2529   fP[2] = p[1]/t;
2530   fP[3] = p[2]/t; 
2531   fP[4] = GetSign()/(t*pp);
2532
2533   return kTRUE;
2534 }
2535
2536
2537 Bool_t AliExternalTrackParam::Translate(Double_t *vTrasl,Double_t *covV){
2538   //
2539   //Translation: in the event mixing, the tracks can be shifted 
2540   //of the difference among primary vertices (vTrasl) and 
2541   //the covariance matrix is changed accordingly 
2542   //(covV = covariance of the primary vertex).
2543   //Origin: "Romita, Rossella" <R.Romita@gsi.de>
2544   // 
2545   TVector3 translation;
2546   // vTrasl coordinates in the local system
2547   translation.SetXYZ(vTrasl[0],vTrasl[1],vTrasl[2]);
2548   translation.RotateZ(-fAlpha);
2549   translation.GetXYZ(vTrasl);
2550
2551  //compute the new x,y,z of the track
2552   Double_t newX=fX-vTrasl[0];
2553   Double_t newY=fP[0]-vTrasl[1];
2554   Double_t newZ=fP[1]-vTrasl[2];
2555   
2556   //define the new parameters
2557   Double_t newParam[5];
2558   newParam[0]=newY;
2559   newParam[1]=newZ;
2560   newParam[2]=fP[2];
2561   newParam[3]=fP[3];
2562   newParam[4]=fP[4];
2563
2564   // recompute the covariance matrix:
2565   // 1. covV in the local system
2566   Double_t cosRot=TMath::Cos(fAlpha), sinRot=TMath::Sin(fAlpha);
2567   TMatrixD qQi(3,3);
2568   qQi(0,0) = cosRot;
2569   qQi(0,1) = sinRot;
2570   qQi(0,2) = 0.;
2571   qQi(1,0) = -sinRot;
2572   qQi(1,1) = cosRot;
2573   qQi(1,2) = 0.;
2574   qQi(2,0) = 0.;
2575   qQi(2,1) = 0.;
2576   qQi(2,2) = 1.;
2577   TMatrixD uUi(3,3);
2578   uUi(0,0) = covV[0];
2579   uUi(0,0) = covV[0];
2580   uUi(1,0) = covV[1];
2581   uUi(0,1) = covV[1];
2582   uUi(2,0) = covV[3];
2583   uUi(0,2) = covV[3];
2584   uUi(1,1) = covV[2];
2585   uUi(2,2) = covV[5];
2586   uUi(1,2) = covV[4];
2587   if(uUi.Determinant() <= 0.) {return kFALSE;}
2588   TMatrixD uUiQi(uUi,TMatrixD::kMult,qQi);
2589   TMatrixD m(qQi,TMatrixD::kTransposeMult,uUiQi);
2590
2591   //2. compute the new covariance matrix of the track
2592   Double_t sigmaXX=m(0,0);
2593   Double_t sigmaXZ=m(2,0);
2594   Double_t sigmaXY=m(1,0);
2595   Double_t sigmaYY=GetSigmaY2()+m(1,1);
2596   Double_t sigmaYZ=fC[1]+m(1,2);
2597   Double_t sigmaZZ=fC[2]+m(2,2);
2598   Double_t covarianceYY=sigmaYY + (-1.)*((sigmaXY*sigmaXY)/sigmaXX);
2599   Double_t covarianceYZ=sigmaYZ-(sigmaXZ*sigmaXY/sigmaXX);
2600   Double_t covarianceZZ=sigmaZZ-((sigmaXZ*sigmaXZ)/sigmaXX);
2601
2602   Double_t newCov[15];
2603   newCov[0]=covarianceYY;
2604   newCov[1]=covarianceYZ;
2605   newCov[2]=covarianceZZ;
2606   for(Int_t i=3;i<15;i++){
2607     newCov[i]=fC[i];
2608    }
2609
2610   // set the new parameters
2611
2612   Set(newX,fAlpha,newParam,newCov);
2613
2614   return kTRUE;
2615  }
2616
2617 void AliExternalTrackParam::CheckCovariance() {
2618
2619   // This function forces the diagonal elements of the covariance matrix to be positive.
2620   // In case the diagonal element is bigger than the maximal allowed value, it is set to
2621   // the limit and the off-diagonal elements that correspond to it are set to zero.
2622
2623   fC[0] = TMath::Abs(fC[0]);
2624   if (fC[0]>kC0max) {
2625     double scl = TMath::Sqrt(kC0max/fC[0]);
2626     fC[0] = kC0max;
2627     fC[1] *= scl;
2628     fC[3] *= scl;
2629     fC[6] *= scl;
2630     fC[10] *= scl;
2631   }
2632   fC[2] = TMath::Abs(fC[2]);
2633   if (fC[2]>kC2max) {
2634     double scl = TMath::Sqrt(kC2max/fC[2]);
2635     fC[2] = kC2max;
2636     fC[1] *= scl;
2637     fC[4] *= scl;
2638     fC[7] *= scl;
2639     fC[11] *= scl;
2640   }
2641   fC[5] = TMath::Abs(fC[5]);
2642   if (fC[5]>kC5max) {
2643     double scl = TMath::Sqrt(kC5max/fC[5]);
2644     fC[5] = kC5max;
2645     fC[3] *= scl;
2646     fC[4] *= scl;
2647     fC[8] *= scl;
2648     fC[12] *= scl;
2649   }
2650   fC[9] = TMath::Abs(fC[9]);
2651   if (fC[9]>kC9max) {
2652     double scl = TMath::Sqrt(kC9max/fC[9]);
2653     fC[9] = kC9max;
2654     fC[6] *= scl;
2655     fC[7] *= scl;
2656     fC[8] *= scl;
2657     fC[13] *= scl;
2658   }
2659   fC[14] = TMath::Abs(fC[14]);
2660   if (fC[14]>kC14max) {
2661     double scl = TMath::Sqrt(kC14max/fC[14]);
2662     fC[14] = kC14max;
2663     fC[10] *= scl;
2664     fC[11] *= scl;
2665     fC[12] *= scl;
2666     fC[13] *= scl;
2667   }
2668       
2669     // The part below is used for tests and normally is commented out    
2670 //     TMatrixDSym m(5);
2671 //     TVectorD eig(5);
2672     
2673 //     m(0,0)=fC[0];
2674 //     m(1,0)=fC[1];  m(1,1)=fC[2];
2675 //     m(2,0)=fC[3];  m(2,1)=fC[4];  m(2,2)=fC[5];
2676 //     m(3,0)=fC[6];  m(3,1)=fC[7];  m(3,2)=fC[8];  m(3,3)=fC[9];
2677 //     m(4,0)=fC[10]; m(4,1)=fC[11]; m(4,2)=fC[12]; m(4,3)=fC[13]; m(4,4)=fC[14];
2678     
2679 //     m(0,1)=m(1,0);
2680 //     m(0,2)=m(2,0); m(1,2)=m(2,1);
2681 //     m(0,3)=m(3,0); m(1,3)=m(3,1); m(2,3)=m(3,2);
2682 //     m(0,4)=m(4,0); m(1,4)=m(4,1); m(2,4)=m(4,2); m(3,4)=m(4,3);
2683 //     m.EigenVectors(eig);
2684
2685 //     //    assert(eig(0)>=0 && eig(1)>=0 && eig(2)>=0 && eig(3)>=0 && eig(4)>=0);
2686 //     if (!(eig(0)>=0 && eig(1)>=0 && eig(2)>=0 && eig(3)>=0 && eig(4)>=0)) {
2687 //       AliWarning("Negative eigenvalues of the covariance matrix!");
2688 //       this->Print();
2689 //       eig.Print();
2690 //     }
2691 }
2692
2693 Bool_t AliExternalTrackParam::ConstrainToVertex(const AliVVertex* vtx, Double_t b[3])
2694 {
2695   // Constrain TPC inner params constrained
2696   //
2697   if (!vtx) 
2698     return kFALSE;
2699
2700   Double_t dz[2], cov[3];
2701   if (!PropagateToDCABxByBz(vtx, b, 3, dz, cov)) 
2702     return kFALSE; 
2703
2704   Double_t covar[6]; 
2705   vtx->GetCovarianceMatrix(covar);
2706   
2707   Double_t p[2]= { fP[0] - dz[0], fP[1] - dz[1] };
2708   Double_t c[3]= { covar[2], 0., covar[5] };
2709   
2710   Double_t chi2C = GetPredictedChi2(p,c);
2711   if (chi2C>kVeryBig) 
2712     return kFALSE; 
2713
2714   if (!Update(p,c)) 
2715     return kFALSE; 
2716
2717   return kTRUE;
2718 }
2719
2720 //___________________________________________________________________________________________
2721 Bool_t AliExternalTrackParam::GetXatLabR(Double_t r,Double_t &x, Double_t bz, Int_t dir) const
2722 {
2723   // Get local X of the track position estimated at the radius lab radius r. 
2724   // The track curvature is accounted exactly
2725   //
2726   // The flag "dir" can be used to remove the ambiguity of which intersection to take (out of 2 possible)
2727   // 0  - take the intersection closest to the current track position
2728   // >0 - go along the track (increasing fX)
2729   // <0 - go backward (decreasing fX)
2730   //
2731   const Double_t &fy=fP[0], &sn = fP[2];
2732   //
2733   double crv = GetC(bz);
2734   if (TMath::Abs(crv)<=kAlmost0) { // this is a straight track
2735     if (TMath::Abs(sn)>=kAlmost1) { // || to Y axis
2736       double det = (r-fX)*(r+fX);
2737       if (det<0) return kFALSE;     // does not reach raduis r
2738       x = fX;
2739       if (dir==0) return kTRUE;
2740       det = TMath::Sqrt(det);
2741       if (dir>0) {                       // along the track direction
2742         if (sn>0) {if (fy>det)  return kFALSE;} // track is along Y axis and above the circle
2743         else      {if (fy<-det) return kFALSE;} // track is against Y axis amd belo the circle
2744       }
2745       else {                                    // agains track direction
2746         if (sn>0) {if (fy<-det) return kFALSE;} // track is along Y axis
2747         else if (fy>det)  return kFALSE;        // track is against Y axis
2748       }
2749     }
2750     else if (TMath::Abs(sn)<=kAlmost0) { // || to X axis
2751       double det = (r-fy)*(r+fy);
2752       if (det<0) return kFALSE;     // does not reach raduis r
2753       det = TMath::Sqrt(det);
2754       if (!dir) {
2755         x = fX>0  ? det : -det;    // choose the solution requiring the smalest step
2756         return kTRUE;
2757       }
2758       else if (dir>0) {                    // along the track direction
2759         if      (fX > det) return kFALSE;  // current point is in on the right from the circle
2760         else if (fX <-det) x = -det;       // on the left
2761         else               x =  det;       // within the circle
2762       }
2763       else {                               // against the track direction
2764         if      (fX <-det) return kFALSE;  
2765         else if (fX > det) x =  det;
2766         else               x = -det;
2767       }
2768     }
2769     else {                                 // general case of straight line
2770       double cs = TMath::Sqrt((1-sn)*(1+sn));
2771       double xsyc = fX*sn-fy*cs;
2772       double det = (r-xsyc)*(r+xsyc);
2773       if (det<0) return kFALSE;    // does not reach raduis r
2774       det = TMath::Sqrt(det);
2775       double xcys = fX*cs+fy*sn;
2776       double t = -xcys;
2777       if (dir==0) t += t>0 ? -det:det;  // chose the solution requiring the smalest step
2778       else if (dir>0) {                 // go in increasing fX direction. ( t+-det > 0)
2779         if (t>=-det) t += -det;         // take minimal step giving t>0
2780         else return kFALSE;             // both solutions have negative t
2781       }
2782       else {                            // go in increasing fX direction. (t+-det < 0)
2783         if (t<det) t -= det;            // take minimal step giving t<0
2784         else return kFALSE;             // both solutions have positive t
2785       }
2786       x = fX + cs*t;
2787     }
2788   }
2789   else {                                 // helix
2790     // get center of the track circle
2791     double tR = 1./crv;   // track radius (for the moment signed)
2792     double cs = TMath::Sqrt((1-sn)*(1+sn));
2793     double x0 = fX - sn*tR;
2794     double y0 = fy + cs*tR;
2795     double r0 = TMath::Sqrt(x0*x0+y0*y0);
2796     //    printf("Xc:%+e Yc:%+e\n",x0,y0);
2797     //
2798     if (r0<=kAlmost0) return kFALSE;            // the track is concentric to circle
2799     tR = TMath::Abs(tR);
2800     double tR2r0 = tR/r0;
2801     double g = 0.5*(r*r/(r0*tR) - tR2r0 - 1./tR2r0);
2802     double det = (1.-g)*(1.+g);
2803     if (det<0) return kFALSE;         // does not reach raduis r
2804     det = TMath::Sqrt(det);
2805     //
2806     // the intersection happens in 2 points: {x0+tR*C,y0+tR*S} 
2807     // with C=f*c0+-|s0|*det and S=f*s0-+c0 sign(s0)*det
2808     // where s0 and c0 make direction for the circle center (=x0/r0 and y0/r0)
2809     //
2810     double tmp = 1.+g*tR2r0;
2811     x = x0*tmp; 
2812     double y = y0*tmp;
2813     if (TMath::Abs(y0)>kAlmost0) { // when y0==0 the x,y is unique
2814       double dfx = tR2r0*TMath::Abs(y0)*det;
2815       double dfy = tR2r0*x0*TMath::Sign(det,y0);
2816       if (dir==0) {                    // chose the one which corresponds to smallest step 
2817         double delta = (x-fX)*dfx-(y-fy)*dfy; // the choice of + in C will lead to smaller step if delta<0
2818         if (delta<0) x += dfx;
2819         else         x -= dfx;
2820       }
2821       else if (dir>0) {  // along track direction: x must be > fX
2822         x -= dfx; // try the smallest step (dfx is positive)
2823         if (x<fX && (x+=dfx+dfx)<fX) return kFALSE;
2824       }
2825       else { // backward: x must be < fX
2826         x += dfx; // try the smallest step (dfx is positive)
2827         if (x>fX && (x-=dfx+dfx)>fX) return kFALSE;
2828       }
2829     }
2830     else { // special case: track touching the circle just in 1 point
2831       if ( (dir>0&&x<fX) || (dir<0&&x>fX) ) return kFALSE; 
2832     }
2833   }
2834   //
2835   return kTRUE;
2836 }
2837 //_________________________________________________________
2838 Bool_t AliExternalTrackParam::GetXYZatR(Double_t xr,Double_t bz, Double_t *xyz, Double_t* alpSect) const
2839 {
2840   // This method has 3 modes of behaviour
2841   // 1) xyz[3] array is provided but alpSect pointer is 0: calculate the position of track intersection 
2842   //    with circle of radius xr and fill it in xyz array
2843   // 2) alpSect pointer is provided: find alpha of the sector where the track reaches local coordinate xr
2844   //    Note that in this case xr is NOT the radius but the local coordinate.
2845   //    If the xyz array is provided, it will be filled by track lab coordinates at local X in this sector
2846   // 3) Neither alpSect nor xyz pointers are provided: just check if the track reaches radius xr
2847   //
2848   //
2849   double crv = GetC(bz);
2850   if ( (TMath::Abs(bz))<kAlmost0Field ) crv=0.;
2851   const double &fy = fP[0];
2852   const double &fz = fP[1];
2853   const double &sn = fP[2];
2854   const double &tgl = fP[3];
2855   //
2856   // general circle parameterization:
2857   // x = (r0+tR)cos(phi0) - tR cos(t+phi0)
2858   // y = (r0+tR)sin(phi0) - tR sin(t+phi0)
2859   // where qb is the sign of the curvature, tR is the track's signed radius and r0 
2860   // is the DCA of helix to origin
2861   //
2862   double tR = 1./crv;            // track radius signed
2863   double cs = TMath::Sqrt((1-sn)*(1+sn));
2864   double x0 = fX - sn*tR;        // helix center coordinates
2865   double y0 = fy + cs*tR;
2866   double phi0 = TMath::ATan2(y0,x0);  // angle of PCA wrt to the origin
2867   if (tR<0) phi0 += TMath::Pi();
2868   if      (phi0 > TMath::Pi()) phi0 -= 2.*TMath::Pi();
2869   else if (phi0 <-TMath::Pi()) phi0 += 2.*TMath::Pi();
2870   double cs0 = TMath::Cos(phi0);
2871   double sn0 = TMath::Sin(phi0);
2872   double r0 = x0*cs0 + y0*sn0 - tR; // DCA to origin
2873   double r2R = 1.+r0/tR;
2874   //
2875   //
2876   if (r2R<kAlmost0) return kFALSE;  // helix is centered at the origin, no specific intersection with other concetric circle
2877   if (!xyz && !alpSect) return kTRUE;
2878   double xr2R = xr/tR;
2879   double r2Ri = 1./r2R;
2880   // the intersection cos(t) = [1 + (r0/tR+1)^2 - (r0/tR)^2]/[2(1+r0/tR)]
2881   double cosT = 0.5*(r2R + (1-xr2R*xr2R)*r2Ri);
2882   if ( TMath::Abs(cosT)>kAlmost1 ) {
2883     //    printf("Does not reach : %f %f\n",r0,tR);
2884     return kFALSE; // track does not reach the radius xr
2885   }
2886   //
2887   double t = TMath::ACos(cosT);
2888   if (tR<0) t = -t;
2889   // intersection point
2890   double xyzi[3];
2891   xyzi[0] = x0 - tR*TMath::Cos(t+phi0);
2892   xyzi[1] = y0 - tR*TMath::Sin(t+phi0);
2893   if (xyz) { // if postition is requested, then z is needed:
2894     double t0 = TMath::ATan2(cs,-sn) - phi0;
2895     double z0 = fz - t0*tR*tgl;    
2896     xyzi[2] = z0 + tR*t*tgl;
2897   }
2898   else xyzi[2] = 0;
2899   //
2900   Local2GlobalPosition(xyzi,fAlpha);
2901   //
2902   if (xyz) {
2903     xyz[0] = xyzi[0];
2904     xyz[1] = xyzi[1];
2905     xyz[2] = xyzi[2];
2906   }
2907   //
2908   if (alpSect) {
2909     double &alp = *alpSect;
2910     // determine the sector of crossing
2911     double phiPos = TMath::Pi()+TMath::ATan2(-xyzi[1],-xyzi[0]);
2912     int sect = ((Int_t)(phiPos*TMath::RadToDeg()))/20;
2913     alp = TMath::DegToRad()*(20*sect+10);
2914     double x2r,f1,f2,r1,r2,dx,dy2dx,yloc=0, ylocMax = xr*TMath::Tan(TMath::Pi()/18); // min max Y within sector at given X
2915     //
2916     while(1) {
2917       Double_t ca=TMath::Cos(alp-fAlpha), sa=TMath::Sin(alp-fAlpha);
2918       if ((cs*ca+sn*sa)<0) {
2919         AliDebug(1,Form("Rotation to target sector impossible: local cos(phi) would become %.2f",cs*ca+sn*sa));
2920         return kFALSE;
2921       }
2922       //
2923       f1 = sn*ca - cs*sa;
2924       if (TMath::Abs(f1) >= kAlmost1) {
2925         AliDebug(1,Form("Rotation to target sector impossible: local sin(phi) would become %.2f",f1));
2926         return kFALSE;
2927       }
2928       //
2929       double tmpX =  fX*ca + fy*sa;
2930       double tmpY = -fX*sa + fy*ca;
2931       //
2932       // estimate Y at X=xr
2933       dx=xr-tmpX;
2934       x2r = crv*dx;
2935       f2=f1 + x2r;
2936       if (TMath::Abs(f2) >= kAlmost1) {
2937         AliDebug(1,Form("Propagation in target sector failed ! %.10e",f2));
2938         return kFALSE;
2939       }
2940       r1 = TMath::Sqrt((1.-f1)*(1.+f1));
2941       r2 = TMath::Sqrt((1.-f2)*(1.+f2));
2942       dy2dx = (f1+f2)/(r1+r2);
2943       yloc = tmpY + dx*dy2dx;
2944       if      (yloc>ylocMax)  {alp += 2*TMath::Pi()/18; sect++;}
2945       else if (yloc<-ylocMax) {alp -= 2*TMath::Pi()/18; sect--;}
2946       else break;
2947       if      (alp >= TMath::Pi()) alp -= 2*TMath::Pi();
2948       else if (alp < -TMath::Pi()) alp += 2*TMath::Pi();
2949       //      if (sect>=18) sect = 0;
2950       //      if (sect<=0) sect = 17;
2951     }
2952     //
2953     // if alpha was requested, then recalculate the position at intersection in sector
2954     if (xyz) {
2955       xyz[0] = xr;
2956       xyz[1] = yloc;
2957       if (TMath::Abs(x2r)<0.05) xyz[2] = fz + dx*(r2 + f2*dy2dx)*tgl;
2958       else {
2959         // for small dx/R the linear apporximation of the arc by the segment is OK,
2960         // but at large dx/R the error is very large and leads to incorrect Z propagation
2961         // angle traversed delta = 2*asin(dist_start_end / R / 2), hence the arc is: R*deltaPhi
2962         // The dist_start_end is obtained from sqrt(dx^2+dy^2) = x/(r1+r2)*sqrt(2+f1*f2+r1*r2)
2963         // Similarly, the rotation angle in linear in dx only for dx<<R
2964         double chord = dx*TMath::Sqrt(1+dy2dx*dy2dx);   // distance from old position to new one
2965         double rot = 2*TMath::ASin(0.5*chord*crv); // angular difference seen from the circle center
2966         xyz[2] = fz + rot/crv*tgl;
2967       }
2968       Local2GlobalPosition(xyz,alp);
2969     }
2970   }
2971   return kTRUE;  
2972   //
2973 }
2974
2975
2976 Double_t  AliExternalTrackParam::GetParameterAtRadius(Double_t r, Double_t bz, Int_t parType) const
2977 {
2978   //
2979   // Get track parameters at the radius of interest.
2980   // Given function is aimed to be used to interactivelly (tree->Draw())
2981   // access track properties at different radii
2982   //
2983   // TO BE USED WITH SPECICAL CARE - 
2984   //     it is aimed to be used for rough calculation as constant field and  
2985   //     no correction for material is used
2986   //  
2987   // r  - radius of interest
2988   // bz - magentic field 
2989   // retun values dependens on parType:
2990   //    parType = 0  -gx 
2991   //    parType = 1  -gy 
2992   //    parType = 2  -gz 
2993   //
2994   //    parType = 3  -pgx 
2995   //    parType = 4  -pgy 
2996   //    parType = 5  -pgz
2997   //
2998   //    parType = 6  - r
2999   //    parType = 7  - global position phi
3000   //    parType = 8  - global direction phi
3001   //    parType = 9  - direction phi- positionphi
3002   if (parType<0) {
3003     parType=-1;
3004      return 0;
3005   }
3006   Double_t xyz[3];
3007   Double_t pxyz[3];  
3008   Double_t localX=0;
3009   Bool_t res = GetXatLabR(r,localX,bz,1);
3010   if (!res) {
3011     parType=-1;
3012     return 0;
3013   }
3014   //
3015   // position parameters
3016   // 
3017   GetXYZAt(localX,bz,xyz); 
3018   if (parType<3)   {
3019     return xyz[parType];
3020   }
3021
3022   if (parType==6) return TMath::Sqrt(xyz[0]*xyz[0]+xyz[1]*xyz[1]);
3023   if (parType==7) return TMath::ATan2(xyz[1],xyz[0]);
3024   //
3025   // momenta parameters
3026   //
3027   GetPxPyPzAt(localX,bz,pxyz); 
3028   if (parType==8) return TMath::ATan2(pxyz[1],pxyz[0]);
3029   if (parType==9) {
3030     Double_t diff = TMath::ATan2(pxyz[1],pxyz[0])-TMath::ATan2(xyz[1],xyz[0]);
3031     if (diff>TMath::Pi()) diff-=TMath::TwoPi();
3032     if (diff<-TMath::Pi()) diff+=TMath::TwoPi();
3033     return diff;
3034   }
3035   if (parType>=3&&parType<6) {
3036     return pxyz[parType%3];
3037   }
3038   return 0;
3039 }