]> git.uio.no Git - u/mrichter/AliRoot.git/blame - TRD/AliTRDseedV1.cxx
- new gain calibb
[u/mrichter/AliRoot.git] / TRD / AliTRDseedV1.cxx
CommitLineData
e4f2f73d 1/**************************************************************************
29b87567 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**************************************************************************/
e4f2f73d 15
16/* $Id$ */
17
18////////////////////////////////////////////////////////////////////////////
dd8059a8 19////
20// The TRD offline tracklet
21//
22// The running horse of the TRD reconstruction. The following tasks are preformed:
23// 1. Clusters attachment to tracks based on prior information stored at tracklet level (see AttachClusters)
24// 2. Clusters position recalculation based on track information (see GetClusterXY and Fit)
25// 3. Cluster error parametrization recalculation (see Fit)
26// 4. Linear track approximation (Fit)
27// 5. Optimal position (including z estimate for pad row cross tracklets) and covariance matrix of the track fit inside one TRD chamber (Fit)
28// 6. Tilt pad correction and systematic effects (GetCovAt)
29// 7. dEdx calculation (CookdEdx)
30// 8. PID probabilities estimation (CookPID)
31//
e4f2f73d 32// Authors: //
33// Alex Bercuci <A.Bercuci@gsi.de> //
34// Markus Fasel <M.Fasel@gsi.de> //
35// //
36////////////////////////////////////////////////////////////////////////////
37
38#include "TMath.h"
9dcc64cc 39#include "TTreeStream.h"
40#include "TGraphErrors.h"
e4f2f73d 41
42#include "AliLog.h"
43#include "AliMathBase.h"
4ecadb52 44#include "AliRieman.h"
d937ad7a 45#include "AliCDBManager.h"
e4f2f73d 46
4ecadb52 47#include "AliTRDReconstructor.h"
03cef9b2 48#include "AliTRDpadPlane.h"
9dcc64cc 49#include "AliTRDtransform.h"
e4f2f73d 50#include "AliTRDcluster.h"
f3d3af1b 51#include "AliTRDseedV1.h"
52#include "AliTRDtrackV1.h"
e4f2f73d 53#include "AliTRDcalibDB.h"
eb38ed55 54#include "AliTRDchamberTimeBin.h"
55#include "AliTRDtrackingChamber.h"
56#include "AliTRDtrackerV1.h"
e4f2f73d 57#include "AliTRDrecoParam.h"
a076fc2f 58#include "AliTRDCommonParam.h"
9dcc64cc 59#include "AliTRDtrackletOflHelper.h"
d937ad7a 60
9dcc64cc 61#include "Cal/AliTRDCalTrkAttach.h"
0906e73e 62#include "Cal/AliTRDCalPID.h"
d937ad7a 63#include "Cal/AliTRDCalROC.h"
64#include "Cal/AliTRDCalDet.h"
e4f2f73d 65
4ecadb52 66class AliTracker;
67
e4f2f73d 68ClassImp(AliTRDseedV1)
69
70//____________________________________________________________________
ae4e8b84 71AliTRDseedV1::AliTRDseedV1(Int_t det)
3e778975 72 :AliTRDtrackletBase()
4d6aee34 73 ,fkReconstructor(NULL)
74 ,fClusterIter(NULL)
e3cf3d02 75 ,fExB(0.)
76 ,fVD(0.)
77 ,fT0(0.)
78 ,fS2PRF(0.)
79 ,fDiffL(0.)
80 ,fDiffT(0.)
ae4e8b84 81 ,fClusterIdx(0)
7c3eecb8 82 ,fErrorMsg(0)
3e778975 83 ,fN(0)
ae4e8b84 84 ,fDet(det)
b25a5e9e 85 ,fPt(0.)
bcb6fb78 86 ,fdX(0.)
e3cf3d02 87 ,fX0(0.)
88 ,fX(0.)
89 ,fY(0.)
90 ,fZ(0.)
91 ,fS2Y(0.)
92 ,fS2Z(0.)
e3cf3d02 93 ,fChi2(0.)
e4f2f73d 94{
95 //
96 // Constructor
97 //
f301a656 98 memset(fIndexes,0xFF,kNclusters*sizeof(fIndexes[0]));
8d2bec9e 99 memset(fClusters, 0, kNclusters*sizeof(AliTRDcluster*));
2eb10c34 100 memset(fPad, 0, 4*sizeof(Float_t));
e3cf3d02 101 fYref[0] = 0.; fYref[1] = 0.;
102 fZref[0] = 0.; fZref[1] = 0.;
103 fYfit[0] = 0.; fYfit[1] = 0.;
104 fZfit[0] = 0.; fZfit[1] = 0.;
8d2bec9e 105 memset(fdEdx, 0, kNslices*sizeof(Float_t));
29b87567 106 for(int ispec=0; ispec<AliPID::kSPECIES; ispec++) fProb[ispec] = -1.;
e3cf3d02 107 fLabels[0]=-1; fLabels[1]=-1; // most freq MC labels
108 fLabels[2]=0; // number of different labels for tracklet
16cca13f 109 memset(fRefCov, 0, 7*sizeof(Double_t));
68f9b6bd 110 // stand alone curvature
111 fC[0] = 0.; fC[1] = 0.;
d937ad7a 112 // covariance matrix [diagonal]
113 // default sy = 200um and sz = 2.3 cm
114 fCov[0] = 4.e-4; fCov[1] = 0.; fCov[2] = 5.3;
f29f13a6 115 SetStandAlone(kFALSE);
e4f2f73d 116}
117
118//____________________________________________________________________
0906e73e 119AliTRDseedV1::AliTRDseedV1(const AliTRDseedV1 &ref)
3e778975 120 :AliTRDtrackletBase((AliTRDtrackletBase&)ref)
4d6aee34 121 ,fkReconstructor(NULL)
122 ,fClusterIter(NULL)
e3cf3d02 123 ,fExB(0.)
124 ,fVD(0.)
125 ,fT0(0.)
126 ,fS2PRF(0.)
127 ,fDiffL(0.)
128 ,fDiffT(0.)
ae4e8b84 129 ,fClusterIdx(0)
7c3eecb8 130 ,fErrorMsg(0)
3e778975 131 ,fN(0)
e3cf3d02 132 ,fDet(-1)
b25a5e9e 133 ,fPt(0.)
e3cf3d02 134 ,fdX(0.)
135 ,fX0(0.)
136 ,fX(0.)
137 ,fY(0.)
138 ,fZ(0.)
139 ,fS2Y(0.)
140 ,fS2Z(0.)
e3cf3d02 141 ,fChi2(0.)
e4f2f73d 142{
143 //
144 // Copy Constructor performing a deep copy
145 //
e3cf3d02 146 if(this != &ref){
147 ref.Copy(*this);
148 }
29b87567 149 SetBit(kOwner, kFALSE);
f29f13a6 150 SetStandAlone(ref.IsStandAlone());
fbb2ea06 151}
d9950a5a 152
0906e73e 153
e4f2f73d 154//____________________________________________________________________
155AliTRDseedV1& AliTRDseedV1::operator=(const AliTRDseedV1 &ref)
156{
157 //
158 // Assignment Operator using the copy function
159 //
160
29b87567 161 if(this != &ref){
162 ref.Copy(*this);
163 }
221ab7e0 164 SetBit(kOwner, kFALSE);
165
29b87567 166 return *this;
e4f2f73d 167}
168
169//____________________________________________________________________
170AliTRDseedV1::~AliTRDseedV1()
171{
172 //
173 // Destructor. The RecoParam object belongs to the underlying tracker.
174 //
175
29b87567 176 //printf("I-AliTRDseedV1::~AliTRDseedV1() : Owner[%s]\n", IsOwner()?"YES":"NO");
e4f2f73d 177
e3cf3d02 178 if(IsOwner()) {
8d2bec9e 179 for(int itb=0; itb<kNclusters; itb++){
29b87567 180 if(!fClusters[itb]) continue;
181 //AliInfo(Form("deleting c %p @ %d", fClusters[itb], itb));
182 delete fClusters[itb];
4d6aee34 183 fClusters[itb] = NULL;
29b87567 184 }
e3cf3d02 185 }
e4f2f73d 186}
187
188//____________________________________________________________________
189void AliTRDseedV1::Copy(TObject &ref) const
190{
191 //
192 // Copy function
193 //
194
29b87567 195 //AliInfo("");
196 AliTRDseedV1 &target = (AliTRDseedV1 &)ref;
197
4d6aee34 198 target.fkReconstructor = fkReconstructor;
199 target.fClusterIter = NULL;
e3cf3d02 200 target.fExB = fExB;
201 target.fVD = fVD;
202 target.fT0 = fT0;
203 target.fS2PRF = fS2PRF;
204 target.fDiffL = fDiffL;
205 target.fDiffT = fDiffT;
ae4e8b84 206 target.fClusterIdx = 0;
7c3eecb8 207 target.fErrorMsg = fErrorMsg;
3e778975 208 target.fN = fN;
ae4e8b84 209 target.fDet = fDet;
b25a5e9e 210 target.fPt = fPt;
29b87567 211 target.fdX = fdX;
e3cf3d02 212 target.fX0 = fX0;
213 target.fX = fX;
214 target.fY = fY;
215 target.fZ = fZ;
216 target.fS2Y = fS2Y;
217 target.fS2Z = fS2Z;
e3cf3d02 218 target.fChi2 = fChi2;
29b87567 219
8d2bec9e 220 memcpy(target.fIndexes, fIndexes, kNclusters*sizeof(Int_t));
221 memcpy(target.fClusters, fClusters, kNclusters*sizeof(AliTRDcluster*));
2eb10c34 222 memcpy(target.fPad, fPad, 4*sizeof(Float_t));
e3cf3d02 223 target.fYref[0] = fYref[0]; target.fYref[1] = fYref[1];
224 target.fZref[0] = fZref[0]; target.fZref[1] = fZref[1];
225 target.fYfit[0] = fYfit[0]; target.fYfit[1] = fYfit[1];
226 target.fZfit[0] = fZfit[0]; target.fZfit[1] = fZfit[1];
8d2bec9e 227 memcpy(target.fdEdx, fdEdx, kNslices*sizeof(Float_t));
e3cf3d02 228 memcpy(target.fProb, fProb, AliPID::kSPECIES*sizeof(Float_t));
229 memcpy(target.fLabels, fLabels, 3*sizeof(Int_t));
16cca13f 230 memcpy(target.fRefCov, fRefCov, 7*sizeof(Double_t));
68f9b6bd 231 target.fC[0] = fC[0]; target.fC[1] = fC[1];
e3cf3d02 232 memcpy(target.fCov, fCov, 3*sizeof(Double_t));
29b87567 233
e3cf3d02 234 TObject::Copy(ref);
e4f2f73d 235}
236
0906e73e 237
4ecadb52 238//____________________________________________________________
239void AliTRDseedV1::Init(const AliRieman *rieman)
240{
241// Initialize this tracklet using the riemann fit information
242
243
244 fZref[0] = rieman->GetZat(fX0);
245 fZref[1] = rieman->GetDZat(fX0);
246 fYref[0] = rieman->GetYat(fX0);
247 fYref[1] = rieman->GetDYat(fX0);
248 if(fkReconstructor && fkReconstructor->IsHLT()){
249 fRefCov[0] = 1;
250 fRefCov[2] = 10;
251 }else{
252 fRefCov[0] = rieman->GetErrY(fX0);
253 fRefCov[2] = rieman->GetErrZ(fX0);
254 }
255 fC[0] = rieman->GetC();
256 fChi2 = rieman->GetChi2();
257}
258
259
0906e73e 260//____________________________________________________________
f3d3af1b 261Bool_t AliTRDseedV1::Init(AliTRDtrackV1 *track)
0906e73e 262{
263// Initialize this tracklet using the track information
264//
265// Parameters:
266// track - the TRD track used to initialize the tracklet
267//
268// Detailed description
269// The function sets the starting point and direction of the
270// tracklet according to the information from the TRD track.
271//
272// Caution
273// The TRD track has to be propagated to the beginning of the
274// chamber where the tracklet will be constructed
275//
276
29b87567 277 Double_t y, z;
278 if(!track->GetProlongation(fX0, y, z)) return kFALSE;
16cca13f 279 Update(track);
29b87567 280 return kTRUE;
0906e73e 281}
282
bcb6fb78 283
e3cf3d02 284//_____________________________________________________________________________
980d5a2a 285void AliTRDseedV1::Reset(Option_t *opt)
e3cf3d02 286{
980d5a2a 287//
288// Reset seed. If option opt="c" is given only cluster arrays are cleared.
289//
290 for(Int_t ic=kNclusters; ic--;) fIndexes[ic] = -1;
291 memset(fClusters, 0, kNclusters*sizeof(AliTRDcluster*));
560e5c05 292 fN=0; SetBit(kRowCross, kFALSE);
980d5a2a 293 if(strcmp(opt, "c")==0) return;
294
e3cf3d02 295 fExB=0.;fVD=0.;fT0=0.;fS2PRF=0.;
296 fDiffL=0.;fDiffT=0.;
3e778975 297 fClusterIdx=0;
7c3eecb8 298 fErrorMsg = 0;
dd8059a8 299 fDet=-1;
b25a5e9e 300 fPt=0.;
e3cf3d02 301 fdX=0.;fX0=0.; fX=0.; fY=0.; fZ=0.;
302 fS2Y=0.; fS2Z=0.;
68f9b6bd 303 fC[0]=0.; fC[1]=0.;
304 fChi2 = 0.;
e3cf3d02 305
2eb10c34 306 memset(fPad, 0, 4*sizeof(Float_t));
e3cf3d02 307 fYref[0] = 0.; fYref[1] = 0.;
308 fZref[0] = 0.; fZref[1] = 0.;
309 fYfit[0] = 0.; fYfit[1] = 0.;
310 fZfit[0] = 0.; fZfit[1] = 0.;
8d2bec9e 311 memset(fdEdx, 0, kNslices*sizeof(Float_t));
e3cf3d02 312 for(int ispec=0; ispec<AliPID::kSPECIES; ispec++) fProb[ispec] = -1.;
313 fLabels[0]=-1; fLabels[1]=-1; // most freq MC labels
314 fLabels[2]=0; // number of different labels for tracklet
16cca13f 315 memset(fRefCov, 0, 7*sizeof(Double_t));
e3cf3d02 316 // covariance matrix [diagonal]
317 // default sy = 200um and sz = 2.3 cm
318 fCov[0] = 4.e-4; fCov[1] = 0.; fCov[2] = 5.3;
319}
320
b1957d3c 321//____________________________________________________________________
16cca13f 322void AliTRDseedV1::Update(const AliTRDtrackV1 *trk)
b1957d3c 323{
324 // update tracklet reference position from the TRD track
b1957d3c 325
e3cf3d02 326 Double_t fSnp = trk->GetSnp();
327 Double_t fTgl = trk->GetTgl();
b25a5e9e 328 fPt = trk->Pt();
bfd20868 329 Double_t norm =1./TMath::Sqrt((1.-fSnp)*(1.+fSnp));
1fd9389f 330 fYref[1] = fSnp*norm;
331 fZref[1] = fTgl*norm;
b1957d3c 332 SetCovRef(trk->GetCovariance());
333
334 Double_t dx = trk->GetX() - fX0;
335 fYref[0] = trk->GetY() - dx*fYref[1];
336 fZref[0] = trk->GetZ() - dx*fZref[1];
337}
338
e3cf3d02 339//_____________________________________________________________________________
340void AliTRDseedV1::UpdateUsed()
341{
342 //
f29f13a6 343 // Calculate number of used clusers in the tracklet
e3cf3d02 344 //
345
3e778975 346 Int_t nused = 0, nshared = 0;
8d2bec9e 347 for (Int_t i = kNclusters; i--; ) {
e3cf3d02 348 if (!fClusters[i]) continue;
3e778975 349 if(fClusters[i]->IsUsed()){
350 nused++;
351 } else if(fClusters[i]->IsShared()){
352 if(IsStandAlone()) nused++;
353 else nshared++;
354 }
e3cf3d02 355 }
3e778975 356 SetNUsed(nused);
357 SetNShared(nshared);
e3cf3d02 358}
359
360//_____________________________________________________________________________
361void AliTRDseedV1::UseClusters()
362{
363 //
364 // Use clusters
365 //
f29f13a6 366 // In stand alone mode:
367 // Clusters which are marked as used or shared from another track are
368 // removed from the tracklet
369 //
370 // In barrel mode:
371 // - Clusters which are used by another track become shared
372 // - Clusters which are attached to a kink track become shared
373 //
e3cf3d02 374 AliTRDcluster **c = &fClusters[0];
8d2bec9e 375 for (Int_t ic=kNclusters; ic--; c++) {
e3cf3d02 376 if(!(*c)) continue;
f29f13a6 377 if(IsStandAlone()){
378 if((*c)->IsShared() || (*c)->IsUsed()){
b82b4de1 379 if((*c)->IsShared()) SetNShared(GetNShared()-1);
380 else SetNUsed(GetNUsed()-1);
4d6aee34 381 (*c) = NULL;
f29f13a6 382 fIndexes[ic] = -1;
3e778975 383 SetN(GetN()-1);
3e778975 384 continue;
f29f13a6 385 }
3e778975 386 } else {
f29f13a6 387 if((*c)->IsUsed() || IsKink()){
3e778975 388 (*c)->SetShared();
389 continue;
f29f13a6 390 }
391 }
392 (*c)->Use();
e3cf3d02 393 }
394}
395
396
f29f13a6 397
bcb6fb78 398//____________________________________________________________________
399void AliTRDseedV1::CookdEdx(Int_t nslices)
400{
401// Calculates average dE/dx for all slices and store them in the internal array fdEdx.
402//
403// Parameters:
404// nslices : number of slices for which dE/dx should be calculated
405// Output:
406// store results in the internal array fdEdx. This can be accessed with the method
407// AliTRDseedV1::GetdEdx()
408//
409// Detailed description
410// Calculates average dE/dx for all slices. Depending on the PID methode
411// the number of slices can be 3 (LQ) or 8(NN).
3ee48d6e 412// The calculation of dQ/dl are done using the tracklet fit results (see AliTRDseedV1::GetdQdl(Int_t))
bcb6fb78 413//
414// The following effects are included in the calculation:
415// 1. calibration values for t0 and vdrift (using x coordinate to calculate slice)
416// 2. cluster sharing (optional see AliTRDrecoParam::SetClusterSharing())
417// 3. cluster size
418//
419
8d2bec9e 420 memset(fdEdx, 0, kNslices*sizeof(Float_t));
e73abf77 421 const Double_t kDriftLength = (.5 * AliTRDgeometry::AmThick() + AliTRDgeometry::DrThick());
29b87567 422
0d80a563 423 AliTRDcluster *c(NULL);
424 for(int ic=0; ic<AliTRDtrackerV1::GetNTimeBins(); ic++){
425 if(!(c = fClusters[ic]) && !(c = fClusters[ic+kNtb])) continue;
426 Float_t dx = TMath::Abs(fX0 - c->GetX());
427
29b87567 428 // Filter clusters for dE/dx calculation
0d80a563 429
29b87567 430 // 1.consider calibration effects for slice determination
0d80a563 431 Int_t slice;
432 if(dx<kDriftLength){ // TODO should be replaced by c->IsInChamber()
433 slice = Int_t(dx * nslices / kDriftLength);
434 } else slice = c->GetX() < fX0 ? nslices-1 : 0;
435
e73abf77 436
29b87567 437 // 2. take sharing into account
3e778975 438 Float_t w = /*c->IsShared() ? .5 :*/ 1.;
0d80a563 439
29b87567 440 // 3. take into account large clusters TODO
441 //w *= c->GetNPads() > 3 ? .8 : 1.;
85b917f6 442
0d80a563 443 //CHECK !!!
444 fdEdx[slice] += w * GetdQdl(ic); //fdQdl[ic];
445 } // End of loop over clusters
bcb6fb78 446}
447
e3cf3d02 448//_____________________________________________________________________________
449void AliTRDseedV1::CookLabels()
450{
451 //
452 // Cook 2 labels for seed
453 //
454
455 Int_t labels[200];
456 Int_t out[200];
457 Int_t nlab = 0;
8d2bec9e 458 for (Int_t i = 0; i < kNclusters; i++) {
e3cf3d02 459 if (!fClusters[i]) continue;
460 for (Int_t ilab = 0; ilab < 3; ilab++) {
461 if (fClusters[i]->GetLabel(ilab) >= 0) {
462 labels[nlab] = fClusters[i]->GetLabel(ilab);
463 nlab++;
464 }
465 }
466 }
467
fac58f00 468 fLabels[2] = AliMathBase::Freq(nlab,labels,out,kTRUE);
e3cf3d02 469 fLabels[0] = out[0];
470 if ((fLabels[2] > 1) && (out[3] > 1)) fLabels[1] = out[2];
471}
472
2eb10c34 473//____________________________________________________________
474Float_t AliTRDseedV1::GetAnodeWireOffset(Float_t zt)
475{
4ecadb52 476// Find position inside the amplification cell for reading drift velocity map
477
2eb10c34 478 Float_t d = fPad[3] - zt;
479 if(d<0.){
480 AliError(Form("Fail AnodeWireOffset calculation z0[%+7.2f] zt[%+7.2f] d[%+7.2f].", fPad[3], zt, d));
481 return 0.125;
482 }
483 d -= ((Int_t)(2 * d)) / 2.0;
484 if(d > 0.25) d = 0.5 - d;
485 return d;
486}
487
e3cf3d02 488
85b917f6 489//____________________________________________________________________
9dcc64cc 490Float_t AliTRDseedV1::GetCharge(Bool_t useOutliers) const
85b917f6 491{
492// Computes total charge attached to tracklet. If "useOutliers" is set clusters
493// which are not in chamber are also used (default false)
494
495 AliTRDcluster *c(NULL); Float_t qt(0.);
496 for(int ic=0; ic<kNclusters; ic++){
497 if(!(c=fClusters[ic])) continue;
498 if(c->IsInChamber() && !useOutliers) continue;
499 qt += TMath::Abs(c->GetQ());
500 }
501 return qt;
502}
503
e1bcf0af 504//____________________________________________________________________
505Bool_t AliTRDseedV1::GetEstimatedCrossPoint(Float_t &x, Float_t &z) const
506{
507// Algorithm to estimate cross point in the x-z plane for pad row cross tracklets.
508// Returns true in case of success.
509 if(!IsRowCross()) return kFALSE;
510
511 x=0.; z=0.;
512 AliTRDcluster *c(NULL);
513 // Find radial range for first row
514 Float_t x1[] = {0., 1.e3};
515 for(int ic=0; ic<kNtb; ic++){
516 if(!(c=fClusters[ic])) continue;
517 if(!c->IsInChamber()) continue;
518 if(c->GetX() <= x1[1]) x1[1] = c->GetX();
519 if(c->GetX() >= x1[0]) x1[0] = c->GetX();
520 z=c->GetZ();
521 }
522 if((x1[0] - x1[1])<1.e-5) return kFALSE;
523
524 // Find radial range for second row
525 Bool_t kZ(kFALSE);
526 Float_t x2[] = {0., 1.e3};
527 for(int ic=kNtb; ic<kNclusters; ic++){
528 if(!(c=fClusters[ic])) continue;
529 if(!c->IsInChamber()) continue;
530 if(c->GetX() <= x2[1]) x2[1] = c->GetX();
531 if(c->GetX() >= x2[0]) x2[0] = c->GetX();
532 if(!kZ){
533 z+=c->GetZ();
534 z*=0.5;
535 kZ=kTRUE;
536 }
537 }
538 if((x2[0] - x2[1])<1.e-5) return kFALSE;
539
540 // Find intersection of the 2 radial regions
541 x = 0.5*((x1[0]+x1[1] > x2[0]+x2[1]) ? (x1[1]+x2[0]) : (x1[0]+x2[1]));
542 return kTRUE;
543}
544
a0bb5615 545//____________________________________________________________________
546Float_t AliTRDseedV1::GetQperTB(Int_t tb) const
547{
548 //
549 // Charge of the clusters at timebin
550 //
551 Float_t Q = 0;
552 if(fClusters[tb] /*&& fClusters[tb]->IsInChamber()*/)
553 Q += TMath::Abs(fClusters[tb]->GetQ());
554 if(fClusters[tb+kNtb] /*&& fClusters[tb+kNtb]->IsInChamber()*/)
555 Q += TMath::Abs(fClusters[tb+kNtb]->GetQ());
556 return Q/TMath::Sqrt(1. + fYref[1]*fYref[1] + fZref[1]*fZref[1]);
557}
558
9dcc64cc 559//____________________________________________________________________
560Float_t AliTRDseedV1::GetdQdl() const
561{
562// Calculate total charge / tracklet length for 1D PID
563//
564 Float_t Q = GetCharge(kTRUE);
565 return Q/TMath::Sqrt(1. + fYref[1]*fYref[1] + fZref[1]*fZref[1]);
566}
567
bcb6fb78 568//____________________________________________________________________
0b433f72 569Float_t AliTRDseedV1::GetdQdl(Int_t ic, Float_t *dl) const
bcb6fb78 570{
3ee48d6e 571// Using the linear approximation of the track inside one TRD chamber (TRD tracklet)
572// the charge per unit length can be written as:
573// BEGIN_LATEX
500851ab 574// #frac{dq}{dl} = #frac{q_{c}}{dx * #sqrt{1 + #(){#frac{dy}{dx}}^{2}_{fit} + #(){#frac{dz}{dx}}^{2}_{ref}}}
3ee48d6e 575// END_LATEX
576// where qc is the total charge collected in the current time bin and dx is the length
0b433f72 577// of the time bin.
578// The following correction are applied :
579// - charge : pad row cross corrections
580// [diffusion and TRF assymetry] TODO
581// - dx : anisochronity, track inclination - see Fit and AliTRDcluster::GetXloc()
582// and AliTRDcluster::GetYloc() for the effects taken into account
3ee48d6e 583//
0fa1a8ee 584//Begin_Html
585//<img src="TRD/trackletDQDT.gif">
586//End_Html
587// In the picture the energy loss measured on the tracklet as a function of drift time [left] and respectively
588// drift length [right] for different particle species is displayed.
3ee48d6e 589// Author : Alex Bercuci <A.Bercuci@gsi.de>
590//
591 Float_t dq = 0.;
5d401b45 592 // check whether both clusters are inside the chamber
593 Bool_t hasClusterInChamber = kFALSE;
594 if(fClusters[ic] && fClusters[ic]->IsInChamber()){
595 hasClusterInChamber = kTRUE;
1742f24c 596 dq += TMath::Abs(fClusters[ic]->GetQ());
b30d8c09 597 }
598 if(fClusters[ic+kNtb] && fClusters[ic+kNtb]->IsInChamber()){
5d401b45 599 hasClusterInChamber = kTRUE;
600 dq += TMath::Abs(fClusters[ic+kNtb]->GetQ());
1742f24c 601 }
5d401b45 602 if(!hasClusterInChamber) return 0.;
0b433f72 603 if(dq<1.e-3) return 0.;
3ee48d6e 604
a2abcbc5 605 Double_t dx = fdX;
606 if(ic-1>=0 && ic+1<kNtb){
607 Float_t x2(0.), x1(0.);
5d401b45 608 // try to estimate upper radial position (find the cluster which is inside the chamber)
609 if(fClusters[ic-1] && fClusters[ic-1]->IsInChamber()) x2 = fClusters[ic-1]->GetX();
610 else if(fClusters[ic-1+kNtb] && fClusters[ic-1+kNtb]->IsInChamber()) x2 = fClusters[ic-1+kNtb]->GetX();
611 else if(fClusters[ic] && fClusters[ic]->IsInChamber()) x2 = fClusters[ic]->GetX()+fdX;
a2abcbc5 612 else x2 = fClusters[ic+kNtb]->GetX()+fdX;
5d401b45 613 // try to estimate lower radial position (find the cluster which is inside the chamber)
614 if(fClusters[ic+1] && fClusters[ic+1]->IsInChamber()) x1 = fClusters[ic+1]->GetX();
615 else if(fClusters[ic+1+kNtb] && fClusters[ic+1+kNtb]->IsInChamber()) x1 = fClusters[ic+1+kNtb]->GetX();
616 else if(fClusters[ic] && fClusters[ic]->IsInChamber()) x1 = fClusters[ic]->GetX()-fdX;
a2abcbc5 617 else x1 = fClusters[ic+kNtb]->GetX()-fdX;
618
619 dx = .5*(x2 - x1);
620 }
0b433f72 621 dx *= TMath::Sqrt(1. + fYfit[1]*fYfit[1] + fZref[1]*fZref[1]);
0b433f72 622 if(dl) (*dl) = dx;
283604d2 623 if(dx>1.e-9) return dq/dx;
624 else return 0.;
bcb6fb78 625}
626
0b433f72 627//____________________________________________________________
628Float_t AliTRDseedV1::GetMomentum(Float_t *err) const
629{
630// Returns momentum of the track after update with the current tracklet as:
631// BEGIN_LATEX
632// p=#frac{1}{1/p_{t}} #sqrt{1+tgl^{2}}
633// END_LATEX
634// and optionally the momentum error (if err is not null).
635// The estimated variance of the momentum is given by:
636// BEGIN_LATEX
637// #sigma_{p}^{2} = (#frac{dp}{dp_{t}})^{2} #sigma_{p_{t}}^{2}+(#frac{dp}{dtgl})^{2} #sigma_{tgl}^{2}+2#frac{dp}{dp_{t}}#frac{dp}{dtgl} cov(tgl,1/p_{t})
638// END_LATEX
639// which can be simplified to
640// BEGIN_LATEX
641// #sigma_{p}^{2} = p^{2}p_{t}^{4}tgl^{2}#sigma_{tgl}^{2}-2p^{2}p_{t}^{3}tgl cov(tgl,1/p_{t})+p^{2}p_{t}^{2}#sigma_{1/p_{t}}^{2}
642// END_LATEX
643//
644
645 Double_t p = fPt*TMath::Sqrt(1.+fZref[1]*fZref[1]);
646 Double_t p2 = p*p;
647 Double_t tgl2 = fZref[1]*fZref[1];
648 Double_t pt2 = fPt*fPt;
649 if(err){
650 Double_t s2 =
651 p2*tgl2*pt2*pt2*fRefCov[4]
652 -2.*p2*fZref[1]*fPt*pt2*fRefCov[5]
653 +p2*pt2*fRefCov[6];
654 (*err) = TMath::Sqrt(s2);
655 }
656 return p;
657}
658
9dcc64cc 659
b453ef55 660//____________________________________________________________________
5c5d503a 661Int_t AliTRDseedV1::GetTBoccupancy() const
b453ef55 662{
5c5d503a 663// Returns no. of TB occupied by clusters
b453ef55 664
665 Int_t n(0);
5c5d503a 666 for(int ic(0); ic<kNtb; ic++){
667 if(!fClusters[ic] && !fClusters[ic+kNtb]) continue;
b453ef55 668 n++;
669 }
5c5d503a 670 return n;
671}
b453ef55 672
5c5d503a 673//____________________________________________________________________
674Int_t AliTRDseedV1::GetTBcross() const
675{
676// Returns no. of TB occupied by 2 clusters for pad row cross tracklets
677
678 if(!IsRowCross()) return 0;
679 Int_t n(0);
680 for(int ic(0); ic<kNtb; ic++){
681 if(fClusters[ic] && fClusters[ic+kNtb]) n++;
682 }
683 return n;
b453ef55 684}
0b433f72 685
0906e73e 686//____________________________________________________________________
3e778975 687Float_t* AliTRDseedV1::GetProbability(Bool_t force)
0906e73e 688{
3e778975 689 if(!force) return &fProb[0];
4d6aee34 690 if(!CookPID()) return NULL;
3e778975 691 return &fProb[0];
692}
693
694//____________________________________________________________
695Bool_t AliTRDseedV1::CookPID()
696{
0906e73e 697// Fill probability array for tracklet from the DB.
698//
699// Parameters
700//
701// Output
4d6aee34 702// returns pointer to the probability array and NULL if missing DB access
0906e73e 703//
2a3191bb 704// Retrieve PID probabilities for e+-, mu+-, K+-, pi+- and p+- from the DB according to tracklet information:
705// - estimated momentum at tracklet reference point
706// - dE/dx measurements
707// - tracklet length
708// - TRD layer
709// According to the steering settings specified in the reconstruction one of the following methods are used
710// - Neural Network [default] - option "nn"
711// - 2D Likelihood - option "!nn"
0906e73e 712
0906e73e 713 AliTRDcalibDB *calibration = AliTRDcalibDB::Instance();
714 if (!calibration) {
715 AliError("No access to calibration data");
3e778975 716 return kFALSE;
0906e73e 717 }
718
4d6aee34 719 if (!fkReconstructor) {
3a039a31 720 AliError("Reconstructor not set.");
3e778975 721 return kFALSE;
4ba1d6ae 722 }
723
0906e73e 724 // Retrieve the CDB container class with the parametric detector response
4d6aee34 725 const AliTRDCalPID *pd = calibration->GetPIDObject(fkReconstructor->GetPIDMethod());
0906e73e 726 if (!pd) {
727 AliError("No access to AliTRDCalPID object");
3e778975 728 return kFALSE;
0906e73e 729 }
10f75631 730
29b87567 731 // calculate tracklet length TO DO
560e5c05 732 Float_t length = (AliTRDgeometry::AmThick() + AliTRDgeometry::DrThick())/ TMath::Sqrt((1.0 - GetSnp()*GetSnp()) / (1.0 + GetTgl()*GetTgl()));
0906e73e 733
734 //calculate dE/dx
9ded305e 735 CookdEdx(AliTRDCalPID::kNSlicesNN);
736 AliDebug(4, Form("p=%6.4f[GeV/c] dEdx{%7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f} l=%4.2f[cm]", GetMomentum(), fdEdx[0], fdEdx[1], fdEdx[2], fdEdx[3], fdEdx[4], fdEdx[5], fdEdx[6], fdEdx[7], length));
0217fcd0 737
0906e73e 738 // Sets the a priori probabilities
11d80e40 739 Bool_t kPIDNN(fkReconstructor->GetPIDMethod()==AliTRDpidUtil::kNN);
f83cd814 740 for(int ispec=0; ispec<AliPID::kSPECIES; ispec++)
11d80e40 741 fProb[ispec] = pd->GetProbability(ispec, GetMomentum(), &fdEdx[0], length, kPIDNN?GetPlane():fkReconstructor->GetRecoParam()->GetPIDLQslices());
f301a656 742
3e778975 743 return kTRUE;
0906e73e 744}
745
e4f2f73d 746//____________________________________________________________________
747Float_t AliTRDseedV1::GetQuality(Bool_t kZcorr) const
748{
749 //
750 // Returns a quality measurement of the current seed
751 //
752
dd8059a8 753 Float_t zcorr = kZcorr ? GetTilt() * (fZfit[0] - fZref[0]) : 0.;
29b87567 754 return
3e778975 755 .5 * TMath::Abs(18.0 - GetN())
29b87567 756 + 10.* TMath::Abs(fYfit[1] - fYref[1])
757 + 5. * TMath::Abs(fYfit[0] - fYref[0] + zcorr)
dd8059a8 758 + 2. * TMath::Abs(fZfit[0] - fZref[0]) / GetPadLength();
e4f2f73d 759}
760
0906e73e 761//____________________________________________________________________
d937ad7a 762void AliTRDseedV1::GetCovAt(Double_t x, Double_t *cov) const
0906e73e 763{
d937ad7a 764// Computes covariance in the y-z plane at radial point x (in tracking coordinates)
765// and returns the results in the preallocated array cov[3] as :
766// cov[0] = Var(y)
767// cov[1] = Cov(yz)
768// cov[2] = Var(z)
769//
770// Details
771//
772// For the linear transformation
773// BEGIN_LATEX
774// Y = T_{x} X^{T}
775// END_LATEX
776// The error propagation has the general form
777// BEGIN_LATEX
778// C_{Y} = T_{x} C_{X} T_{x}^{T}
779// END_LATEX
780// We apply this formula 2 times. First to calculate the covariance of the tracklet
781// at point x we consider:
782// BEGIN_LATEX
783// T_{x} = (1 x); X=(y0 dy/dx); C_{X}=#(){#splitline{Var(y0) Cov(y0, dy/dx)}{Cov(y0, dy/dx) Var(dy/dx)}}
784// END_LATEX
785// and secondly to take into account the tilt angle
786// BEGIN_LATEX
787// T_{#alpha} = #(){#splitline{cos(#alpha) __ sin(#alpha)}{-sin(#alpha) __ cos(#alpha)}}; X=(y z); C_{X}=#(){#splitline{Var(y) 0}{0 Var(z)}}
788// END_LATEX
789//
790// using simple trigonometrics one can write for this last case
791// BEGIN_LATEX
792// C_{Y}=#frac{1}{1+tg^{2}#alpha} #(){#splitline{(#sigma_{y}^{2}+tg^{2}#alpha#sigma_{z}^{2}) __ tg#alpha(#sigma_{z}^{2}-#sigma_{y}^{2})}{tg#alpha(#sigma_{z}^{2}-#sigma_{y}^{2}) __ (#sigma_{z}^{2}+tg^{2}#alpha#sigma_{y}^{2})}}
793// END_LATEX
794// which can be aproximated for small alphas (2 deg) with
795// BEGIN_LATEX
796// C_{Y}=#(){#splitline{#sigma_{y}^{2} __ (#sigma_{z}^{2}-#sigma_{y}^{2})tg#alpha}{((#sigma_{z}^{2}-#sigma_{y}^{2})tg#alpha __ #sigma_{z}^{2}}}
797// END_LATEX
798//
799// before applying the tilt rotation we also apply systematic uncertainties to the tracklet
800// position which can be tunned from outside via the AliTRDrecoParam::SetSysCovMatrix(). They might
801// account for extra misalignment/miscalibration uncertainties.
802//
803// Author :
804// Alex Bercuci <A.Bercuci@gsi.de>
805// Date : Jan 8th 2009
806//
b1957d3c 807
808
d937ad7a 809 Double_t xr = fX0-x;
810 Double_t sy2 = fCov[0] +2.*xr*fCov[1] + xr*xr*fCov[2];
b72f4eaf 811 Double_t sz2 = fS2Z;
812 //GetPadLength()*GetPadLength()/12.;
0906e73e 813
d937ad7a 814 // insert systematic uncertainties
4d6aee34 815 if(fkReconstructor){
bb2db46c 816 Double_t sys[15]; memset(sys, 0, 15*sizeof(Double_t));
4d6aee34 817 fkReconstructor->GetRecoParam()->GetSysCovMatrix(sys);
bb2db46c 818 sy2 += sys[0];
819 sz2 += sys[1];
820 }
2eb10c34 821
822 // rotate covariance matrix if no RC
823 if(!IsRowCross()){
824 Double_t t2 = GetTilt()*GetTilt();
825 Double_t correction = 1./(1. + t2);
826 cov[0] = (sy2+t2*sz2)*correction;
827 cov[1] = GetTilt()*(sz2 - sy2)*correction;
828 cov[2] = (t2*sy2+sz2)*correction;
829 } else {
830 cov[0] = sy2; cov[1] = 0.; cov[2] = sy2;
831 }
832
833 AliDebug(4, Form("C(%6.1f %+6.3f %6.1f) RC[%c]", 1.e4*TMath::Sqrt(cov[0]), cov[1], 1.e4*TMath::Sqrt(cov[2]), IsRowCross()?'y':'n'));
d937ad7a 834}
eb38ed55 835
bb2db46c 836//____________________________________________________________
66765e8e 837Int_t AliTRDseedV1::GetCovSqrt(const Double_t * const c, Double_t *d)
bb2db46c 838{
839// Helper function to calculate the square root of the covariance matrix.
840// The input matrix is stored in the vector c and the result in the vector d.
41b7c7b6 841// Both arrays have to be initialized by the user with at least 3 elements. Return negative in case of failure.
bb2db46c 842//
ec3f0161 843// For calculating the square root of the symmetric matrix c
844// the following relation is used:
bb2db46c 845// BEGIN_LATEX
ec3f0161 846// C^{1/2} = VD^{1/2}V^{-1}
bb2db46c 847// END_LATEX
41b7c7b6 848// with V being the matrix with the n eigenvectors as columns.
ec3f0161 849// In case C is symmetric the followings are true:
850// - matrix D is diagonal with the diagonal given by the eigenvalues of C
41b7c7b6 851// - V = V^{-1}
bb2db46c 852//
853// Author A.Bercuci <A.Bercuci@gsi.de>
854// Date Mar 19 2009
855
66765e8e 856 const Double_t kZero(1.e-20);
4d6aee34 857 Double_t l[2], // eigenvalues
858 v[3]; // eigenvectors
bb2db46c 859 // the secular equation and its solution :
860 // (c[0]-L)(c[2]-L)-c[1]^2 = 0
861 // L^2 - L*Tr(c)+DET(c) = 0
862 // L12 = [Tr(c) +- sqrt(Tr(c)^2-4*DET(c))]/2
4d6aee34 863 Double_t tr = c[0]+c[2], // trace
864 det = c[0]*c[2]-c[1]*c[1]; // determinant
66765e8e 865 if(TMath::Abs(det)<kZero) return 1;
4d6aee34 866 Double_t dd = TMath::Sqrt(tr*tr - 4*det);
66765e8e 867 l[0] = .5*(tr + dd*(c[0]>c[2]?-1.:1.));
868 l[1] = .5*(tr + dd*(c[0]>c[2]?1.:-1.));
869 if(l[0]<kZero || l[1]<kZero) return 2;
41b7c7b6 870 // the sym V matrix
871 // | v00 v10|
872 // | v10 v11|
66765e8e 873 Double_t den = (l[0]-c[0])*(l[0]-c[0])+c[1]*c[1];
874 if(den<kZero){ // almost diagonal
875 v[0] = TMath::Sign(0., c[1]);
876 v[1] = TMath::Sign(1., (l[0]-c[0]));
877 v[2] = TMath::Sign(0., c[1]*(l[0]-c[0])*(l[1]-c[2]));
878 } else {
879 Double_t tmp = 1./TMath::Sqrt(den);
880 v[0] = c[1]* tmp;
881 v[1] = (l[0]-c[0])*tmp;
882 if(TMath::Abs(l[1]-c[2])<kZero) v[2] = TMath::Sign(v[0]*(l[0]-c[0])/kZero, (l[1]-c[2]));
883 else v[2] = v[0]*(l[0]-c[0])/(l[1]-c[2]);
884 }
41b7c7b6 885 // the VD^{1/2}V is:
4d6aee34 886 l[0] = TMath::Sqrt(l[0]); l[1] = TMath::Sqrt(l[1]);
887 d[0] = v[0]*v[0]*l[0]+v[1]*v[1]*l[1];
888 d[1] = v[0]*v[1]*l[0]+v[1]*v[2]*l[1];
889 d[2] = v[1]*v[1]*l[0]+v[2]*v[2]*l[1];
bb2db46c 890
66765e8e 891 return 0;
bb2db46c 892}
893
894//____________________________________________________________
4d6aee34 895Double_t AliTRDseedV1::GetCovInv(const Double_t * const c, Double_t *d)
bb2db46c 896{
897// Helper function to calculate the inverse of the covariance matrix.
898// The input matrix is stored in the vector c and the result in the vector d.
899// Both arrays have to be initialized by the user with at least 3 elements
900// The return value is the determinant or 0 in case of singularity.
901//
902// Author A.Bercuci <A.Bercuci@gsi.de>
903// Date Mar 19 2009
904
4d6aee34 905 Double_t det = c[0]*c[2] - c[1]*c[1];
906 if(TMath::Abs(det)<1.e-20) return 0.;
907 Double_t invDet = 1./det;
908 d[0] = c[2]*invDet;
909 d[1] =-c[1]*invDet;
910 d[2] = c[0]*invDet;
911 return det;
bb2db46c 912}
0906e73e 913
b72f4eaf 914//____________________________________________________________________
915UShort_t AliTRDseedV1::GetVolumeId() const
916{
4ecadb52 917// Returns geometry volume id by delegation
918
fbe11be7 919 for(Int_t ic(0);ic<kNclusters; ic++){
920 if(fClusters[ic]) return fClusters[ic]->GetVolumeId();
921 }
922 return 0;
b72f4eaf 923}
924
925
d937ad7a 926//____________________________________________________________________
e3cf3d02 927void AliTRDseedV1::Calibrate()
d937ad7a 928{
e3cf3d02 929// Retrieve calibration and position parameters from OCDB.
930// The following information are used
d937ad7a 931// - detector index
e3cf3d02 932// - column and row position of first attached cluster. If no clusters are attached
933// to the tracklet a random central chamber position (c=70, r=7) will be used.
934//
935// The following information is cached in the tracklet
936// t0 (trigger delay)
937// drift velocity
938// PRF width
939// omega*tau = tg(a_L)
940// diffusion coefficients (longitudinal and transversal)
d937ad7a 941//
942// Author :
943// Alex Bercuci <A.Bercuci@gsi.de>
944// Date : Jan 8th 2009
945//
eb38ed55 946
d937ad7a 947 AliCDBManager *cdb = AliCDBManager::Instance();
948 if(cdb->GetRun() < 0){
949 AliError("OCDB manager not properly initialized");
950 return;
951 }
0906e73e 952
e3cf3d02 953 AliTRDcalibDB *calib = AliTRDcalibDB::Instance();
954 AliTRDCalROC *vdROC = calib->GetVdriftROC(fDet),
955 *t0ROC = calib->GetT0ROC(fDet);;
956 const AliTRDCalDet *vdDet = calib->GetVdriftDet();
957 const AliTRDCalDet *t0Det = calib->GetT0Det();
d937ad7a 958
959 Int_t col = 70, row = 7;
960 AliTRDcluster **c = &fClusters[0];
3e778975 961 if(GetN()){
d937ad7a 962 Int_t ic = 0;
8d2bec9e 963 while (ic<kNclusters && !(*c)){ic++; c++;}
d937ad7a 964 if(*c){
965 col = (*c)->GetPadCol();
966 row = (*c)->GetPadRow();
967 }
968 }
3a039a31 969
e17f4785 970 fT0 = (t0Det->GetValue(fDet) + t0ROC->GetValue(col,row)) / AliTRDCommonParam::Instance()->GetSamplingFrequency();
e3cf3d02 971 fVD = vdDet->GetValue(fDet) * vdROC->GetValue(col, row);
972 fS2PRF = calib->GetPRFWidth(fDet, col, row); fS2PRF *= fS2PRF;
973 fExB = AliTRDCommonParam::Instance()->GetOmegaTau(fVD);
974 AliTRDCommonParam::Instance()->GetDiffCoeff(fDiffL,
975 fDiffT, fVD);
903326c1 976 AliDebug(4, Form("Calibration params for Det[%3d] Col[%3d] Row[%2d]\n t0[%f] vd[%f] s2PRF[%f] ExB[%f] Dl[%f] Dt[%f]", fDet, col, row, fT0, fVD, fS2PRF, fExB, fDiffL, fDiffT));
977
978
e3cf3d02 979 SetBit(kCalib, kTRUE);
0906e73e 980}
981
0906e73e 982//____________________________________________________________________
29b87567 983void AliTRDseedV1::SetOwner()
0906e73e 984{
29b87567 985 //AliInfo(Form("own [%s] fOwner[%s]", own?"YES":"NO", fOwner?"YES":"NO"));
986
987 if(TestBit(kOwner)) return;
8d2bec9e 988 for(int ic=0; ic<kNclusters; ic++){
29b87567 989 if(!fClusters[ic]) continue;
990 fClusters[ic] = new AliTRDcluster(*fClusters[ic]);
991 }
992 SetBit(kOwner);
0906e73e 993}
994
eb2b4f91 995//____________________________________________________________
4ecadb52 996void AliTRDseedV1::SetPadPlane(AliTRDpadPlane * const p)
eb2b4f91 997{
998// Shortcut method to initialize pad geometry.
2eb10c34 999 fPad[0] = p->GetLengthIPad();
1000 fPad[1] = p->GetWidthIPad();
1001 fPad[2] = TMath::Tan(TMath::DegToRad()*p->GetTiltingAngle());
1002 fPad[3] = p->GetRow0() + p->GetAnodeWireOffset();
eb2b4f91 1003}
1004
1005
9dcc64cc 1006
e4f2f73d 1007//____________________________________________________________________
9dcc64cc 1008Bool_t AliTRDseedV1::AttachClusters(AliTRDtrackingChamber *const chamber, Bool_t tilt, Bool_t chgPos, Int_t ev)
e4f2f73d 1009{
1fd9389f 1010//
1011// Projective algorithm to attach clusters to seeding tracklets. The following steps are performed :
1012// 1. Collapse x coordinate for the full detector plane
1013// 2. truncated mean on y (r-phi) direction
1014// 3. purge clusters
1015// 4. truncated mean on z direction
1016// 5. purge clusters
1017//
1018// Parameters
1019// - chamber : pointer to tracking chamber container used to search the tracklet
1020// - tilt : switch for tilt correction during road building [default true]
1021// Output
1022// - true : if tracklet found successfully. Failure can happend because of the following:
1023// -
1024// Detailed description
9dcc64cc 1025//
1fd9389f 1026// We start up by defining the track direction in the xy plane and roads. The roads are calculated based
8a7ff53c 1027// on tracking information (variance in the r-phi direction) and estimated variance of the standard
1028// clusters (see AliTRDcluster::SetSigmaY2()) corrected for tilt (see GetCovAt()). From this the road is
1029// BEGIN_LATEX
500851ab 1030// r_{y} = 3*#sqrt{12*(#sigma^{2}_{Trk}(y) + #frac{#sigma^{2}_{cl}(y) + tg^{2}(#alpha_{L})#sigma^{2}_{cl}(z)}{1+tg^{2}(#alpha_{L})})}
8a7ff53c 1031// r_{z} = 1.5*L_{pad}
1032// END_LATEX
1fd9389f 1033//
4b755889 1034// Author : Alexandru Bercuci <A.Bercuci@gsi.de>
9dcc64cc 1035// Debug : level = 2 for calibration
1036// level = 3 for visualization in the track SR
1037// level = 4 for full visualization including digit level
1fd9389f 1038
fc0882f3 1039 const AliTRDrecoParam* const recoParam = fkReconstructor->GetRecoParam(); //the dynamic cast in GetRecoParam is slow, so caching the pointer to it
1040
1041 if(!recoParam){
560e5c05 1042 AliError("Tracklets can not be used without a valid RecoParam.");
29b87567 1043 return kFALSE;
1044 }
9dcc64cc 1045 AliTRDcalibDB *calibration = AliTRDcalibDB::Instance();
1046 if (!calibration) {
1047 AliError("No access to calibration data");
1048 return kFALSE;
1049 }
1050 // Retrieve the CDB container class with the parametric likelihood
1051 const AliTRDCalTrkAttach *attach = calibration->GetAttachObject();
1052 if (!attach) {
1053 AliError("No usable AttachClusters calib object.");
1054 return kFALSE;
1055 }
1056
b1957d3c 1057 // Initialize reco params for this tracklet
1058 // 1. first time bin in the drift region
a2abcbc5 1059 Int_t t0 = 14;
fc0882f3 1060 Int_t kClmin = Int_t(recoParam->GetFindableClusters()*AliTRDtrackerV1::GetNTimeBins());
9dcc64cc 1061 Int_t kTBmin = 4;
29b87567 1062
9dcc64cc 1063 Double_t sysCov[5]; recoParam->GetSysCovMatrix(sysCov);
8a7ff53c 1064 Double_t s2yTrk= fRefCov[0],
1065 s2yCl = 0.,
1066 s2zCl = GetPadLength()*GetPadLength()/12.,
1067 syRef = TMath::Sqrt(s2yTrk),
1068 t2 = GetTilt()*GetTilt();
29b87567 1069 //define roads
9dcc64cc 1070 const Double_t kroady = 3.; //recoParam->GetRoad1y();
1071 const Double_t kroadz = GetPadLength() * recoParam->GetRoadzMultiplicator() + 1.;
8a7ff53c 1072 // define probing cluster (the perfect cluster) and default calibration
1073 Short_t sig[] = {0, 0, 10, 30, 10, 0,0};
1074 AliTRDcluster cp(fDet, 6, 75, 0, sig, 0);
560e5c05 1075 if(fkReconstructor->IsHLT()) cp.SetRPhiMethod(AliTRDcluster::kCOG);
1076 if(!IsCalibrated()) Calibrate();
8a7ff53c 1077
9dcc64cc 1078 Int_t kroadyShift(0);
1079 Float_t bz(AliTrackerBase::GetBz());
1080 if(TMath::Abs(bz)>2.){
1081 if(bz<0.) kroadyShift = chgPos ? +1 : -1;
1082 else kroadyShift = chgPos ? -1 : +1;
1083 }
1084 AliDebug(4, Form("\n syTrk[cm]=%4.2f dydxTrk[deg]=%+6.2f rs[%d] Chg[%c] rY[cm]=%4.2f rZ[cm]=%5.2f TC[%c]", syRef, TMath::ATan(fYref[1])*TMath::RadToDeg(), kroadyShift, chgPos?'+':'-', kroady, kroadz, tilt?'y':'n'));
1085 Double_t phiTrk(TMath::ATan(fYref[1])),
1086 thtTrk(TMath::ATan(fZref[1]));
29b87567 1087
1088 // working variables
b1957d3c 1089 const Int_t kNrows = 16;
4b755889 1090 const Int_t kNcls = 3*kNclusters; // buffer size
9dcc64cc 1091 TObjArray clst[kNrows];
3044dfe5 1092 Bool_t blst[kNrows][kNcls];
9dcc64cc 1093 Double_t cond[4],
1094 dx, dy, dz,
1095 yt, zt,
1096 zc[kNrows],
1097 xres[kNrows][kNcls], yres[kNrows][kNcls], zres[kNrows][kNcls], s2y[kNrows][kNcls];
4b755889 1098 Int_t idxs[kNrows][kNcls], ncl[kNrows], ncls = 0;
b1957d3c 1099 memset(ncl, 0, kNrows*sizeof(Int_t));
9dcc64cc 1100 memset(zc, 0, kNrows*sizeof(Double_t));
1101 memset(idxs, 0, kNrows*kNcls*sizeof(Int_t));
1102 memset(xres, 0, kNrows*kNcls*sizeof(Double_t));
4b755889 1103 memset(yres, 0, kNrows*kNcls*sizeof(Double_t));
9dcc64cc 1104 memset(zres, 0, kNrows*kNcls*sizeof(Double_t));
1105 memset(s2y, 0, kNrows*kNcls*sizeof(Double_t));
3044dfe5 1106 memset(blst, 0, kNrows*kNcls*sizeof(Bool_t)); //this is 8 times faster to memset than "memset(clst, 0, kNrows*kNcls*sizeof(AliTRDcluster*))"
b1957d3c 1107
9dcc64cc 1108 Double_t roady(0.), s2Mean(0.), sMean(0.); Int_t ns2Mean(0);
1109
1110 // Do cluster projection and pick up cluster candidates
1111 AliTRDcluster *c(NULL);
1112 AliTRDchamberTimeBin *layer(NULL);
b1957d3c 1113 Bool_t kBUFFER = kFALSE;
4b755889 1114 for (Int_t it = 0; it < kNtb; it++) {
b1957d3c 1115 if(!(layer = chamber->GetTB(it))) continue;
29b87567 1116 if(!Int_t(*layer)) continue;
8a7ff53c 1117 // get track projection at layers position
b1957d3c 1118 dx = fX0 - layer->GetX();
1119 yt = fYref[0] - fYref[1] * dx;
1120 zt = fZref[0] - fZref[1] * dx;
9dcc64cc 1121 // get standard cluster error corrected for tilt if selected
8a7ff53c 1122 cp.SetLocalTimeBin(it);
1123 cp.SetSigmaY2(0.02, fDiffT, fExB, dx, -1./*zt*/, fYref[1]);
9dcc64cc 1124 s2yCl = cp.GetSigmaY2() + sysCov[0]; if(!tilt) s2yCl = (s2yCl + t2*s2zCl)/(1.+t2);
1125 if(TMath::Abs(it-12)<7){ s2Mean += cp.GetSigmaY2(); ns2Mean++;}
1126 // get estimated road in r-phi direction
1127 roady = TMath::Min(3.*TMath::Sqrt(12.*(s2yTrk + s2yCl)), kroady);
1128
1129 AliDebug(5, Form("\n"
1130 " %2d xd[cm]=%6.3f yt[cm]=%7.2f zt[cm]=%8.2f\n"
1131 " syTrk[um]=%6.2f syCl[um]=%6.2f syClTlt[um]=%6.2f\n"
1132 " Ry[mm]=%f"
1133 , it, dx, yt, zt
1134 , 1.e4*TMath::Sqrt(s2yTrk), 1.e4*TMath::Sqrt(cp.GetSigmaY2()+sysCov[0]), 1.e4*TMath::Sqrt(s2yCl)
1135 , 1.e1*roady));
1136
1137 // get clusters from layer
1138 cond[0] = yt/*+0.5*kroadyShift*kroady*/; cond[2] = roady;
b1957d3c 1139 cond[1] = zt; cond[3] = kroadz;
9dcc64cc 1140 Int_t n=0, idx[6]; layer->GetClusters(cond, idx, n, 6);
b1957d3c 1141 for(Int_t ic = n; ic--;){
1142 c = (*layer)[idx[ic]];
9dcc64cc 1143 dx = fX0 - c->GetX();
1144 yt = fYref[0] - fYref[1] * dx;
1145 zt = fZref[0] - fZref[1] * dx;
1146 dz = zt - c->GetZ();
1147 dy = yt - (c->GetY() + (tilt ? (GetTilt() * dz) : 0.));
b1957d3c 1148 Int_t r = c->GetPadRow();
9dcc64cc 1149 clst[r].AddAtAndExpand(c, ncl[r]);
3044dfe5 1150 blst[r][ncl[r]] = kTRUE;
b1957d3c 1151 idxs[r][ncl[r]] = idx[ic];
9dcc64cc 1152 zres[r][ncl[r]] = dz/GetPadLength();
b1957d3c 1153 yres[r][ncl[r]] = dy;
9dcc64cc 1154 xres[r][ncl[r]] = dx;
1155 zc[r] = c->GetZ();
1156 // TODO temporary solution to avoid divercences in error parametrization
1157 s2y[r][ncl[r]] = TMath::Min(c->GetSigmaY2()+sysCov[0], 0.025);
1158 AliDebug(5, Form(" -> dy[cm]=%+7.4f yc[cm]=%7.2f row[%d] idx[%2d]", dy, c->GetY(), r, ncl[r]));
b1957d3c 1159 ncl[r]++; ncls++;
1160
4b755889 1161 if(ncl[r] >= kNcls) {
560e5c05 1162 AliWarning(Form("Cluster candidates row[%d] reached buffer limit[%d]. Some may be lost.", r, kNcls));
b1957d3c 1163 kBUFFER = kTRUE;
29b87567 1164 break;
1165 }
1166 }
b1957d3c 1167 if(kBUFFER) break;
29b87567 1168 }
ee8fb199 1169 if(ncls<kClmin){
560e5c05 1170 AliDebug(1, Form("CLUSTERS FOUND %d LESS THAN THRESHOLD %d.", ncls, kClmin));
7c3eecb8 1171 SetErrorMsg(kAttachClFound);
9dcc64cc 1172 for(Int_t ir(kNrows);ir--;) clst[ir].Clear();
ee8fb199 1173 return kFALSE;
1174 }
9dcc64cc 1175 if(ns2Mean<kTBmin){
1176 AliDebug(1, Form("CLUSTERS IN TimeBins %d LESS THAN THRESHOLD %d.", ns2Mean, kTBmin));
1177 SetErrorMsg(kAttachClFound);
1178 for(Int_t ir(kNrows);ir--;) clst[ir].Clear();
1179 return kFALSE;
1180 }
1181 s2Mean /= ns2Mean; sMean = TMath::Sqrt(s2Mean);
1182 //Double_t sRef(TMath::Sqrt(s2Mean+s2yTrk)); // reference error parameterization
1183
1184 // organize row candidates
1185 Int_t idxRow[kNrows], nrc(0); Double_t zresRow[kNrows];
1186 for(Int_t ir(0); ir<kNrows; ir++){
1187 idxRow[ir]=-1; zresRow[ir] = 999.;
1188 if(!ncl[ir]) continue;
1189 // get mean z resolution
1190 dz = 0.; for(Int_t ic = ncl[ir]; ic--;) dz += zres[ir][ic]; dz/=ncl[ir];
1191 // insert row
1192 idxRow[nrc] = ir; zresRow[nrc] = TMath::Abs(dz); nrc++;
1193 }
1194 AliDebug(4, Form("Found %d clusters in %d rows. Sorting ...", ncls, nrc));
1195
1196 // sort row candidates
1197 if(nrc>=2){
1198 if(nrc==2){
1199 if(zresRow[0]>zresRow[1]){ // swap
1200 Int_t itmp=idxRow[1]; idxRow[1] = idxRow[0]; idxRow[0] = itmp;
1201 Double_t dtmp=zresRow[1]; zresRow[1] = zresRow[0]; zresRow[0] = dtmp;
1202 }
1203 if(TMath::Abs(idxRow[1] - idxRow[0]) != 1){
1204 SetErrorMsg(kAttachRowGap);
1205 AliDebug(2, Form("Rows attached not continuous. Select first candidate.\n"
1206 " row[%2d] Ncl[%2d] <dz>[cm]=%+8.2f row[%2d] Ncl[%2d] <dz>[cm]=%+8.2f",
0a62661e 1207 idxRow[0], ncl[idxRow[0]], zresRow[0], idxRow[1], idxRow[1]<0?0:ncl[idxRow[1]], zresRow[1]));
9dcc64cc 1208 nrc=1; idxRow[1] = -1; zresRow[1] = 999.;
1209 }
1210 } else {
1211 Int_t idx0[kNrows];
1212 TMath::Sort(nrc, zresRow, idx0, kFALSE);
1213 nrc = 3; // select only maximum first 3 candidates
1214 Int_t iatmp[] = {-1, -1, -1}; Double_t datmp[] = {999., 999., 999.};
1215 for(Int_t irc(0); irc<nrc; irc++){
1216 iatmp[irc] = idxRow[idx0[irc]];
1217 datmp[irc] = zresRow[idx0[irc]];
1218 }
1219 idxRow[0] = iatmp[0]; zresRow[0] = datmp[0];
1220 idxRow[1] = iatmp[1]; zresRow[1] = datmp[1];
1221 idxRow[2] = iatmp[2]; zresRow[2] = datmp[2]; // temporary
1222 if(TMath::Abs(idxRow[1] - idxRow[0]) != 1){
1223 SetErrorMsg(kAttachRowGap);
1224 AliDebug(2, Form("Rows attached not continuous. Turn on selection.\n"
1225 "row[%2d] Ncl[%2d] <dz>[cm]=%+8.2f\n"
1226 "row[%2d] Ncl[%2d] <dz>[cm]=%+8.2f\n"
1227 "row[%2d] Ncl[%2d] <dz>[cm]=%+8.2f",
1228 idxRow[0], ncl[idxRow[0]], zresRow[0],
1229 idxRow[1], ncl[idxRow[1]], zresRow[1],
1230 idxRow[2], ncl[idxRow[2]], zresRow[2]));
1231 if(TMath::Abs(idxRow[0] - idxRow[2]) == 1){ // select second candidate
1232 AliDebug(2, "Solved ! Remove second candidate.");
1233 nrc = 2;
1234 idxRow[1] = idxRow[2]; zresRow[1] = zresRow[2]; // swap
1235 idxRow[2] = -1; zresRow[2] = 999.; // remove
1236 } else if(TMath::Abs(idxRow[1] - idxRow[2]) == 1){
1237 if(ncl[idxRow[1]]+ncl[idxRow[2]] > ncl[idxRow[0]]){
1238 AliDebug(2, "Solved ! Remove first candidate.");
1239 nrc = 2;
1240 idxRow[0] = idxRow[1]; zresRow[0] = zresRow[1]; // swap
1241 idxRow[1] = idxRow[2]; zresRow[1] = zresRow[2]; // swap
1242 } else {
1243 AliDebug(2, "Solved ! Remove second and third candidate.");
1244 nrc = 1;
1245 idxRow[1] = -1; zresRow[1] = 999.; // remove
1246 idxRow[2] = -1; zresRow[2] = 999.; // remove
1247 }
1248 } else {
1249 AliDebug(2, "Unsolved !!! Remove second and third candidate.");
1250 nrc = 1;
1251 idxRow[1] = -1; zresRow[1] = 999.; // remove
1252 idxRow[2] = -1; zresRow[2] = 999.; // remove
1253 }
1254 } else { // remove temporary candidate
1255 nrc = 2;
1256 idxRow[2] = -1; zresRow[2] = 999.;
b1957d3c 1257 }
b1957d3c 1258 }
29b87567 1259 }
9dcc64cc 1260 AliDebug(4, Form("Sorted row candidates:\n"
1261 " row[%2d] Ncl[%2d] <dz>[cm]=%+8.2f row[%2d] Ncl[%2d] <dz>[cm]=%+8.2f"
dbb2e0a7 1262 , idxRow[0], ncl[idxRow[0]], zresRow[0], idxRow[1], idxRow[1]<0?0:ncl[idxRow[1]], zresRow[1]));
9dcc64cc 1263
1264 // initialize debug streamer
1265 TTreeSRedirector *pstreamer(NULL);
1266 if(recoParam->GetStreamLevel(AliTRDrecoParam::kTracker) > 3 && fkReconstructor->IsDebugStreaming()) pstreamer = fkReconstructor->GetDebugStream(AliTRDrecoParam::kTracker);
1267 if(pstreamer){
1268 // save config. for calibration
1269 TVectorD vdy[2], vdx[2], vs2[2];
1270 for(Int_t jr(0); jr<nrc; jr++){
1271 Int_t ir(idxRow[jr]);
1272 vdx[jr].ResizeTo(ncl[ir]); vdy[jr].ResizeTo(ncl[ir]); vs2[jr].ResizeTo(ncl[ir]);
1273 for(Int_t ic(ncl[ir]); ic--;){
1274 vdx[jr](ic) = xres[ir][ic];
1275 vdy[jr](ic) = yres[ir][ic];
1276 vs2[jr](ic) = s2y[ir][ic];
1277 }
1278 }
1279 (*pstreamer) << "AttachClusters4"
1280 << "r0=" << idxRow[0]
1281 << "dz0=" << zresRow[0]
1282 << "dx0=" << &vdx[0]
560e5c05 1283 << "dy0=" << &vdy[0]
9dcc64cc 1284 << "s20=" << &vs2[0]
1285 << "r1=" << idxRow[1]
1286 << "dz1=" << zresRow[1]
1287 << "dx1=" << &vdx[1]
560e5c05 1288 << "dy1=" << &vdy[1]
9dcc64cc 1289 << "s21=" << &vs2[1]
560e5c05 1290 << "\n";
9dcc64cc 1291 vdx[0].Clear(); vdy[0].Clear(); vs2[0].Clear();
1292 vdx[1].Clear(); vdy[1].Clear(); vs2[1].Clear();
1293 if(recoParam->GetStreamLevel(AliTRDrecoParam::kTracker) > 4){
2f4384e6 1294 Int_t idx(idxRow[1]);
1295 if(idx<0){
9dcc64cc 1296 for(Int_t ir(0); ir<kNrows; ir++){
1297 if(clst[ir].GetEntries()>0) continue;
1298 idx = ir;
1299 break;
1300 }
2f4384e6 1301 }
9dcc64cc 1302 (*pstreamer) << "AttachClusters5"
1303 << "c0.=" << &clst[idxRow[0]]
1304 << "c1.=" << &clst[idx]
1305 << "\n";
1306 }
560e5c05 1307 }
1308
9dcc64cc 1309//=======================================================================================
1310 // Analyse cluster topology
1311 Double_t f[kNcls], // likelihood factors for segments
1312 r[2][kNcls], // d(dydx) of tracklet candidate with respect to track
1313 xm[2][kNcls], // mean <x>
1314 ym[2][kNcls], // mean <y>
1315 sm[2][kNcls], // mean <s_y>
1316 s[2][kNcls], // sigma_y
2f4384e6 1317 p[2][kNcls], // prob of Gauss
1318 q[2][kNcls]; // charge/segment
9dcc64cc 1319 memset(f, 0, kNcls*sizeof(Double_t));
1320 Int_t index[2][kNcls], n[2][kNcls];
1321 memset(n, 0, 2*kNcls*sizeof(Int_t));
1322 Int_t mts(0), nts[2] = {0, 0}; // no of tracklet segments in row
1323 AliTRDpadPlane *pp(AliTRDtransform::Geometry().GetPadPlane(fDet));
1324 AliTRDtrackletOflHelper helper;
1325 Int_t lyDet(AliTRDgeometry::GetLayer(fDet));
1326 for(Int_t jr(0), n0(0); jr<nrc; jr++){
1327 Int_t ir(idxRow[jr]);
1328 // cluster segmentation
1329 Bool_t kInit(kFALSE);
1330 if(jr==0){
1331 n0 = helper.Init(pp, &clst[ir]); kInit = kTRUE;
1332 if(!n0 || (helper.ClassifyTopology() == AliTRDtrackletOflHelper::kNormal)){
1333 nts[jr] = 1; memset(index[jr], 0, ncl[ir]*sizeof(Int_t));
1334 n[jr][0] = ncl[ir];
560e5c05 1335 }
9dcc64cc 1336 }
1337 if(!n[jr][0]){
1338 nts[jr] = AliTRDtrackletOflHelper::Segmentation(ncl[ir], xres[ir], yres[ir], index[jr]);
1339 for(Int_t ic(ncl[ir]);ic--;) n[jr][index[jr][ic]]++;
1340 }
1341 mts += nts[jr];
1342
1343 // tracklet segment processing
1344 for(Int_t its(0); its<nts[jr]; its++){
1345 if(n[jr][its]<=2) { // don't touch small segments
1346 xm[jr][its] = 0.;ym[jr][its] = 0.;sm[jr][its] = 0.;
1347 for(Int_t ic(ncl[ir]); ic--;){
1348 if(its != index[jr][ic]) continue;
1349 ym[jr][its] += yres[ir][ic];
1350 xm[jr][its] += xres[ir][ic];
1351 sm[jr][its] += TMath::Sqrt(s2y[ir][ic]);
1352 }
1353 if(n[jr][its]==2){ xm[jr][its] *= 0.5; ym[jr][its] *= 0.5; sm[jr][its] *= 0.5;}
1354 xm[jr][its]= fX0 - xm[jr][its];
1355 r[jr][its] = 0.;
1356 s[jr][its] = 1.e-5;
1357 p[jr][its] = 1.;
2f4384e6 1358 q[jr][its] = -1.;
9dcc64cc 1359 continue;
560e5c05 1360 }
9dcc64cc 1361
1362 // for longer tracklet segments
1363 if(!kInit) n0 = helper.Init(pp, &clst[ir], index[jr], its);
2f4384e6 1364 Int_t n1 = helper.GetRMS(r[jr][its], ym[jr][its], s[jr][its], fX0/*xm[jr][its]*/);
1365 p[jr][its] = Double_t(n1)/n0;
9dcc64cc 1366 sm[jr][its] = helper.GetSyMean();
2f4384e6 1367 q[jr][its] = helper.GetQ()/TMath::Sqrt(1. + fYref[1]*fYref[1] + fZref[1]*fZref[1]);
1368 xm[jr][its] = fX0;
9dcc64cc 1369 Double_t dxm= fX0 - xm[jr][its];
2f4384e6 1370 yt = fYref[0] - fYref[1]*dxm;
9dcc64cc 1371 zt = fZref[0] - fZref[1]*dxm;
1372 // correct tracklet fit for tilt
1373 ym[jr][its]+= GetTilt()*(zt - zc[ir]);
1374 r[jr][its] += GetTilt() * fZref[1];
1375 // correct tracklet fit for track position/inclination
2f4384e6 1376 ym[jr][its] = yt - ym[jr][its];
1377 r[jr][its] = (r[jr][its] - fYref[1])/(1+r[jr][its]*fYref[1]);
9dcc64cc 1378 // report inclination in radians
1379 r[jr][its] = TMath::ATan(r[jr][its]);
1380 if(jr) continue; // calculate only for first row likelihoods
1381
1382 f[its] = attach->CookLikelihood(chgPos, lyDet, fPt, phiTrk, n[jr][its], ym[jr][its]/*sRef*/, r[jr][its]*TMath::RadToDeg(), s[jr][its]/sm[jr][its]);
29b87567 1383 }
1384 }
9dcc64cc 1385 AliDebug(4, Form(" Tracklet candidates: row[%2d] = %2d row[%2d] = %2d:", idxRow[0], nts[0], idxRow[1], nts[1]));
1386 if(AliLog::GetDebugLevel("TRD", "AliTRDseedV1")>3){
1387 for(Int_t jr(0); jr<nrc; jr++){
1388 Int_t ir(idxRow[jr]);
1389 for(Int_t its(0); its<nts[jr]; its++){
1390 printf(" segId[%2d] row[%2d] Ncl[%2d] x[cm]=%7.2f dz[pu]=%4.2f dy[mm]=%+7.3f r[deg]=%+6.2f p[%%]=%6.2f s[um]=%7.2f\n",
1391 its, ir, n[jr][its], xm[jr][its], zresRow[jr], 1.e1*ym[jr][its], r[jr][its]*TMath::RadToDeg(), 100.*p[jr][its], 1.e4*s[jr][its]);
1392 }
560e5c05 1393 }
ee8fb199 1394 }
9dcc64cc 1395 if(!pstreamer && recoParam->GetStreamLevel(AliTRDrecoParam::kTracker) > 2 && fkReconstructor->IsDebugStreaming()) pstreamer = fkReconstructor->GetDebugStream(AliTRDrecoParam::kTracker);
1396 if(pstreamer){
1397 // save config. for calibration
1398 TVectorD vidx, vn, vx, vy, vr, vs, vsm, vp, vf;
1399 vidx.ResizeTo(ncl[idxRow[0]]+(idxRow[1]<0?0:ncl[idxRow[1]]));
1400 vn.ResizeTo(mts);
1401 vx.ResizeTo(mts);
1402 vy.ResizeTo(mts);
1403 vr.ResizeTo(mts);
1404 vs.ResizeTo(mts);
1405 vsm.ResizeTo(mts);
1406 vp.ResizeTo(mts);
1407 vf.ResizeTo(mts);
1408 for(Int_t jr(0), jts(0), jc(0); jr<nrc; jr++){
1409 Int_t ir(idxRow[jr]);
1410 for(Int_t its(0); its<nts[jr]; its++, jts++){
1411 vn[jts] = n[jr][its];
1412 vx[jts] = xm[jr][its];
1413 vy[jts] = ym[jr][its];
1414 vr[jts] = r[jr][its];
1415 vs[jts] = s[jr][its];
1416 vsm[jts]= sm[jr][its];
1417 vp[jts] = p[jr][its];
1418 vf[jts] = jr?-1.:f[its];
6ad5e6b2 1419 }
9dcc64cc 1420 for(Int_t ic(0); ic<ncl[ir]; ic++, jc++) vidx[jc] = index[jr][ic];
1421 }
1422 (*pstreamer) << "AttachClusters3"
1423 << "idx=" << &vidx
1424 << "n=" << &vn
1425 << "x=" << &vx
1426 << "y=" << &vy
1427 << "r=" << &vr
1428 << "s=" << &vs
1429 << "sm=" << &vsm
1430 << "p=" << &vp
1431 << "f=" << &vf
1432 << "\n";
1433 }
6ad5e6b2 1434
9dcc64cc 1435//=========================================================
1436 // Get seed tracklet segment
1437 Int_t idx2[kNcls]; memset(idx2, 0, kNcls*sizeof(Int_t)); // seeding indexing
1438 if(nts[0]>1) TMath::Sort(nts[0], f, idx2);
1439 Int_t is(idx2[0]); // seed index
1440 Int_t idxTrklt[kNcls],
1441 kts(0),
1442 nTrklt(n[0][is]);
1443 Double_t fTrklt(f[is]),
1444 rTrklt(r[0][is]),
1445 yTrklt(ym[0][is]),
1446 sTrklt(s[0][is]),
1447 smTrklt(sm[0][is]),
1448 xTrklt(xm[0][is]),
2f4384e6 1449 pTrklt(p[0][is]),
1450 qTrklt(q[0][is]);
9dcc64cc 1451 memset(idxTrklt, 0, kNcls*sizeof(Int_t));
1452 // check seed idx2[0] exit if not found
1453 if(f[is]<1.e-2){
1454 AliDebug(1, Form("Seed seg[%d] row[%2d] n[%2d] f[%f]<0.01.", is, idxRow[0], n[0][is], f[is]));
1455 SetErrorMsg(kAttachClAttach);
1456 if(!pstreamer && recoParam->GetStreamLevel(AliTRDrecoParam::kTracker) > 1 && fkReconstructor->IsDebugStreaming()) pstreamer = fkReconstructor->GetDebugStream(AliTRDrecoParam::kTracker);
1457 if(pstreamer){
1458 UChar_t stat(0);
1459 if(IsKink()) SETBIT(stat, 1);
1460 if(IsStandAlone()) SETBIT(stat, 2);
1461 if(IsRowCross()) SETBIT(stat, 3);
1462 SETBIT(stat, 4); // set error bit
1463 TVectorD vidx; vidx.ResizeTo(1); vidx[0] = is;
1464 (*pstreamer) << "AttachClusters2"
1465 << "stat=" << stat
1466 << "ev=" << ev
1467 << "chg=" << chgPos
1468 << "det=" << fDet
1469 << "x0=" << fX0
1470 << "y0=" << fYref[0]
1471 << "z0=" << fZref[0]
1472 << "phi=" << phiTrk
1473 << "tht=" << thtTrk
1474 << "pt=" << fPt
1475 << "s2Trk=" << s2yTrk
1476 << "s2Cl=" << s2Mean
1477 << "idx=" << &vidx
1478 << "n=" << nTrklt
1479 << "f=" << fTrklt
1480 << "x=" << xTrklt
1481 << "y=" << yTrklt
1482 << "r=" << rTrklt
1483 << "s=" << sTrklt
1484 << "sm=" << smTrklt
1485 << "p=" << pTrklt
2f4384e6 1486 << "q=" << qTrklt
9dcc64cc 1487 << "\n";
1488 }
1489 return kFALSE;
1490 }
2f4384e6 1491 AliDebug(2, Form("Seed seg[%d] row[%2d] n[%2d] dy[%f] r[%+5.2f] s[%+5.2f] f[%5.3f] q[%6.2f]", is, idxRow[0], n[0][is], ym[0][is], r[0][is]*TMath::RadToDeg(), s[0][is]/sm[0][is], f[is], q[0][is]));
9dcc64cc 1492
1493 // save seeding segment in the helper
1494 idxTrklt[kts++] = is;
1495 helper.Init(pp, &clst[idxRow[0]], index[0], is);
1496 AliTRDtrackletOflHelper test; // helper to test segment expantion
1497 Float_t rcLikelihood(0.); SetBit(kRowCross, kFALSE);
1498 Double_t dyRez[kNcls]; Int_t idx3[kNcls];
1499
1500 //=========================================================
1501 // Define filter parameters from OCDB
1502 Int_t kNSgmDy[2]; attach->GetNsgmDy(kNSgmDy[0], kNSgmDy[1]);
1503 Float_t kLikeMinRelDecrease[2]; attach->GetLikeMinRelDecrease(kLikeMinRelDecrease[0], kLikeMinRelDecrease[1]);
1504 Float_t kRClikeLimit(attach->GetRClikeLimit());
1505
1506 //=========================================================
1507 // Try attaching next segments from first row (if any)
1508 if(nts[0]>1){
1509 Int_t jr(0), ir(idxRow[jr]);
1510 // organize secondary sgms. in decreasing order of their distance from seed
1511 memset(dyRez, 0, nts[jr]*sizeof(Double_t));
1512 for(Int_t jts(1); jts<nts[jr]; jts++) {
1513 Int_t its(idx2[jts]);
1514 Double_t rot(TMath::Tan(r[0][is]));
1515 dyRez[its] = TMath::Abs(ym[0][is] - ym[jr][its] + rot*(xm[0][is]-xm[jr][its]));
1516 }
1517 TMath::Sort(nts[jr], dyRez, idx3, kFALSE);
1518 for (Int_t jts(1); jts<nts[jr]; jts++) {
1519 Int_t its(idx3[jts]);
1520 if(dyRez[its] > kNSgmDy[jr]*smTrklt){
1521 AliDebug(2, Form("Reject seg[%d] row[%2d] n[%2d] dy[%f] > %d*s[%f].", its, idxRow[jr], n[jr][its], dyRez[its], kNSgmDy[jr], kNSgmDy[jr]*smTrklt));
1522 continue;
1523 }
1524
1525 test = helper;
1526 Int_t n0 = test.Expand(&clst[ir], index[jr], its);
2f4384e6 1527 Double_t rt, dyt, st, xt, smt, pt, qt, ft;
1528 Int_t n1 = test.GetRMS(rt, dyt, st, fX0/*xt*/);
9dcc64cc 1529 pt = Double_t(n1)/n0;
1530 smt = test.GetSyMean();
2f4384e6 1531 qt = test.GetQ()/TMath::Sqrt(1. + fYref[1]*fYref[1] + fZref[1]*fZref[1]);
1532 xt = fX0;
9dcc64cc 1533 // correct position
1534 Double_t dxm= fX0 - xt;
1535 yt = fYref[0] - fYref[1]*dxm;
1536 zt = fZref[0] - fZref[1]*dxm;
1537 // correct tracklet fit for tilt
1538 dyt+= GetTilt()*(zt - zc[idxRow[0]]);
1539 rt += GetTilt() * fZref[1];
1540 // correct tracklet fit for track position/inclination
2f4384e6 1541 dyt = yt - dyt;
1542 rt = (rt - fYref[1])/(1+rt*fYref[1]);
9dcc64cc 1543 // report inclination in radians
1544 rt = TMath::ATan(rt);
1545
1546 ft = (n0>=2) ? attach->CookLikelihood(chgPos, lyDet, fPt, phiTrk, n0, dyt/*sRef*/, rt*TMath::RadToDeg(), st/smt) : 0.;
1547 Bool_t kAccept(ft>=fTrklt*(1.-kLikeMinRelDecrease[jr]));
1548
1549 AliDebug(2, Form("%s seg[%d] row[%2d] n[%2d] dy[%f] r[%+5.2f] s[%+5.2f] f[%f] < %4.2f*F[%f].",
1550 (kAccept?"Adding":"Reject"), its, idxRow[jr], n0, dyt, rt*TMath::RadToDeg(), st/smt, ft, 1.-kLikeMinRelDecrease[jr], fTrklt*(1.-kLikeMinRelDecrease[jr])));
1551 if(kAccept){
1552 idxTrklt[kts++] = its;
1553 nTrklt = n0;
1554 fTrklt = ft;
1555 rTrklt = rt;
1556 yTrklt = dyt;
1557 sTrklt = st;
1558 smTrklt= smt;
1559 xTrklt = xt;
1560 pTrklt = pt;
2f4384e6 1561 qTrklt = qt;
9dcc64cc 1562 helper.Expand(&clst[ir], index[jr], its);
1563 }
b1957d3c 1564 }
560e5c05 1565 }
9dcc64cc 1566
1567 //=========================================================
1568 // Try attaching next segments from second row (if any)
1569 if(nts[1] && (rcLikelihood = zresRow[0]/zresRow[1]) > kRClikeLimit){
1570 // organize secondaries in decreasing order of their distance from seed
1571 Int_t jr(1), ir(idxRow[jr]);
1572 memset(dyRez, 0, nts[jr]*sizeof(Double_t));
1573 Double_t rot(TMath::Tan(r[0][is]));
1574 for(Int_t jts(0); jts<nts[jr]; jts++) {
1575 dyRez[jts] = TMath::Abs(ym[0][is] - ym[jr][jts] + rot*(xm[0][is]-xm[jr][jts]));
1576 }
1577 TMath::Sort(nts[jr], dyRez, idx3, kFALSE);
1578 for (Int_t jts(0); jts<nts[jr]; jts++) {
1579 Int_t its(idx3[jts]);
1580 if(dyRez[its] > kNSgmDy[jr]*smTrklt){
1581 AliDebug(2, Form("Reject seg[%d] row[%2d] n[%2d] dy[%f] > %d*s[%f].", its, idxRow[jr], n[jr][its], dyRez[its], kNSgmDy[jr], kNSgmDy[jr]*smTrklt));
1582 continue;
1583 }
1584
1585 test = helper;
1586 Int_t n0 = test.Expand(&clst[ir], index[jr], its);
2f4384e6 1587 Double_t rt, dyt, st, xt, smt, pt, qt, ft;
1588 Int_t n1 = test.GetRMS(rt, dyt, st, fX0/*xt*/);
9dcc64cc 1589 pt = Double_t(n1)/n0;
1590 smt = test.GetSyMean();
2f4384e6 1591 qt = test.GetQ()/TMath::Sqrt(1. + fYref[1]*fYref[1] + fZref[1]*fZref[1]);
1592 xt = fX0;
9dcc64cc 1593 // correct position
1594 Double_t dxm= fX0 - xt;
1595 yt = fYref[0] - fYref[1]*dxm;
1596 zt = fZref[0] - fZref[1]*dxm;
1597 // correct tracklet fit for tilt
1598 dyt+= GetTilt()*(zt - zc[idxRow[0]]);
1599 rt += GetTilt() * fZref[1];
1600 // correct tracklet fit for track position/inclination
2f4384e6 1601 dyt = yt - dyt;
1602 rt = (rt - fYref[1])/(1+rt*fYref[1]);
9dcc64cc 1603 // report inclination in radians
1604 rt = TMath::ATan(rt);
1605
1606 ft = (n0>=2) ? attach->CookLikelihood(chgPos, lyDet, fPt, phiTrk, n0, dyt/*sRef*/, rt*TMath::RadToDeg(), st/smt) : 0.;
1607 Bool_t kAccept(ft>=fTrklt*(1.-kLikeMinRelDecrease[jr]));
1608
1609 AliDebug(2, Form("%s seg[%d] row[%2d] n[%2d] dy[%f] r[%+5.2f] s[%+5.2f] f[%f] < %4.2f*F[%f].",
1610 (kAccept?"Adding":"Reject"), its, idxRow[jr], n0, dyt, rt*TMath::RadToDeg(), st/smt, ft, 1.-kLikeMinRelDecrease[jr], fTrklt*(1.-kLikeMinRelDecrease[jr])));
1611 if(kAccept){
1612 idxTrklt[kts++] = its;
1613 nTrklt = n0;
1614 fTrklt = ft;
1615 rTrklt = rt;
1616 yTrklt = dyt;
1617 sTrklt = st;
1618 smTrklt= smt;
1619 xTrklt = xt;
1620 pTrklt = pt;
2f4384e6 1621 qTrklt = qt;
9dcc64cc 1622 helper.Expand(&clst[ir], index[jr], its);
1623 SetBit(kRowCross, kTRUE); // mark pad row crossing
1624 }
1625 }
1626 }
1627 // clear local copy of clusters
1628 for(Int_t ir(0); ir<kNrows; ir++) clst[ir].Clear();
1629
1630 if(!pstreamer && recoParam->GetStreamLevel(AliTRDrecoParam::kTracker) > 1 && fkReconstructor->IsDebugStreaming()) pstreamer = fkReconstructor->GetDebugStream(AliTRDrecoParam::kTracker);
1631 if(pstreamer){
1632 UChar_t stat(0);
1633 if(IsKink()) SETBIT(stat, 1);
1634 if(IsStandAlone()) SETBIT(stat, 2);
1635 if(IsRowCross()) SETBIT(stat, 3);
1636 TVectorD vidx; vidx.ResizeTo(kts);
1637 for(Int_t its(0); its<kts; its++) vidx[its] = idxTrklt[its];
1638 (*pstreamer) << "AttachClusters2"
1639 << "stat=" << stat
1640 << "ev=" << ev
1641 << "chg=" << chgPos
1642 << "det=" << fDet
1643 << "x0=" << fX0
1644 << "y0=" << fYref[0]
1645 << "z0=" << fZref[0]
1646 << "phi=" << phiTrk
1647 << "tht=" << thtTrk
1648 << "pt=" << fPt
1649 << "s2Trk=" << s2yTrk
1650 << "s2Cl=" << s2Mean
1651 << "idx=" << &vidx
1652 << "n=" << nTrklt
2f4384e6 1653 << "q=" << qTrklt
9dcc64cc 1654 << "f=" << fTrklt
1655 << "x=" << xTrklt
1656 << "y=" << yTrklt
1657 << "r=" << rTrklt
1658 << "s=" << sTrklt
1659 << "sm=" << smTrklt
1660 << "p=" << pTrklt
1661 << "\n";
1662 }
1663
1664
1665 //=========================================================
1666 // Store clusters
1667 Int_t nselected(0), nc(0);
1668 TObjArray *selected(helper.GetClusters());
1669 if(!selected || !(nselected = selected->GetEntriesFast())){
1670 AliError("Cluster candidates missing !!!");
1671 SetErrorMsg(kAttachClAttach);
1672 return kFALSE;
1673 }
1674 for(Int_t ic(0); ic<nselected; ic++){
1675 if(!(c = (AliTRDcluster*)selected->At(ic))) continue;
1676 Int_t it(c->GetPadTime()),
1677 jr(Int_t(helper.GetRow() != c->GetPadRow())),
1678 idx(it+kNtb*jr);
1679 if(fClusters[idx]){
1680 AliDebug(1, Form("Multiple clusters/tb for D[%03d] Tb[%02d] Row[%2d]", fDet, it, c->GetPadRow()));
1681 continue; // already booked
1682 }
1683 // TODO proper indexing of clusters !!
1684 fIndexes[idx] = chamber->GetTB(it)->GetGlobalIndex(idxs[idxRow[jr]][ic]);
1685 fClusters[idx] = c;
1686 nc++;
1687 }
1688 AliDebug(2, Form("Clusters Found[%2d] Attached[%2d] RC[%c]", nselected, nc, IsRowCross()?'y':'n'));
b1957d3c 1689
29b87567 1690 // number of minimum numbers of clusters expected for the tracklet
9dcc64cc 1691 if (nc < kClmin){
1692 AliDebug(1, Form("NOT ENOUGH CLUSTERS %d ATTACHED TO THE TRACKLET [min %d] FROM FOUND %d.", nc, kClmin, ncls));
7c3eecb8 1693 SetErrorMsg(kAttachClAttach);
e4f2f73d 1694 return kFALSE;
1695 }
9dcc64cc 1696 SetN(nc);
0906e73e 1697
e3cf3d02 1698 // Load calibration parameters for this tracklet
9dcc64cc 1699 //Calibrate();
b1957d3c 1700
1701 // calculate dx for time bins in the drift region (calibration aware)
a2abcbc5 1702 Float_t x[2] = {0.,0.}; Int_t tb[2]={0,0};
1703 for (Int_t it = t0, irp=0; irp<2 && it < AliTRDtrackerV1::GetNTimeBins(); it++) {
b1957d3c 1704 if(!fClusters[it]) continue;
1705 x[irp] = fClusters[it]->GetX();
a2abcbc5 1706 tb[irp] = fClusters[it]->GetLocalTimeBin();
b1957d3c 1707 irp++;
e3cf3d02 1708 }
d86ed84c 1709 Int_t dtb = tb[1] - tb[0];
1710 fdX = dtb ? (x[0] - x[1]) / dtb : 0.15;
29b87567 1711 return kTRUE;
e4f2f73d 1712}
1713
03cef9b2 1714//____________________________________________________________
1715void AliTRDseedV1::Bootstrap(const AliTRDReconstructor *rec)
1716{
1717// Fill in all derived information. It has to be called after recovery from file or HLT.
1718// The primitive data are
1719// - list of clusters
1720// - detector (as the detector will be removed from clusters)
1721// - position of anode wire (fX0) - temporary
1722// - track reference position and direction
1723// - momentum of the track
1724// - time bin length [cm]
1725//
1726// A.Bercuci <A.Bercuci@gsi.de> Oct 30th 2008
1727//
4d6aee34 1728 fkReconstructor = rec;
03cef9b2 1729 AliTRDgeometry g;
2eb10c34 1730 SetPadPlane(g.GetPadPlane(fDet));
1731
e3cf3d02 1732 //fSnp = fYref[1]/TMath::Sqrt(1+fYref[1]*fYref[1]);
1733 //fTgl = fZref[1];
3e778975 1734 Int_t n = 0, nshare = 0, nused = 0;
03cef9b2 1735 AliTRDcluster **cit = &fClusters[0];
8d2bec9e 1736 for(Int_t ic = kNclusters; ic--; cit++){
03cef9b2 1737 if(!(*cit)) return;
3e778975 1738 n++;
1739 if((*cit)->IsShared()) nshare++;
1740 if((*cit)->IsUsed()) nused++;
03cef9b2 1741 }
3e778975 1742 SetN(n); SetNUsed(nused); SetNShared(nshare);
e3cf3d02 1743 Fit();
03cef9b2 1744 CookLabels();
1745 GetProbability();
1746}
1747
1748
e4f2f73d 1749//____________________________________________________________________
2eb10c34 1750Bool_t AliTRDseedV1::Fit(UChar_t opt)
e4f2f73d 1751{
16cca13f 1752//
1753// Linear fit of the clusters attached to the tracklet
1754//
1755// Parameters :
2eb10c34 1756// - opt : switch for tilt pad correction of cluster y position. Options are
1757// 0 no correction [default]
1758// 1 full tilt correction [dz/dx and z0]
1759// 2 pseudo tilt correction [dz/dx from pad-chamber geometry]
1760//
16cca13f 1761// Output :
1762// True if successful
1763//
1764// Detailed description
1765//
1766// Fit in the xy plane
1767//
1fd9389f 1768// The fit is performed to estimate the y position of the tracklet and the track
1769// angle in the bending plane. The clusters are represented in the chamber coordinate
1770// system (with respect to the anode wire - see AliTRDtrackerV1::FollowBackProlongation()
1771// on how this is set). The x and y position of the cluster and also their variances
1772// are known from clusterizer level (see AliTRDcluster::GetXloc(), AliTRDcluster::GetYloc(),
1773// AliTRDcluster::GetSX() and AliTRDcluster::GetSY()).
1774// If gaussian approximation is used to calculate y coordinate of the cluster the position
1775// is recalculated taking into account the track angle. The general formula to calculate the
1776// error of cluster position in the gaussian approximation taking into account diffusion and track
1777// inclination is given for TRD by:
1778// BEGIN_LATEX
1779// #sigma^{2}_{y} = #sigma^{2}_{PRF} + #frac{x#delta_{t}^{2}}{(1+tg(#alpha_{L}))^{2}} + #frac{x^{2}tg^{2}(#phi-#alpha_{L})tg^{2}(#alpha_{L})}{12}
1780// END_LATEX
1781//
1782// Since errors are calculated only in the y directions, radial errors (x direction) are mapped to y
1783// by projection i.e.
1784// BEGIN_LATEX
1785// #sigma_{x|y} = tg(#phi) #sigma_{x}
1786// END_LATEX
1787// and also by the lorentz angle correction
1788//
1789// Fit in the xz plane
1790//
1791// The "fit" is performed to estimate the radial position (x direction) where pad row cross happens.
1792// If no pad row crossing the z position is taken from geometry and radial position is taken from the xy
1793// fit (see below).
1794//
1795// There are two methods to estimate the radial position of the pad row cross:
1796// 1. leading cluster radial position : Here the lower part of the tracklet is considered and the last
1797// cluster registered (at radial x0) on this segment is chosen to mark the pad row crossing. The error
1798// of the z estimate is given by :
1799// BEGIN_LATEX
1800// #sigma_{z} = tg(#theta) #Delta x_{x_{0}}/12
1801// END_LATEX
1802// The systematic errors for this estimation are generated by the following sources:
1803// - no charge sharing between pad rows is considered (sharp cross)
1804// - missing cluster at row cross (noise peak-up, under-threshold signal etc.).
1805//
1806// 2. charge fit over the crossing point : Here the full energy deposit along the tracklet is considered
1807// to estimate the position of the crossing by a fit in the qx plane. The errors in the q directions are
1808// parameterized as s_q = q^2. The systematic errors for this estimation are generated by the following sources:
1809// - no general model for the qx dependence
1810// - physical fluctuations of the charge deposit
1811// - gain calibration dependence
1812//
1813// Estimation of the radial position of the tracklet
16cca13f 1814//
1fd9389f 1815// For pad row cross the radial position is taken from the xz fit (see above). Otherwise it is taken as the
1816// interpolation point of the tracklet i.e. the point where the error in y of the fit is minimum. The error
1817// in the y direction of the tracklet is (see AliTRDseedV1::GetCovAt()):
1818// BEGIN_LATEX
1819// #sigma_{y} = #sigma^{2}_{y_{0}} + 2xcov(y_{0}, dy/dx) + #sigma^{2}_{dy/dx}
1820// END_LATEX
1821// and thus the radial position is:
1822// BEGIN_LATEX
1823// x = - cov(y_{0}, dy/dx)/#sigma^{2}_{dy/dx}
1824// END_LATEX
1825//
1826// Estimation of tracklet position error
1827//
1828// The error in y direction is the error of the linear fit at the radial position of the tracklet while in the z
1829// direction is given by the cluster error or pad row cross error. In case of no pad row cross this is given by:
1830// BEGIN_LATEX
1831// #sigma_{y} = #sigma^{2}_{y_{0}} - 2cov^{2}(y_{0}, dy/dx)/#sigma^{2}_{dy/dx} + #sigma^{2}_{dy/dx}
1832// #sigma_{z} = Pad_{length}/12
1833// END_LATEX
1834// For pad row cross the full error is calculated at the radial position of the crossing (see above) and the error
1835// in z by the width of the crossing region - being a matter of parameterization.
1836// BEGIN_LATEX
1837// #sigma_{z} = tg(#theta) #Delta x_{x_{0}}/12
1838// END_LATEX
1839// In case of no tilt correction (default in the barrel tracking) the tilt is taken into account by the rotation of
1840// the covariance matrix. See AliTRDseedV1::GetCovAt() for details.
1841//
1842// Author
1843// A.Bercuci <A.Bercuci@gsi.de>
e4f2f73d 1844
a723055f 1845 if(!fkReconstructor){
1846 AliError("The tracklet needs the reconstruction setup. Please initialize by SetReconstructor().");
1847 return kFALSE;
1848 }
b72f4eaf 1849 if(!IsCalibrated()) Calibrate();
2eb10c34 1850 if(opt>2){
7e5954f0 1851 AliWarning(Form("Option [%d] outside range [0, 2]. Using default",opt));
2eb10c34 1852 opt=0;
1853 }
e3cf3d02 1854
29b87567 1855 const Int_t kClmin = 8;
2eb10c34 1856 const Float_t kScalePulls = 10.; // factor to scale y pulls - NOT UNDERSTOOD
2f7d6ac8 1857 // get track direction
1858 Double_t y0 = fYref[0];
1859 Double_t dydx = fYref[1];
1860 Double_t z0 = fZref[0];
1861 Double_t dzdx = fZref[1];
ae4e8b84 1862
5f1ae1e7 1863 AliTRDtrackerV1::AliTRDLeastSquare fitterY;
1864 AliTRDtrackerV1::AliTRDLeastSquare fitterZ;
f301a656 1865
29b87567 1866 // book cluster information
8d2bec9e 1867 Double_t qc[kNclusters], xc[kNclusters], yc[kNclusters], zc[kNclusters], sy[kNclusters];
e3cf3d02 1868
2eb10c34 1869 Bool_t tilt(opt==1) // full tilt correction
1870 ,pseudo(opt==2) // pseudo tilt correction
1871 ,rc(IsRowCross()) // row cross candidate
1872 ,kDZDX(IsPrimary());// switch dzdx calculation for barrel primary tracks
1873 Int_t n(0); // clusters used in fit
1874 AliTRDcluster *c(NULL), *cc(NULL), **jc = &fClusters[0];
fc0882f3 1875 const AliTRDrecoParam* const recoParam = fkReconstructor->GetRecoParam(); //the dynamic cast in GetRecoParam is slow, so caching the pointer to it
2eb10c34 1876
1877 const Char_t *tcName[]={"NONE", "FULL", "HALF"};
1878 AliDebug(2, Form("Options : TC[%s] dzdx[%c]", tcName[opt], kDZDX?'Y':'N'));
1879
9dcc64cc 1880
2eb10c34 1881 for (Int_t ic=0; ic<kNclusters; ic++, ++jc) {
1882 xc[ic] = -1.; yc[ic] = 999.; zc[ic] = 999.; sy[ic] = 0.;
9eb2d46c 1883 if(!(c = (*jc))) continue;
29b87567 1884 if(!c->IsInChamber()) continue;
2eb10c34 1885 // compute pseudo tilt correction
1886 if(kDZDX){
1887 fZfit[0] = c->GetZ();
1888 if(rc){
1889 for(Int_t kc=AliTRDseedV1::kNtb; kc<AliTRDseedV1::kNclusters; kc++){
1890 if(!(cc=fClusters[kc])) continue;
1891 if(!cc->IsInChamber()) continue;
1892 fZfit[0] += cc->GetZ(); fZfit[0] *= 0.5;
1893 break;
1894 }
1895 }
1896 fZfit[1] = fZfit[0]/fX0;
1897 if(rc){
1898 fZfit[0] += fZfit[1]*0.5*AliTRDgeometry::CdrHght();
1899 fZfit[1] = fZfit[0]/fX0;
1900 }
1901 kDZDX=kFALSE;
1902 }
9462866a 1903
29b87567 1904 Float_t w = 1.;
1905 if(c->GetNPads()>4) w = .5;
1906 if(c->GetNPads()>5) w = .2;
010d62b0 1907
1fd9389f 1908 // cluster charge
dd8059a8 1909 qc[n] = TMath::Abs(c->GetQ());
1fd9389f 1910 // pad row of leading
1911
b72f4eaf 1912 xc[n] = fX0 - c->GetX();
1913
1fd9389f 1914 // Recalculate cluster error based on tracking information
2eb10c34 1915 c->SetSigmaY2(fS2PRF, fDiffT, fExB, xc[n], -1./*zcorr?zt:-1.*/, dydx);
c79857d5 1916 c->SetSigmaZ2(fPad[0]*fPad[0]/12.); // for HLT
1fd9389f 1917 sy[n] = TMath::Sqrt(c->GetSigmaY2());
1918
fc0882f3 1919 yc[n] = recoParam->UseGAUS() ?
1fd9389f 1920 c->GetYloc(y0, sy[n], GetPadWidth()): c->GetY();
1921 zc[n] = c->GetZ();
2eb10c34 1922
1923 //optional r-phi correction
1924 //printf(" n[%2d] yc[%7.5f] ", n, yc[n]);
1925 Float_t correction(0.);
1926 if(tilt) correction = fPad[2]*(xc[n]*dzdx + zc[n] - z0);
1927 else if(pseudo) correction = fPad[2]*(xc[n]*fZfit[1] + zc[n]-fZfit[0]);
1928 yc[n]-=correction;
1929 //printf("corr(%s%s)[%7.5f] yc1[%7.5f]\n", (tilt?"TC":""), (zcorr?"PC":""), correction, yc[n]);
1fd9389f 1930
fbe11be7 1931 AliDebug(5, Form(" tb[%2d] dx[%6.3f] y[%6.2f+-%6.3f]", c->GetLocalTimeBin(), xc[n], yc[n], sy[n]));
903326c1 1932 fitterY.AddPoint(&xc[n], yc[n], sy[n]);
2eb10c34 1933 if(rc) fitterZ.AddPoint(&xc[n], qc[n]*(ic<kNtb?1.:-1.), 1.);
dd8059a8 1934 n++;
29b87567 1935 }
3044dfe5 1936
47d5d320 1937 // to few clusters
c79857d5 1938 if (n < kClmin){
c388cdcb 1939 AliDebug(1, Form("Not enough clusters to fit. Clusters: Attached[%d] Fit[%d].", GetN(), n));
2eb10c34 1940 SetErrorMsg(kFitCl);
c79857d5 1941 return kFALSE;
1942 }
d937ad7a 1943 // fit XY
903326c1 1944 if(!fitterY.Eval()){
c388cdcb 1945 AliDebug(1, "Fit Y failed.");
2eb10c34 1946 SetErrorMsg(kFitFailedY);
903326c1 1947 return kFALSE;
1948 }
5f1ae1e7 1949 fYfit[0] = fitterY.GetFunctionParameter(0);
1950 fYfit[1] = -fitterY.GetFunctionParameter(1);
d937ad7a 1951 // store covariance
5f1ae1e7 1952 Double_t p[3];
1953 fitterY.GetCovarianceMatrix(p);
2eb10c34 1954 fCov[0] = kScalePulls*p[1]; // variance of y0
1955 fCov[1] = kScalePulls*p[2]; // covariance of y0, dydx
1956 fCov[2] = kScalePulls*p[0]; // variance of dydx
b1957d3c 1957 // the ref radial position is set at the minimum of
1958 // the y variance of the tracklet
b72f4eaf 1959 fX = -fCov[1]/fCov[2];
2eb10c34 1960 fS2Y = fCov[0] +2.*fX*fCov[1] + fX*fX*fCov[2];
1961
903326c1 1962 Float_t xs=fX+.5*AliTRDgeometry::CamHght();
1963 if(xs < 0. || xs > AliTRDgeometry::CamHght()+AliTRDgeometry::CdrHght()){
1964 AliDebug(1, Form("Ref radial position ouside chamber x[%5.2f].", fX));
2eb10c34 1965 SetErrorMsg(kFitFailedY);
903326c1 1966 return kFALSE;
1967 }
b1957d3c 1968
2eb10c34 1969/* // THE LEADING CLUSTER METHOD for z fit
1fd9389f 1970 Float_t xMin = fX0;
b72f4eaf 1971 Int_t ic=n=kNclusters-1; jc = &fClusters[ic];
1fd9389f 1972 AliTRDcluster *c0 =0x0, **kc = &fClusters[kNtb-1];
1973 for(; ic>kNtb; ic--, --jc, --kc){
1974 if((c0 = (*kc)) && c0->IsInChamber() && (xMin>c0->GetX())) xMin = c0->GetX();
1975 if(!(c = (*jc))) continue;
1976 if(!c->IsInChamber()) continue;
1977 zc[kNclusters-1] = c->GetZ();
1978 fX = fX0 - c->GetX();
1979 }
1980 fZfit[0] = .5*(zc[0]+zc[kNclusters-1]); fZfit[1] = 0.;
1981 // Error parameterization
1982 fS2Z = fdX*fZref[1];
e355f67a 1983 fS2Z *= fS2Z; fS2Z *= 0.2887; // 1/sqrt(12)*/
1984
2eb10c34 1985 // fit QZ
1986 if(opt!=1 && IsRowCross()){
1987 if(!fitterZ.Eval()) SetErrorMsg(kFitFailedZ);
4ecadb52 1988 if(!HasError(kFitFailedZ) && TMath::Abs(fitterZ.GetFunctionParameter(1))>1.e-10){
2eb10c34 1989 // TODO - one has to recalculate xy fit based on
1990 // better knowledge of z position
1991// Double_t x = -fitterZ.GetFunctionParameter(0)/fitterZ.GetFunctionParameter(1);
1992// Double_t z0 = .5*(zc[0]+zc[n-1]);
1993// fZfit[0] = z0 + fZfit[1]*x;
1994// fZfit[1] = fZfit[0]/fX0;
1995// redo fit on xy plane
b72f4eaf 1996 }
c850c351 1997 // temporary external error parameterization
1998 fS2Z = 0.05+0.4*TMath::Abs(fZref[1]); fS2Z *= fS2Z;
1999 // TODO correct formula
2000 //fS2Z = sigma_x*TMath::Abs(fZref[1]);
b1957d3c 2001 } else {
2eb10c34 2002 //fZfit[0] = zc[0] + dzdx*0.5*AliTRDgeometry::CdrHght();
dd8059a8 2003 fS2Z = GetPadLength()*GetPadLength()/12.;
29b87567 2004 }
29b87567 2005 return kTRUE;
e4f2f73d 2006}
2007
e4f2f73d 2008
9dcc64cc 2009//____________________________________________________________________
2010Bool_t AliTRDseedV1::FitRobust(Bool_t chg)
e3cf3d02 2011{
2012//
9dcc64cc 2013// Linear fit of the clusters attached to the tracklet
e3cf3d02 2014//
9dcc64cc 2015// Author
2016// A.Bercuci <A.Bercuci@gsi.de>
e3cf3d02 2017
9dcc64cc 2018 TTreeSRedirector *pstreamer(NULL);
2019 const AliTRDrecoParam* const recoParam = fkReconstructor->GetRecoParam(); if(recoParam->GetStreamLevel(AliTRDrecoParam::kTracker) > 3 && fkReconstructor->IsDebugStreaming()) pstreamer = fkReconstructor->GetDebugStream(AliTRDrecoParam::kTracker);
e3cf3d02 2020
9dcc64cc 2021 // factor to scale y pulls.
2022 // ideally if error parametrization correct this is 1.
2023 //Float_t lyScaler = 1./(AliTRDgeometry::GetLayer(fDet)+1.);
2024 Float_t kScalePulls = 1.;
2025 AliTRDcalibDB *calibration = AliTRDcalibDB::Instance();
2026 if(!calibration){
2027 AliWarning("No access to calibration data");
2028 } else {
2029 // Retrieve the CDB container class with the parametric likelihood
2030 const AliTRDCalTrkAttach *attach = calibration->GetAttachObject();
2031 if(!attach){
2032 AliWarning("No usable AttachClusters calib object.");
2033 } else {
2034 kScalePulls = attach->GetScaleCov();//*lyScaler;
2035 }
e3cf3d02 2036 }
9dcc64cc 2037 Double_t xc[kNclusters], yc[kNclusters], sy[kNclusters];
2038 Int_t n(0), // clusters used in fit
2039 row[]={-1, 0}; // pad row spanned by the tracklet
2040 AliTRDcluster *c(NULL), **jc = &fClusters[0];
2041 for(Int_t ic=0; ic<kNtb; ic++, ++jc) {
2042 if(!(c = (*jc))) continue;
2043 if(!c->IsInChamber()) continue;
2044 if(row[0]<0){
2045 fZfit[0] = c->GetZ();
2046 fZfit[1] = 0.;
2047 row[0] = c->GetPadRow();
e3cf3d02 2048 }
2f4384e6 2049 xc[n] = c->GetX();
9dcc64cc 2050 yc[n] = c->GetY();
2051 sy[n] = c->GetSigmaY2()>0?(TMath::Min(TMath::Sqrt(c->GetSigmaY2()), 0.08)):0.08;
2052 n++;
e3cf3d02 2053 }
9dcc64cc 2054 Double_t corr = fPad[2]*fPad[0];
e3cf3d02 2055
9dcc64cc 2056 for(Int_t ic=kNtb; ic<kNclusters; ic++, ++jc) {
2057 if(!(c = (*jc))) continue;
2058 if(!c->IsInChamber()) continue;
2059 if(row[1]==0) row[1] = c->GetPadRow() - row[0];
2f4384e6 2060 xc[n] = c->GetX();
9dcc64cc 2061 yc[n] = c->GetY() + corr*row[1];
2062 sy[n] = c->GetSigmaY2()>0?(TMath::Min(TMath::Sqrt(c->GetSigmaY2()), 0.08)):0.08;
2063 n++;
e3cf3d02 2064 }
9dcc64cc 2065 UChar_t status(0);
2f4384e6 2066 Double_t par[3] = {0.,0.,fX0}, cov[3];
9dcc64cc 2067 if(!AliTRDtrackletOflHelper::Fit(n, xc, yc, sy, par, 1.5, cov)){
2068 AliDebug(1, Form("Tracklet fit failed D[%03d].", fDet));
2069 SetErrorMsg(kFitCl);
2070 return kFALSE;
e3cf3d02 2071 }
9dcc64cc 2072 fYfit[0] = par[0];
2f4384e6 2073 fYfit[1] = par[1];
9dcc64cc 2074 // store covariance
2075 fCov[0] = kScalePulls*cov[0]; // variance of y0
2076 fCov[1] = kScalePulls*cov[2]; // covariance of y0, dydx
2077 fCov[2] = kScalePulls*cov[1]; // variance of dydx
2078 // the ref radial position is set at the minimum of
2079 // the y variance of the tracklet
2f4384e6 2080 fX = 0.;//-fCov[1]/fCov[2];
9dcc64cc 2081 // check radial position
2082 Float_t xs=fX+.5*AliTRDgeometry::CamHght();
2083 if(xs < 0. || xs > AliTRDgeometry::CamHght()+AliTRDgeometry::CdrHght()){
2084 AliDebug(1, Form("Ref radial position x[%5.2f] ouside D[%3d].", fX, fDet));
2085 SetErrorMsg(kFitFailedY);
2086 return kFALSE;
e3cf3d02 2087 }
9dcc64cc 2088 fS2Y = fCov[0] + fX*fCov[1];
2089 fS2Z = fPad[0]*fPad[0]/12.;
2090 AliDebug(2, Form("[I] x[cm]=%6.2f y[cm]=%+5.2f z[cm]=%+6.2f dydx[deg]=%+5.2f sy[um]=%6.2f sz[cm]=%6.2f", GetX(), GetY(), GetZ(), TMath::ATan(fYfit[1])*TMath::RadToDeg(), TMath::Sqrt(fS2Y)*1.e4, TMath::Sqrt(fS2Z)));
2091 if(IsRowCross()){
2092 Float_t x,z;
2093 if(!GetEstimatedCrossPoint(x,z)){
2f4384e6 2094 AliDebug(2, Form("Failed(I) getting crossing point D[%03d].", fDet));
9dcc64cc 2095 SetErrorMsg(kFitFailedY);
2096 return kTRUE;
2097 }
2f4384e6 2098 //if(IsPrimary()){
2099 fZfit[0] = fX0*z/x;
9dcc64cc 2100 fZfit[1] = z/x;
2101 fS2Z = 0.05+0.4*TMath::Abs(fZfit[1]); fS2Z *= fS2Z;
2f4384e6 2102 //}
2103 AliDebug(2, Form("s2y[%f] s2z[%f]", fS2Y, fS2Z));
9dcc64cc 2104 AliDebug(2, Form("[II] x[cm]=%6.2f y[cm]=%+5.2f z[cm]=%+6.2f dydx[deg]=%+5.2f sy[um]=%6.2f sz[um]=%6.2f dzdx[deg]=%+5.2f", GetX(), GetY(), GetZ(), TMath::ATan(fYfit[1])*TMath::RadToDeg(), TMath::Sqrt(fS2Y)*1.e4, TMath::Sqrt(fS2Z)*1.e4, TMath::ATan(fZfit[1])*TMath::RadToDeg()));
e3cf3d02 2105 }
e3cf3d02 2106
9dcc64cc 2107 if(pstreamer){
2108 Float_t x= fX0 -fX,
2109 y = GetY(),
2110 yt = fYref[0]-fX*fYref[1];
2111 SETBIT(status, 2);
2112 TVectorD vcov(3); vcov[0]=cov[0];vcov[1]=cov[1];vcov[2]=cov[2];
2113 Double_t sm(0.), chi2(0.), tmp, dy[kNclusters];
2114 for(Int_t ic(0); ic<n; ic++){
2115 sm += sy[ic];
2f4384e6 2116 dy[ic] = yc[ic]-(fYfit[0]+(xc[ic]-fX0)*fYfit[1]); tmp = dy[ic]/sy[ic];
9dcc64cc 2117 chi2 += tmp*tmp;
2118 }
2119 sm /= n; chi2 = TMath::Sqrt(chi2);
2120 Double_t m(0.), s(0.);
2121 AliMathBase::EvaluateUni(n, dy, m, s, 0);
2122 (*pstreamer) << "FitRobust4"
2123 << "stat=" << status
2124 << "chg=" << chg
2125 << "ncl=" << n
2126 << "det=" << fDet
2127 << "x0=" << fX0
2128 << "y0=" << fYfit[0]
2129 << "x=" << x
2130 << "y=" << y
2131 << "dydx=" << fYfit[1]
2132 << "pt=" << fPt
2133 << "yt=" << yt
2134 << "dydxt="<< fYref[1]
2135 << "cov=" << &vcov
2136 << "chi2=" << chi2
2137 << "sm=" << sm
2138 << "ss=" << s
2139 << "\n";
2140 }
2141 return kTRUE;
2142}
e3cf3d02 2143
e4f2f73d 2144//___________________________________________________________________
203967fc 2145void AliTRDseedV1::Print(Option_t *o) const
e4f2f73d 2146{
2147 //
2148 // Printing the seedstatus
2149 //
2150
b72f4eaf 2151 AliInfo(Form("Det[%3d] X0[%7.2f] Pad{L[%5.2f] W[%5.2f] Tilt[%+6.2f]}", fDet, fX0, GetPadLength(), GetPadWidth(), GetTilt()));
dd8059a8 2152 AliInfo(Form("N[%2d] Nused[%2d] Nshared[%2d] [%d]", GetN(), GetNUsed(), GetNShared(), fN));
b72f4eaf 2153 AliInfo(Form("FLAGS : RC[%c] Kink[%c] SA[%c]", IsRowCross()?'y':'n', IsKink()?'y':'n', IsStandAlone()?'y':'n'));
525f399b 2154 AliInfo(Form("CALIB PARAMS : T0[%5.2f] Vd[%5.2f] s2PRF[%5.2f] ExB[%5.2f] Dl[%5.2f] Dt[%5.2f]", fT0, fVD, fS2PRF, fExB, fDiffL, fDiffT));
dd8059a8 2155
2156 Double_t cov[3], x=GetX();
2157 GetCovAt(x, cov);
2158 AliInfo(" | x[cm] | y[cm] | z[cm] | dydx | dzdx |");
2159 AliInfo(Form("Fit | %7.2f | %7.2f+-%7.2f | %7.2f+-%7.2f| %5.2f | ----- |", x, GetY(), TMath::Sqrt(cov[0]), GetZ(), TMath::Sqrt(cov[2]), fYfit[1]));
21aad919 2160 AliInfo(Form("Ref | %7.2f | %7.2f+-%7.2f | %7.2f+-%7.2f| %5.2f | %5.2f |", x, fYref[0]-fX*fYref[1], TMath::Sqrt(fRefCov[0]), fZref[0]-fX*fYref[1], TMath::Sqrt(fRefCov[2]), fYref[1], fZref[1]));
ee8fb199 2161 AliInfo(Form("P / Pt [GeV/c] = %f / %f", GetMomentum(), fPt));
68f9b6bd 2162 if(IsStandAlone()) AliInfo(Form("C Rieman / Vertex [1/cm] = %f / %f", fC[0], fC[1]));
ee8fb199 2163 AliInfo(Form("dEdx [a.u.] = %f / %f / %f / %f / %f/ %f / %f / %f", fdEdx[0], fdEdx[1], fdEdx[2], fdEdx[3], fdEdx[4], fdEdx[5], fdEdx[6], fdEdx[7]));
2164 AliInfo(Form("PID = %5.3f / %5.3f / %5.3f / %5.3f / %5.3f", fProb[0], fProb[1], fProb[2], fProb[3], fProb[4]));
203967fc 2165
2166 if(strcmp(o, "a")!=0) return;
2167
4dc4dc2e 2168 AliTRDcluster* const* jc = &fClusters[0];
8d2bec9e 2169 for(int ic=0; ic<kNclusters; ic++, jc++) {
4dc4dc2e 2170 if(!(*jc)) continue;
203967fc 2171 (*jc)->Print(o);
4dc4dc2e 2172 }
e4f2f73d 2173}
47d5d320 2174
203967fc 2175
2176//___________________________________________________________________
2177Bool_t AliTRDseedV1::IsEqual(const TObject *o) const
2178{
2179 // Checks if current instance of the class has the same essential members
2180 // as the given one
2181
2182 if(!o) return kFALSE;
2183 const AliTRDseedV1 *inTracklet = dynamic_cast<const AliTRDseedV1*>(o);
2184 if(!inTracklet) return kFALSE;
2185
2186 for (Int_t i = 0; i < 2; i++){
e3cf3d02 2187 if ( fYref[i] != inTracklet->fYref[i] ) return kFALSE;
2188 if ( fZref[i] != inTracklet->fZref[i] ) return kFALSE;
203967fc 2189 }
2190
4ecadb52 2191 if ( TMath::Abs(fS2Y - inTracklet->fS2Y)>1.e-10 ) return kFALSE;
2192 if ( TMath::Abs(GetTilt() - inTracklet->GetTilt())>1.e-10 ) return kFALSE;
2193 if ( TMath::Abs(GetPadLength() - inTracklet->GetPadLength())>1.e-10 ) return kFALSE;
203967fc 2194
8d2bec9e 2195 for (Int_t i = 0; i < kNclusters; i++){
e3cf3d02 2196// if ( fX[i] != inTracklet->GetX(i) ) return kFALSE;
2197// if ( fY[i] != inTracklet->GetY(i) ) return kFALSE;
2198// if ( fZ[i] != inTracklet->GetZ(i) ) return kFALSE;
2199 if ( fIndexes[i] != inTracklet->fIndexes[i] ) return kFALSE;
203967fc 2200 }
f29f13a6 2201// if ( fUsable != inTracklet->fUsable ) return kFALSE;
203967fc 2202
2203 for (Int_t i=0; i < 2; i++){
e3cf3d02 2204 if ( fYfit[i] != inTracklet->fYfit[i] ) return kFALSE;
2205 if ( fZfit[i] != inTracklet->fZfit[i] ) return kFALSE;
2206 if ( fLabels[i] != inTracklet->fLabels[i] ) return kFALSE;
203967fc 2207 }
2208
e3cf3d02 2209/* if ( fMeanz != inTracklet->GetMeanz() ) return kFALSE;
2210 if ( fZProb != inTracklet->GetZProb() ) return kFALSE;*/
3e778975 2211 if ( fN != inTracklet->fN ) return kFALSE;
2212 //if ( fNUsed != inTracklet->fNUsed ) return kFALSE;
e3cf3d02 2213 //if ( fFreq != inTracklet->GetFreq() ) return kFALSE;
2214 //if ( fNChange != inTracklet->GetNChange() ) return kFALSE;
203967fc 2215
4ecadb52 2216 if ( TMath::Abs(fC[0] - inTracklet->fC[0])>1.e-10 ) return kFALSE;
e3cf3d02 2217 //if ( fCC != inTracklet->GetCC() ) return kFALSE;
4ecadb52 2218 if ( TMath::Abs(fChi2 - inTracklet->fChi2)>1.e-10 ) return kFALSE;
203967fc 2219 // if ( fChi2Z != inTracklet->GetChi2Z() ) return kFALSE;
2220
e3cf3d02 2221 if ( fDet != inTracklet->fDet ) return kFALSE;
4ecadb52 2222 if ( TMath::Abs(fPt - inTracklet->fPt)>1.e-10 ) return kFALSE;
2223 if ( TMath::Abs(fdX - inTracklet->fdX)>1.e-10 ) return kFALSE;
203967fc 2224
8d2bec9e 2225 for (Int_t iCluster = 0; iCluster < kNclusters; iCluster++){
203967fc 2226 AliTRDcluster *curCluster = fClusters[iCluster];
e3cf3d02 2227 AliTRDcluster *inCluster = inTracklet->fClusters[iCluster];
203967fc 2228 if (curCluster && inCluster){
2229 if (! curCluster->IsEqual(inCluster) ) {
2230 curCluster->Print();
2231 inCluster->Print();
2232 return kFALSE;
2233 }
2234 } else {
2235 // if one cluster exists, and corresponding
2236 // in other tracklet doesn't - return kFALSE
2237 if(curCluster || inCluster) return kFALSE;
2238 }
2239 }
2240 return kTRUE;
2241}
5d401b45 2242