1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
17 // This class stores a tracklet (a track that lives only in a single TPC
18 // sector). Its objects can be constructed out of TPCseeds, that are
19 // holding the necessary cluster information.
24 #include "AliTPCTracklet.h"
25 #include "TObjArray.h"
26 #include "TLinearFitter.h"
27 #include "AliTPCseed.h"
28 #include "AliESDVertex.h"
29 #include "AliTracker.h"
30 #include "TTreeStream.h"
32 #include "TDecompChol.h"
37 ClassImp(AliTPCTracklet)
39 const Double_t AliTPCTracklet::kB2C=0.299792458e-3;
41 AliTPCTracklet::AliTPCTracklet()
42 : fNClusters(0),fNStoredClusters(0),fClusters(0),fSector(-1),fOuter(0),
43 fInner(0),fPrimary(0) {
45 // The default constructor. It is intended to be used for I/O only.
49 AliTPCTracklet::AliTPCTracklet(const AliTPCseed *track,Int_t sector,
50 TrackType type,Bool_t storeClusters)
51 : fNClusters(0),fNStoredClusters(0),fClusters(0),fSector(sector),fOuter(0),
52 fInner(0),fPrimary(0) {
54 // Contructor for a tracklet out of a track. Only clusters within a given
58 //TODO: only kalman works
60 for (Int_t i=0;i<160;++i) {
61 AliTPCclusterMI *c=track->GetClusterPointer(i);
62 if (c && c->GetType()<0) continue;
63 if (c&&c->GetDetector()==sector)
68 fClusters=new AliTPCclusterMI[fNClusters];
69 for (Int_t i=0;i<160;++i) {
70 AliTPCclusterMI *c=track->GetClusterPointer(i);
71 if (c && c->GetType()<0) continue;
72 if (c&&c->GetDetector()==sector)
73 fClusters[fNStoredClusters]=*c;
80 FitKalman(track,sector);
84 FitLinear(track,sector,type);
87 FitRiemann(track,sector);
93 AliTPCTracklet::AliTPCTracklet(const TObjArray &/*clusters*/,Int_t sector,
94 TrackType /*type*/,Bool_t /*storeClusters*/)
95 : fNClusters(0),fNStoredClusters(0),fClusters(0),fSector(sector),fOuter(0),
96 fInner(0),fPrimary(0) {
100 AliTPCTracklet::AliTPCTracklet(const AliTPCTracklet &t)
101 : TObject(t),fNClusters(t.fNClusters),fNStoredClusters(t.fNStoredClusters),fClusters(0),
102 fSector(t.fSector),fOuter(0),fInner(0),
105 // The copy constructor. You can copy tracklets!
109 fClusters=new AliTPCclusterMI[t.fNStoredClusters];
110 for (int i=0;i<t.fNStoredClusters;++i)
111 fClusters[i]=t.fClusters[i];
114 fOuter=new AliExternalTrackParam(*t.fOuter);
116 fInner=new AliExternalTrackParam(*t.fInner);
118 fPrimary=new AliExternalTrackParam(*t.fPrimary);
121 AliTPCTracklet& AliTPCTracklet::operator=(const AliTPCTracklet &t) {
123 // The assignment constructor. You can assign tracklets!
126 fNClusters=t.fNClusters;
127 fNStoredClusters=fNStoredClusters;
130 fClusters=new AliTPCclusterMI[t.fNStoredClusters];
131 for (int i=0;i<t.fNStoredClusters;++i)
132 fClusters[i]=t.fClusters[i];
141 fOuter=new AliExternalTrackParam(*t.fOuter);
152 fInner=new AliExternalTrackParam(*t.fInner);
161 *fPrimary=*t.fPrimary;
163 fPrimary=new AliExternalTrackParam(*t.fPrimary);
173 AliTPCTracklet::~AliTPCTracklet() {
175 // The destructor. Yes, you can even destruct tracklets.
183 void AliTPCTracklet::FitKalman(const AliTPCseed *track,Int_t sector) {
185 // Fit using Kalman filter
187 AliTPCseed *t=new AliTPCseed(*track);
188 if (!t->Rotate(TMath::DegToRad()*(sector%18*20.+10.)-t->GetAlpha())) {
192 // fit from inner to outer row
193 AliTPCseed *outerSeed=new AliTPCseed(*t);
195 for (Int_t i=0;i<160;++i) {
196 AliTPCclusterMI *c=t->GetClusterPointer(i);
197 if (c && c->GetType()<0) continue;
198 if (c&&c->GetDetector()==sector) {
200 outerSeed->ResetCovariance(100.);
203 Double_t r[3]={c->GetX(),c->GetY(),c->GetZ()};
204 Double_t cov[3]={0.1,0.,0.1}; //TODO: correct error parametrisation
205 if (!outerSeed->PropagateTo(r[0]) ||
206 !static_cast<AliExternalTrackParam*>(outerSeed)->Update(&r[1],cov)) {
214 fOuter=new AliExternalTrackParam(*outerSeed);
216 // fit from outer to inner rows
217 AliTPCseed *innerSeed=new AliTPCseed(*t);
219 for (Int_t i=159;i>=0;--i) {
220 AliTPCclusterMI *c=t->GetClusterPointer(i);
221 if (c && c->GetType()<0) continue;
222 if (c&&c->GetDetector()==sector) {
224 innerSeed->ResetCovariance(100.);
227 Double_t r[3]={c->GetX(),c->GetY(),c->GetZ()};
228 Double_t cov[3]={0.1,0.,0.1};
229 if (!innerSeed->PropagateTo(r[0]) ||
230 !static_cast<AliExternalTrackParam*>(innerSeed)->Update(&r[1],cov)) {
238 fInner=new AliExternalTrackParam(*innerSeed);
239 // propagate to the primary vertex
241 AliTPCseed *primarySeed=new AliTPCseed(*innerSeed);
242 Double_t pos[]={0.,0.,0.};
243 Double_t sigma[]={.1,.1,.1}; //TODO: is this correct?
244 AliESDVertex vertex(pos,sigma);
245 if (primarySeed->PropagateToVertex(&vertex))
246 fPrimary=new AliExternalTrackParam(*primarySeed);
248 // for better comparison one does not want to have alpha changed...
249 if (fPrimary) if (!fPrimary->Rotate(fInner->GetAlpha())) {
259 void AliTPCTracklet::FitLinear(const AliTPCseed *track,Int_t sector,
263 fy.StoreData(kFALSE);
264 fz.StoreData(kFALSE);
267 fy.SetFormula("1 ++ x");
268 fz.SetFormula("1 ++ x");
271 fy.SetFormula("1 ++ x ++ x*x");
272 fz.SetFormula("1 ++ x");
280 for (Int_t i=0;i<160;++i) {
281 AliTPCclusterMI *c=track->GetClusterPointer(i);
282 if (c && c->GetType()<0) continue;
283 if (c&&c->GetDetector()==sector) {
284 Double_t x=c->GetX();
285 fy.AddPoint(&x,c->GetY());
286 fz.AddPoint(&x,c->GetZ());
287 xmax=TMath::Max(xmax,x);
288 xmin=TMath::Min(xmin,x);
293 Double_t a[3]={fy.GetParameter(0),
295 type==kQuadratic?fy.GetParameter(2):0.};
296 Double_t ca[6]={fy.GetCovarianceMatrixElement(0,0),
297 fy.GetCovarianceMatrixElement(1,0),
298 fy.GetCovarianceMatrixElement(1,1),
299 type==kQuadratic?fy.GetCovarianceMatrixElement(2,0):0.,
300 type==kQuadratic?fy.GetCovarianceMatrixElement(2,1):0.,
301 type==kQuadratic?fy.GetCovarianceMatrixElement(2,2):0.};
302 for (int i=0;i<6;++i) ca[i]*=fy.GetChisquare()/fNClusters;
303 Double_t b[2]={fz.GetParameter(0),
305 Double_t cb[3]={fz.GetCovarianceMatrixElement(0,0),
306 fz.GetCovarianceMatrixElement(1,0),
307 fz.GetCovarianceMatrixElement(1,1)};
308 for (int i=0;i<3;++i) cb[i]*=fz.GetChisquare()/fNClusters;
311 Double_t alpha=track->GetAlpha();
312 Quadratic2Helix(a,ca,b,cb,0.,p,c);
313 fPrimary=new AliExternalTrackParam(0.,alpha,p,c);
314 Quadratic2Helix(a,ca,b,cb,xmin,p,c);
315 fInner=new AliExternalTrackParam(xmin,alpha,p,c);
316 Quadratic2Helix(a,ca,b,cb,xmax,p,c);
317 fOuter=new AliExternalTrackParam(xmax,alpha,p,c);
320 void AliTPCTracklet::Quadratic2Helix(Double_t *a,Double_t *ca,
321 Double_t *b,Double_t *cb,
323 Double_t *p,Double_t *c) {
324 // y(x)=a[0]+a[1]*x+a[2]*x^2
326 // parametrises the corosponding helix at x0
328 // get the polynoms at x0
329 Double_t a0=x0*x0*a[2] + x0*a[1] + a[0];
330 Double_t a1=2.*x0*a[2] + a[1];
332 Double_t ca00=ca[0]+x0*(2.*ca[1]+x0*(ca[2]+2.*ca[3]+x0*(2.*ca[4]+x0*ca[5])));
333 Double_t ca10=ca[1]+x0*(ca[2]+2.*ca[3]+x0*(3.*ca[4]+x0*2.*ca[5]));
334 Double_t ca11=ca[2]+x0*4.*(ca[4]+x0*ca[5]);
335 Double_t ca20=ca[3]+x0*(ca[4]+x0*ca[5]);
336 Double_t ca21=ca[3]+x0*2.*ca[5];
339 Double_t b0=x0*b[1] + b[0];
341 Double_t cb00=cb[0]+x0*(2.*cb[1]+x0*cb[2]);
342 Double_t cb10=cb[1]+x0*cb[2];
345 // transform to helix parameters
346 Double_t f =1.+a1*a1;
349 Double_t fi12=TMath::Sqrt(fi);
350 Double_t fi32=fi*fi12;
352 Double_t fi52=fi2*fi12;
353 Double_t fi3 =fi2*fi;
354 Double_t fi5 =fi2*fi3;
356 Double_t xyz[3]={0.}; // TODO...
357 Double_t fc=1./(GetBz(xyz)*kB2C);
363 p[4]=2.*a2*fi32*fc; // 1/pt
368 c[3] =ca10*fi32; // snp-y0
370 c[5] =ca11*fi3; // snp-snp
372 c[7] =cb10; // tgl-z0
374 c[9] =cb11; // tgl-tgl
375 c[10]=2.*(-3.*a1*a2*ca10+f*ca20)*fi3*fc; // 1/pt-y0
377 c[12]=2.*(-3.*a1*a2*ca11+f*ca21)*fi52*fc; // 1/pt-snp
378 c[13]=0.; // 1/pt-tgl
379 c[14]=(-12.*a1*a2*(-3.*a1*a2*ca11+2.*f*ca21)+4.*f2*ca22)*fi5
384 void AliTPCTracklet::FitRiemann(const AliTPCseed *track,Int_t sector) {
386 fy.StoreData(kFALSE);
387 fy.SetFormula("hyp2");
390 for (Int_t i=0;i<160;++i) {
391 AliTPCclusterMI *c=track->GetClusterPointer(i);
392 if (c && c->GetType()<0) continue;
393 if (c&&c->GetDetector()==sector) {
394 Double_t x=c->GetX();
395 Double_t y=c->GetY();
396 Double_t xy[2]={x,y};
398 Double_t errx=1.,erry=1.;//TODO!
399 Double_t err=TMath::Sqrt(4.*x*x*errx+4.*y*y*erry);
401 fy.AddPoint(xy,r,err);
402 xmax=TMath::Max(xmax,x);
403 xmin=TMath::Min(xmin,x);
407 Double_t a[3]={fy.GetParameter(0),
410 Double_t ca[6]={fy.GetCovarianceMatrixElement(0,0),
411 fy.GetCovarianceMatrixElement(1,0),
412 fy.GetCovarianceMatrixElement(1,1),
413 fy.GetCovarianceMatrixElement(2,0),
414 fy.GetCovarianceMatrixElement(2,1),
415 fy.GetCovarianceMatrixElement(2,2)};
418 fz.StoreData(kFALSE);
419 fz.SetFormula("hyp1");
420 Double_t R=.5*TMath::Sqrt(4.*a[0]+a[1]*a[1]+a[2]*a[2]);
424 for (Int_t i=0;i<160;++i) {
425 AliTPCclusterMI *c=track->GetClusterPointer(i);
426 if (c && c->GetType()<0) continue;
427 if (c&&c->GetDetector()==sector) {
428 Double_t x=c->GetX();
429 Double_t y=c->GetY();
432 phi+=2.*TMath::Abs(TMath::ATan2(.5*TMath::Sqrt(dx*dx+dy*dy),R));
434 fz.AddPoint(&phi,c->GetZ(),err);
440 Double_t b[2]={fz.GetParameter(0),
442 Double_t cb[3]={fz.GetCovarianceMatrixElement(0,0),
443 fz.GetCovarianceMatrixElement(1,0),
444 fz.GetCovarianceMatrixElement(1,1)};
448 Double_t alpha=track->GetAlpha();
449 if (Riemann2Helix(a,ca,b,cb,0.,p,c))
450 fPrimary=new AliExternalTrackParam(0.,alpha,p,c);
451 if (Riemann2Helix(a,ca,b,cb,xmin,p,c))
452 fInner=new AliExternalTrackParam(xmin,alpha,p,c);
453 if (Riemann2Helix(a,ca,b,cb,xmax,p,c))
454 fOuter=new AliExternalTrackParam(xmax,alpha,p,c);
457 Bool_t AliTPCTracklet::Riemann2Helix(Double_t *a,Double_t */*ca*/,
458 Double_t *b,Double_t */*cb*/,
460 Double_t *p,Double_t *c) {
463 Double_t xr0=.5*a[1];
464 Double_t yr0=.5*a[2];
465 Double_t R=.5*TMath::Sqrt(4.*a[0]+a[1]*a[1]+a[2]*a[2]);
467 if (dx*dx>=R*R) return kFALSE;
468 Double_t dy=TMath::Sqrt(R*R-dx*dx); //sign!!
469 if (TMath::Abs(yr0+dy)>TMath::Abs(yr0-dy))
472 Double_t tgp=-dx/dy; //TODO: dy!=0
473 Double_t z0=b[0]+TMath::ATan(tgp)*b[1];
474 Double_t xyz[3]={x0,y0,z0};
475 Double_t fc=1./(GetBz(xyz)*kB2C);
479 p[2]=tgp/TMath::Sqrt(1.+tgp*tgp); // snp
481 p[4]=1./R*fc; // 1/pt
495 c[12]=0.; // 1/pt-snp
496 c[13]=0.; // 1/pt-tgl
497 c[14]=0.; // 1/pt-1/pt
502 TObjArray AliTPCTracklet::CreateTracklets(const AliTPCseed *track,
504 Bool_t storeClusters,
506 Int_t maxTracklets) {
507 // The tracklet factory: It creates several tracklets out of a track. They
508 // are created for sectors that fullfill the constraint of having enough
509 // clusters inside. Futhermore you can specify the maximum amount of
510 // tracklets that are to be created.
511 // The tracklets appear in a sorted fashion, beginning with those having the
514 Int_t sectors[72]={0};
515 for (Int_t i=0;i<160;++i) {
516 AliTPCclusterMI *c=track->GetClusterPointer(i);
517 if (c && c->GetType()<0) continue;
519 ++sectors[c->GetDetector()];
522 TMath::Sort(72,sectors,indices);
524 if (maxTracklets>72) maxTracklets=72; // just to protect against "users".
525 for (Int_t i=0;i<maxTracklets&§ors[indices[i]]>=minClusters;++i) {
526 tracklets.Add(new AliTPCTracklet(track,indices[i],type,storeClusters));
531 TObjArray AliTPCTracklet::CreateTracklets(const TObjArray &/*clusters*/,
533 Bool_t /*storeClusters*/,
534 Int_t /*minClusters*/,
535 Int_t /*maxTracklets*/) {
542 Bool_t AliTPCTracklet::PropagateToMeanX(const AliTPCTracklet &t1,
543 const AliTPCTracklet &t2,
544 AliExternalTrackParam *&t1m,
545 AliExternalTrackParam *&t2m) {
546 // This function propagates two Tracklets to a common x-coordinate. This
547 // x is dermined as the one that is in the middle of the two tracklets (they
548 // are assumed to live on two distinct x-intervalls).
549 // The inner parametrisation of the outer Tracklet and the outer
550 // parametrisation of the inner Tracklet are used and propagated to this
551 // common x. This result is saved not inside the Tracklets but two new
552 // ExternalTrackParams are created (that means you might want to delete
554 // In the case that the alpha angles of the Tracklets differ both angles
555 // are tried out for this propagation.
556 // In case of any failure kFALSE is returned, no AliExternalTrackParam
557 // is created und the pointers are set to 0.
559 if (t1.GetInner() && t1.GetOuter() &&
560 t2.GetInner() && t2.GetOuter()) {
561 if (t1.GetOuter()->GetX()<t2.GetInner()->GetX()) {
562 t1m=new AliExternalTrackParam(*t1.GetOuter());
563 t2m=new AliExternalTrackParam(*t2.GetInner());
566 t1m=new AliExternalTrackParam(*t1.GetInner());
567 t2m=new AliExternalTrackParam(*t2.GetOuter());
569 Double_t mx=.5*(t1m->GetX()+t2m->GetX());
576 if (t1m->Rotate(t2m->GetAlpha())
577 && t1m->PropagateTo(mx,b1)
578 && t2m->PropagateTo(mx,b2));
580 if (t2m->Rotate(t1m->GetAlpha())
581 && t1m->PropagateTo(mx,b1)
582 && t2m->PropagateTo(mx,b2));
595 double AliTPCTracklet::GetBz(Double_t *xyz) {
596 if (AliTracker::UniformField())
597 return AliTracker::GetBz();
599 return AliTracker::GetBz(xyz);
602 void AliTPCTracklet::RandomND(Int_t ndim,const Double_t *p,const Double_t *c,
604 // This function generates a n-dimensional random variable x with mean
605 // p and covariance c.
606 // That is done using the cholesky decomposition of the covariance matrix,
607 // Begin_Latex C=U^{t} U End_Latex, with Begin_Latex U End_Latex being an
608 // upper triangular matrix. Given a vector v of iid gausian random variables
609 // with variance 1 one obtains the asked result as: Begin_Latex x=U^t v
611 // c is expected to be in a lower triangular format:
616 static TRandom3 random;
617 Double_t *c2= new Double_t[ndim*ndim];
619 for (Int_t i=0;i<ndim;++i)
620 for (Int_t j=0;j<=i;++j)
621 c2[i*ndim+j]=c2[j*ndim+i]=c[k++];
622 TMatrixDSym cm(ndim,c2);
624 TDecompChol chol(cm);
626 const TVectorD pv(ndim);
627 const_cast<TVectorD*>(&pv)->Use(ndim,const_cast<Double_t*>(p));
630 for (Int_t i=0;i<ndim;++i)
632 TMatrixD L=chol.GetU();
637 TEllipse AliTPCTracklet::ErrorEllipse(Double_t x,Double_t y,
638 Double_t sx,Double_t sy,Double_t sxy) {
640 r_{1,2}=1/2 (a+c#pm#sqrt{(a-c)^{2}+(2b)^{2}})
642 Double_t det1=1./(sx*sy-sxy*sxy);
644 Double_t b=-sxy*det1;
647 Double_t s=TMath::Sqrt(d*d+4.*b*b);
648 Double_t r1=TMath::Sqrt(.5*(a+c-s));
649 Double_t r2=TMath::Sqrt(.5*(a+c+s));
650 Double_t alpha=.5*TMath::ATan2(2.*b,d);
651 return TEllipse(x,y,r1,r2,0.,360.,alpha*TMath::RadToDeg());
654 void AliTPCTracklet::Test(const char* filename) {
657 AliTPCTracklet::Test("");
658 TFile f("AliTPCTrackletDebug.root");
659 TTree *t=f.Get("AliTPCTrackletDebug");
661 TEllipse e=AliTPCTracklet::ErrorEllipse(0.,0.,4.,1.,1.8);
664 TTreeSRedirector ds(filename);
671 for (Int_t i=0;i<10000;++i) {
674 ds<<"AliTPCTrackletDebug"
687 Double_t param[5]={0.};
688 Double_t covar[15]={1.,
693 AliExternalTrackParam track(x,alpha,param,covar);
697 for (Int_t i=0;i<points.GetNPoints();++i) {
700 Double_t param[5]={0.};
701 Double_t covar[15]={1.,
706 AliExternalTrackParam track(x,alpha,param,covar);
707 for (x=90.;x<250.;x+=1.) {
708 track.PropagateTo(x,b);