+//__________________________________________________________________
+void AliEMCALRecoUtils::RecalculateClusterPID(AliVCluster * cluster)
+{
+ //re-evaluate identification parameters with bayesian
+
+ if(!cluster)
+ {
+ AliInfo("Cluster pointer null!");
+ return;
+ }
+
+ if ( cluster->GetM02() != 0)
+ fPIDUtils->ComputePID(cluster->E(),cluster->GetM02());
+
+ Float_t pidlist[AliPID::kSPECIESCN+1];
+ for(Int_t i = 0; i < AliPID::kSPECIESCN+1; i++) pidlist[i] = fPIDUtils->GetPIDFinal(i);
+
+ cluster->SetPID(pidlist);
+}
+
+//___________________________________________________________________________________________________________________
+void AliEMCALRecoUtils::RecalculateClusterShowerShapeParameters(const AliEMCALGeometry * geom,
+ AliVCaloCells* cells,
+ AliVCluster * cluster,
+ Float_t & l0, Float_t & l1,
+ Float_t & disp, Float_t & dEta, Float_t & dPhi,
+ Float_t & sEta, Float_t & sPhi, Float_t & sEtaPhi)
+{
+ // Calculates new center of gravity in the local EMCAL-module coordinates
+ // and tranfers into global ALICE coordinates
+ // Calculates Dispersion and main axis
+
+ if(!cluster)
+ {
+ AliInfo("Cluster pointer null!");
+ return;
+ }
+
+ Double_t eCell = 0.;
+ Float_t fraction = 1.;
+ Float_t recalFactor = 1.;
+
+ Int_t iSupMod = -1;
+ Int_t iTower = -1;
+ Int_t iIphi = -1;
+ Int_t iIeta = -1;
+ Int_t iphi = -1;
+ Int_t ieta = -1;
+ Double_t etai = -1.;
+ Double_t phii = -1.;
+
+ Int_t nstat = 0 ;
+ Float_t wtot = 0.;
+ Double_t w = 0.;
+ Double_t etaMean = 0.;
+ Double_t phiMean = 0.;
+
+ //Loop on cells, calculate the cluster energy, in case a cut on cell energy is added
+ // and to check if the cluster is between 2 SM in eta
+ Int_t iSM0 = -1;
+ Bool_t shared = kFALSE;
+ Float_t energy = 0;
+
+ for(Int_t iDigit=0; iDigit < cluster->GetNCells(); iDigit++)
+ {
+ //Get from the absid the supermodule, tower and eta/phi numbers
+ geom->GetCellIndex(cluster->GetCellAbsId(iDigit),iSupMod,iTower,iIphi,iIeta);
+ geom->GetCellPhiEtaIndexInSModule(iSupMod,iTower,iIphi,iIeta, iphi,ieta);
+
+ //Check if there are cells of different SM
+ if (iDigit == 0 ) iSM0 = iSupMod;
+ else if(iSupMod!= iSM0) shared = kTRUE;
+
+ //Get the cell energy, if recalibration is on, apply factors
+ fraction = cluster->GetCellAmplitudeFraction(iDigit);
+ if(fraction < 1e-4) fraction = 1.; // in case unfolding is off
+
+ if(IsRecalibrationOn())
+ {
+ recalFactor = GetEMCALChannelRecalibrationFactor(iSupMod,ieta,iphi);
+ }
+
+ eCell = cells->GetCellAmplitude(cluster->GetCellAbsId(iDigit))*fraction*recalFactor;
+
+ energy += eCell;
+
+ }//cell loop
+
+ //Loop on cells
+ for(Int_t iDigit=0; iDigit < cluster->GetNCells(); iDigit++)
+ {
+ //Get from the absid the supermodule, tower and eta/phi numbers
+ geom->GetCellIndex(cluster->GetCellAbsId(iDigit),iSupMod,iTower,iIphi,iIeta);
+ geom->GetCellPhiEtaIndexInSModule(iSupMod,iTower,iIphi,iIeta, iphi,ieta);
+
+ //Get the cell energy, if recalibration is on, apply factors
+ fraction = cluster->GetCellAmplitudeFraction(iDigit);
+ if(fraction < 1e-4) fraction = 1.; // in case unfolding is off
+
+ if (!fCellsRecalibrated)
+ {
+ if(IsRecalibrationOn())
+ {
+ recalFactor = GetEMCALChannelRecalibrationFactor(iSupMod,ieta,iphi);
+ }
+ }
+
+ eCell = cells->GetCellAmplitude(cluster->GetCellAbsId(iDigit))*fraction*recalFactor;
+
+ // In case of a shared cluster, index of SM in C side, columns start at 48 and ends at 48*2
+ // C Side impair SM, nSupMod%2=1; A side pair SM, nSupMod%2=0
+ if(shared && iSupMod%2) ieta+=AliEMCALGeoParams::fgkEMCALCols;
+
+ if(cluster->E() > 0 && eCell > 0)
+ {
+ w = GetCellWeight(eCell,cluster->E());
+
+ etai=(Double_t)ieta;
+ phii=(Double_t)iphi;
+
+ if(w > 0.0)
+ {
+ wtot += w ;
+ nstat++;
+ //Shower shape
+ sEta += w * etai * etai ;
+ etaMean += w * etai ;
+ sPhi += w * phii * phii ;
+ phiMean += w * phii ;
+ sEtaPhi += w * etai * phii ;
+ }
+ }
+ else
+ AliError(Form("Wrong energy %f and/or amplitude %f\n", eCell, cluster->E()));
+ }//cell loop
+
+ //Normalize to the weight
+ if (wtot > 0)
+ {
+ etaMean /= wtot ;
+ phiMean /= wtot ;
+ }
+ else
+ AliError(Form("Wrong weight %f\n", wtot));
+
+ //Calculate dispersion
+ for(Int_t iDigit=0; iDigit < cluster->GetNCells(); iDigit++)
+ {
+ //Get from the absid the supermodule, tower and eta/phi numbers
+ geom->GetCellIndex(cluster->GetCellAbsId(iDigit),iSupMod,iTower,iIphi,iIeta);
+ geom->GetCellPhiEtaIndexInSModule(iSupMod,iTower,iIphi,iIeta, iphi,ieta);
+
+ //Get the cell energy, if recalibration is on, apply factors
+ fraction = cluster->GetCellAmplitudeFraction(iDigit);
+ if(fraction < 1e-4) fraction = 1.; // in case unfolding is off
+ if (IsRecalibrationOn())
+ {
+ recalFactor = GetEMCALChannelRecalibrationFactor(iSupMod,ieta,iphi);
+ }
+ eCell = cells->GetCellAmplitude(cluster->GetCellAbsId(iDigit))*fraction*recalFactor;
+
+ // In case of a shared cluster, index of SM in C side, columns start at 48 and ends at 48*2
+ // C Side impair SM, nSupMod%2=1; A side pair SM, nSupMod%2=0
+ if(shared && iSupMod%2) ieta+=AliEMCALGeoParams::fgkEMCALCols;
+
+ if(cluster->E() > 0 && eCell > 0)
+ {
+ w = GetCellWeight(eCell,cluster->E());
+
+ etai=(Double_t)ieta;
+ phii=(Double_t)iphi;
+ if(w > 0.0)
+ {
+ disp += w *((etai-etaMean)*(etai-etaMean)+(phii-phiMean)*(phii-phiMean));
+ dEta += w * (etai-etaMean)*(etai-etaMean) ;
+ dPhi += w * (phii-phiMean)*(phii-phiMean) ;
+ }
+ }
+ else
+ AliError(Form("Wrong energy %f and/or amplitude %f\n", eCell, cluster->E()));
+ }// cell loop
+
+ //Normalize to the weigth and set shower shape parameters
+ if (wtot > 0 && nstat > 1)
+ {
+ disp /= wtot ;
+ dEta /= wtot ;
+ dPhi /= wtot ;
+ sEta /= wtot ;
+ sPhi /= wtot ;
+ sEtaPhi /= wtot ;
+
+ sEta -= etaMean * etaMean ;
+ sPhi -= phiMean * phiMean ;
+ sEtaPhi -= etaMean * phiMean ;
+
+ l0 = (0.5 * (sEta + sPhi) + TMath::Sqrt( 0.25 * (sEta - sPhi) * (sEta - sPhi) + sEtaPhi * sEtaPhi ));
+ l1 = (0.5 * (sEta + sPhi) - TMath::Sqrt( 0.25 * (sEta - sPhi) * (sEta - sPhi) + sEtaPhi * sEtaPhi ));
+ }
+ else
+ {
+ l0 = 0. ;
+ l1 = 0. ;
+ dEta = 0. ; dPhi = 0. ; disp = 0. ;
+ sEta = 0. ; sPhi = 0. ; sEtaPhi = 0. ;
+ }
+
+}
+
+//____________________________________________________________________________________________
+void AliEMCALRecoUtils::RecalculateClusterShowerShapeParameters(const AliEMCALGeometry * geom,
+ AliVCaloCells* cells,
+ AliVCluster * cluster)
+{
+ // Calculates new center of gravity in the local EMCAL-module coordinates
+ // and tranfers into global ALICE coordinates
+ // Calculates Dispersion and main axis and puts them into the cluster
+
+ Float_t l0 = 0., l1 = 0.;
+ Float_t disp = 0., dEta = 0., dPhi = 0.;
+ Float_t sEta = 0., sPhi = 0., sEtaPhi = 0.;
+
+ AliEMCALRecoUtils::RecalculateClusterShowerShapeParameters(geom,cells,cluster,l0,l1,disp,
+ dEta, dPhi, sEta, sPhi, sEtaPhi);
+
+ cluster->SetM02(l0);
+ cluster->SetM20(l1);
+ if(disp > 0. ) cluster->SetDispersion(TMath::Sqrt(disp)) ;
+
+}
+
+//____________________________________________________________________________
+void AliEMCALRecoUtils::FindMatches(AliVEvent *event,
+ TObjArray * clusterArr,
+ const AliEMCALGeometry *geom)
+{
+ //This function should be called before the cluster loop
+ //Before call this function, please recalculate the cluster positions
+ //Given the input event, loop over all the tracks, select the closest cluster as matched with fCutR
+ //Store matched cluster indexes and residuals
+
+ fMatchedTrackIndex ->Reset();
+ fMatchedClusterIndex->Reset();
+ fResidualPhi->Reset();
+ fResidualEta->Reset();
+
+ fMatchedTrackIndex ->Set(1000);
+ fMatchedClusterIndex->Set(1000);
+ fResidualPhi->Set(1000);
+ fResidualEta->Set(1000);
+
+ AliESDEvent* esdevent = dynamic_cast<AliESDEvent*> (event);
+ AliAODEvent* aodevent = dynamic_cast<AliAODEvent*> (event);
+
+ // init the magnetic field if not already on
+ if(!TGeoGlobalMagField::Instance()->GetField())
+ {
+ AliInfo("Init the magnetic field\n");
+ if (esdevent)
+ {
+ esdevent->InitMagneticField();
+ }
+ else if(aodevent)
+ {
+ Double_t curSol = 30000*aodevent->GetMagneticField()/5.00668;
+ Double_t curDip = 6000 *aodevent->GetMuonMagFieldScale();
+ AliMagF *field = AliMagF::CreateFieldMap(curSol,curDip);
+ TGeoGlobalMagField::Instance()->SetField(field);
+ }
+ else
+ {
+ AliInfo("Mag Field not initialized, null esd/aod evetn pointers");
+ }
+
+ } // Init mag field
+
+ if (esdevent) {
+ UInt_t mask1 = esdevent->GetESDRun()->GetDetectorsInDAQ();
+ UInt_t mask2 = esdevent->GetESDRun()->GetDetectorsInReco();
+ Bool_t desc1 = (mask1 >> 3) & 0x1;
+ Bool_t desc2 = (mask2 >> 3) & 0x1;
+ if (desc1==0 || desc2==0) {
+// AliError(Form("TPC not in DAQ/RECO: %u (%u)/%u (%u)",
+// mask1, esdevent->GetESDRun()->GetDetectorsInReco(),
+// mask2, esdevent->GetESDRun()->GetDetectorsInDAQ()));
+ fITSTrackSA=kTRUE;
+ }
+ }
+
+ TObjArray *clusterArray = 0x0;
+ if(!clusterArr)
+ {
+ clusterArray = new TObjArray(event->GetNumberOfCaloClusters());
+ for(Int_t icl=0; icl<event->GetNumberOfCaloClusters(); icl++)
+ {
+ AliVCluster *cluster = (AliVCluster*) event->GetCaloCluster(icl);
+ if(geom && !IsGoodCluster(cluster,geom,(AliVCaloCells*)event->GetEMCALCells())) continue;
+ clusterArray->AddAt(cluster,icl);
+ }
+ }
+
+ Int_t matched=0;
+ Double_t cv[21];
+ for (Int_t i=0; i<21;i++) cv[i]=0;
+ for(Int_t itr=0; itr<event->GetNumberOfTracks(); itr++)
+ {
+ AliExternalTrackParam *trackParam = 0;
+
+ //If the input event is ESD, the starting point for extrapolation is TPCOut, if available, or TPCInner
+ AliESDtrack *esdTrack = 0;
+ AliAODTrack *aodTrack = 0;
+ if(esdevent)
+ {
+ esdTrack = esdevent->GetTrack(itr);
+ if(!esdTrack) continue;
+ if(!IsAccepted(esdTrack)) continue;
+ if(esdTrack->Pt()<fCutMinTrackPt) continue;
+ Double_t phi = esdTrack->Phi()*TMath::RadToDeg();
+ if(TMath::Abs(esdTrack->Eta())>0.8 || phi <= 20 || phi >= 240 ) continue;
+ if(!fITSTrackSA)
+ trackParam = const_cast<AliExternalTrackParam*>(esdTrack->GetInnerParam()); // if TPC Available
+ else
+ trackParam = new AliExternalTrackParam(*esdTrack); // If ITS Track Standing alone
+ }
+
+ //If the input event is AOD, the starting point for extrapolation is at vertex
+ //AOD tracks are selected according to its filterbit.
+ else if(aodevent)
+ {
+ aodTrack = aodevent->GetTrack(itr);
+ if(!aodTrack) continue;
+
+ //Check mask if not hybrid
+ if(!fAODHybridTracks && !aodTrack->TestFilterMask(fAODFilterMask) ) continue; //Select AOD tracks that fulfill GetStandardITSTPCTrackCuts2010()
+
+ //Check hybrid
+ if( fAODHybridTracks && !aodTrack->IsHybridGlobalConstrainedGlobal()) continue ;
+
+ if(aodTrack->Pt()<fCutMinTrackPt) continue;
+
+ Double_t phi = aodTrack->Phi()*TMath::RadToDeg();
+ if(TMath::Abs(aodTrack->Eta())>0.8 || phi <= 20 || phi >= 240 ) continue;
+ Double_t pos[3],mom[3];
+ aodTrack->GetXYZ(pos);
+ aodTrack->GetPxPyPz(mom);
+ AliDebug(5,Form("aod track: i=%d | pos=(%5.4f,%5.4f,%5.4f) | mom=(%5.4f,%5.4f,%5.4f) | charge=%d\n",itr,pos[0],pos[1],pos[2],mom[0],mom[1],mom[2],aodTrack->Charge()));
+
+ trackParam= new AliExternalTrackParam(pos,mom,cv,aodTrack->Charge());
+ }
+
+ //Return if the input data is not "AOD" or "ESD"
+ else
+ {
+ printf("Wrong input data type! Should be \"AOD\" or \"ESD\"\n");
+ if(clusterArray)
+ {
+ clusterArray->Clear();
+ delete clusterArray;
+ }
+ return;
+ }
+
+ if(!trackParam) continue;
+
+ //Extrapolate the track to EMCal surface
+ AliExternalTrackParam emcalParam(*trackParam);
+ Float_t eta, phi;
+ if(!ExtrapolateTrackToEMCalSurface(&emcalParam, 430., fMass, fStepSurface, eta, phi))
+ {
+ if(aodevent && trackParam) delete trackParam;
+ if(fITSTrackSA && trackParam) delete trackParam;
+ continue;
+ }
+
+// if(esdevent)
+// {
+// esdTrack->SetOuterParam(&emcalParam,AliExternalTrackParam::kMultSec);
+// }
+
+ if(TMath::Abs(eta)>0.75 || (phi) < 70*TMath::DegToRad() || (phi) > 190*TMath::DegToRad())
+ {
+ if(aodevent && trackParam) delete trackParam;
+ if(fITSTrackSA && trackParam) delete trackParam;
+ continue;
+ }
+
+
+ //Find matched clusters
+ Int_t index = -1;
+ Float_t dEta = -999, dPhi = -999;
+ if(!clusterArr)
+ {
+ index = FindMatchedClusterInClusterArr(&emcalParam, &emcalParam, clusterArray, dEta, dPhi);
+ }
+ else
+ {
+ index = FindMatchedClusterInClusterArr(&emcalParam, &emcalParam, clusterArr, dEta, dPhi);
+ }
+
+ if(index>-1)
+ {
+ fMatchedTrackIndex ->AddAt(itr,matched);
+ fMatchedClusterIndex ->AddAt(index,matched);
+ fResidualEta ->AddAt(dEta,matched);
+ fResidualPhi ->AddAt(dPhi,matched);
+ matched++;
+ }
+ if(aodevent && trackParam) delete trackParam;
+ if(fITSTrackSA && trackParam) delete trackParam;
+ }//track loop
+
+ if(clusterArray)
+ {
+ clusterArray->Clear();
+ delete clusterArray;
+ }
+
+ AliDebug(2,Form("Number of matched pairs = %d !\n",matched));
+
+ fMatchedTrackIndex ->Set(matched);
+ fMatchedClusterIndex ->Set(matched);
+ fResidualPhi ->Set(matched);
+ fResidualEta ->Set(matched);
+}
+
+//________________________________________________________________________________
+Int_t AliEMCALRecoUtils::FindMatchedClusterInEvent(const AliESDtrack *track,
+ const AliVEvent *event,
+ const AliEMCALGeometry *geom,
+ Float_t &dEta, Float_t &dPhi)
+{
+ //
+ // This function returns the index of matched cluster to input track
+ // Returns -1 if no match is found
+ Int_t index = -1;
+ Double_t phiV = track->Phi()*TMath::RadToDeg();
+ if(TMath::Abs(track->Eta())>0.8 || phiV <= 20 || phiV >= 240 ) return index;
+ AliExternalTrackParam *trackParam = 0;
+ if(!fITSTrackSA)
+ trackParam = const_cast<AliExternalTrackParam*>(track->GetInnerParam()); // If TPC
+ else
+ trackParam = new AliExternalTrackParam(*track);
+
+ if(!trackParam) return index;
+ AliExternalTrackParam emcalParam(*trackParam);
+ Float_t eta, phi;
+
+ if(!ExtrapolateTrackToEMCalSurface(&emcalParam, 430., fMass, fStepSurface, eta, phi)) {
+ if(fITSTrackSA) delete trackParam;
+ return index;
+ }
+ if(TMath::Abs(eta)>0.75 || (phi) < 70*TMath::DegToRad() || (phi) > 190*TMath::DegToRad()){
+ if(fITSTrackSA) delete trackParam;
+ return index;
+ }
+
+ TObjArray *clusterArr = new TObjArray(event->GetNumberOfCaloClusters());
+
+ for(Int_t icl=0; icl<event->GetNumberOfCaloClusters(); icl++)
+ {
+ AliVCluster *cluster = (AliVCluster*) event->GetCaloCluster(icl);
+ if(geom && !IsGoodCluster(cluster,geom,(AliVCaloCells*)event->GetEMCALCells())) continue;
+ clusterArr->AddAt(cluster,icl);
+ }
+
+ index = FindMatchedClusterInClusterArr(&emcalParam, &emcalParam, clusterArr, dEta, dPhi);
+ clusterArr->Clear();
+ delete clusterArr;
+ if(fITSTrackSA) delete trackParam;
+
+ return index;
+}
+
+//_______________________________________________________________________________________________
+Int_t AliEMCALRecoUtils::FindMatchedClusterInClusterArr(const AliExternalTrackParam *emcalParam,
+ AliExternalTrackParam *trkParam,
+ const TObjArray * clusterArr,
+ Float_t &dEta, Float_t &dPhi)
+{
+ // Find matched cluster in array
+
+ dEta=-999, dPhi=-999;
+ Float_t dRMax = fCutR, dEtaMax=fCutEta, dPhiMax=fCutPhi;
+ Int_t index = -1;
+ Float_t tmpEta=-999, tmpPhi=-999;
+
+ Double_t exPos[3] = {0.,0.,0.};
+ if(!emcalParam->GetXYZ(exPos)) return index;
+
+ Float_t clsPos[3] = {0.,0.,0.};
+ for(Int_t icl=0; icl<clusterArr->GetEntriesFast(); icl++)
+ {
+ AliVCluster *cluster = dynamic_cast<AliVCluster*> (clusterArr->At(icl)) ;
+ if(!cluster || !cluster->IsEMCAL()) continue;
+ cluster->GetPosition(clsPos);
+ Double_t dR = TMath::Sqrt(TMath::Power(exPos[0]-clsPos[0],2)+TMath::Power(exPos[1]-clsPos[1],2)+TMath::Power(exPos[2]-clsPos[2],2));
+ if(dR > fClusterWindow) continue;
+
+ AliExternalTrackParam trkPamTmp (*trkParam);//Retrieve the starting point every time before the extrapolation
+ if(!ExtrapolateTrackToCluster(&trkPamTmp, cluster, fMass, fStepCluster, tmpEta, tmpPhi)) continue;
+ if(fCutEtaPhiSum)
+ {
+ Float_t tmpR=TMath::Sqrt(tmpEta*tmpEta + tmpPhi*tmpPhi);
+ if(tmpR<dRMax)
+ {
+ dRMax=tmpR;
+ dEtaMax=tmpEta;
+ dPhiMax=tmpPhi;
+ index=icl;
+ }
+ }
+ else if(fCutEtaPhiSeparate)
+ {
+ if(TMath::Abs(tmpEta)<TMath::Abs(dEtaMax) && TMath::Abs(tmpPhi)<TMath::Abs(dPhiMax))
+ {
+ dEtaMax = tmpEta;
+ dPhiMax = tmpPhi;
+ index=icl;
+ }
+ }
+ else
+ {
+ printf("Error: please specify your cut criteria\n");
+ printf("To cut on sqrt(dEta^2+dPhi^2), use: SwitchOnCutEtaPhiSum()\n");
+ printf("To cut on dEta and dPhi separately, use: SwitchOnCutEtaPhiSeparate()\n");
+ return index;
+ }
+ }
+
+ dEta=dEtaMax;
+ dPhi=dPhiMax;
+
+ return index;
+}
+
+//------------------------------------------------------------------------------------
+Bool_t AliEMCALRecoUtils::ExtrapolateTrackToEMCalSurface(AliExternalTrackParam *trkParam,
+ const Double_t emcalR,
+ const Double_t mass,
+ const Double_t step,
+ Float_t &eta,
+ Float_t &phi)
+{
+ //Extrapolate track to EMCAL surface
+
+ eta = -999, phi = -999;
+ if(!trkParam) return kFALSE;
+ if(!AliTrackerBase::PropagateTrackToBxByBz(trkParam, emcalR, mass, step, kTRUE, 0.8, -1)) return kFALSE;
+ Double_t trkPos[3] = {0.,0.,0.};
+ if(!trkParam->GetXYZ(trkPos)) return kFALSE;
+ TVector3 trkPosVec(trkPos[0],trkPos[1],trkPos[2]);
+ eta = trkPosVec.Eta();
+ phi = trkPosVec.Phi();
+ if(phi<0)
+ phi += 2*TMath::Pi();
+
+ return kTRUE;
+}
+
+//-----------------------------------------------------------------------------------
+Bool_t AliEMCALRecoUtils::ExtrapolateTrackToPosition(AliExternalTrackParam *trkParam,
+ const Float_t *clsPos,
+ Double_t mass,
+ Double_t step,
+ Float_t &tmpEta,
+ Float_t &tmpPhi)
+{
+ //
+ //Return the residual by extrapolating a track param to a global position
+ //
+ tmpEta = -999;
+ tmpPhi = -999;
+ if(!trkParam) return kFALSE;
+ Double_t trkPos[3] = {0.,0.,0.};
+ TVector3 vec(clsPos[0],clsPos[1],clsPos[2]);
+ Double_t alpha = ((int)(vec.Phi()*TMath::RadToDeg()/20)+0.5)*20*TMath::DegToRad();
+ vec.RotateZ(-alpha); //Rotate the cluster to the local extrapolation coordinate system
+ if(!AliTrackerBase::PropagateTrackToBxByBz(trkParam, vec.X(), mass, step,kTRUE, 0.8, -1)) return kFALSE;
+ if(!trkParam->GetXYZ(trkPos)) return kFALSE; //Get the extrapolated global position
+
+ TVector3 clsPosVec(clsPos[0],clsPos[1],clsPos[2]);
+ TVector3 trkPosVec(trkPos[0],trkPos[1],trkPos[2]);
+
+ // track cluster matching
+ tmpPhi = clsPosVec.DeltaPhi(trkPosVec); // tmpPhi is between -pi and pi
+ tmpEta = clsPosVec.Eta()-trkPosVec.Eta();
+
+ return kTRUE;
+}
+
+//----------------------------------------------------------------------------------
+Bool_t AliEMCALRecoUtils::ExtrapolateTrackToCluster(AliExternalTrackParam *trkParam,
+ const AliVCluster *cluster,
+ const Double_t mass,
+ const Double_t step,
+ Float_t &tmpEta,
+ Float_t &tmpPhi)
+{
+ //
+ //Return the residual by extrapolating a track param to a cluster
+ //
+ tmpEta = -999;
+ tmpPhi = -999;
+ if(!cluster || !trkParam) return kFALSE;
+
+ Float_t clsPos[3] = {0.,0.,0.};
+ cluster->GetPosition(clsPos);
+
+ return ExtrapolateTrackToPosition(trkParam, clsPos, mass, step, tmpEta, tmpPhi);
+}
+
+//---------------------------------------------------------------------------------
+Bool_t AliEMCALRecoUtils::ExtrapolateTrackToCluster(AliExternalTrackParam *trkParam,
+ const AliVCluster *cluster,
+ Float_t &tmpEta,
+ Float_t &tmpPhi)
+{
+ //
+ //Return the residual by extrapolating a track param to a clusterfStepCluster
+ //
+
+ return ExtrapolateTrackToCluster(trkParam, cluster, fMass, fStepCluster, tmpEta, tmpPhi);
+}
+
+//_______________________________________________________________________
+void AliEMCALRecoUtils::GetMatchedResiduals(const Int_t clsIndex,
+ Float_t &dEta, Float_t &dPhi)
+{
+ //Given a cluster index as in AliESDEvent::GetCaloCluster(clsIndex)
+ //Get the residuals dEta and dPhi for this cluster to the closest track
+ //Works with ESDs and AODs
+
+ if( FindMatchedPosForCluster(clsIndex) >= 999 )
+ {
+ AliDebug(2,"No matched tracks found!\n");
+ dEta=999.;
+ dPhi=999.;
+ return;
+ }
+ dEta = fResidualEta->At(FindMatchedPosForCluster(clsIndex));
+ dPhi = fResidualPhi->At(FindMatchedPosForCluster(clsIndex));
+}
+
+//______________________________________________________________________________________________
+void AliEMCALRecoUtils::GetMatchedClusterResiduals(Int_t trkIndex, Float_t &dEta, Float_t &dPhi)
+{
+ //Given a track index as in AliESDEvent::GetTrack(trkIndex)
+ //Get the residuals dEta and dPhi for this track to the closest cluster
+ //Works with ESDs and AODs
+
+ if( FindMatchedPosForTrack(trkIndex) >= 999 )
+ {
+ AliDebug(2,"No matched cluster found!\n");
+ dEta=999.;
+ dPhi=999.;
+ return;
+ }
+ dEta = fResidualEta->At(FindMatchedPosForTrack(trkIndex));
+ dPhi = fResidualPhi->At(FindMatchedPosForTrack(trkIndex));
+}
+
+//__________________________________________________________
+Int_t AliEMCALRecoUtils::GetMatchedTrackIndex(Int_t clsIndex)
+{
+ //Given a cluster index as in AliESDEvent::GetCaloCluster(clsIndex)
+ //Get the index of matched track to this cluster
+ //Works with ESDs and AODs
+
+ if(IsClusterMatched(clsIndex))
+ return fMatchedTrackIndex->At(FindMatchedPosForCluster(clsIndex));
+ else
+ return -1;
+}
+
+//__________________________________________________________
+Int_t AliEMCALRecoUtils::GetMatchedClusterIndex(Int_t trkIndex)
+{
+ //Given a track index as in AliESDEvent::GetTrack(trkIndex)
+ //Get the index of matched cluster to this track
+ //Works with ESDs and AODs
+
+ if(IsTrackMatched(trkIndex))
+ return fMatchedClusterIndex->At(FindMatchedPosForTrack(trkIndex));
+ else
+ return -1;
+}
+
+//______________________________________________________________
+Bool_t AliEMCALRecoUtils::IsClusterMatched(Int_t clsIndex) const
+{
+ //Given a cluster index as in AliESDEvent::GetCaloCluster(clsIndex)
+ //Returns if the cluster has a match
+ if(FindMatchedPosForCluster(clsIndex) < 999)
+ return kTRUE;
+ else
+ return kFALSE;
+}
+
+//____________________________________________________________
+Bool_t AliEMCALRecoUtils::IsTrackMatched(Int_t trkIndex) const
+{
+ //Given a track index as in AliESDEvent::GetTrack(trkIndex)
+ //Returns if the track has a match
+ if(FindMatchedPosForTrack(trkIndex) < 999)
+ return kTRUE;
+ else
+ return kFALSE;
+}
+
+//______________________________________________________________________
+UInt_t AliEMCALRecoUtils::FindMatchedPosForCluster(Int_t clsIndex) const
+{
+ //Given a cluster index as in AliESDEvent::GetCaloCluster(clsIndex)
+ //Returns the position of the match in the fMatchedClusterIndex array
+ Float_t tmpR = fCutR;
+ UInt_t pos = 999;
+
+ for(Int_t i=0; i<fMatchedClusterIndex->GetSize(); i++)
+ {
+ if(fMatchedClusterIndex->At(i)==clsIndex)
+ {
+ Float_t r = TMath::Sqrt(fResidualEta->At(i)*fResidualEta->At(i) + fResidualPhi->At(i)*fResidualPhi->At(i));
+ if(r<tmpR)
+ {
+ pos=i;
+ tmpR=r;
+ AliDebug(3,Form("Matched cluster index: index: %d, dEta: %2.4f, dPhi: %2.4f.\n",
+ fMatchedClusterIndex->At(i),fResidualEta->At(i),fResidualPhi->At(i)));
+ }
+ }
+ }
+ return pos;
+}
+
+//____________________________________________________________________
+UInt_t AliEMCALRecoUtils::FindMatchedPosForTrack(Int_t trkIndex) const
+{
+ //Given a track index as in AliESDEvent::GetTrack(trkIndex)
+ //Returns the position of the match in the fMatchedTrackIndex array
+ Float_t tmpR = fCutR;
+ UInt_t pos = 999;
+
+ for(Int_t i=0; i<fMatchedTrackIndex->GetSize(); i++)
+ {
+ if(fMatchedTrackIndex->At(i)==trkIndex)
+ {
+ Float_t r = TMath::Sqrt(fResidualEta->At(i)*fResidualEta->At(i) + fResidualPhi->At(i)*fResidualPhi->At(i));
+ if(r<tmpR)
+ {
+ pos=i;
+ tmpR=r;
+ AliDebug(3,Form("Matched track index: index: %d, dEta: %2.4f, dPhi: %2.4f.\n",
+ fMatchedTrackIndex->At(i),fResidualEta->At(i),fResidualPhi->At(i)));
+ }
+ }
+ }
+ return pos;
+}
+
+//__________________________________________________________________________
+Bool_t AliEMCALRecoUtils::IsGoodCluster(AliVCluster *cluster,
+ const AliEMCALGeometry *geom,
+ AliVCaloCells* cells,const Int_t bc)
+{
+ // check if the cluster survives some quality cut
+ //
+ //
+ Bool_t isGood=kTRUE;
+
+ if(!cluster || !cluster->IsEMCAL()) return kFALSE;
+
+ if(ClusterContainsBadChannel(geom,cluster->GetCellsAbsId(),cluster->GetNCells())) return kFALSE;
+
+ if(!CheckCellFiducialRegion(geom,cluster,cells)) return kFALSE;
+
+ if(IsExoticCluster(cluster, cells,bc)) return kFALSE;
+
+ return isGood;
+}
+
+//__________________________________________________________
+Bool_t AliEMCALRecoUtils::IsAccepted(AliESDtrack *esdTrack)
+{
+ // Given a esd track, return whether the track survive all the cuts
+
+ // The different quality parameter are first
+ // retrieved from the track. then it is found out what cuts the
+ // track did not survive and finally the cuts are imposed.
+
+ UInt_t status = esdTrack->GetStatus();
+
+ Int_t nClustersITS = esdTrack->GetITSclusters(0);
+ Int_t nClustersTPC = esdTrack->GetTPCclusters(0);
+
+ Float_t chi2PerClusterITS = -1;
+ Float_t chi2PerClusterTPC = -1;
+ if (nClustersITS!=0)
+ chi2PerClusterITS = esdTrack->GetITSchi2()/Float_t(nClustersITS);
+ if (nClustersTPC!=0)
+ chi2PerClusterTPC = esdTrack->GetTPCchi2()/Float_t(nClustersTPC);
+
+
+ //DCA cuts
+ if(fTrackCutsType==kGlobalCut)
+ {
+ Float_t maxDCAToVertexXYPtDep = 0.0182 + 0.0350/TMath::Power(esdTrack->Pt(),1.01); //This expression comes from AliESDtrackCuts::GetStandardITSTPCTrackCuts2010()
+ //AliDebug(3,Form("Track pT = %f, DCAtoVertexXY = %f",esdTrack->Pt(),MaxDCAToVertexXYPtDep));
+ SetMaxDCAToVertexXY(maxDCAToVertexXYPtDep); //Set pT dependent DCA cut to vertex in x-y plane
+ }
+
+
+ Float_t b[2];
+ Float_t bCov[3];
+ esdTrack->GetImpactParameters(b,bCov);
+ if (bCov[0]<=0 || bCov[2]<=0)
+ {
+ AliDebug(1, "Estimated b resolution lower or equal zero!");
+ bCov[0]=0; bCov[2]=0;
+ }
+
+ Float_t dcaToVertexXY = b[0];
+ Float_t dcaToVertexZ = b[1];
+ Float_t dcaToVertex = -1;
+
+ if (fCutDCAToVertex2D)
+ dcaToVertex = TMath::Sqrt(dcaToVertexXY*dcaToVertexXY/fCutMaxDCAToVertexXY/fCutMaxDCAToVertexXY + dcaToVertexZ*dcaToVertexZ/fCutMaxDCAToVertexZ/fCutMaxDCAToVertexZ);
+ else
+ dcaToVertex = TMath::Sqrt(dcaToVertexXY*dcaToVertexXY + dcaToVertexZ*dcaToVertexZ);
+
+ // cut the track?
+
+ Bool_t cuts[kNCuts];
+ for (Int_t i=0; i<kNCuts; i++) cuts[i]=kFALSE;
+
+ // track quality cuts
+ if (fCutRequireTPCRefit && (status&AliESDtrack::kTPCrefit)==0)
+ cuts[0]=kTRUE;
+ if (fCutRequireITSRefit && (status&AliESDtrack::kITSrefit)==0)
+ cuts[1]=kTRUE;
+ if (nClustersTPC<fCutMinNClusterTPC)
+ cuts[2]=kTRUE;
+ if (nClustersITS<fCutMinNClusterITS)
+ cuts[3]=kTRUE;
+ if (chi2PerClusterTPC>fCutMaxChi2PerClusterTPC)
+ cuts[4]=kTRUE;
+ if (chi2PerClusterITS>fCutMaxChi2PerClusterITS)
+ cuts[5]=kTRUE;
+ if (!fCutAcceptKinkDaughters && esdTrack->GetKinkIndex(0)>0)
+ cuts[6]=kTRUE;
+ if (fCutDCAToVertex2D && dcaToVertex > 1)
+ cuts[7] = kTRUE;
+ if (!fCutDCAToVertex2D && TMath::Abs(dcaToVertexXY) > fCutMaxDCAToVertexXY)
+ cuts[8] = kTRUE;
+ if (!fCutDCAToVertex2D && TMath::Abs(dcaToVertexZ) > fCutMaxDCAToVertexZ)
+ cuts[9] = kTRUE;
+
+ if(fTrackCutsType==kGlobalCut)
+ {
+ //Require at least one SPD point + anything else in ITS
+ if( (esdTrack->HasPointOnITSLayer(0) || esdTrack->HasPointOnITSLayer(1)) == kFALSE)
+ cuts[10] = kTRUE;
+ }
+
+ // ITS
+ if(fCutRequireITSStandAlone || fCutRequireITSpureSA){
+ if ((status & AliESDtrack::kITSin) == 0 || (status & AliESDtrack::kTPCin)){
+ // TPC tracks
+ cuts[11] = kTRUE;
+ }else{
+ // ITS standalone tracks
+ if(fCutRequireITSStandAlone && !fCutRequireITSpureSA){
+ if(status & AliESDtrack::kITSpureSA) cuts[11] = kTRUE;
+ }else if(fCutRequireITSpureSA){
+ if(!(status & AliESDtrack::kITSpureSA)) cuts[11] = kTRUE;
+ }
+ }
+ }
+
+ Bool_t cut=kFALSE;
+ for (Int_t i=0; i<kNCuts; i++)
+ if (cuts[i]) { cut = kTRUE ; }
+
+ // cut the track
+ if (cut)
+ return kFALSE;
+ else
+ return kTRUE;
+}
+
+//_____________________________________
+void AliEMCALRecoUtils::InitTrackCuts()
+{
+ //Intilize the track cut criteria
+ //By default these cuts are set according to AliESDtrackCuts::GetStandardTPCOnlyTrackCuts()
+ //Also you can customize the cuts using the setters
+
+ switch (fTrackCutsType)
+ {
+ case kTPCOnlyCut:
+ {
+ AliInfo(Form("Track cuts for matching: GetStandardTPCOnlyTrackCuts()"));
+ //TPC
+ SetMinNClustersTPC(70);
+ SetMaxChi2PerClusterTPC(4);
+ SetAcceptKinkDaughters(kFALSE);
+ SetRequireTPCRefit(kFALSE);
+
+ //ITS
+ SetRequireITSRefit(kFALSE);
+ SetMaxDCAToVertexZ(3.2);
+ SetMaxDCAToVertexXY(2.4);
+ SetDCAToVertex2D(kTRUE);
+
+ break;
+ }
+
+ case kGlobalCut:
+ {
+ AliInfo(Form("Track cuts for matching: GetStandardITSTPCTrackCuts2010(kTURE)"));
+ //TPC
+ SetMinNClustersTPC(70);
+ SetMaxChi2PerClusterTPC(4);
+ SetAcceptKinkDaughters(kFALSE);
+ SetRequireTPCRefit(kTRUE);
+
+ //ITS
+ SetRequireITSRefit(kTRUE);
+ SetMaxDCAToVertexZ(2);
+ SetMaxDCAToVertexXY();
+ SetDCAToVertex2D(kFALSE);
+
+ break;
+ }
+
+ case kLooseCut:
+ {
+ AliInfo(Form("Track cuts for matching: Loose cut w/o DCA cut"));
+ SetMinNClustersTPC(50);
+ SetAcceptKinkDaughters(kTRUE);
+
+ break;
+ }
+
+ case kITSStandAlone:
+ {
+ AliInfo(Form("Track cuts for matching: ITS Stand Alone tracks cut w/o DCA cut"));
+ SetRequireITSRefit(kTRUE);
+ SetRequireITSStandAlone(kTRUE);
+ SetITSTrackSA(kTRUE);
+ break;
+ }
+
+ }
+}
+
+
+//________________________________________________________________________
+void AliEMCALRecoUtils::SetClusterMatchedToTrack(const AliVEvent *event)
+{
+ // Checks if tracks are matched to EMC clusters and set the matched EMCAL cluster index to ESD track.
+
+ Int_t nTracks = event->GetNumberOfTracks();
+ for (Int_t iTrack = 0; iTrack < nTracks; ++iTrack)
+ {
+ AliVTrack* track = dynamic_cast<AliVTrack*>(event->GetTrack(iTrack));
+ if (!track)
+ {
+ AliWarning(Form("Could not receive track %d", iTrack));
+ continue;
+ }
+
+ Int_t matchClusIndex = GetMatchedClusterIndex(iTrack);
+ track->SetEMCALcluster(matchClusIndex); //sets -1 if track not matched within residual
+ /*the following can be done better if AliVTrack::SetStatus will be there. Patch pending with Andreas/Peter*/
+ AliESDtrack* esdtrack = dynamic_cast<AliESDtrack*>(track);
+ if (esdtrack) {
+ if(matchClusIndex != -1)
+ esdtrack->SetStatus(AliESDtrack::kEMCALmatch);
+ else
+ esdtrack->ResetStatus(AliESDtrack::kEMCALmatch);
+ } else {
+ AliAODTrack* aodtrack = dynamic_cast<AliAODTrack*>(track);
+ if(matchClusIndex != -1)
+ aodtrack->SetStatus(AliESDtrack::kEMCALmatch);
+ else
+ aodtrack->ResetStatus(AliESDtrack::kEMCALmatch);
+ }
+
+ }
+ AliDebug(2,"Track matched to closest cluster");
+}
+
+//_________________________________________________________________________
+void AliEMCALRecoUtils::SetTracksMatchedToCluster(const AliVEvent *event)
+{
+ // Checks if EMC clusters are matched to ESD track.
+ // Adds track indexes of all the tracks matched to a cluster withing residuals in ESDCalocluster.
+
+ for (Int_t iClus=0; iClus < event->GetNumberOfCaloClusters(); ++iClus)
+ {
+ AliVCluster *cluster = event->GetCaloCluster(iClus);
+ if (!cluster->IsEMCAL())
+ continue;
+
+ Int_t nTracks = event->GetNumberOfTracks();
+ TArrayI arrayTrackMatched(nTracks);
+
+ // Get the closest track matched to the cluster
+ Int_t nMatched = 0;
+ Int_t matchTrackIndex = GetMatchedTrackIndex(iClus);
+ if (matchTrackIndex != -1)
+ {
+ arrayTrackMatched[nMatched] = matchTrackIndex;
+ nMatched++;
+ }
+
+ // Get all other tracks matched to the cluster
+ for(Int_t iTrk=0; iTrk<nTracks; ++iTrk)
+ {
+ AliVTrack* track = dynamic_cast<AliVTrack*>(event->GetTrack(iTrk));
+ if(iTrk == matchTrackIndex) continue;
+ if(track->GetEMCALcluster() == iClus)
+ {
+ arrayTrackMatched[nMatched] = iTrk;
+ ++nMatched;
+ }
+ }
+
+ //printf("Tender::SetTracksMatchedToCluster - cluster E %f, N matches %d, first match %d\n",cluster->E(),nMatched,arrayTrackMatched[0]);
+
+ arrayTrackMatched.Set(nMatched);
+ AliESDCaloCluster *esdcluster = dynamic_cast<AliESDCaloCluster*>(cluster);
+ if (esdcluster)
+ esdcluster->AddTracksMatched(arrayTrackMatched);
+ else if (nMatched>0) {
+ AliAODCaloCluster *aodcluster = dynamic_cast<AliAODCaloCluster*>(cluster);
+ if (aodcluster)
+ aodcluster->AddTrackMatched(event->GetTrack(arrayTrackMatched.At(0)));
+ }
+
+ Float_t eta= -999, phi = -999;
+ if (matchTrackIndex != -1)
+ GetMatchedResiduals(iClus, eta, phi);
+ cluster->SetTrackDistance(phi, eta);
+ }
+
+ AliDebug(2,"Cluster matched to tracks");
+}
+
+//___________________________________________________