+
+//______________________________________________________________________________
+// private non cached versions of the PID calculation
+//
+
+
+//______________________________________________________________________________
+Float_t AliPIDResponse::GetNumberOfSigmas(EDetector detector, const AliVParticle *vtrack, AliPID::EParticleType type) const
+{
+ //
+ // NumberOfSigmas for 'detCode'
+ //
+
+ const AliVTrack *track=static_cast<const AliVTrack*>(vtrack);
+
+ switch (detector){
+ case kITS: return GetNumberOfSigmasITS(track, type); break;
+ case kTPC: return GetNumberOfSigmasTPC(track, type); break;
+ case kTOF: return GetNumberOfSigmasTOF(track, type); break;
+ case kHMPID: return GetNumberOfSigmasHMPID(track, type); break;
+ case kEMCAL: return GetNumberOfSigmasEMCAL(track, type); break;
+ default: return -999.;
+ }
+
+ return -999.;
+}
+
+//______________________________________________________________________________
+Float_t AliPIDResponse::GetNumberOfSigmasITS(const AliVParticle *vtrack, AliPID::EParticleType type) const
+{
+ //
+ // Calculate the number of sigmas in the ITS
+ //
+
+ AliVTrack *track=(AliVTrack*)vtrack;
+
+ const EDetPidStatus pidStatus=GetITSPIDStatus(track);
+ if (pidStatus!=kDetPidOk) return -999.;
+
+ return fITSResponse.GetNumberOfSigmas(track,type);
+}
+
+//______________________________________________________________________________
+Float_t AliPIDResponse::GetNumberOfSigmasTPC(const AliVParticle *vtrack, AliPID::EParticleType type) const
+{
+ //
+ // Calculate the number of sigmas in the TPC
+ //
+
+ AliVTrack *track=(AliVTrack*)vtrack;
+
+ const EDetPidStatus pidStatus=GetTPCPIDStatus(track);
+ if (pidStatus!=kDetPidOk) return -999.;
+
+ // the following call is needed in order to fill the transient data member
+ // fTPCsignalTuned which is used in the TPCPIDResponse to judge
+ // if using tuned on data
+ if (fTuneMConData && ((fTuneMConDataMask & kDetTPC) == kDetTPC))
+ this->GetTPCsignalTunedOnData(track);
+
+ return fTPCResponse.GetNumberOfSigmas(track, type, AliTPCPIDResponse::kdEdxDefault, fUseTPCEtaCorrection, fUseTPCMultiplicityCorrection);
+}
+
+//______________________________________________________________________________
+Float_t AliPIDResponse::GetNumberOfSigmasTOF(const AliVParticle *vtrack, AliPID::EParticleType type) const
+{
+ //
+ // Calculate the number of sigmas in the TOF
+ //
+
+ AliVTrack *track=(AliVTrack*)vtrack;
+
+ const EDetPidStatus pidStatus=GetTOFPIDStatus(track);
+ if (pidStatus!=kDetPidOk) return -999.;
+
+ return GetNumberOfSigmasTOFold(vtrack, type);
+}
+//______________________________________________________________________________
+
+Float_t AliPIDResponse::GetNumberOfSigmasHMPID(const AliVParticle *vtrack, AliPID::EParticleType type) const
+{
+ //
+ // Calculate the number of sigmas in the HMPID
+ //
+ AliVTrack *track=(AliVTrack*)vtrack;
+
+ const EDetPidStatus pidStatus=GetHMPIDPIDStatus(track);
+ if (pidStatus!=kDetPidOk) return -999.;
+
+ return fHMPIDResponse.GetNumberOfSigmas(track, type);
+}
+
+//______________________________________________________________________________
+Float_t AliPIDResponse::GetNumberOfSigmasEMCAL(const AliVParticle *vtrack, AliPID::EParticleType type) const
+{
+ //
+ // Calculate the number of sigmas in the EMCAL
+ //
+
+ AliVTrack *track=(AliVTrack*)vtrack;
+
+ const EDetPidStatus pidStatus=GetEMCALPIDStatus(track);
+ if (pidStatus!=kDetPidOk) return -999.;
+
+ const Int_t nMatchClus = track->GetEMCALcluster();
+ AliVCluster *matchedClus = (AliVCluster*)fCurrentEvent->GetCaloCluster(nMatchClus);
+
+ const Double_t mom = track->P();
+ const Double_t pt = track->Pt();
+ const Int_t charge = track->Charge();
+ const Double_t fClsE = matchedClus->E();
+ const Double_t EovP = fClsE/mom;
+
+ return fEMCALResponse.GetNumberOfSigmas(pt,EovP,type,charge);
+}
+
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse::GetSignalDeltaITS(const AliVParticle *vtrack, AliPID::EParticleType type, Double_t &val, Bool_t ratio/*=kFALSE*/) const
+{
+ //
+ // Signal minus expected Signal for ITS
+ //
+ AliVTrack *track=(AliVTrack*)vtrack;
+ val=fITSResponse.GetSignalDelta(track,type,ratio);
+
+ return GetITSPIDStatus(track);
+}
+
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse::GetSignalDeltaTPC(const AliVParticle *vtrack, AliPID::EParticleType type, Double_t &val, Bool_t ratio/*=kFALSE*/) const
+{
+ //
+ // Signal minus expected Signal for TPC
+ //
+ AliVTrack *track=(AliVTrack*)vtrack;
+
+ // the following call is needed in order to fill the transient data member
+ // fTPCsignalTuned which is used in the TPCPIDResponse to judge
+ // if using tuned on data
+ if (fTuneMConData && ((fTuneMConDataMask & kDetTPC) == kDetTPC))
+ this->GetTPCsignalTunedOnData(track);
+
+ val=fTPCResponse.GetSignalDelta(track, type, AliTPCPIDResponse::kdEdxDefault, fUseTPCEtaCorrection, fUseTPCMultiplicityCorrection, ratio);
+
+ return GetTPCPIDStatus(track);
+}
+
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse::GetSignalDeltaTOF(const AliVParticle *vtrack, AliPID::EParticleType type, Double_t &val, Bool_t ratio/*=kFALSE*/) const
+{
+ //
+ // Signal minus expected Signal for TOF
+ //
+ AliVTrack *track=(AliVTrack*)vtrack;
+ val=GetSignalDeltaTOFold(track, type, ratio);
+
+ return GetTOFPIDStatus(track);
+}
+
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse::GetSignalDeltaHMPID(const AliVParticle *vtrack, AliPID::EParticleType type, Double_t &val, Bool_t ratio/*=kFALSE*/) const
+{
+ //
+ // Signal minus expected Signal for HMPID
+ //
+ AliVTrack *track=(AliVTrack*)vtrack;
+ val=fHMPIDResponse.GetSignalDelta(track, type, ratio);
+
+ return GetHMPIDPIDStatus(track);
+}
+
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse::GetComputePIDProbability (EDetector detCode, const AliVTrack *track, Int_t nSpecies, Double_t p[]) const
+{
+ //
+ // Compute PID response of 'detCode'
+ //
+
+ switch (detCode){
+ case kITS: return GetComputeITSProbability(track, nSpecies, p); break;
+ case kTPC: return GetComputeTPCProbability(track, nSpecies, p); break;
+ case kTRD: return GetComputeTRDProbability(track, nSpecies, p); break;
+ case kTOF: return GetComputeTOFProbability(track, nSpecies, p); break;
+ case kPHOS: return GetComputePHOSProbability(track, nSpecies, p); break;
+ case kEMCAL: return GetComputeEMCALProbability(track, nSpecies, p); break;
+ case kHMPID: return GetComputeHMPIDProbability(track, nSpecies, p); break;
+ default: return kDetNoSignal;
+ }
+}
+
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse::GetComputeITSProbability (const AliVTrack *track, Int_t nSpecies, Double_t p[]) const
+{
+ //
+ // Compute PID response for the ITS
+ //
+
+ // set flat distribution (no decision)
+ for (Int_t j=0; j<nSpecies; j++) p[j]=1./nSpecies;
+
+ const EDetPidStatus pidStatus=GetITSPIDStatus(track);
+ if (pidStatus!=kDetPidOk) return pidStatus;
+
+ if (track->GetDetectorPID()){
+ return track->GetDetectorPID()->GetRawProbability(kITS, p, nSpecies);
+ }
+
+ //check for ITS standalone tracks
+ Bool_t isSA=kTRUE;
+ if( track->GetStatus() & AliVTrack::kTPCin ) isSA=kFALSE;
+
+ Double_t mom=track->P();
+ Double_t dedx=track->GetITSsignal();
+ Double_t momITS=mom;
+ UChar_t clumap=track->GetITSClusterMap();
+ Int_t nPointsForPid=0;
+ for(Int_t i=2; i<6; i++){
+ if(clumap&(1<<i)) ++nPointsForPid;
+ }
+
+ Bool_t mismatch=kTRUE/*, heavy=kTRUE*/;
+ for (Int_t j=0; j<nSpecies; j++) {
+ Double_t mass=AliPID::ParticleMassZ(j);//GeV/c^2
+ const Double_t chargeFactor = TMath::Power(AliPID::ParticleCharge(j),2.);
+ Double_t bethe=fITSResponse.Bethe(momITS,mass)*chargeFactor;
+ //TODO: in case of the electron, use the SA parametrisation,
+ // this needs to be changed if ITS provides a parametrisation
+ // for electrons also for ITS+TPC tracks
+ Double_t sigma=fITSResponse.GetResolution(bethe,nPointsForPid,isSA || (j==(Int_t)AliPID::kElectron));
+ if (TMath::Abs(dedx-bethe) > fRange*sigma) {
+ p[j]=TMath::Exp(-0.5*fRange*fRange)/sigma;
+ } else {
+ p[j]=TMath::Exp(-0.5*(dedx-bethe)*(dedx-bethe)/(sigma*sigma))/sigma;
+ mismatch=kFALSE;
+ }
+ }
+
+ if (mismatch){
+ for (Int_t j=0; j<nSpecies; j++) p[j]=1./nSpecies;
+ }
+
+ return kDetPidOk;
+}
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse::GetComputeTPCProbability (const AliVTrack *track, Int_t nSpecies, Double_t p[]) const
+{
+ //
+ // Compute PID response for the TPC
+ //
+
+ // set flat distribution (no decision)
+ for (Int_t j=0; j<nSpecies; j++) p[j]=1./nSpecies;
+
+ const EDetPidStatus pidStatus=GetTPCPIDStatus(track);
+ if (pidStatus!=kDetPidOk) return pidStatus;
+
+ Double_t dedx=track->GetTPCsignal();
+ Bool_t mismatch=kTRUE/*, heavy=kTRUE*/;
+
+ if (fTuneMConData && ((fTuneMConDataMask & kDetTPC) == kDetTPC)) dedx = this->GetTPCsignalTunedOnData(track);
+
+ Double_t bethe = 0.;
+ Double_t sigma = 0.;
+
+ for (Int_t j=0; j<nSpecies; j++) {
+ AliPID::EParticleType type=AliPID::EParticleType(j);
+
+ bethe=fTPCResponse.GetExpectedSignal(track, type, AliTPCPIDResponse::kdEdxDefault, fUseTPCEtaCorrection, fUseTPCMultiplicityCorrection);
+ sigma=fTPCResponse.GetExpectedSigma(track, type, AliTPCPIDResponse::kdEdxDefault, fUseTPCEtaCorrection, fUseTPCMultiplicityCorrection);
+
+ if (TMath::Abs(dedx-bethe) > fRange*sigma) {
+ p[j]=TMath::Exp(-0.5*fRange*fRange)/sigma;
+ } else {
+ p[j]=TMath::Exp(-0.5*(dedx-bethe)*(dedx-bethe)/(sigma*sigma))/sigma;
+ mismatch=kFALSE;
+ }
+ }
+
+ if (mismatch){
+ for (Int_t j=0; j<nSpecies; j++) p[j]=1./nSpecies;
+ }
+
+ return kDetPidOk;
+}
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse::GetComputeTOFProbability (const AliVTrack *track, Int_t nSpecies, Double_t p[]) const
+{
+ //
+ // Compute PID probabilities for TOF
+ //
+
+ // set flat distribution (no decision)
+ for (Int_t j=0; j<nSpecies; j++) p[j]=1./nSpecies;
+
+ const EDetPidStatus pidStatus=GetTOFPIDStatus(track);
+ if (pidStatus!=kDetPidOk) return pidStatus;
+
+ const Double_t meanCorrFactor = 0.07/fTOFtail; // Correction factor on the mean because of the tail (should be ~ 0.1 with tail = 1.1)
+
+ for (Int_t j=0; j<nSpecies; j++) {
+ AliPID::EParticleType type=AliPID::EParticleType(j);
+ const Double_t nsigmas=GetNumberOfSigmasTOFold(track,type) + meanCorrFactor;
+
+ const Double_t expTime = fTOFResponse.GetExpectedSignal(track,type);
+ const Double_t sig = fTOFResponse.GetExpectedSigma(track->P(),expTime,AliPID::ParticleMassZ(type));
+ if (TMath::Abs(nsigmas) > (fRange+2)) {
+ if(nsigmas < fTOFtail)
+ p[j] = TMath::Exp(-0.5*(fRange+2)*(fRange+2))/sig;
+ else
+ p[j] = TMath::Exp(-(fRange+2 - fTOFtail*0.5)*fTOFtail)/sig;
+ } else{
+ if(nsigmas < fTOFtail)
+ p[j] = TMath::Exp(-0.5*nsigmas*nsigmas)/sig;
+ else
+ p[j] = TMath::Exp(-(nsigmas - fTOFtail*0.5)*fTOFtail)/sig;
+ }
+ }
+
+ return kDetPidOk;
+}
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse::GetComputeTRDProbability (const AliVTrack *track, Int_t nSpecies, Double_t p[],AliTRDPIDResponse::ETRDPIDMethod PIDmethod/*=AliTRDPIDResponse::kLQ1D*/) const
+{
+ //
+ // Compute PID probabilities for the TRD
+ //
+
+ // set flat distribution (no decision)
+ for (Int_t j=0; j<nSpecies; j++) p[j]=1./nSpecies;
+
+ const EDetPidStatus pidStatus=GetTRDPIDStatus(track);
+ if (pidStatus!=kDetPidOk) return pidStatus;
+
+ UInt_t TRDslicesForPID[2];
+ SetTRDSlices(TRDslicesForPID,PIDmethod);
+
+ Float_t mom[6]={0.};
+ Double_t dedx[48]={0.}; // Allocate space for the maximum number of TRD slices
+ Int_t nslices = TRDslicesForPID[1] - TRDslicesForPID[0] + 1;
+ AliDebug(1, Form("First Slice: %d, Last Slice: %d, Number of slices: %d", TRDslicesForPID[0], TRDslicesForPID[1], nslices));
+ for(UInt_t ilayer = 0; ilayer < 6; ilayer++){
+ mom[ilayer] = track->GetTRDmomentum(ilayer);
+ for(UInt_t islice = TRDslicesForPID[0]; islice <= TRDslicesForPID[1]; islice++){
+ dedx[ilayer*nslices+islice-TRDslicesForPID[0]] = track->GetTRDslice(ilayer, islice);
+ }
+ }
+
+ fTRDResponse.GetResponse(nslices, dedx, mom, p,PIDmethod);
+ return kDetPidOk;
+}
+
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse::GetComputeEMCALProbability (const AliVTrack *track, Int_t nSpecies, Double_t p[]) const
+{
+ //
+ // Compute PID response for the EMCAL
+ //
+
+ for (Int_t j=0; j<nSpecies; j++) p[j]=1./nSpecies;
+
+ const EDetPidStatus pidStatus=GetEMCALPIDStatus(track);
+ if (pidStatus!=kDetPidOk) return pidStatus;
+
+ const Int_t nMatchClus = track->GetEMCALcluster();
+ AliVCluster *matchedClus = (AliVCluster*)fCurrentEvent->GetCaloCluster(nMatchClus);
+
+ const Double_t mom = track->P();
+ const Double_t pt = track->Pt();
+ const Int_t charge = track->Charge();
+ const Double_t fClsE = matchedClus->E();
+ const Double_t EovP = fClsE/mom;
+
+ // compute the probabilities
+ fEMCALResponse.ComputeEMCALProbability(nSpecies,pt,EovP,charge,p);
+ return kDetPidOk;
+}
+
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse::GetComputePHOSProbability (const AliVTrack */*track*/, Int_t nSpecies, Double_t p[]) const
+{
+ //
+ // Compute PID response for the PHOS
+ //
+
+ // set flat distribution (no decision)
+ for (Int_t j=0; j<nSpecies; j++) p[j]=1./nSpecies;
+ return kDetNoSignal;
+}
+
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse::GetComputeHMPIDProbability(const AliVTrack *track, Int_t nSpecies, Double_t p[]) const
+{
+ //
+ // Compute PID response for the HMPID
+ //
+
+ // set flat distribution (no decision)
+ for (Int_t j=0; j<nSpecies; j++) p[j]=1./nSpecies;
+
+ const EDetPidStatus pidStatus=GetHMPIDPIDStatus(track);
+ if (pidStatus!=kDetPidOk) return pidStatus;
+
+ fHMPIDResponse.GetProbability(track,nSpecies,p);
+
+ return kDetPidOk;
+}
+
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse::GetITSPIDStatus(const AliVTrack *track) const
+{
+ // compute ITS pid status
+
+ // check status bits
+ if ((track->GetStatus()&AliVTrack::kITSin)==0 &&
+ (track->GetStatus()&AliVTrack::kITSout)==0) return kDetNoSignal;
+
+ const Float_t dEdx=track->GetITSsignal();
+ if (dEdx<=0) return kDetNoSignal;
+
+ // requite at least 3 pid clusters
+ const UChar_t clumap=track->GetITSClusterMap();
+ Int_t nPointsForPid=0;
+ for(Int_t i=2; i<6; i++){
+ if(clumap&(1<<i)) ++nPointsForPid;
+ }
+
+ if(nPointsForPid<3) {
+ return kDetNoSignal;
+ }
+
+ return kDetPidOk;
+}
+
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse:: GetTPCPIDStatus(const AliVTrack *track) const
+{
+ // compute TPC pid status
+
+ // check quality of the track
+ if ( (track->GetStatus()&AliVTrack::kTPCin )==0 && (track->GetStatus()&AliVTrack::kTPCout)==0 ) return kDetNoSignal;
+
+ // check pid values
+ const Double_t dedx=track->GetTPCsignal();
+ const UShort_t signalN=track->GetTPCsignalN();
+ if (signalN<10 || dedx<10) return kDetNoSignal;
+
+ if (!(fArrPidResponseMaster && fArrPidResponseMaster->At(AliPID::kPion))) return kDetNoParams;
+
+ return kDetPidOk;
+}
+
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse::GetTRDPIDStatus(const AliVTrack *track) const
+{
+ // compute TRD pid status
+
+ if((track->GetStatus()&AliVTrack::kTRDout)==0) return kDetNoSignal;
+ return kDetPidOk;
+}
+
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse::GetTOFPIDStatus(const AliVTrack *track) const
+{
+ // compute TOF pid status
+
+ if ((track->GetStatus()&AliVTrack::kTOFout)==0) return kDetNoSignal;
+ if ((track->GetStatus()&AliVTrack::kTIME)==0) return kDetNoSignal;
+
+ return kDetPidOk;
+}
+
+//______________________________________________________________________________
+Float_t AliPIDResponse::GetTOFMismatchProbability(const AliVTrack *track) const
+{
+ // compute mismatch probability cross-checking at 5 sigmas with TPC
+ // currently just implemented as a 5 sigma compatibility cut
+
+ // check pid status
+ const EDetPidStatus tofStatus=GetTOFPIDStatus(track);
+ if (tofStatus!=kDetPidOk) return 0.;
+
+ //mismatch
+ const EDetPidStatus tpcStatus=GetTPCPIDStatus(track);
+ if (tpcStatus!=kDetPidOk) return 0.;
+
+ const Double_t meanCorrFactor = 0.11/fTOFtail; // Correction factor on the mean because of the tail (should be ~ 0.1 with tail = 1.1)
+ Bool_t mismatch = kTRUE/*, heavy = kTRUE*/;
+ for (Int_t j=0; j<AliPID::kSPECIESC; j++) {
+ AliPID::EParticleType type=AliPID::EParticleType(j);
+ const Double_t nsigmas=GetNumberOfSigmasTOFold(track,type) + meanCorrFactor;
+
+ if (TMath::Abs(nsigmas)<5.){
+ const Double_t nsigmasTPC=GetNumberOfSigmasTPC(track,type);
+ if (TMath::Abs(nsigmasTPC)<5.) mismatch=kFALSE;
+ }
+ }
+
+ if (mismatch){
+ return 1.;
+ }
+
+ return 0.;
+}
+
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse:: GetHMPIDPIDStatus(const AliVTrack *track) const
+{
+ // compute HMPID pid status
+
+ Int_t ch = track->GetHMPIDcluIdx()/1000000;
+ Double_t HMPIDsignal = track->GetHMPIDsignal();
+
+ if((track->GetStatus()&AliVTrack::kHMPIDpid)==0 || ch<0 || ch>6 || HMPIDsignal<0) return kDetNoSignal;
+
+ return kDetPidOk;
+}
+
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse:: GetPHOSPIDStatus(const AliVTrack */*track*/) const
+{
+ // compute PHOS pid status
+ return kDetNoSignal;
+}
+
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse:: GetEMCALPIDStatus(const AliVTrack *track) const
+{
+ // compute EMCAL pid status
+
+
+ // Track matching
+ const Int_t nMatchClus = track->GetEMCALcluster();
+ if (nMatchClus<0) return kDetNoSignal;
+
+ AliVCluster *matchedClus = (AliVCluster*)fCurrentEvent->GetCaloCluster(nMatchClus);
+
+ if (!(matchedClus && matchedClus->IsEMCAL())) return kDetNoSignal;
+
+ const Int_t charge = track->Charge();
+ if (TMath::Abs(charge)!=1) return kDetNoSignal;
+
+ if (!(fEMCALPIDParams && fEMCALPIDParams->At(AliPID::kElectron))) return kDetNoParams;
+
+ return kDetPidOk;
+
+}
+
+//______________________________________________________________________________
+AliPIDResponse::EDetPidStatus AliPIDResponse::GetPIDStatus(EDetector detector, const AliVTrack *track) const
+{
+ //
+ // check pid status for a track
+ //
+
+ switch (detector){
+ case kITS: return GetITSPIDStatus(track); break;
+ case kTPC: return GetTPCPIDStatus(track); break;
+ case kTRD: return GetTRDPIDStatus(track); break;
+ case kTOF: return GetTOFPIDStatus(track); break;
+ case kPHOS: return GetPHOSPIDStatus(track); break;
+ case kEMCAL: return GetEMCALPIDStatus(track); break;
+ case kHMPID: return GetHMPIDPIDStatus(track); break;
+ default: return kDetNoSignal;
+ }
+ return kDetNoSignal;
+
+}
+
+//______________________________________________________________________________
+TString AliPIDResponse::GetChecksum(const TObject* obj) const
+{
+ // Return the checksum for an object obj (tested to work properly at least for histograms and TSplines).
+
+ TString fileName = Form("tempChecksum.C"); // File name must be fixed for data type "TSpline3", since the file name will end up in the file content!
+
+ // For parallel processing, a unique file pathname is required. Uniqueness can be guaranteed by using a unique directory name
+ UInt_t index = 0;
+ TString uniquePathName = Form("tempChecksum_%u", index);
+
+ // To get a unique path name, increase the index until no directory
+ // of such a name exists.
+ // NOTE: gSystem->AccessPathName(...) returns kTRUE, if the access FAILED!
+ while (!gSystem->AccessPathName(uniquePathName.Data()))
+ uniquePathName = Form("tempChecksum_%u", ++index);
+
+ if (gSystem->mkdir(uniquePathName.Data()) < 0) {
+ AliError("Could not create temporary directory to store temp file for checksum determination!");
+ return "ERROR";
+ }
+
+ TString option = "";
+
+ // Save object as a macro, which will be deleted immediately after the checksum has been computed
+ // (does not work for desired data types if saved as *.root for some reason) - one only wants to compare the content, not
+ // the modification time etc. ...
+ if (dynamic_cast<const TH1*>(obj))
+ option = "colz"; // Histos need this option, since w/o this option, a counter is added to the filename
+
+
+ // SaveAs must be called with the fixed fileName only, since the first argument goes into the file content
+ // for some object types. Thus, change the directory, save the file and then go back
+ TString oldDir = gSystem->pwd();
+ gSystem->cd(uniquePathName.Data());
+ obj->SaveAs(fileName.Data(), option.Data());
+ gSystem->cd(oldDir.Data());
+
+ // Use the file to calculate the MD5 checksum
+ TMD5* md5 = TMD5::FileChecksum(Form("%s/%s", uniquePathName.Data(), fileName.Data()));
+ TString checksum = md5->AsString();
+
+ // Clean up
+ delete md5;
+ gSystem->Exec(Form("rm -rf %s", uniquePathName.Data()));
+
+ return checksum;
+}