+//____________________________________________________________
+Float_t AliTRDseedV1::GetAnodeWireOffset(Float_t zt)
+{
+// Find position inside the amplification cell for reading drift velocity map
+
+ Float_t d = fPad[3] - zt;
+ if(d<0.){
+ AliError(Form("Fail AnodeWireOffset calculation z0[%+7.2f] zt[%+7.2f] d[%+7.2f].", fPad[3], zt, d));
+ return 0.125;
+ }
+ d -= ((Int_t)(2 * d)) / 2.0;
+ if(d > 0.25) d = 0.5 - d;
+ return d;
+}
+
+
+//____________________________________________________________________
+Float_t AliTRDseedV1::GetCharge(Bool_t useOutliers) const
+{
+// Computes total charge attached to tracklet. If "useOutliers" is set clusters
+// which are not in chamber are also used (default false)
+
+ AliTRDcluster *c(NULL); Float_t qt(0.);
+ for(int ic=0; ic<kNclusters; ic++){
+ if(!(c=fClusters[ic])) continue;
+ if(!c->IsInChamber() && !useOutliers) continue;
+ qt += TMath::Abs(c->GetQ());
+ }
+ return qt;
+}
+
+//____________________________________________________________________
+Int_t AliTRDseedV1::GetChargeGaps(Float_t sz[kNtb], Float_t pos[kNtb], Int_t isz[kNtb]) const
+{
+// Find number, size and position of charge gaps (consecutive missing time bins).
+// Returns the number of gaps and fills their size in input array "sz" and position in array "pos"
+
+ Bool_t gap(kFALSE);
+ Int_t n(0);
+ Int_t ipos[kNtb]; memset(isz, 0, kNtb*sizeof(Int_t));memset(ipos, 0, kNtb*sizeof(Int_t));
+ for(int ic(0); ic<kNtb; ic++){
+ if(fClusters[ic] || fClusters[ic+kNtb]){
+ if(gap) n++;
+ continue;
+ }
+ gap = kTRUE;
+ isz[n]++;
+ ipos[n] = ic;
+ }
+ if(!n) return 0;
+
+ // write calibrated values
+ AliTRDcluster fake;
+ for(Int_t igap(0); igap<n; igap++){
+ sz[igap] = isz[igap]*fVD/AliTRDCommonParam::Instance()->GetSamplingFrequency();
+ fake.SetPadTime(ipos[igap]);
+ pos[igap] = fake.GetXloc(fT0, fVD);
+ if(isz[igap]>1){
+ fake.SetPadTime(ipos[igap]-isz[igap]+1);
+ pos[igap] += fake.GetXloc(fT0, fVD);
+ pos[igap] /= 2.;
+ }
+ }
+ return n;
+}
+
+
+//____________________________________________________________________
+Double_t AliTRDseedV1::EstimatedCrossPoint(AliTRDpadPlane *pp)
+{
+// Algorithm to estimate cross point in the x-z plane for pad row cross tracklets or the z coordinate of pad row without pad row cross in the local chamber coordinates.
+// Returns variance of the radial offset from anode wire in case of raw cross or 0 otherwise.
+
+ Int_t row[] = {-1, -1};
+ Double_t zoff(0.5 * (pp->GetRow0() + pp->GetRowEnd())), sx(0.), mean(0.5*pp->GetNrows()-0.5);
+ AliTRDcluster *c(NULL);
+ fS2Y = 0.;
+
+ if(!IsRowCross()){
+ for(int ic=0; ic<kNtb; ic++){
+ if(!(c=fClusters[ic])) continue;
+ if(!c->IsInChamber()) continue;
+ row[0] = c->GetPadRow();
+ fZfit[0] = Int_t(mean-row[0])*pp->GetLengthIPad() +
+ 0.5*(mean-row[0]>0.?1.:-1.)*(row[0]>0&&row[0]<pp->GetNrows()-1?pp->GetLengthIPad():pp->GetLengthOPad());
+ break;
+ }
+ } else {
+ Float_t tbm[2] = {0.}; // mean value of time bin in rows
+ Int_t tb[kNtb]={0}, //array of time bins from first row
+ nc[2] = {0}, // no. of clusters in rows
+ mc(0); // no. of common clusters
+ Bool_t w[2] = {kFALSE, kFALSE}; // acceptance flag for rows
+ // Find radial range for first row
+ for(int ic(0); ic<kNtb; ic++){
+ tb[ic]= -1;
+ if(!(c=fClusters[ic]) || !c->IsInChamber()) continue;
+ if(row[0]<0) row[0] = c->GetPadRow();
+ tb[nc[0]++] = ic; tbm[0] += ic;
+ }
+ if(nc[0]>2){
+ tbm[0] /= nc[0];
+ w[0] = kTRUE;
+ }
+ // Find radial range for second row
+ for(int ic(kNtb), jc(0); ic<kNclusters; ic++, jc++){
+ if(!(c=fClusters[ic]) || !c->IsInChamber()) continue;
+ if(row[1]<0) row[1] = c->GetPadRow();
+ tbm[1] += jc; nc[1]++;
+ for(Int_t kc(0); kc<nc[0]; kc++)
+ if(tb[kc]==jc){
+ tb[kc] += 100; // mark common cluster
+ mc++;
+ break;
+ }
+ }
+ if(nc[1]>2){
+ tbm[1] /= nc[1];
+ w[1] = kTRUE;
+ }
+ //printf("0 : %f[%2d] 1 : %f[%2d] mc[%d]\n", tbm[0], nc[0], tbm[1], nc[1], mc);
+ if(!w[0] && !w[1]){
+ AliError("Too few clusters to estimate tracklet.");
+ return -1;
+ }
+ if(!w[0] || !w[1]){
+ SetBit(kRowCross, kFALSE); // reset RC bit
+ if(w[1]) row[0] = row[1];
+ fZfit[0] = Int_t(mean-row[0])*pp->GetLengthIPad() +
+ 0.5*(mean-row[0]>0.?1.:-1.)*(row[0]>0&&row[0]<pp->GetNrows()-1?pp->GetLengthIPad():pp->GetLengthOPad());
+ }else{ // find the best matching timebin
+ fZfit[0] = Int_t(mean-0.5*(row[0]+row[1]))*pp->GetLengthIPad();
+ Int_t itb(0), dtb(0);
+ if(!mc) { // no common range
+ itb = Int_t(0.5*(tbm[0] + tbm[1]));
+ dtb = Int_t(0.5*TMath::Abs(tbm[0] - tbm[1])); // simple parameterization of the cluster gap
+ } else {
+ Double_t rmax(100.); Int_t itbStart(-1), itbStop(0);
+ // compute distance from
+ for(Int_t jc(0); jc<nc[0]; jc++){
+ if(tb[jc] < 100) continue;
+ Int_t ltb(tb[jc]-100);
+ Double_t r = (1. - ltb/tbm[0])*(1. - ltb/tbm[1]);
+ //printf("tb[%2d] dr[%f %f %f] rmax[%f]\n", ltb, r, 1. - ltb/tbm[0], 1. - ltb/tbm[1], rmax);
+ if(TMath::Abs(r)<rmax){ rmax = TMath::Abs(r); itb = ltb; }
+ if(itbStart<0) itbStart = ltb;
+ itbStop = ltb;
+ }
+ dtb = itbStop-itbStart+1;
+ }
+ AliTRDCommonParam *cp = AliTRDCommonParam::Instance();
+ Double_t freq(cp?cp->GetSamplingFrequency():10.);
+ fS2Y = ((itb-0.5)/freq - fT0 - 0.189)*fVD; // xOff
+ sx = dtb*0.288675134594812921/freq; sx *= sx; sx += 1.56e-2; sx *= fVD*fVD;
+ }
+ }
+
+ // estimate dzdx
+ Float_t dx(fX0-fS2Y);
+ fZfit[1] = (fZfit[0]+zoff)/dx;
+
+ // correct dzdx for the bias
+ UnbiasDZDX(IsRowCross());
+ if(IsRowCross()){
+ // correct x_cross/sigma(x_cross) for the bias in dzdx
+ const AliTRDrecoParam* const recoParam = fkReconstructor->GetRecoParam();
+ if(recoParam){
+ fS2Y += recoParam->GetCorrDZDXxcross()*TMath::Abs(fZfit[1]);
+ sx += recoParam->GetCorrDZDXxcross()*recoParam->GetCorrDZDXxcross()*GetS2DZDX(fZfit[1]);
+ }
+ // correct sigma(x_cross) for the width of the crossing area
+ sx += GetS2XcrossDZDX(TMath::Abs(fZfit[1]));
+
+ // estimate z and error @ anode wire
+ fZfit[0] += fZfit[1]*fS2Y;
+ fS2Z = fZfit[1]*fZfit[1]*sx+fS2Y*fS2Y*GetS2DZDX(fZfit[1]);
+ }
+ return sx;
+}
+
+//____________________________________________________________________
+void AliTRDseedV1::UnbiasDZDX(Bool_t rc)
+{
+ // correct dzdx for the bias in z according to MC
+ const AliTRDrecoParam* const recoParam = fkReconstructor->GetRecoParam();
+ if(!recoParam) return;
+ fZfit[1] *= recoParam->GetCorrDZDX(rc);
+ if(rc) fZfit[1] += recoParam->GetCorrDZDXbiasRC(fZfit[1]<0);
+}
+
+//____________________________________________________________________
+Double_t AliTRDseedV1::UnbiasY(Bool_t rc, Bool_t sgn, Int_t chg)
+{
+// correct y coordinate for tail cancellation. This should be fixed by considering TC as a function of q/pt.
+// rc : TRUE if tracklet crosses rows
+// sgn : TRUE if track has same sign with magnetic field
+// chg : -1 for negative particles, +1 for the rest
+
+ const AliTRDrecoParam* const recoParam = fkReconstructor->GetRecoParam();
+ if(!recoParam) return 0.;
+ Double_t par[2]={0.};
+ if(rc) recoParam->GetYcorrTailCancel(2, par);
+ else{
+ if(sgn && 1./fPt > 1.5) recoParam->GetYcorrTailCancel(1, par);
+ else if(!sgn) recoParam->GetYcorrTailCancel(0, par);
+ }
+ return par[0]+par[1]*chg/fPt;
+}
+
+
+//____________________________________________________________________
+Float_t AliTRDseedV1::GetQperTB(Int_t tb) const
+{
+ //
+ // Charge of the clusters at timebin
+ //
+ Float_t q = 0;
+ if(fClusters[tb] /*&& fClusters[tb]->IsInChamber()*/)
+ q += TMath::Abs(fClusters[tb]->GetQ());
+ if(fClusters[tb+kNtb] /*&& fClusters[tb+kNtb]->IsInChamber()*/)
+ q += TMath::Abs(fClusters[tb+kNtb]->GetQ());
+ return q/TMath::Sqrt(1. + fYref[1]*fYref[1] + fZref[1]*fZref[1]);
+}
+
+//____________________________________________________________________
+Float_t AliTRDseedV1::GetdQdl() const
+{
+// Calculate total charge / tracklet length for 1D PID
+//
+ Float_t Q = GetCharge(kTRUE);
+ return Q/TMath::Sqrt(1. + fYref[1]*fYref[1] + fZref[1]*fZref[1]);
+}