]> git.uio.no Git - u/mrichter/AliRoot.git/blob - TRD/AliTRDseedV1.cxx
extend functionality for HLT usage and improved verbosity (Kostya Alex)
[u/mrichter/AliRoot.git] / TRD / AliTRDseedV1.cxx
1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3 *                                                                        *
4 * Author: The ALICE Off-line Project.                                    *
5 * Contributors are mentioned in the code where appropriate.              *
6 *                                                                        *
7 * Permission to use, copy, modify and distribute this software and its   *
8 * documentation strictly for non-commercial purposes is hereby granted   *
9 * without fee, provided that the above copyright notice appears in all   *
10 * copies and that both the copyright notice and this permission notice   *
11 * appear in the supporting documentation. The authors make no claims     *
12 * about the suitability of this software for any purpose. It is          *
13 * provided "as is" without express or implied warranty.                  *
14 **************************************************************************/
15
16 /* $Id$ */
17
18 ////////////////////////////////////////////////////////////////////////////
19 //                                                                        //
20 //  The TRD track seed                                                    //
21 //                                                                        //
22 //  Authors:                                                              //
23 //    Alex Bercuci <A.Bercuci@gsi.de>                                     //
24 //    Markus Fasel <M.Fasel@gsi.de>                                       //
25 //                                                                        //
26 ////////////////////////////////////////////////////////////////////////////
27
28 #include "TMath.h"
29 #include "TLinearFitter.h"
30 #include "TClonesArray.h" // tmp
31 #include <TTreeStream.h>
32
33 #include "AliLog.h"
34 #include "AliMathBase.h"
35
36 #include "AliTRDpadPlane.h"
37 #include "AliTRDcluster.h"
38 #include "AliTRDseedV1.h"
39 #include "AliTRDtrackV1.h"
40 #include "AliTRDcalibDB.h"
41 #include "AliTRDchamberTimeBin.h"
42 #include "AliTRDtrackingChamber.h"
43 #include "AliTRDtrackerV1.h"
44 #include "AliTRDReconstructor.h"
45 #include "AliTRDrecoParam.h"
46 #include "Cal/AliTRDCalPID.h"
47
48 ClassImp(AliTRDseedV1)
49
50 //____________________________________________________________________
51 AliTRDseedV1::AliTRDseedV1(Int_t det) 
52   :AliTRDseed()
53   ,fReconstructor(0x0)
54   ,fClusterIter(0x0)
55   ,fClusterIdx(0)
56   ,fDet(det)
57   ,fMom(0.)
58   ,fSnp(0.)
59   ,fTgl(0.)
60   ,fdX(0.)
61 {
62   //
63   // Constructor
64   //
65   //printf("AliTRDseedV1::AliTRDseedV1()\n");
66
67   for(int islice=0; islice < knSlices; islice++) fdEdx[islice] = 0.;
68   for(int ispec=0; ispec<AliPID::kSPECIES; ispec++) fProb[ispec]  = -1.;
69 }
70
71 //____________________________________________________________________
72 AliTRDseedV1::AliTRDseedV1(const AliTRDseedV1 &ref)
73   :AliTRDseed((AliTRDseed&)ref)
74   ,fReconstructor(ref.fReconstructor)
75   ,fClusterIter(0x0)
76   ,fClusterIdx(0)
77   ,fDet(ref.fDet)
78   ,fMom(ref.fMom)
79   ,fSnp(ref.fSnp)
80   ,fTgl(ref.fTgl)
81   ,fdX(ref.fdX)
82 {
83   //
84   // Copy Constructor performing a deep copy
85   //
86
87   //printf("AliTRDseedV1::AliTRDseedV1(const AliTRDseedV1 &)\n");
88   SetBit(kOwner, kFALSE);
89   for(int islice=0; islice < knSlices; islice++) fdEdx[islice] = ref.fdEdx[islice];
90   for(int ispec=0; ispec<AliPID::kSPECIES; ispec++) fProb[ispec] = ref.fProb[ispec];
91 }
92
93
94 //____________________________________________________________________
95 AliTRDseedV1& AliTRDseedV1::operator=(const AliTRDseedV1 &ref)
96 {
97   //
98   // Assignment Operator using the copy function
99   //
100
101   if(this != &ref){
102     ref.Copy(*this);
103   }
104   SetBit(kOwner, kFALSE);
105
106   return *this;
107
108 }
109
110 //____________________________________________________________________
111 AliTRDseedV1::~AliTRDseedV1()
112 {
113   //
114   // Destructor. The RecoParam object belongs to the underlying tracker.
115   //
116
117   //printf("I-AliTRDseedV1::~AliTRDseedV1() : Owner[%s]\n", IsOwner()?"YES":"NO");
118
119   if(IsOwner()) 
120     for(int itb=0; itb<knTimebins; itb++){
121       if(!fClusters[itb]) continue; 
122       //AliInfo(Form("deleting c %p @ %d", fClusters[itb], itb));
123       delete fClusters[itb];
124       fClusters[itb] = 0x0;
125     }
126 }
127
128 //____________________________________________________________________
129 void AliTRDseedV1::Copy(TObject &ref) const
130 {
131   //
132   // Copy function
133   //
134
135   //AliInfo("");
136   AliTRDseedV1 &target = (AliTRDseedV1 &)ref; 
137
138   target.fClusterIter   = 0x0;
139   target.fClusterIdx    = 0;
140   target.fDet           = fDet;
141   target.fMom           = fMom;
142   target.fSnp           = fSnp;
143   target.fTgl           = fTgl;
144   target.fdX            = fdX;
145   target.fReconstructor = fReconstructor;
146   
147   for(int islice=0; islice < knSlices; islice++) target.fdEdx[islice] = fdEdx[islice];
148   for(int ispec=0; ispec<AliPID::kSPECIES; ispec++) target.fProb[ispec] = fProb[ispec];
149   
150   AliTRDseed::Copy(target);
151 }
152
153
154 //____________________________________________________________
155 Bool_t AliTRDseedV1::Init(AliTRDtrackV1 *track)
156 {
157 // Initialize this tracklet using the track information
158 //
159 // Parameters:
160 //   track - the TRD track used to initialize the tracklet
161 // 
162 // Detailed description
163 // The function sets the starting point and direction of the
164 // tracklet according to the information from the TRD track.
165 // 
166 // Caution
167 // The TRD track has to be propagated to the beginning of the
168 // chamber where the tracklet will be constructed
169 //
170
171   Double_t y, z; 
172   if(!track->GetProlongation(fX0, y, z)) return kFALSE;
173   fYref[0] = y;
174   fYref[1] = track->GetSnp()/(1. - track->GetSnp()*track->GetSnp());
175   fZref[0] = z;
176   fZref[1] = track->GetTgl();
177
178   //printf("Tracklet ref x[%7.3f] y[%7.3f] z[%7.3f], snp[%f] tgl[%f]\n", fX0, fYref[0], fZref[0], track->GetSnp(), track->GetTgl());
179   return kTRUE;
180 }
181
182
183 //____________________________________________________________________
184 void AliTRDseedV1::CookdEdx(Int_t nslices)
185 {
186 // Calculates average dE/dx for all slices and store them in the internal array fdEdx. 
187 //
188 // Parameters:
189 //  nslices : number of slices for which dE/dx should be calculated
190 // Output:
191 //  store results in the internal array fdEdx. This can be accessed with the method
192 //  AliTRDseedV1::GetdEdx()
193 //
194 // Detailed description
195 // Calculates average dE/dx for all slices. Depending on the PID methode 
196 // the number of slices can be 3 (LQ) or 8(NN). 
197 // The calculation of dQ/dl are done using the tracklet fit results (see AliTRDseedV1::GetdQdl(Int_t)) i.e.
198 //
199 // dQ/dl = qc/(dx * sqrt(1 + dy/dx^2 + dz/dx^2))
200 //
201 // The following effects are included in the calculation:
202 // 1. calibration values for t0 and vdrift (using x coordinate to calculate slice)
203 // 2. cluster sharing (optional see AliTRDrecoParam::SetClusterSharing())
204 // 3. cluster size
205 //
206
207   Int_t nclusters[knSlices];
208   for(int i=0; i<knSlices; i++){ 
209     fdEdx[i]     = 0.;
210     nclusters[i] = 0;
211   }
212   Float_t clength = (/*.5 * */AliTRDgeometry::AmThick() + AliTRDgeometry::DrThick());
213
214   AliTRDcluster *cluster = 0x0;
215   for(int ic=0; ic<AliTRDtrackerV1::GetNTimeBins(); ic++){
216     if(!(cluster = fClusters[ic])) continue;
217     Float_t x = cluster->GetX();
218     
219     // Filter clusters for dE/dx calculation
220     
221     // 1.consider calibration effects for slice determination
222     Int_t slice; 
223     if(cluster->IsInChamber()) slice = Int_t(TMath::Abs(fX0 - x) * nslices / clength);
224     else slice = x < fX0 ? 0 : nslices-1;
225     
226     // 2. take sharing into account
227     Float_t w = cluster->IsShared() ? .5 : 1.;
228     
229     // 3. take into account large clusters TODO
230     //w *= c->GetNPads() > 3 ? .8 : 1.;
231     
232     //CHECK !!!
233     fdEdx[slice]   += w * GetdQdl(ic); //fdQdl[ic];
234     nclusters[slice]++;
235   } // End of loop over clusters
236
237   //if(fReconstructor->GetPIDMethod() == AliTRDReconstructor::kLQPID){
238   if(nslices == AliTRDReconstructor::kLQslices){
239   // calculate mean charge per slice (only LQ PID)
240     for(int is=0; is<nslices; is++){ 
241       if(nclusters[is]) fdEdx[is] /= nclusters[is];
242     }
243   }
244 }
245
246
247 //____________________________________________________________________
248 Float_t AliTRDseedV1::GetdQdl(Int_t ic) const
249 {
250   return fClusters[ic] ? TMath::Abs(fClusters[ic]->GetQ()) /fdX / TMath::Sqrt(1. + fYfit[1]*fYfit[1] + fZref[1]*fZref[1]) : 0.;
251 }
252
253 //____________________________________________________________________
254 Double_t* AliTRDseedV1::GetProbability()
255 {       
256 // Fill probability array for tracklet from the DB.
257 //
258 // Parameters
259 //
260 // Output
261 //   returns pointer to the probability array and 0x0 if missing DB access 
262 //
263 // Detailed description
264
265   
266   // retrive calibration db
267   AliTRDcalibDB *calibration = AliTRDcalibDB::Instance();
268   if (!calibration) {
269     AliError("No access to calibration data");
270     return 0x0;
271   }
272
273   if (!fReconstructor) {
274     AliError("Reconstructor not set.");
275     return 0x0;
276   }
277
278   // Retrieve the CDB container class with the parametric detector response
279   const AliTRDCalPID *pd = calibration->GetPIDObject(fReconstructor->GetPIDMethod());
280   if (!pd) {
281     AliError("No access to AliTRDCalPID object");
282     return 0x0;
283   }
284   //AliInfo(Form("Method[%d] : %s", fReconstructor->GetRecoParam() ->GetPIDMethod(), pd->IsA()->GetName()));
285
286   // calculate tracklet length TO DO
287   Float_t length = (AliTRDgeometry::AmThick() + AliTRDgeometry::DrThick());
288   /// TMath::Sqrt((1.0 - fSnp[iPlane]*fSnp[iPlane]) / (1.0 + fTgl[iPlane]*fTgl[iPlane]));
289   
290   //calculate dE/dx
291   CookdEdx(fReconstructor->GetNdEdxSlices());
292   
293   // Sets the a priori probabilities
294   for(int ispec=0; ispec<AliPID::kSPECIES; ispec++) {
295     fProb[ispec] = pd->GetProbability(ispec, fMom, &fdEdx[0], length, GetPlane());      
296   }
297
298   return &fProb[0];
299 }
300
301 //____________________________________________________________________
302 Float_t AliTRDseedV1::GetQuality(Bool_t kZcorr) const
303 {
304   //
305   // Returns a quality measurement of the current seed
306   //
307
308   Float_t zcorr = kZcorr ? fTilt * (fZProb - fZref[0]) : 0.;
309   return 
310       .5 * TMath::Abs(18.0 - fN2)
311     + 10.* TMath::Abs(fYfit[1] - fYref[1])
312     + 5. * TMath::Abs(fYfit[0] - fYref[0] + zcorr)
313     + 2. * TMath::Abs(fMeanz - fZref[0]) / fPadLength;
314 }
315
316 //____________________________________________________________________
317 void AliTRDseedV1::GetCovAt(Double_t /*x*/, Double_t *cov) const
318 {
319 // Computes covariance in the y-z plane at radial point x
320
321   Int_t ic = 0; while (!fClusters[ic]) ic++; 
322   AliTRDcalibDB *fCalib = AliTRDcalibDB::Instance();
323   Double_t exB         = fCalib->GetOmegaTau(fCalib->GetVdriftAverage(fClusters[ic]->GetDetector()), -AliTracker::GetBz()*0.1);
324
325   Double_t sy2    = fSigmaY2*fSigmaY2 + .2*(fYfit[1]-exB)*(fYfit[1]-exB);
326   Double_t sz2    = fPadLength/12.;
327
328
329   //printf("Yfit[1] %f sy20 %f SigmaY2 %f\n", fYfit[1], sy20, fSigmaY2);
330
331   cov[0] = sy2;
332   cov[1] = fTilt*(sy2-sz2);
333   cov[2] = sz2;
334
335   // insert systematic uncertainties calibration and misalignment
336   Double_t sys[15];
337   fReconstructor->GetRecoParam()->GetSysCovMatrix(sys);
338   cov[0] += (sys[0]*sys[0]);
339   cov[2] += (sys[1]*sys[1]);
340 }
341
342
343 //____________________________________________________________________
344 void AliTRDseedV1::SetOwner()
345 {
346   //AliInfo(Form("own [%s] fOwner[%s]", own?"YES":"NO", fOwner?"YES":"NO"));
347   
348   if(TestBit(kOwner)) return;
349   for(int ic=0; ic<knTimebins; ic++){
350     if(!fClusters[ic]) continue;
351     fClusters[ic] = new AliTRDcluster(*fClusters[ic]);
352   }
353   SetBit(kOwner);
354 }
355
356 //____________________________________________________________________
357 Bool_t  AliTRDseedV1::AttachClustersIter(AliTRDtrackingChamber *chamber, Float_t quality, Bool_t kZcorr, AliTRDcluster *c)
358 {
359   //
360   // Iterative process to register clusters to the seed.
361   // In iteration 0 we try only one pad-row and if quality not
362   // sufficient we try 2 pad-rows (about 5% of tracks cross 2 pad-rows)
363   //
364   // debug level 7
365   //
366   
367   if(!fReconstructor->GetRecoParam() ){
368     AliError("Seed can not be used without a valid RecoParam.");
369     return kFALSE;
370   }
371
372   AliTRDchamberTimeBin *layer = 0x0;
373   if(fReconstructor->GetStreamLevel(AliTRDReconstructor::kTracker)>=7){
374     AliTRDtrackingChamber ch(*chamber);
375     ch.SetOwner(); 
376     (*AliTRDtrackerV1::DebugStreamer()) << "AttachClustersIter"
377       << "chamber.="   << &ch
378       << "tracklet.="  << this
379       << "\n";  
380   }
381
382   Float_t  tquality;
383   Double_t kroady = fReconstructor->GetRecoParam() ->GetRoad1y();
384   Double_t kroadz = fPadLength * .5 + 1.;
385   
386   // initialize configuration parameters
387   Float_t zcorr = kZcorr ? fTilt * (fZProb - fZref[0]) : 0.;
388   Int_t   niter = kZcorr ? 1 : 2;
389   
390   Double_t yexp, zexp;
391   Int_t ncl = 0;
392   // start seed update
393   for (Int_t iter = 0; iter < niter; iter++) {
394     ncl = 0;
395     for (Int_t iTime = 0; iTime < AliTRDtrackerV1::GetNTimeBins(); iTime++) {
396       if(!(layer = chamber->GetTB(iTime))) continue;
397       if(!Int_t(*layer)) continue;
398       
399       // define searching configuration
400       Double_t dxlayer = layer->GetX() - fX0;
401       if(c){
402         zexp = c->GetZ();
403         //Try 2 pad-rows in second iteration
404         if (iter > 0) {
405           zexp = fZref[0] + fZref[1] * dxlayer - zcorr;
406           if (zexp > c->GetZ()) zexp = c->GetZ() + fPadLength*0.5;
407           if (zexp < c->GetZ()) zexp = c->GetZ() - fPadLength*0.5;
408         }
409       } else zexp = fZref[0] + (kZcorr ? fZref[1] * dxlayer : 0.);
410       yexp  = fYref[0] + fYref[1] * dxlayer - zcorr;
411       
412       // Get and register cluster
413       Int_t    index = layer->SearchNearestCluster(yexp, zexp, kroady, kroadz);
414       if (index < 0) continue;
415       AliTRDcluster *cl = (*layer)[index];
416       
417       fIndexes[iTime]  = layer->GetGlobalIndex(index);
418       fClusters[iTime] = cl;
419       fY[iTime]        = cl->GetY();
420       fZ[iTime]        = cl->GetZ();
421       ncl++;
422     }
423     if(fReconstructor->GetStreamLevel(AliTRDReconstructor::kTracker)>=7) AliInfo(Form("iter = %d ncl [%d] = %d", iter, fDet, ncl));
424     
425     if(ncl>1){  
426       // calculate length of the time bin (calibration aware)
427       Int_t irp = 0; Float_t x[2]; Int_t tb[2];
428       for (Int_t iTime = 0; iTime < AliTRDtrackerV1::GetNTimeBins(); iTime++) {
429         if(!fClusters[iTime]) continue;
430         x[irp]  = fClusters[iTime]->GetX();
431         tb[irp] = iTime;
432         irp++;
433         if(irp==2) break;
434       } 
435       fdX = (x[1] - x[0]) / (tb[0] - tb[1]);
436   
437       // update X0 from the clusters (calibration/alignment aware)
438       for (Int_t iTime = 0; iTime < AliTRDtrackerV1::GetNTimeBins(); iTime++) {
439         if(!(layer = chamber->GetTB(iTime))) continue;
440         if(!layer->IsT0()) continue;
441         if(fClusters[iTime]){ 
442           fX0 = fClusters[iTime]->GetX();
443           break;
444         } else { // we have to infere the position of the anode wire from the other clusters
445           for (Int_t jTime = iTime+1; jTime < AliTRDtrackerV1::GetNTimeBins(); jTime++) {
446             if(!fClusters[jTime]) continue;
447             fX0 = fClusters[jTime]->GetX() + fdX * (jTime - iTime);
448           }
449           break;
450         }
451       } 
452       
453       // update YZ reference point
454       // TODO
455       
456       // update x reference positions (calibration/alignment aware)
457       for (Int_t iTime = 0; iTime < AliTRDtrackerV1::GetNTimeBins(); iTime++) {
458         if(!fClusters[iTime]) continue;
459         fX[iTime] = fClusters[iTime]->GetX() - fX0;
460       } 
461       
462       AliTRDseed::Update();
463     }
464     if(fReconstructor->GetStreamLevel(AliTRDReconstructor::kTracker)>=7) AliInfo(Form("iter = %d nclFit [%d] = %d", iter, fDet, fN2));
465     
466     if(IsOK()){
467       tquality = GetQuality(kZcorr);
468       if(tquality < quality) break;
469       else quality = tquality;
470     }
471     kroadz *= 2.;
472   } // Loop: iter
473   if (!IsOK()) return kFALSE;
474
475   if(fReconstructor->GetStreamLevel(AliTRDReconstructor::kTracker)>=1) CookLabels();
476   UpdateUsed();
477   return kTRUE; 
478 }
479
480 //____________________________________________________________________
481 Bool_t  AliTRDseedV1::AttachClusters(AliTRDtrackingChamber *chamber
482                                       ,Bool_t kZcorr)
483 {
484   //
485   // Projective algorithm to attach clusters to seeding tracklets
486   //
487   // Parameters
488   //
489   // Output
490   //
491   // Detailed description
492   // 1. Collapse x coordinate for the full detector plane
493   // 2. truncated mean on y (r-phi) direction
494   // 3. purge clusters
495   // 4. truncated mean on z direction
496   // 5. purge clusters
497   // 6. fit tracklet
498   //    
499
500   if(!fReconstructor->GetRecoParam() ){
501     AliError("Seed can not be used without a valid RecoParam.");
502     return kFALSE;
503   }
504
505   const Int_t kClusterCandidates = 2 * knTimebins;
506   
507   //define roads
508   Double_t kroady = fReconstructor->GetRecoParam() ->GetRoad1y();
509   Double_t kroadz = fPadLength * 1.5 + 1.;
510   // correction to y for the tilting angle
511   Float_t zcorr = kZcorr ? fTilt * (fZProb - fZref[0]) : 0.;
512
513   // working variables
514   AliTRDcluster *clusters[kClusterCandidates];
515   Double_t cond[4], yexp[knTimebins], zexp[knTimebins],
516     yres[kClusterCandidates], zres[kClusterCandidates];
517   Int_t ncl, *index = 0x0, tboundary[knTimebins];
518   
519   // Do cluster projection
520   AliTRDchamberTimeBin *layer = 0x0;
521   Int_t nYclusters = 0; Bool_t kEXIT = kFALSE;
522   for (Int_t iTime = 0; iTime < AliTRDtrackerV1::GetNTimeBins(); iTime++) {
523     if(!(layer = chamber->GetTB(iTime))) continue;
524     if(!Int_t(*layer)) continue;
525     
526     fX[iTime] = layer->GetX() - fX0;
527     zexp[iTime] = fZref[0] + fZref[1] * fX[iTime];
528     yexp[iTime] = fYref[0] + fYref[1] * fX[iTime] - zcorr;
529     
530     // build condition and process clusters
531     cond[0] = yexp[iTime] - kroady; cond[1] = yexp[iTime] + kroady;
532     cond[2] = zexp[iTime] - kroadz; cond[3] = zexp[iTime] + kroadz;
533     layer->GetClusters(cond, index, ncl);
534     for(Int_t ic = 0; ic<ncl; ic++){
535       AliTRDcluster *c = layer->GetCluster(index[ic]);
536       clusters[nYclusters] = c;
537       yres[nYclusters++] = c->GetY() - yexp[iTime];
538       if(nYclusters >= kClusterCandidates) {
539         AliWarning(Form("Cluster candidates reached limit %d. Some may be lost.", kClusterCandidates));
540         kEXIT = kTRUE;
541         break;
542       }
543     }
544     tboundary[iTime] = nYclusters;
545     if(kEXIT) break;
546   }
547   
548   // Evaluate truncated mean on the y direction
549   Double_t mean, sigma;
550   AliMathBase::EvaluateUni(nYclusters, yres, mean, sigma, Int_t(nYclusters*.8)-2);
551   // purge cluster candidates
552   Int_t nZclusters = 0;
553   for(Int_t ic = 0; ic<nYclusters; ic++){
554     if(yres[ic] - mean > 4. * sigma){
555       clusters[ic] = 0x0;
556       continue;
557     }
558     zres[nZclusters++] = clusters[ic]->GetZ() - zexp[clusters[ic]->GetLocalTimeBin()];
559   }
560   
561   // Evaluate truncated mean on the z direction
562   AliMathBase::EvaluateUni(nZclusters, zres, mean, sigma, Int_t(nZclusters*.8)-2);
563   // purge cluster candidates
564   for(Int_t ic = 0; ic<nZclusters; ic++){
565     if(zres[ic] - mean > 4. * sigma){
566       clusters[ic] = 0x0;
567       continue;
568     }
569   }
570
571   
572   // Select only one cluster/TimeBin
573   Int_t lastCluster = 0;
574   fN2 = 0;
575   for (Int_t iTime = 0; iTime < AliTRDtrackerV1::GetNTimeBins(); iTime++) {
576     ncl = tboundary[iTime] - lastCluster;
577     if(!ncl) continue;
578     Int_t iptr = lastCluster;
579     if(ncl > 1){
580       Float_t dold = 9999.;
581       for(int ic=lastCluster; ic<tboundary[iTime]; ic++){
582         if(!clusters[ic]) continue;
583         Float_t y = yexp[iTime] - clusters[ic]->GetY();
584         Float_t z = zexp[iTime] - clusters[ic]->GetZ();
585         Float_t d = y * y + z * z;
586         if(d > dold) continue;
587         dold = d;
588         iptr = ic;
589       }
590     }
591     fIndexes[iTime]  = chamber->GetTB(iTime)->GetGlobalIndex(iptr);
592     fClusters[iTime] = clusters[iptr];
593     fY[iTime]        = clusters[iptr]->GetY();
594     fZ[iTime]        = clusters[iptr]->GetZ();
595     lastCluster      = tboundary[iTime];
596     fN2++;
597   }
598   
599   // number of minimum numbers of clusters expected for the tracklet
600   Int_t kClmin = Int_t(fReconstructor->GetRecoParam() ->GetFindableClusters()*AliTRDtrackerV1::GetNTimeBins());
601   if (fN2 < kClmin){
602     AliWarning(Form("Not enough clusters to fit the tracklet %d [%d].", fN2, kClmin));
603     fN2 = 0;
604     return kFALSE;
605   }
606
607   // update used clusters
608   fNUsed = 0;
609   for (Int_t iTime = 0; iTime < AliTRDtrackerV1::GetNTimeBins(); iTime++) {
610     if(!fClusters[iTime]) continue;
611     if((fClusters[iTime]->IsUsed())) fNUsed++;
612   }
613
614   if (fN2-fNUsed < kClmin){
615     AliWarning(Form("Too many clusters already in use %d (from %d).", fNUsed, fN2));
616     fN2 = 0;
617     return kFALSE;
618   }
619   
620   return kTRUE;
621 }
622
623 //____________________________________________________________
624 void AliTRDseedV1::Bootstrap(const AliTRDReconstructor *rec)
625 {
626 //   Fill in all derived information. It has to be called after recovery from file or HLT.
627 //   The primitive data are
628 //   - list of clusters
629 //   - detector (as the detector will be removed from clusters)
630 //   - position of anode wire (fX0) - temporary
631 //   - track reference position and direction
632 //   - momentum of the track
633 //   - time bin length [cm]
634 // 
635 //   A.Bercuci <A.Bercuci@gsi.de> Oct 30th 2008
636 //
637   fReconstructor = rec;
638   AliTRDgeometry g;
639   AliTRDpadPlane *pp = g.GetPadPlane(fDet);
640   fTilt      = TMath::Tan(TMath::DegToRad()*pp->GetTiltingAngle());
641   fPadLength = pp->GetLengthIPad();
642   fSnp = fYref[1]/TMath::Sqrt(1+fYref[1]*fYref[1]);
643   fTgl = fZref[1];
644   fN = 0; fN2 = 0; fMPads = 0.;
645   AliTRDcluster **cit = &fClusters[0];
646   for(Int_t ic = knTimebins; ic--; cit++){
647     if(!(*cit)) return;
648     fN++; fN2++;
649     fX[ic] = (*cit)->GetX() - fX0;
650     fY[ic] = (*cit)->GetY();
651     fZ[ic] = (*cit)->GetZ();
652   }
653   Update(); // Fit();
654   CookLabels();
655   GetProbability();
656 }
657
658
659 //____________________________________________________________________
660 Bool_t AliTRDseedV1::Fit(Bool_t tilt)
661 {
662   //
663   // Linear fit of the tracklet
664   //
665   // Parameters :
666   //
667   // Output :
668   //  True if successful
669   //
670   // Detailed description
671   // 2. Check if tracklet crosses pad row boundary
672   // 1. Calculate residuals in the y (r-phi) direction
673   // 3. Do a Least Square Fit to the data
674   //
675
676   const Int_t kClmin = 8;
677   const Float_t q0 = 100.;
678   const Float_t clSigma0 = 2.E-2;    //[cm]
679   const Float_t clSlopeQ = -1.19E-2; //[1/cm]
680
681   // get track direction
682   Double_t y0   = fYref[0];
683   Double_t dydx = fYref[1]; 
684   Double_t z0   = fZref[0];
685   Double_t dzdx = fZref[1];
686   Double_t yt, zt;
687
688   const Int_t kNtb = AliTRDtrackerV1::GetNTimeBins();
689   AliTRDtrackerV1::AliTRDLeastSquare fitterY, fitterZ;
690
691   // convertion factor from square to gauss distribution for sigma
692   Double_t convert = 1./TMath::Sqrt(12.);
693   
694   // book cluster information
695   Double_t xc[knTimebins], yc[knTimebins], zc[knTimebins], sy[knTimebins], sz[knTimebins];
696   Int_t zRow[knTimebins];
697
698
699   fN = 0;
700   AliTRDcluster *c=0x0, **jc = &fClusters[0];
701   for (Int_t ic=0; ic<kNtb; ic++, ++jc) {
702     zRow[ic] = -1;
703     xc[ic]  = -1.;
704     yc[ic]  = 999.;
705     zc[ic]  = 999.;
706     sy[ic]  = 0.;
707     sz[ic]  = 0.;
708     if(!(c = (*jc))) continue;
709     if(!c->IsInChamber()) continue;
710     Float_t w = 1.;
711     if(c->GetNPads()>4) w = .5;
712     if(c->GetNPads()>5) w = .2;
713     zRow[fN] = c->GetPadRow();
714     xc[fN]   = fX0 - c->GetX();
715     yc[fN]   = c->GetY();
716     zc[fN]   = c->GetZ();
717
718     // extrapolated y value for the track
719     yt = y0 - xc[fN]*dydx; 
720     // extrapolated z value for the track
721     zt = z0 - xc[fN]*dzdx; 
722     // tilt correction
723     if(tilt) yc[fN] -= fTilt*(zc[fN] - zt); 
724
725     // elaborate cluster error
726     Float_t qr = c->GetQ() - q0;
727     sy[fN]   = qr < 0. ? clSigma0*TMath::Exp(clSlopeQ*qr) : clSigma0;
728
729     fitterY.AddPoint(&xc[fN], yc[fN]-yt, sy[fN]);
730
731     sz[fN]   = fPadLength*convert;
732     fitterZ.AddPoint(&xc[fN], zc[fN], sz[fN]);
733     fN++;
734   }
735   // to few clusters
736   if (fN < kClmin) return kFALSE; 
737
738   // fit XY plane
739   fitterY.Eval();
740   fYfit[0] = y0+fitterY.GetFunctionParameter(0);
741   fYfit[1] = dydx-fitterY.GetFunctionParameter(1);
742
743   // check par row crossing
744   Int_t zN[2*AliTRDseed::knTimebins];
745   Int_t nz = AliTRDtrackerV1::Freq(fN, zRow, zN, kFALSE);
746   // more than one pad row crossing
747   if(nz>2) return kFALSE; 
748
749
750   // determine z offset of the fit
751   Float_t zslope = 0.;
752   Int_t nchanges = 0, nCross = 0;
753   if(nz==2){ // tracklet is crossing pad row
754     // Find the break time allowing one chage on pad-rows
755     // with maximal number of accepted clusters
756     Int_t padRef = zRow[0];
757     for (Int_t ic=1; ic<fN; ic++) {
758       if(zRow[ic] == padRef) continue;
759       
760       // debug
761       if(zRow[ic-1] == zRow[ic]){
762         printf("ERROR in pad row change!!!\n");
763       }
764     
765       // evaluate parameters of the crossing point
766       Float_t sx = (xc[ic-1] - xc[ic])*convert;
767       fCross[0] = .5 * (xc[ic-1] + xc[ic]);
768       fCross[2] = .5 * (zc[ic-1] + zc[ic]);
769       fCross[3] = TMath::Max(dzdx * sx, .01);
770       zslope    = zc[ic-1] > zc[ic] ? 1. : -1.;
771       padRef    = zRow[ic];
772       nCross    = ic;
773       nchanges++;
774     }
775   }
776
777   // condition on nCross and reset nchanges TODO
778
779   if(nchanges==1){
780     if(dzdx * zslope < 0.){
781       AliInfo("tracklet direction does not correspond to the track direction. TODO.");
782     }
783     SetBit(kRowCross, kTRUE); // mark pad row crossing
784     fitterZ.AddPoint(&fCross[0], fCross[2], fCross[3]);
785     fitterZ.Eval();
786     //zc[nc] = fitterZ.GetFunctionParameter(0); 
787     fCross[1] = fYfit[0] - fCross[0] * fYfit[1];
788     fCross[0] = fX0 - fCross[0];
789   } else if(nchanges > 1){ // debug
790     AliError("N pad row crossing > 1.");
791     return kFALSE;
792   }
793
794   UpdateUsed();
795
796   return kTRUE;
797 }
798
799
800 //___________________________________________________________________
801 void AliTRDseedV1::Print(Option_t *o) const
802 {
803   //
804   // Printing the seedstatus
805   //
806
807   AliInfo(Form("Det[%3d] Tilt[%+6.2f] Pad[%5.2f]", fDet, fTilt, fPadLength));
808   AliInfo(Form("Nattach[%2d] Nfit[%2d] Nuse[%2d] pads[%f]", fN, fN2, fNUsed, fMPads));
809   AliInfo(Form("x[%7.2f] y[%7.2f] z[%7.2f] dydx[%5.2f] dzdx[%5.2f]", fX0, fYfit[0], fZfit[0], fYfit[1], fZfit[1]));
810   AliInfo(Form("Ref        y[%7.2f] z[%7.2f] dydx[%5.2f] dzdx[%5.2f]", fYref[0], fZref[0], fYref[1], fZref[1]))
811
812
813   if(strcmp(o, "a")!=0) return;
814
815   AliTRDcluster* const* jc = &fClusters[0];
816   for(int ic=0; ic<AliTRDtrackerV1::GetNTimeBins(); ic++, jc++) {
817     if(!(*jc)) continue;
818     (*jc)->Print(o);
819   }
820
821 /*  printf("  fSigmaY =%f\n", fSigmaY);
822   printf("  fSigmaY2=%f\n", fSigmaY2);            
823   printf("  fMeanz  =%f\n", fMeanz);
824   printf("  fZProb  =%f\n", fZProb);
825   printf("  fLabels[0]=%d fLabels[1]=%d\n", fLabels[0], fLabels[1]);*/
826   
827 /*  printf("  fC      =%f\n", fC);        
828   printf("  fCC     =%f\n",fCC);      
829   printf("  fChi2   =%f\n", fChi2);  
830   printf("  fChi2Z  =%f\n", fChi2Z);*/
831 }
832
833
834 //___________________________________________________________________
835 Bool_t AliTRDseedV1::IsEqual(const TObject *o) const
836 {
837   // Checks if current instance of the class has the same essential members
838   // as the given one
839
840   if(!o) return kFALSE;
841   const AliTRDseedV1 *inTracklet = dynamic_cast<const AliTRDseedV1*>(o);
842   if(!inTracklet) return kFALSE;
843
844   for (Int_t i = 0; i < 2; i++){
845     if ( fYref[i] != inTracklet->GetYref(i) ) return kFALSE;
846     if ( fZref[i] != inTracklet->GetZref(i) ) return kFALSE;
847   }
848   
849   if ( fSigmaY != inTracklet->GetSigmaY() ) return kFALSE;
850   if ( fSigmaY2 != inTracklet->GetSigmaY2() ) return kFALSE;
851   if ( fTilt != inTracklet->GetTilt() ) return kFALSE;
852   if ( fPadLength != inTracklet->GetPadLength() ) return kFALSE;
853   
854   for (Int_t i = 0; i < knTimebins; i++){
855     if ( fX[i] != inTracklet->GetX(i) ) return kFALSE;
856     if ( fY[i] != inTracklet->GetY(i) ) return kFALSE;
857     if ( fZ[i] != inTracklet->GetZ(i) ) return kFALSE;
858     if ( fIndexes[i] != inTracklet->GetIndexes(i) ) return kFALSE;
859     if ( fUsable[i] != inTracklet->IsUsable(i) ) return kFALSE;
860   }
861
862   for (Int_t i=0; i < 2; i++){
863     if ( fYfit[i] != inTracklet->GetYfit(i) ) return kFALSE;
864     if ( fZfit[i] != inTracklet->GetZfit(i) ) return kFALSE;
865     if ( fYfitR[i] != inTracklet->GetYfitR(i) ) return kFALSE;
866     if ( fZfitR[i] != inTracklet->GetZfitR(i) ) return kFALSE;
867     if ( fLabels[i] != inTracklet->GetLabels(i) ) return kFALSE;
868   }
869   
870   if ( fMeanz != inTracklet->GetMeanz() ) return kFALSE;
871   if ( fZProb != inTracklet->GetZProb() ) return kFALSE;
872   if ( fN2 != inTracklet->GetN2() ) return kFALSE;
873   if ( fNUsed != inTracklet->GetNUsed() ) return kFALSE;
874   if ( fFreq != inTracklet->GetFreq() ) return kFALSE;
875   if ( fNChange != inTracklet->GetNChange() ) return kFALSE;
876   if ( fNChange != inTracklet->GetNChange() ) return kFALSE;
877    
878   if ( fC != inTracklet->GetC() ) return kFALSE;
879   if ( fCC != inTracklet->GetCC() ) return kFALSE;
880   if ( fChi2 != inTracklet->GetChi2() ) return kFALSE;
881   //  if ( fChi2Z != inTracklet->GetChi2Z() ) return kFALSE;
882
883   if ( fDet != inTracklet->GetDetector() ) return kFALSE;
884   if ( fMom != inTracklet->GetMomentum() ) return kFALSE;
885   if ( fdX != inTracklet->GetdX() ) return kFALSE;
886   
887   for (Int_t iCluster = 0; iCluster < knTimebins; iCluster++){
888     AliTRDcluster *curCluster = fClusters[iCluster];
889     AliTRDcluster *inCluster = inTracklet->GetClusters(iCluster);
890     if (curCluster && inCluster){
891       if (! curCluster->IsEqual(inCluster) ) {
892         curCluster->Print();
893         inCluster->Print();
894         return kFALSE;
895       }
896     } else {
897       // if one cluster exists, and corresponding 
898       // in other tracklet doesn't - return kFALSE
899       if(curCluster || inCluster) return kFALSE;
900     }
901   }
902   return kTRUE;
903 }