+ if(!fPlaneEff)
+ {AliWarning("IsOKForPlaneEff: null pointer to AliITSPlaneEff"); return kFALSE;}
+ AliITSlayer &layer=fgLayers[ilayer];
+ Double_t r=layer.GetR();
+ AliITStrackMI tmp(*track);
+
+// require a minimal number of cluster in other layers and eventually clusters in closest layers
+ Int_t ncl_out=0; Int_t ncl_in=0;
+ for(Int_t lay=AliITSgeomTGeo::kNLayers-1;lay>ilayer;lay--) { // count n. of cluster in outermost layers
+ AliDebug(2,Form("trak=%d lay=%d ; index=%d ESD label= %d",tmp.GetLabel(),lay,
+ tmp.GetClIndex(lay),((AliESDtrack*)tmp.GetESDtrack())->GetLabel())) ;
+ // if (tmp.GetClIndex(lay)>=0) ncl_out++;
+if(index[lay]>=0)ncl_out++;
+ }
+ for(Int_t lay=ilayer-1; lay>=0;lay--) { // count n. of cluster in innermost layers
+ AliDebug(2,Form("trak=%d lay=%d ; index=%d ESD label= %d",tmp.GetLabel(),lay,
+ tmp.GetClIndex(lay),((AliESDtrack*)tmp.GetESDtrack())->GetLabel())) ;
+ if (index[lay]>=0) ncl_in++;
+ }
+ Int_t ncl=ncl_out+ncl_in;
+ Bool_t nextout = kFALSE;
+ if(ilayer==AliITSgeomTGeo::kNLayers-1) nextout=kTRUE; // you are already on the outermost layer
+ else nextout = ((tmp.GetClIndex(ilayer+1)>=0)? kTRUE : kFALSE );
+ Bool_t nextin = kFALSE;
+ if(ilayer==0) nextin=kTRUE; // you are already on the innermost layer
+ else nextin = ((index[ilayer-1]>=0)? kTRUE : kFALSE );
+ // maximum number of missing clusters allowed in outermost layers
+ if(ncl_out<AliITSgeomTGeo::kNLayers-(ilayer+1)-AliITSReconstructor::GetRecoParam()->GetMaxMissingClustersOutPlaneEff())
+ return kFALSE;
+ // maximum number of missing clusters allowed (both in innermost and in outermost layers)
+ if(ncl<AliITSgeomTGeo::kNLayers-1-AliITSReconstructor::GetRecoParam()->GetMaxMissingClustersPlaneEff())
+ return kFALSE;
+ if(AliITSReconstructor::GetRecoParam()->GetRequireClusterInOuterLayerPlaneEff() && !nextout) return kFALSE;
+ if(AliITSReconstructor::GetRecoParam()->GetRequireClusterInInnerLayerPlaneEff() && !nextin) return kFALSE;
+ if(tmp.Pt() < AliITSReconstructor::GetRecoParam()->GetMinPtPlaneEff()) return kFALSE;
+ // if(AliITSReconstructor::GetRecoParam()->GetOnlyConstraintPlaneEff() && !tmp.GetConstrain()) return kFALSE;
+
+// detector number
+ Double_t phi,z;
+ if (!tmp.GetPhiZat(r,phi,z)) return kFALSE;
+ Int_t idet=layer.FindDetectorIndex(phi,z);
+ if(idet<0) { AliInfo(Form("cannot find detector"));
+ return kFALSE;}
+
+ // here check if it has good Chi Square.
+
+ //propagate to the intersection with the detector plane
+ const AliITSdetector &det=layer.GetDetector(idet);
+ if (!tmp.Propagate(det.GetPhi(),det.GetR())) return kFALSE;
+
+ Float_t locx; //
+ Float_t locz; //
+ if(!LocalModuleCoord(ilayer,idet,&tmp,locx,locz)) return kFALSE;
+ UInt_t key=fPlaneEff->GetKeyFromDetLocCoord(ilayer,idet,locx,locz);
+ if(key>fPlaneEff->Nblock()) return kFALSE;
+ Float_t blockXmn,blockXmx,blockZmn,blockZmx;
+ if (!fPlaneEff->GetBlockBoundaries(key,blockXmn,blockXmx,blockZmn,blockZmx)) return kFALSE;
+ //***************
+ // DEFINITION OF SEARCH ROAD FOR accepting a track
+ //
+ Double_t nsigx=AliITSReconstructor::GetRecoParam()->GetNSigXFromBoundaryPlaneEff();
+ Double_t nsigz=AliITSReconstructor::GetRecoParam()->GetNSigZFromBoundaryPlaneEff();
+ Double_t dx=nsigx*TMath::Sqrt(tmp.GetSigmaY2()); // those are precisions in the tracking reference system
+ Double_t dz=nsigz*TMath::Sqrt(tmp.GetSigmaZ2()); // Use it also for the module reference system, as it is
+ // done for RecPoints
+
+ // exclude tracks at boundary between detectors
+ //Double_t boundaryWidth=AliITSRecoParam::GetBoundaryWidthPlaneEff();
+ Double_t boundaryWidth=0; // for the time being hard-wired, later on from AliITSRecoParam
+ AliDebug(2,Form("Tracking: track impact x=%f, y=%f, z=%f",tmp.GetX(), tmp.GetY(), tmp.GetZ()));
+ AliDebug(2,Form("Local: track impact x=%f, z=%f",locx,locz));
+ AliDebug(2,Form("Search Road. Tracking: dy=%f , dz=%f",dx,dz));
+ if ( (locx-dx < blockXmn+boundaryWidth) ||
+ (locx+dx > blockXmx-boundaryWidth) ||
+ (locz-dz < blockZmn+boundaryWidth) ||
+ (locz+dz > blockZmx-boundaryWidth) ) return kFALSE;
+ return kTRUE;
+}
+//------------------------------------------------------------------------
+void AliITStrackerMI::UseTrackForPlaneEff(const AliITStrackMI* track, Int_t ilayer) {
+//
+// This Method has to be optimized! For the time-being it uses the same criteria
+// as those used in the search of extra clusters for overlapping modules.
+//
+// Method Purpose: estabilish whether a track has produced a recpoint or not
+// in the layer under study (For Plane efficiency)
+//
+// inputs: AliITStrackMI* track (pointer to a usable track)
+// outputs: none
+// side effects: update (by 1 count) the Plane Efficiency statistics of the basic block
+// traversed by this very track. In details:
+// - if a cluster can be associated to the track then call
+// AliITSPlaneEff::UpDatePlaneEff(key,kTRUE);
+// - if not, the AliITSPlaneEff::UpDatePlaneEff(key,kFALSE) is called
+//
+ if(!fPlaneEff)
+ {AliWarning("UseTrackForPlaneEff: null pointer to AliITSPlaneEff"); return;}
+ AliITSlayer &layer=fgLayers[ilayer];
+ Double_t r=layer.GetR();
+ AliITStrackMI tmp(*track);
+
+// detector number
+ Double_t phi,z;
+ if (!tmp.GetPhiZat(r,phi,z)) return;
+ Int_t idet=layer.FindDetectorIndex(phi,z);
+
+ if(idet<0) { AliInfo(Form("cannot find detector"));
+ return;}
+
+
+//propagate to the intersection with the detector plane
+ const AliITSdetector &det=layer.GetDetector(idet);
+ if (!tmp.Propagate(det.GetPhi(),det.GetR())) return;
+
+
+//***************
+// DEFINITION OF SEARCH ROAD FOR CLUSTERS SELECTION
+//
+ Double_t dz=AliITSReconstructor::GetRecoParam()->GetNSigmaRoadZ()*
+ TMath::Sqrt(tmp.GetSigmaZ2() +
+ AliITSReconstructor::GetRecoParam()->GetNSigmaZLayerForRoadZ()*
+ AliITSReconstructor::GetRecoParam()->GetNSigmaZLayerForRoadZ()*
+ AliITSReconstructor::GetRecoParam()->GetSigmaZ2(ilayer));
+ Double_t dy=AliITSReconstructor::GetRecoParam()->GetNSigmaRoadY()*
+ TMath::Sqrt(tmp.GetSigmaY2() +
+ AliITSReconstructor::GetRecoParam()->GetNSigmaYLayerForRoadY()*
+ AliITSReconstructor::GetRecoParam()->GetNSigmaYLayerForRoadY()*
+ AliITSReconstructor::GetRecoParam()->GetSigmaY2(ilayer));
+
+// road in global (rphi,z) [i.e. in tracking ref. system]
+ Double_t zmin = tmp.GetZ() - dz;
+ Double_t zmax = tmp.GetZ() + dz;
+ Double_t ymin = tmp.GetY() + r*det.GetPhi() - dy;
+ Double_t ymax = tmp.GetY() + r*det.GetPhi() + dy;
+
+// select clusters in road
+ layer.SelectClusters(zmin,zmax,ymin,ymax);
+
+// Define criteria for track-cluster association
+ Double_t msz = tmp.GetSigmaZ2() +
+ AliITSReconstructor::GetRecoParam()->GetNSigmaZLayerForRoadZ()*
+ AliITSReconstructor::GetRecoParam()->GetNSigmaZLayerForRoadZ()*
+ AliITSReconstructor::GetRecoParam()->GetSigmaZ2(ilayer);
+ Double_t msy = tmp.GetSigmaY2() +
+ AliITSReconstructor::GetRecoParam()->GetNSigmaYLayerForRoadY()*
+ AliITSReconstructor::GetRecoParam()->GetNSigmaYLayerForRoadY()*
+ AliITSReconstructor::GetRecoParam()->GetSigmaY2(ilayer);
+ if (tmp.GetConstrain()) {
+ msz *= AliITSReconstructor::GetRecoParam()->GetNSigma2RoadZC();
+ msy *= AliITSReconstructor::GetRecoParam()->GetNSigma2RoadYC();
+ } else {
+ msz *= AliITSReconstructor::GetRecoParam()->GetNSigma2RoadZNonC();
+ msy *= AliITSReconstructor::GetRecoParam()->GetNSigma2RoadYNonC();
+ }
+ msz = 1./msz; // 1/RoadZ^2
+ msy = 1./msy; // 1/RoadY^2
+//
+
+ const AliITSRecPoint *cl=0; Int_t clidx=-1, ci=-1;
+ Int_t idetc=-1;
+ Double_t chi2trkcl=1000.*AliITSReconstructor::GetRecoParam()->GetMaxChi2();
+ //Double_t tolerance=0.2;
+ /*while ((cl=layer.GetNextCluster(clidx))!=0) {
+ idetc = cl->GetDetectorIndex();
+ if(idet!=idetc) continue;
+ //Int_t ilay = cl->GetLayer();
+
+ if (TMath::Abs(tmp.GetZ() - cl->GetZ()) > tolerance) continue;
+ if (TMath::Abs(tmp.GetY() - cl->GetY()) > tolerance) continue;
+
+ Double_t chi2=tmp.GetPredictedChi2(cl);
+ if (chi2<chi2trkcl) { chi2trkcl=chi2; ci=clidx; }
+ }*/
+ Float_t locx; //
+ Float_t locz; //
+ if(!LocalModuleCoord(ilayer,idet,&tmp,locx,locz)) return;
+//
+ AliDebug(2,Form("ilayer= %d, idet=%d, x= %f, z=%f",ilayer,idet,locx,locz));
+ UInt_t key=fPlaneEff->GetKeyFromDetLocCoord(ilayer,idet,locx,locz);
+ if(key>fPlaneEff->Nblock()) return;
+ Bool_t found=kFALSE;
+ //if (ci>=0) {
+ Double_t chi2;
+ while ((cl=layer.GetNextCluster(clidx))!=0) {
+ idetc = cl->GetDetectorIndex();
+ if(idet!=idetc) continue;
+ // here real control to see whether the cluster can be associated to the track.
+ // cluster not associated to track
+ if ( (tmp.GetZ()-cl->GetZ())*(tmp.GetZ()-cl->GetZ())*msz +
+ (tmp.GetY()-cl->GetY())*(tmp.GetY()-cl->GetY())*msy > 1. ) continue;
+ // calculate track-clusters chi2
+ chi2 = GetPredictedChi2MI(&tmp,cl,ilayer); // note that this method change track tmp
+ // in particular, the error associated to the cluster
+ //Double_t chi2 = tmp.GetPredictedChi(cl); // this method does not change track tmp
+ // chi2 cut
+ if (chi2 > AliITSReconstructor::GetRecoParam()->GetMaxChi2s(ilayer)) continue;
+ found=kTRUE;
+ if (chi2<chi2trkcl) { chi2trkcl=chi2; ci=clidx; } // this just to trace which cluster is selected
+ // track->SetExtraCluster(ilayer,(ilayer<<28)+ci);
+ // track->SetExtraModule(ilayer,idetExtra);
+ }
+ if(!fPlaneEff->UpDatePlaneEff(found,key))
+ AliWarning(Form("UseTrackForPlaneEff: cannot UpDate PlaneEff for key=%d",key));
+ if(fPlaneEff->GetCreateHistos()&& AliITSReconstructor::GetRecoParam()->GetHistoPlaneEff()) {
+ Float_t tr[4]={99999.,99999.,9999.,9999.}; // initialize to high values
+ Float_t clu[4]={-99999.,-99999.,9999.,9999.}; // (in some cases GetCov fails)
+ Int_t cltype[2]={-999,-999};
+ // and the module
+
+Float_t AngleModTrack[3]={99999.,99999.,99999.}; // angles (phi, z and "absolute angle") between the track and the mormal to the module (see below)
+
+ tr[0]=locx;
+ tr[1]=locz;
+ tr[2]=TMath::Sqrt(tmp.GetSigmaY2()); // those are precisions in the tracking reference system
+ tr[3]=TMath::Sqrt(tmp.GetSigmaZ2()); // Use it also for the module reference system, as it is
+
+ if (found){
+ clu[0]=layer.GetCluster(ci)->GetDetLocalX();
+ clu[1]=layer.GetCluster(ci)->GetDetLocalZ();
+ cltype[0]=layer.GetCluster(ci)->GetNy();
+ cltype[1]=layer.GetCluster(ci)->GetNz();
+
+ // Without the following 6 lines you would retrieve the nominal error of a cluster (e.g. for the SPD:
+ // X->50/sqrt(12)=14 micron Z->450/sqrt(12)= 120 micron)
+ // Within AliTrackerMI/AliTrackMI the error on the cluster is associated to the AliITStrackMI (fSigmaY,Z)
+ // It is computed properly by calling the method
+ // AliITStrackerMI::GetPredictedChi2MI(AliITStrackMI* track, const AliITSRecPoint *cluster,Int_t layer)
+ // T
+ //Double_t x=0.5*(tmp.GetX()+layer.GetCluster(ci)->GetX()); // Take into account the mis-alignment
+ //if (tmp.PropagateTo(x,0.,0.)) {
+ chi2=GetPredictedChi2MI(&tmp,layer.GetCluster(ci),ilayer);
+ AliCluster c(*layer.GetCluster(ci));
+ c.SetSigmaY2(tmp.GetSigmaY(ilayer)*tmp.GetSigmaY(ilayer));
+ c.SetSigmaZ2(tmp.GetSigmaZ(ilayer)*tmp.GetSigmaZ(ilayer));
+ //if (layer.GetCluster(ci)->GetGlobalCov(cov)) // by using this, instead, you got nominal cluster errors
+ clu[2]=TMath::Sqrt(c.GetSigmaY2());
+ clu[3]=TMath::Sqrt(c.GetSigmaZ2());
+ //}
+ }
+ // Compute the angles between the track and the module
+ // compute the angle "in phi direction", i.e. the angle in the transverse plane
+ // between the normal to the module and the projection (in the transverse plane) of the
+ // track trajectory
+ // tgphi and tglambda of the track in tracking frame with alpha=det.GetPhi
+ Float_t tgl = tmp.GetTgl();
+ Float_t phitr = tmp.GetSnp();
+ phitr = TMath::ASin(phitr);
+ Int_t volId = AliGeomManager::LayerToVolUIDSafe(ilayer+1 ,idet );
+
+ Double_t tra[3]; AliGeomManager::GetOrigTranslation(volId,tra);
+ Double_t rot[9]; AliGeomManager::GetOrigRotation(volId,rot);
+ Double_t alpha =0.;
+ alpha = tmp.GetAlpha();
+ Double_t phiglob = alpha+phitr;
+ Double_t p[3];
+ p[0] = TMath::Cos(phiglob);
+ p[1] = TMath::Sin(phiglob);
+ p[2] = tgl;
+ TVector3 pvec(p[0],p[1],p[2]);
+ TVector3 normvec(rot[1],rot[4],rot[7]);
+ Double_t angle = pvec.Angle(normvec);
+
+ if(angle>0.5*TMath::Pi()) angle = (TMath::Pi()-angle);
+ angle *= 180./TMath::Pi();
+
+ //Trasverse Plane
+ TVector3 pt(p[0],p[1],0);
+ TVector3 normt(rot[1],rot[4],0);
+ Double_t anglet = pt.Angle(normt);
+
+ Double_t phiPt = TMath::ATan2(p[1],p[0]);
+ if(phiPt<0)phiPt+=2.*TMath::Pi();
+ Double_t phiNorm = TMath::ATan2(rot[4],rot[1]);
+ if(phiNorm<0) phiNorm+=2.*TMath::Pi();
+ if(anglet>0.5*TMath::Pi()) anglet = (TMath::Pi()-anglet);
+ if(phiNorm>phiPt) anglet*=-1.;// pt-->normt clockwise: anglet>0
+ if((phiNorm-phiPt)>TMath::Pi()) anglet*=-1.;
+ anglet *= 180./TMath::Pi();
+
+ AngleModTrack[2]=(Float_t) angle;
+ AngleModTrack[0]=(Float_t) anglet;
+ // now the "angle in z" (much easier, i.e. the angle between the z axis and the track momentum + 90)
+ AngleModTrack[1]=TMath::ACos(tgl/TMath::Sqrt(tgl*tgl+1.));
+ AngleModTrack[1]-=TMath::Pi()/2.; // range of angle is -pi/2 , pi/2
+ AngleModTrack[1]*=180./TMath::Pi(); // in degree
+
+ fPlaneEff->FillHistos(key,found,tr,clu,cltype,AngleModTrack);
+ }
+return;
+}