/************************************************************************** * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. * * * * Author: The ALICE Off-line Project. * * Contributors are mentioned in the code where appropriate. * * * * Permission to use, copy, modify and distribute this software and its * * documentation strictly for non-commercial purposes is hereby granted * * without fee, provided that the above copyright notice appears in all * * copies and that both the copyright notice and this permission notice * * appear in the supporting documentation. The authors make no claims * * about the suitability of this software for any purpose. It is * * provided "as is" without express or implied warranty. * **************************************************************************/ /* $Id$ */ //////////////////////////////////////////////////////////////////////////// // // // The TRD track seed // // // // Authors: // // Alex Bercuci // // Markus Fasel // // // //////////////////////////////////////////////////////////////////////////// #include "TMath.h" #include "TLinearFitter.h" #include "TClonesArray.h" // tmp #include #include "AliLog.h" #include "AliMathBase.h" #include "AliTRDseedV1.h" #include "AliTRDcluster.h" #include "AliTRDtrack.h" #include "AliTRDcalibDB.h" #include "AliTRDchamberTimeBin.h" #include "AliTRDtrackingChamber.h" #include "AliTRDtrackerV1.h" #include "AliTRDReconstructor.h" #include "AliTRDrecoParam.h" #include "AliTRDgeometry.h" #include "Cal/AliTRDCalPID.h" ClassImp(AliTRDseedV1) //____________________________________________________________________ AliTRDseedV1::AliTRDseedV1(Int_t plane) :AliTRDseed() ,fPlane(plane) ,fMom(0.) ,fSnp(0.) ,fTgl(0.) ,fdX(0.) { // // Constructor // for(int islice=0; islice < knSlices; islice++) fdEdx[islice] = 0.; for(int ispec=0; ispecGetProlongation(fX0, y, z); fYref[0] = y; fYref[1] = track->GetSnp()/(1. - track->GetSnp()*track->GetSnp()); fZref[0] = z; fZref[1] = track->GetTgl(); //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()); } //____________________________________________________________________ void AliTRDseedV1::CookdEdx(Int_t nslices) { // Calculates average dE/dx for all slices and store them in the internal array fdEdx. // // Parameters: // nslices : number of slices for which dE/dx should be calculated // Output: // store results in the internal array fdEdx. This can be accessed with the method // AliTRDseedV1::GetdEdx() // // Detailed description // Calculates average dE/dx for all slices. Depending on the PID methode // the number of slices can be 3 (LQ) or 8(NN). // The calculation of dQ/dl are done using the tracklet fit results (see AliTRDseedV1::GetdQdl(Int_t)) i.e. // // dQ/dl = qc/(dx * sqrt(1 + dy/dx^2 + dz/dx^2)) // // The following effects are included in the calculation: // 1. calibration values for t0 and vdrift (using x coordinate to calculate slice) // 2. cluster sharing (optional see AliTRDrecoParam::SetClusterSharing()) // 3. cluster size // Int_t nclusters[knSlices]; for(int i=0; iGetX(); // Filter clusters for dE/dx calculation // 1.consider calibration effects for slice determination Int_t slice; if(cluster->IsInChamber()) slice = Int_t(TMath::Abs(fX0 - x) * nslices / clength); else slice = x < fX0 ? 0 : nslices-1; // 2. take sharing into account Float_t w = cluster->IsShared() ? .5 : 1.; // 3. take into account large clusters TODO //w *= c->GetNPads() > 3 ? .8 : 1.; //CHECK !!! fdEdx[slice] += w * GetdQdl(ic); //fdQdl[ic]; nclusters[slice]++; } // End of loop over clusters // calculate mean charge per slice for(int is=0; isGetQ()) /fdX / TMath::Sqrt(1. + fYfit[1]*fYfit[1] + fZfit[1]*fZfit[1]) : 0.; } //____________________________________________________________________ Double_t* AliTRDseedV1::GetProbability() { // Fill probability array for tracklet from the DB. // // Parameters // // Output // returns pointer to the probability array and 0x0 if missing DB access // // Detailed description // retrive calibration db AliTRDcalibDB *calibration = AliTRDcalibDB::Instance(); if (!calibration) { AliError("No access to calibration data"); return 0x0; } // Retrieve the CDB container class with the parametric detector response const AliTRDCalPID *pd = calibration->GetPIDObject(AliTRDReconstructor::RecoParam()->GetPIDMethod()); if (!pd) { AliError("No access to AliTRDCalPID object"); return 0x0; } // calculate tracklet length TO DO Float_t length = (AliTRDgeometry::AmThick() + AliTRDgeometry::DrThick()); /// TMath::Sqrt((1.0 - fSnp[iPlane]*fSnp[iPlane]) / (1.0 + fTgl[iPlane]*fTgl[iPlane])); //calculate dE/dx CookdEdx(AliTRDReconstructor::RecoParam()->GetNdEdxSlices()); // Sets the a priori probabilities for(int ispec=0; ispecGetProbability(ispec, fMom, &fdEdx[0], length, fPlane); } return &fProb[0]; } //____________________________________________________________________ Float_t AliTRDseedV1::GetQuality(Bool_t kZcorr) const { // // Returns a quality measurement of the current seed // Float_t zcorr = kZcorr ? fTilt * (fZProb - fZref[0]) : 0.; return .5 * TMath::Abs(18.0 - fN2) + 10.* TMath::Abs(fYfit[1] - fYref[1]) + 5. * TMath::Abs(fYfit[0] - fYref[0] + zcorr) + 2. * TMath::Abs(fMeanz - fZref[0]) / fPadLength; } //____________________________________________________________________ void AliTRDseedV1::GetCovAt(Double_t /*x*/, Double_t *cov) const { // Computes covariance in the y-z plane at radial point x Int_t ic = 0; while (!fClusters[ic]) ic++; AliTRDcalibDB *fCalib = AliTRDcalibDB::Instance(); Double_t exB = fCalib->GetOmegaTau(fCalib->GetVdriftAverage(fClusters[ic]->GetDetector()), -AliTracker::GetBz()*0.1); Double_t sy2 = fSigmaY2*fSigmaY2 + .2*(fYfit[1]-exB)*(fYfit[1]-exB); Double_t sz2 = fPadLength/12.; //printf("Yfit[1] %f sy20 %f SigmaY2 %f\n", fYfit[1], sy20, fSigmaY2); cov[0] = sy2; cov[1] = fTilt*(sy2-sz2); cov[2] = sz2; } //____________________________________________________________________ void AliTRDseedV1::SetOwner(Bool_t own) { //AliInfo(Form("own [%s] fOwner[%s]", own?"YES":"NO", fOwner?"YES":"NO")); if(own){ for(int ic=0; icGetClusters(index) TODO } } SetBit(1, kFALSE); } } //____________________________________________________________________ Bool_t AliTRDseedV1::AttachClustersIter(AliTRDtrackingChamber *chamber, Float_t quality, Bool_t kZcorr, AliTRDcluster *c) { // // Iterative process to register clusters to the seed. // In iteration 0 we try only one pad-row and if quality not // sufficient we try 2 pad-rows (about 5% of tracks cross 2 pad-rows) // // debug level 7 // if(!AliTRDReconstructor::RecoParam()){ AliError("Seed can not be used without a valid RecoParam."); return kFALSE; } AliTRDchamberTimeBin *layer = 0x0; if(AliTRDReconstructor::StreamLevel()>=7 && c){ TClonesArray clusters("AliTRDcluster", 24); clusters.SetOwner(kTRUE); AliTRDcluster *cc = 0x0; Int_t det=-1, ncl, ncls = 0; for (Int_t iTime = 0; iTime < AliTRDtrackerV1::GetNTimeBins(); iTime++) { if(!(layer = chamber->GetTB(iTime))) continue; if(!(ncl = Int_t(*layer))) continue; for(int ic=0; icGetDetector(); new(clusters[ncls++]) AliTRDcluster(*cc); } } AliInfo(Form("N clusters[%d] = %d", fPlane, ncls)); Int_t ref = c ? 1 : 0; TTreeSRedirector &cstreamer = *AliTRDtrackerV1::DebugStreamer(); cstreamer << "AttachClustersIter" << "det=" << det << "ref=" << ref << "clusters.=" << &clusters << "tracklet.=" << this << "cl.=" << c << "\n"; } Float_t tquality; Double_t kroady = AliTRDReconstructor::RecoParam()->GetRoad1y(); Double_t kroadz = fPadLength * .5 + 1.; // initialize configuration parameters Float_t zcorr = kZcorr ? fTilt * (fZProb - fZref[0]) : 0.; Int_t niter = kZcorr ? 1 : 2; Double_t yexp, zexp; Int_t ncl = 0; // start seed update for (Int_t iter = 0; iter < niter; iter++) { ncl = 0; for (Int_t iTime = 0; iTime < AliTRDtrackerV1::GetNTimeBins(); iTime++) { if(!(layer = chamber->GetTB(iTime))) continue; if(!Int_t(*layer)) continue; // define searching configuration Double_t dxlayer = layer->GetX() - fX0; if(c){ zexp = c->GetZ(); //Try 2 pad-rows in second iteration if (iter > 0) { zexp = fZref[0] + fZref[1] * dxlayer - zcorr; if (zexp > c->GetZ()) zexp = c->GetZ() + fPadLength*0.5; if (zexp < c->GetZ()) zexp = c->GetZ() - fPadLength*0.5; } } else zexp = fZref[0] + (kZcorr ? fZref[1] * dxlayer : 0.); yexp = fYref[0] + fYref[1] * dxlayer - zcorr; // Get and register cluster Int_t index = layer->SearchNearestCluster(yexp, zexp, kroady, kroadz); if (index < 0) continue; AliTRDcluster *cl = (*layer)[index]; fIndexes[iTime] = layer->GetGlobalIndex(index); fClusters[iTime] = cl; fY[iTime] = cl->GetY(); fZ[iTime] = cl->GetZ(); ncl++; } if(AliTRDReconstructor::StreamLevel()>=7) AliInfo(Form("iter = %d ncl [%d] = %d", iter, fPlane, ncl)); if(ncl>1){ // calculate length of the time bin (calibration aware) Int_t irp = 0; Float_t x[2]; Int_t tb[2]; for (Int_t iTime = 0; iTime < AliTRDtrackerV1::GetNTimeBins(); iTime++) { if(!fClusters[iTime]) continue; x[irp] = fClusters[iTime]->GetX(); tb[irp] = iTime; irp++; if(irp==2) break; } fdX = (x[1] - x[0]) / (tb[0] - tb[1]); // update X0 from the clusters (calibration/alignment aware) for (Int_t iTime = 0; iTime < AliTRDtrackerV1::GetNTimeBins(); iTime++) { if(!(layer = chamber->GetTB(iTime))) continue; if(!layer->IsT0()) continue; if(fClusters[iTime]){ fX0 = fClusters[iTime]->GetX(); break; } else { // we have to infere the position of the anode wire from the other clusters for (Int_t jTime = iTime+1; jTime < AliTRDtrackerV1::GetNTimeBins(); jTime++) { if(!fClusters[jTime]) continue; fX0 = fClusters[jTime]->GetX() + fdX * (jTime - iTime); } break; } } // update YZ reference point // TODO // update x reference positions (calibration/alignment aware) for (Int_t iTime = 0; iTime < AliTRDtrackerV1::GetNTimeBins(); iTime++) { if(!fClusters[iTime]) continue; fX[iTime] = fClusters[iTime]->GetX() - fX0; } AliTRDseed::Update(); } if(AliTRDReconstructor::StreamLevel()>=7) AliInfo(Form("iter = %d nclFit [%d] = %d", iter, fPlane, fN2)); if(IsOK()){ tquality = GetQuality(kZcorr); if(tquality < quality) break; else quality = tquality; } kroadz *= 2.; } // Loop: iter if (!IsOK()) return kFALSE; CookLabels(); UpdateUsed(); return kTRUE; } //____________________________________________________________________ Bool_t AliTRDseedV1::AttachClusters(AliTRDtrackingChamber *chamber ,Bool_t kZcorr) { // // Projective algorithm to attach clusters to seeding tracklets // // Parameters // // Output // // Detailed description // 1. Collapse x coordinate for the full detector plane // 2. truncated mean on y (r-phi) direction // 3. purge clusters // 4. truncated mean on z direction // 5. purge clusters // 6. fit tracklet // if(!AliTRDReconstructor::RecoParam()){ AliError("Seed can not be used without a valid RecoParam."); return kFALSE; } const Int_t kClusterCandidates = 2 * knTimebins; //define roads Double_t kroady = AliTRDReconstructor::RecoParam()->GetRoad1y(); Double_t kroadz = fPadLength * 1.5 + 1.; // correction to y for the tilting angle Float_t zcorr = kZcorr ? fTilt * (fZProb - fZref[0]) : 0.; // working variables AliTRDcluster *clusters[kClusterCandidates]; Double_t cond[4], yexp[knTimebins], zexp[knTimebins], yres[kClusterCandidates], zres[kClusterCandidates]; Int_t ncl, *index = 0x0, tboundary[knTimebins]; // Do cluster projection AliTRDchamberTimeBin *layer = 0x0; Int_t nYclusters = 0; Bool_t kEXIT = kFALSE; for (Int_t iTime = 0; iTime < AliTRDtrackerV1::GetNTimeBins(); iTime++) { if(!(layer = chamber->GetTB(iTime))) continue; if(!Int_t(*layer)) continue; fX[iTime] = layer->GetX() - fX0; zexp[iTime] = fZref[0] + fZref[1] * fX[iTime]; yexp[iTime] = fYref[0] + fYref[1] * fX[iTime] - zcorr; // build condition and process clusters cond[0] = yexp[iTime] - kroady; cond[1] = yexp[iTime] + kroady; cond[2] = zexp[iTime] - kroadz; cond[3] = zexp[iTime] + kroadz; layer->GetClusters(cond, index, ncl); for(Int_t ic = 0; icGetCluster(index[ic]); clusters[nYclusters] = c; yres[nYclusters++] = c->GetY() - yexp[iTime]; if(nYclusters >= kClusterCandidates) { AliWarning(Form("Cluster candidates reached limit %d. Some may be lost.", kClusterCandidates)); kEXIT = kTRUE; break; } } tboundary[iTime] = nYclusters; if(kEXIT) break; } // Evaluate truncated mean on the y direction Double_t mean, sigma; AliMathBase::EvaluateUni(nYclusters, yres, mean, sigma, Int_t(nYclusters*.8)-2); // purge cluster candidates Int_t nZclusters = 0; for(Int_t ic = 0; ic 4. * sigma){ clusters[ic] = 0x0; continue; } zres[nZclusters++] = clusters[ic]->GetZ() - zexp[clusters[ic]->GetLocalTimeBin()]; } // Evaluate truncated mean on the z direction AliMathBase::EvaluateUni(nZclusters, zres, mean, sigma, Int_t(nZclusters*.8)-2); // purge cluster candidates for(Int_t ic = 0; ic 4. * sigma){ clusters[ic] = 0x0; continue; } } // Select only one cluster/TimeBin Int_t lastCluster = 0; fN2 = 0; for (Int_t iTime = 0; iTime < AliTRDtrackerV1::GetNTimeBins(); iTime++) { ncl = tboundary[iTime] - lastCluster; if(!ncl) continue; Int_t iptr = lastCluster; if(ncl > 1){ Float_t dold = 9999.; for(int ic=lastCluster; icGetY(); Float_t z = zexp[iTime] - clusters[ic]->GetZ(); Float_t d = y * y + z * z; if(d > dold) continue; dold = d; iptr = ic; } } fIndexes[iTime] = chamber->GetTB(iTime)->GetGlobalIndex(iptr); fClusters[iTime] = clusters[iptr]; fY[iTime] = clusters[iptr]->GetY(); fZ[iTime] = clusters[iptr]->GetZ(); lastCluster = tboundary[iTime]; fN2++; } // number of minimum numbers of clusters expected for the tracklet Int_t kClmin = Int_t(AliTRDReconstructor::RecoParam()->GetFindableClusters()*AliTRDtrackerV1::GetNTimeBins()); if (fN2 < kClmin){ AliWarning(Form("Not enough clusters to fit the tracklet %d [%d].", fN2, kClmin)); fN2 = 0; return kFALSE; } // update used clusters fNUsed = 0; for (Int_t iTime = 0; iTime < AliTRDtrackerV1::GetNTimeBins(); iTime++) { if(!fClusters[iTime]) continue; if((fClusters[iTime]->IsUsed())) fNUsed++; } if (fN2-fNUsed < kClmin){ AliWarning(Form("Too many clusters already in use %d (from %d).", fNUsed, fN2)); fN2 = 0; return kFALSE; } return kTRUE; } //____________________________________________________________________ Bool_t AliTRDseedV1::Fit() { // // Linear fit of the tracklet // // Parameters : // // Output : // True if successful // // Detailed description // 2. Check if tracklet crosses pad row boundary // 1. Calculate residuals in the y (r-phi) direction // 3. Do a Least Square Fit to the data // const Int_t kClmin = 8; const Int_t kNtb = AliTRDtrackerV1::GetNTimeBins(); // convertion factor from square to gauss distribution for sigma Double_t convert = 1./TMath::Sqrt(12.); // book cluster information Float_t xc[knTimebins+1], yc[knTimebins], zc[knTimebins+1], sy[knTimebins], sz[knTimebins+1]; Int_t zRow[knTimebins]; AliTRDcluster *c = 0x0; Int_t nc = 0; for (Int_t ic=0; icIsInChamber()) continue; Float_t w = 1.; if(c->GetNPads()>4) w = .5; if(c->GetNPads()>5) w = .2; zRow[nc] = c->GetPadRow(); xc[nc] = fX0 - c->GetX(); yc[nc] = c->GetY(); zc[nc] = c->GetZ(); sy[ic] = w; // all clusters have the same sigma sz[ic] = fPadLength*convert; nc++; } // to few clusters if (nc < kClmin) return kFALSE; Int_t zN[2*35]; Int_t nz = AliTRDtrackerV1::Freq(nc, zRow, zN, kFALSE); // more than one pad row crossing if(nz>2) return kFALSE; // estimate reference parameter at average x Double_t y0 = fYref[0]; Double_t dydx = fYref[1]; Double_t dzdx = fZref[1]; zc[nc] = fZref[0]; // determine z offset of the fit Int_t nchanges = 0, nCross = 0; if(nz==2){ // tracklet is crossing pad row // Find the break time allowing one chage on pad-rows // with maximal number of accepted clusters Int_t padRef = zRow[0]; for (Int_t ic=1; ic zc[ic] ? 1. : -1.; padRef = zRow[ic]; nCross = ic; nchanges++; } } // condition on nCross and reset nchanges TODO Float_t par[5]; if(nchanges==1){ if(dzdx * fZref[1] < 0.){ AliInfo("tracklet direction does not correspond to the track direction. TODO."); } SetBit(2, kTRUE); // mark pad row crossing fCross[0] = xc[nc]; fCross[2] = zc[nc]; fCross[3] = sz[nc]; AliTRDtrackerV1::FitLeastSquare(nc+1, xc, zc, sz, par); dzdx = fZref[1]; // we don't trust par[1] ??; zc[nc] = par[0]; } else if(nchanges > 1){ // debug AliInfo("ERROR in n changes!!!"); return kFALSE; } // estimate deviation from reference direction dzdx *= fTilt; for (Int_t ic=0; ic8 isOK)\n",fN2); printf(" fNUsed =%d\n", fNUsed); printf(" fFreq =%d\n", fFreq); printf(" fNChange=%d\n", fNChange); printf(" fMPads =%f\n", fMPads); printf(" fC =%f\n", fC); printf(" fCC =%f\n",fCC); printf(" fChi2 =%f\n", fChi2); printf(" fChi2Z =%f\n", fChi2Z); }