LCOV - code coverage report
Current view: top level - STEER/STEERBase - AliTPCPIDResponse.cxx (source / functions) Hit Total Coverage
Test: coverage.info Lines: 115 796 14.4 %
Date: 2016-06-14 17:26:59 Functions: 15 58 25.9 %

          Line data    Source code
       1             :     /**************************************************************************
       2             :  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
       3             :  *                                                                        *
       4             :  * Author: The ALICE Off-line Project.                                    *
       5             :  * Contributors are mentioned in the code where appropriate.              *
       6             :  *                                                                        *
       7             :  * Permission to use, copy, modify and distribute this software and its   *
       8             :  * documentation strictly for non-commercial purposes is hereby granted   *
       9             :  * without fee, provided that the above copyright notice appears in all   *
      10             :  * copies and that both the copyright notice and this permission notice   *
      11             :  * appear in the supporting documentation. The authors make no claims     *
      12             :  * about the suitability of this software for any purpose. It is          *
      13             :  * provided "as is" without express or implied warranty.                  *
      14             :  **************************************************************************/
      15             : 
      16             : //-----------------------------------------------------------------
      17             : //           Implementation of the TPC PID class
      18             : // Very naive one... Should be made better by the detector experts...
      19             : //      Origin: Iouri Belikov, CERN, Jouri.Belikov@cern.ch
      20             : // With many additions and modifications suggested by
      21             : //      Alexander Kalweit, GSI, alexander.philipp.kalweit@cern.ch
      22             : //      Dariusz Miskowiec, GSI, D.Miskowiec@gsi.de
      23             : //      Jens Wiechula, IKF, Jens.Wiechula@cern.ch
      24             : // ...and some modifications by
      25             : //      Mikolaj Krzewicki, GSI, mikolaj.krzewicki@cern.ch
      26             : // ...and some modifications plus eta correction functions by
      27             : //      Benjamin Hess, University of Tuebingen, bhess@cern.ch
      28             : //-----------------------------------------------------------------
      29             : 
      30             : #include <TGraph.h>
      31             : #include <TError.h>
      32             : #include <TObjArray.h>
      33             : #include <TSpline.h>
      34             : #include <TBits.h>
      35             : #include <TMath.h>
      36             : #include <TH2D.h>
      37             : #include <TSystem.h>
      38             : #include <TMD5.h>
      39             : 
      40             : #include <AliLog.h>
      41             : #include "AliExternalTrackParam.h"
      42             : #include "AliVTrack.h"
      43             : #include "AliTPCPIDResponse.h"
      44             : #include "AliTPCdEdxInfo.h"
      45             : #include "AliOADBContainer.h"
      46             : #include "TFile.h"
      47             : #include "TSpline.h"
      48             : 
      49         176 : ClassImp(AliTPCPIDResponse);
      50             : 
      51             : 
      52             : AliTPCPIDResponse *AliTPCPIDResponse::fgInstance =0;
      53             : 
      54             : const char* AliTPCPIDResponse::fgkGainScenarioName[fgkNumberOfGainScenarios+1]=
      55             : {
      56             :   "", //default - no name
      57             :   "1", //all high
      58             :   "2", //OROC only
      59             :   "unknown"
      60             : };
      61             : 
      62             : //_________________________________________________________________________
      63             : AliTPCPIDResponse::AliTPCPIDResponse():
      64          10 :   TNamed(),
      65          10 :   fMIP(50.),
      66          10 :   fRes0(),
      67          10 :   fResN2(),
      68          10 :   fKp1(0.0283086),
      69          10 :   fKp2(2.63394e+01),
      70          10 :   fKp3(5.04114e-11),
      71          10 :   fKp4(2.12543),
      72          10 :   fKp5(4.88663),
      73          10 :   fUseDatabase(kFALSE),
      74          10 :   fResponseFunctions(fgkNumberOfParticleSpecies*fgkNumberOfGainScenarios),
      75          10 :   fOADBContainer(0x0),
      76          10 :   fVoltageMap(72),
      77          10 :   fLowGainIROCthreshold(-40),
      78          10 :   fBadIROCthreshhold(-70),
      79          10 :   fLowGainOROCthreshold(-40),
      80          10 :   fBadOROCthreshhold(-40),
      81          10 :   fMaxBadLengthFraction(0.5),
      82          10 :   fMagField(0.),
      83          10 :   fhEtaCorr(0x0),
      84          10 :   fhEtaSigmaPar1(0x0),
      85          10 :   fSigmaPar0(0.0),
      86          10 :   fCurrentEventMultiplicity(0),
      87          10 :   fCorrFuncMultiplicity(0x0),
      88          10 :   fCorrFuncMultiplicityTanTheta(0x0),
      89          10 :   fCorrFuncSigmaMultiplicity(0x0),
      90          10 :   fdEdxType(kdEdxTrack),
      91          10 :   fdEdxChargeType(0),
      92          10 :   fdEdxWeightType(0),
      93          10 :   fIROCweight(1.),
      94          10 :   fOROCmedWeight(1.),
      95          10 :   fOROClongWeight(1.),
      96          10 :   fSplineArray()
      97          50 : {
      98             :   //
      99             :   //  The default constructor
     100             :   //
     101             :   
     102          10 :   AliLog::SetClassDebugLevel("AliTPCPIDResponse", AliLog::kInfo); 
     103             :   
     104          80 :   for (Int_t i=0; i<fgkNumberOfGainScenarios; i++) {fRes0[i]=0.07;fResN2[i]=0.0;}
     105             :   
     106          30 :   fCorrFuncMultiplicity = new TF1("fCorrFuncMultiplicity", 
     107             :                                   "[0] + [1]*TMath::Max([4], TMath::Min(x, [3])) + [2] * TMath::Power(TMath::Max([4], TMath::Min(x, [3])), 2)",
     108             :                                   0., 0.2);
     109          30 :   fCorrFuncMultiplicityTanTheta = new TF1("fCorrFuncMultiplicityTanTheta", "[0] * (x - [2]) + [1] * (x * x - [2] * [2])", -1.5, 1.5);
     110          30 :   fCorrFuncSigmaMultiplicity = new TF1("fCorrFuncSigmaMultiplicity",
     111             :                                        "TMath::Max(0.0, [0] + [1]*TMath::Min(x, [3]) + [2] * TMath::Power(TMath::Min(x, [3]), 2))", 0., 0.2);
     112             : 
     113             :   
     114          10 :   ResetMultiplicityCorrectionFunctions();
     115          10 :   fgInstance=this;
     116          20 : }
     117             : /*TODO remove?
     118             : //_________________________________________________________________________
     119             : AliTPCPIDResponse::AliTPCPIDResponse(const Double_t *param):
     120             :   TNamed(),
     121             :   fMIP(param[0]),
     122             :   fRes0(),
     123             :   fResN2(),
     124             :   fKp1(0.0283086),
     125             :   fKp2(2.63394e+01),
     126             :   fKp3(5.04114e-11),
     127             :   fKp4(2.12543),
     128             :   fKp5(4.88663),
     129             :   fUseDatabase(kFALSE),
     130             :   fResponseFunctions(fgkNumberOfParticleSpecies*fgkNumberOfGainScenarios),
     131             :   fVoltageMap(72),
     132             :   fLowGainIROCthreshold(-40),
     133             :   fBadIROCthreshhold(-70),
     134             :   fLowGainOROCthreshold(-40),
     135             :   fBadOROCthreshhold(-40),
     136             :   fMaxBadLengthFraction(0.5),
     137             :   fMagField(0.),
     138             :   fhEtaCorr(0x0),
     139             :   fhEtaSigmaPar1(0x0),
     140             :   fSigmaPar0(0.0)
     141             : {
     142             :   //
     143             :   //  The main constructor
     144             :   //
     145             :   for (Int_t i=0; i<fgkNumberOfGainScenarios; i++) {fRes0[i]=param[1];fResN2[i]=param[2];}
     146             : }
     147             : */
     148             : 
     149             : //_________________________________________________________________________
     150             : AliTPCPIDResponse::~AliTPCPIDResponse()
     151          40 : {
     152             :   //
     153             :   // Destructor
     154             :   //
     155             :   
     156          10 :   delete fhEtaCorr;
     157          10 :   fhEtaCorr = 0x0;
     158             :   
     159          10 :   delete fhEtaSigmaPar1;
     160          10 :   fhEtaSigmaPar1 = 0x0;
     161             :   
     162          20 :   delete fCorrFuncMultiplicity;
     163          10 :   fCorrFuncMultiplicity = 0x0;
     164             :   
     165          20 :   delete fCorrFuncMultiplicityTanTheta;
     166          10 :   fCorrFuncMultiplicityTanTheta = 0x0;
     167             :   
     168          20 :   delete fCorrFuncSigmaMultiplicity;
     169          10 :   fCorrFuncSigmaMultiplicity = 0x0;
     170          20 :   if (fgInstance==this) fgInstance=0;
     171             : 
     172          10 :   delete fOADBContainer;
     173          20 : }
     174             : 
     175             : 
     176             : //_________________________________________________________________________
     177             : AliTPCPIDResponse::AliTPCPIDResponse(const AliTPCPIDResponse& that):
     178           0 :   TNamed(that),
     179           0 :   fMIP(that.fMIP),
     180           0 :   fRes0(),
     181           0 :   fResN2(),
     182           0 :   fKp1(that.fKp1),
     183           0 :   fKp2(that.fKp2),
     184           0 :   fKp3(that.fKp3),
     185           0 :   fKp4(that.fKp4),
     186           0 :   fKp5(that.fKp5),
     187           0 :   fUseDatabase(that.fUseDatabase),
     188           0 :   fResponseFunctions(that.fResponseFunctions),
     189           0 :   fOADBContainer(0x0),
     190           0 :   fVoltageMap(that.fVoltageMap),
     191           0 :   fLowGainIROCthreshold(that.fLowGainIROCthreshold),
     192           0 :   fBadIROCthreshhold(that.fBadIROCthreshhold),
     193           0 :   fLowGainOROCthreshold(that.fLowGainOROCthreshold),
     194           0 :   fBadOROCthreshhold(that.fBadOROCthreshhold),
     195           0 :   fMaxBadLengthFraction(that.fMaxBadLengthFraction),
     196           0 :   fMagField(that.fMagField),
     197           0 :   fhEtaCorr(0x0),
     198           0 :   fhEtaSigmaPar1(0x0),
     199           0 :   fSigmaPar0(that.fSigmaPar0),
     200           0 :   fCurrentEventMultiplicity(that.fCurrentEventMultiplicity),
     201           0 :   fCorrFuncMultiplicity(0x0),
     202           0 :   fCorrFuncMultiplicityTanTheta(0x0),
     203           0 :   fCorrFuncSigmaMultiplicity(0x0),
     204           0 :   fdEdxType(kdEdxTrack),
     205           0 :   fdEdxChargeType(that.fdEdxChargeType),
     206           0 :   fdEdxWeightType(that.fdEdxWeightType),
     207           0 :   fIROCweight(that.fIROCweight),
     208           0 :   fOROCmedWeight(that.fOROCmedWeight),
     209           0 :   fOROClongWeight(that.fOROClongWeight),
     210           0 :   fSplineArray()
     211           0 : {
     212             :   //copy ctor
     213           0 :   for (Int_t i=0; i<fgkNumberOfGainScenarios; i++) {fRes0[i]=that.fRes0[i];fResN2[i]=that.fResN2[i];}
     214             :  
     215             :   // Copy eta maps
     216           0 :   if (that.fhEtaCorr) {
     217           0 :     fhEtaCorr = new TH2D(*(that.fhEtaCorr));
     218           0 :     fhEtaCorr->SetDirectory(0);
     219             :   }
     220             :   
     221           0 :   if (that.fhEtaSigmaPar1) {
     222           0 :     fhEtaSigmaPar1 = new TH2D(*(that.fhEtaSigmaPar1));
     223           0 :     fhEtaSigmaPar1->SetDirectory(0);
     224             :   }
     225             :   
     226             :   // Copy multiplicity correction functions
     227           0 :   if (that.fCorrFuncMultiplicity) {
     228           0 :     fCorrFuncMultiplicity = new TF1(*(that.fCorrFuncMultiplicity));
     229           0 :   }
     230             :   
     231           0 :   if (that.fCorrFuncMultiplicityTanTheta) {
     232           0 :     fCorrFuncMultiplicityTanTheta = new TF1(*(that.fCorrFuncMultiplicityTanTheta));
     233           0 :   }
     234             :   
     235           0 :   if (that.fCorrFuncSigmaMultiplicity) {
     236           0 :     fCorrFuncSigmaMultiplicity = new TF1(*(that.fCorrFuncSigmaMultiplicity));
     237           0 :   }
     238           0 : }
     239             : 
     240             : //_________________________________________________________________________
     241             : AliTPCPIDResponse& AliTPCPIDResponse::operator=(const AliTPCPIDResponse& that)
     242             : {
     243             :   //assignment
     244           0 :   if (&that==this) return *this;
     245           0 :   TNamed::operator=(that);
     246           0 :   fMIP=that.fMIP;
     247           0 :   fKp1=that.fKp1;
     248           0 :   fKp2=that.fKp2;
     249           0 :   fKp3=that.fKp3;
     250           0 :   fKp4=that.fKp4;
     251           0 :   fKp5=that.fKp5;
     252           0 :   fUseDatabase=that.fUseDatabase;
     253           0 :   fResponseFunctions=that.fResponseFunctions;
     254           0 :   fOADBContainer=0x0;
     255           0 :   fVoltageMap=that.fVoltageMap;
     256           0 :   fLowGainIROCthreshold=that.fLowGainIROCthreshold;
     257           0 :   fBadIROCthreshhold=that.fBadIROCthreshhold;
     258           0 :   fLowGainOROCthreshold=that.fLowGainOROCthreshold;
     259           0 :   fBadOROCthreshhold=that.fBadOROCthreshhold;
     260           0 :   fMaxBadLengthFraction=that.fMaxBadLengthFraction;
     261           0 :   fMagField=that.fMagField;
     262           0 :   fCurrentEventMultiplicity=that.fCurrentEventMultiplicity;
     263           0 :   for (Int_t i=0; i<fgkNumberOfGainScenarios; i++) {fRes0[i]=that.fRes0[i];fResN2[i]=that.fResN2[i];}
     264             : 
     265           0 :   delete fhEtaCorr;
     266           0 :   fhEtaCorr=0x0;
     267           0 :   if (that.fhEtaCorr) {
     268           0 :     fhEtaCorr = new TH2D(*(that.fhEtaCorr));
     269           0 :     fhEtaCorr->SetDirectory(0);
     270           0 :   }
     271             :   
     272           0 :   delete fhEtaSigmaPar1;
     273           0 :   fhEtaSigmaPar1=0x0;
     274           0 :   if (that.fhEtaSigmaPar1) {
     275           0 :     fhEtaSigmaPar1 = new TH2D(*(that.fhEtaSigmaPar1));
     276           0 :     fhEtaSigmaPar1->SetDirectory(0);
     277           0 :   }
     278             :   
     279           0 :   fSigmaPar0 = that.fSigmaPar0;
     280             :   
     281           0 :   delete fCorrFuncMultiplicity;
     282           0 :   fCorrFuncMultiplicity = 0x0;
     283           0 :   if (that.fCorrFuncMultiplicity) {
     284           0 :     fCorrFuncMultiplicity = new TF1(*(that.fCorrFuncMultiplicity));
     285           0 :   }
     286             :   
     287           0 :   delete fCorrFuncMultiplicityTanTheta;
     288           0 :   fCorrFuncMultiplicityTanTheta = 0x0;
     289           0 :   if (that.fCorrFuncMultiplicityTanTheta) {
     290           0 :     fCorrFuncMultiplicityTanTheta = new TF1(*(that.fCorrFuncMultiplicityTanTheta));
     291           0 :   }
     292             :   
     293           0 :   delete fCorrFuncSigmaMultiplicity;
     294           0 :   fCorrFuncSigmaMultiplicity = 0x0;
     295           0 :   if (that.fCorrFuncSigmaMultiplicity) {
     296           0 :     fCorrFuncSigmaMultiplicity = new TF1(*(that.fCorrFuncSigmaMultiplicity));
     297           0 :   }
     298             : 
     299           0 :   fdEdxType      =that.fdEdxType;
     300           0 :   fdEdxChargeType=that.fdEdxChargeType;
     301           0 :   fdEdxWeightType=that.fdEdxWeightType;
     302           0 :   fIROCweight    =that.fIROCweight;
     303           0 :   fOROCmedWeight =that.fOROCmedWeight;
     304           0 :   fOROClongWeight=that.fOROClongWeight;
     305             : 
     306           0 :   return *this;
     307           0 : }
     308             : 
     309             : //_________________________________________________________________________
     310             : Double_t AliTPCPIDResponse::Bethe(Double_t betaGamma) const {
     311             :   //
     312             :   // This is the Bethe-Bloch function normalised to 1 at the minimum
     313             :   // WARNING
     314             :   // Simulated and reconstructed Bethe-Bloch differs
     315             :   //           Simulated  curve is the dNprim/dx
     316             :   //           Reconstructed is proportianal dNtot/dx
     317             :   // Temporary fix for production -  Simple linear correction function
     318             :   // Future    2 Bethe Bloch formulas needed
     319             :   //           1. for simulation
     320             :   //           2. for reconstructed PID
     321             :   //
     322             :   
     323             : //   const Float_t kmeanCorrection =0.1;
     324             :   Double_t bb=
     325        4824 :     AliExternalTrackParam::BetheBlochAleph(betaGamma,fKp1,fKp2,fKp3,fKp4,fKp5);
     326        2412 :   return bb*fMIP;
     327             : }
     328             : 
     329             : //_________________________________________________________________________
     330             : void AliTPCPIDResponse::SetBetheBlochParameters(Double_t kp1,
     331             :                              Double_t kp2,
     332             :                              Double_t kp3,
     333             :                              Double_t kp4,
     334             :                              Double_t kp5) {
     335             :   //
     336             :   // Set the parameters of the ALEPH Bethe-Bloch formula
     337             :   //
     338          16 :   fKp1=kp1;
     339           8 :   fKp2=kp2;
     340           8 :   fKp3=kp3;
     341           8 :   fKp4=kp4;
     342           8 :   fKp5=kp5;
     343           8 : }
     344             : 
     345             : //_________________________________________________________________________
     346             : void AliTPCPIDResponse::SetSigma(Float_t res0, Float_t resN2) {
     347             :   //
     348             :   // Set the relative resolution  sigma_rel = res0 * sqrt(1+resN2/npoint)
     349             :   //
     350           0 :   for (Int_t i=0; i<fgkNumberOfGainScenarios; i++) {fRes0[i]=res0;fResN2[i]=resN2;}
     351           0 : }
     352             : 
     353             : //_________________________________________________________________________
     354             : Double_t AliTPCPIDResponse::GetExpectedSignal(Float_t mom,
     355             :                                               AliPID::EParticleType n) const {
     356             :   //
     357             :   // Deprecated function (for backward compatibility). Please use 
     358             :   // GetExpectedSignal(const AliVTrack* track, AliPID::EParticleType species, ETPCdEdxSource dedxSource,
     359             :   //                   Bool_t correctEta, Bool_t correctMultiplicity);
     360             :   // instead!
     361             :   //
     362             :   //
     363             :   // Calculates the expected PID signal as the function of 
     364             :   // the information stored in the track, for the specified particle type 
     365             :   //  
     366             :   // At the moment, these signals are just the results of calling the 
     367             :   // Bethe-Bloch formula. 
     368             :   // This can be improved. By taking into account the number of
     369             :   // assigned clusters and/or the track dip angle, for example.  
     370             :   //
     371             :   
     372             :   //charge factor. BB goes with z^2, however in reality it is slightly larger (calibration, threshold effects, ...)
     373             :   // !!! Splines for light nuclei need to be normalised to this factor !!!
     374           0 :   const Double_t chargeFactor = TMath::Power(AliPID::ParticleCharge(n),2.3);
     375             :   
     376           0 :   Double_t mass=AliPID::ParticleMassZ(n);
     377           0 :   if (!fUseDatabase) return Bethe(mom/mass) * chargeFactor;
     378             :   //
     379           0 :   const TSpline3 * responseFunction = (TSpline3 *) fResponseFunctions.UncheckedAt(n);
     380             : 
     381           0 :   if (!responseFunction) return Bethe(mom/mass) * chargeFactor;
     382             :   
     383           0 :   return fMIP*responseFunction->Eval(mom/mass)*chargeFactor;
     384             : 
     385           0 : }
     386             : 
     387             : //_________________________________________________________________________
     388             : Double_t AliTPCPIDResponse::GetExpectedSigma(Float_t mom, 
     389             :                                              Int_t nPoints,
     390             :                                              AliPID::EParticleType n) const {
     391             :   //
     392             :   // Deprecated function (for backward compatibility). Please use 
     393             :   // GetExpectedSigma(onst AliVTrack* track, AliPID::EParticleType species, 
     394             :   // ETPCdEdxSource dedxSource, Bool_t correctEta) instead!
     395             :   //
     396             :   //
     397             :   // Calculates the expected sigma of the PID signal as the function of 
     398             :   // the information stored in the track, for the specified particle type 
     399             :   //  
     400             :   
     401           0 :   if (nPoints != 0) 
     402           0 :     return GetExpectedSignal(mom,n)*fRes0[0]*sqrt(1. + fResN2[0]/nPoints);
     403             :   else
     404           0 :     return GetExpectedSignal(mom,n)*fRes0[0];
     405           0 : }
     406             : 
     407             : ////////////////////////////////////////////////////NEW//////////////////////////////
     408             : 
     409             : //_________________________________________________________________________
     410             : void AliTPCPIDResponse::SetSigma(Float_t res0, Float_t resN2, ETPCgainScenario gainScenario) {
     411             :   //
     412             :   // Set the relative resolution  sigma_rel = res0 * sqrt(1+resN2/npoint)
     413             :   //
     414           0 :   if ((Int_t)gainScenario>=(Int_t)fgkNumberOfGainScenarios) return; //TODO: better handling!
     415           0 :   fRes0[gainScenario]=res0;
     416           0 :   fResN2[gainScenario]=resN2;
     417           0 : }
     418             : 
     419             : 
     420             : //_________________________________________________________________________
     421             : Double_t AliTPCPIDResponse::GetExpectedSignal(const AliVTrack* track,
     422             :                                               AliPID::EParticleType species,
     423             :                                               Double_t /*dEdx*/,
     424             :                                               const TSpline3* responseFunction,
     425             :                                               Bool_t correctEta,
     426             :                                               Bool_t correctMultiplicity) const 
     427             : {
     428             :   // Calculates the expected PID signal as the function of 
     429             :   // the information stored in the track and the given parameters,
     430             :   // for the specified particle type 
     431             :   //  
     432             :   // At the moment, these signals are just the results of calling the 
     433             :   // Bethe-Bloch formula plus, if desired, taking into account the eta dependence
     434             :   // and the multiplicity dependence (for PbPb). 
     435             :   // This can be improved. By taking into account the number of
     436             :   // assigned clusters and/or the track dip angle, for example.  
     437             :   //
     438             :   
     439        1206 :   Double_t mom=track->GetTPCmomentum();
     440        1206 :   Double_t mass=AliPID::ParticleMassZ(species);
     441             :   
     442             :   //charge factor. BB goes with z^2, however in reality it is slightly larger (calibration, threshold effects, ...)
     443             :   // !!! Splines for light nuclei need to be normalised to this factor !!!
     444        1206 :   const Double_t chargeFactor = TMath::Power(AliPID::ParticleCharge(species),2.3);
     445             :   
     446        1206 :   if (!responseFunction)
     447        1206 :     return Bethe(mom/mass) * chargeFactor;
     448             :   
     449           0 :   Double_t dEdxSplines = fMIP*responseFunction->Eval(mom/mass) * chargeFactor;
     450             :     
     451           0 :   if (!correctEta && !correctMultiplicity)
     452           0 :     return dEdxSplines;
     453             :   
     454             :   Double_t corrFactorEta = 1.0;
     455             :   Double_t corrFactorMultiplicity = 1.0;
     456             :   
     457           0 :   if (correctEta) {
     458           0 :     corrFactorEta = GetEtaCorrectionFast(track, dEdxSplines);
     459             :     //TODO Alternatively take current track dEdx
     460             :     //corrFactorEta = GetEtaCorrectionFast(track, dEdx);
     461           0 :   }
     462             :   
     463           0 :   if (correctMultiplicity)
     464           0 :     corrFactorMultiplicity = GetMultiplicityCorrectionFast(track, dEdxSplines * corrFactorEta, fCurrentEventMultiplicity);
     465             : 
     466           0 :   return dEdxSplines * corrFactorEta * corrFactorMultiplicity;
     467        1206 : }
     468             : 
     469             : 
     470             : //_________________________________________________________________________
     471             : Double_t AliTPCPIDResponse::GetExpectedSignal(const AliVTrack* track,
     472             :                                               AliPID::EParticleType species,
     473             :                                               ETPCdEdxSource dedxSource,
     474             :                                               Bool_t correctEta,
     475             :                                               Bool_t correctMultiplicity) const
     476             : {
     477             :   // Calculates the expected PID signal as the function of 
     478             :   // the information stored in the track, for the specified particle type 
     479             :   //  
     480             :   // At the moment, these signals are just the results of calling the 
     481             :   // Bethe-Bloch formula plus, if desired, taking into account the eta dependence
     482             :   // and the multiplicity dependence (for PbPb). 
     483             :   // This can be improved. By taking into account the number of
     484             :   // assigned clusters and/or the track dip angle, for example.  
     485             :   //
     486             :   
     487        1206 :   if (!fUseDatabase) {
     488             :     //charge factor. BB goes with z^2, however in reality it is slightly larger (calibration, threshold effects, ...)
     489             :     // !!! Splines for light nuclei need to be normalised to this factor !!!
     490        1206 :     const Double_t chargeFactor = TMath::Power(AliPID::ParticleCharge(species),2.3);
     491             :   
     492        1206 :     return Bethe(track->GetTPCmomentum() / AliPID::ParticleMassZ(species)) * chargeFactor;
     493             :   }
     494             :   
     495           0 :   Double_t dEdx = -1;
     496           0 :   Int_t nPoints = -1;
     497           0 :   ETPCgainScenario gainScenario = kGainScenarioInvalid;
     498           0 :   TSpline3* responseFunction = 0x0;
     499             :     
     500           0 :   if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction)) {
     501             :     // Something is wrong with the track -> Return obviously invalid value
     502           0 :     return -999;
     503             :   }
     504             :   
     505             :   // Charge factor already taken into account inside the following function call
     506           0 :   return GetExpectedSignal(track, species, dEdx, responseFunction, correctEta, correctMultiplicity);
     507        1206 : }
     508             :   
     509             : //_________________________________________________________________________
     510             : TSpline3* AliTPCPIDResponse::GetResponseFunction( AliPID::EParticleType type,
     511             :                                                   AliTPCPIDResponse::ETPCgainScenario gainScenario ) const
     512             : {
     513             :   //get response function
     514           0 :   return dynamic_cast<TSpline3*>(fResponseFunctions.At(ResponseFunctionIndex(type,gainScenario)));
     515             : }
     516             : 
     517             : //_________________________________________________________________________
     518             : TSpline3* AliTPCPIDResponse::GetResponseFunction( const AliVTrack* track,
     519             :                                AliPID::EParticleType species,
     520             :                                ETPCdEdxSource dedxSource) const 
     521             : {
     522             :   //the splines are stored in an array, different scenarios
     523             : 
     524           0 :   Double_t dEdx = -1;
     525           0 :   Int_t nPoints = -1;
     526           0 :   ETPCgainScenario gainScenario = kGainScenarioInvalid;
     527           0 :   TSpline3* responseFunction = 0x0;
     528             :   
     529           0 :   if (ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
     530           0 :     return responseFunction;
     531             :   
     532           0 :   return NULL;
     533           0 : }
     534             : 
     535             : //_________________________________________________________________________
     536             : void AliTPCPIDResponse::ResetSplines()
     537             : {
     538             :   //reset the array with splines
     539           0 :   for (Int_t i=0;i<fResponseFunctions.GetEntriesFast();i++)
     540             :   {
     541           0 :     fResponseFunctions.AddAt(NULL,i);
     542             :   }
     543           0 : }
     544             : //_________________________________________________________________________
     545             : Int_t AliTPCPIDResponse::ResponseFunctionIndex( AliPID::EParticleType species,
     546             :                                                 ETPCgainScenario gainScenario ) const
     547             : {
     548             :   //get the index in fResponseFunctions given type and scenario
     549        2412 :   return Int_t(species)+Int_t(gainScenario)*fgkNumberOfParticleSpecies;
     550             : }
     551             : 
     552             : //_________________________________________________________________________
     553             : void AliTPCPIDResponse::SetResponseFunction( TObject* o,
     554             :                                              AliPID::EParticleType species,
     555             :                                              ETPCgainScenario gainScenario )
     556             : {
     557           0 :   fResponseFunctions.AddAtAndExpand(o,ResponseFunctionIndex(species,gainScenario));
     558           0 : }
     559             : 
     560             : 
     561             : //_________________________________________________________________________
     562             : Double_t AliTPCPIDResponse::GetExpectedSigma(const AliVTrack* track, 
     563             :                                              AliPID::EParticleType species,
     564             :                                              ETPCgainScenario gainScenario,
     565             :                                              Double_t dEdx,
     566             :                                              Int_t nPoints,
     567             :                                              const TSpline3* responseFunction,
     568             :                                              Bool_t correctEta,
     569             :                                              Bool_t correctMultiplicity) const 
     570             : {
     571             :   // Calculates the expected sigma of the PID signal as the function of 
     572             :   // the information stored in the track and the given parameters,
     573             :   // for the specified particle type 
     574             :   //
     575             :   
     576             :   //if (!responseFunction)
     577             :     //return 999;
     578             :     
     579             :   //TODO Check whether it makes sense to set correctMultiplicity to kTRUE while correctEta might be kFALSE
     580             :   
     581             :   // If eta correction (=> new sigma parametrisation) is requested, but no sigma map is available, print error message
     582        1206 :   if (correctEta && !fhEtaSigmaPar1) {
     583           0 :     AliError("New sigma parametrisation requested, but sigma map not initialised (usually via AliPIDResponse). Old sigma parametrisation will be used!");
     584           0 :   }
     585             :   
     586             :   // If no sigma map is available or if no eta correction is requested (sigma maps only for corrected eta!), use the old parametrisation
     587        1206 :   if (!fhEtaSigmaPar1 || !correctEta) {  
     588        2412 :     if (nPoints != 0) 
     589        3618 :       return GetExpectedSignal(track, species, dEdx, responseFunction, kFALSE, correctMultiplicity) *
     590        2412 :                fRes0[gainScenario] * sqrt(1. + fResN2[gainScenario]/nPoints);
     591             :     else
     592           0 :       return GetExpectedSignal(track, species, dEdx, responseFunction, kFALSE, correctMultiplicity)*fRes0[gainScenario];
     593             :   }
     594             :     
     595           0 :   if (nPoints > 0) {
     596             :     // Use eta correction (+ eta-dependent sigma)
     597           0 :     Double_t sigmaPar1 = GetSigmaPar1Fast(track, species, dEdx, responseFunction);
     598             :     
     599           0 :     if (correctMultiplicity) {
     600             :       // In addition, take into account multiplicity dependence of mean and sigma of dEdx
     601           0 :       Double_t dEdxExpectedEtaCorrected = GetExpectedSignal(track, species, dEdx, responseFunction, kTRUE, kFALSE);
     602             :       
     603             :       // GetMultiplicityCorrection and GetMultiplicitySigmaCorrection both need the eta corrected dEdxExpected
     604           0 :       Double_t multiplicityCorrFactor = GetMultiplicityCorrectionFast(track, dEdxExpectedEtaCorrected, fCurrentEventMultiplicity);
     605           0 :       Double_t multiplicitySigmaCorrFactor = GetMultiplicitySigmaCorrectionFast(dEdxExpectedEtaCorrected, fCurrentEventMultiplicity);
     606             :       
     607             :       // multiplicityCorrFactor to correct dEdxExpected for multiplicity. In addition: Correction factor for sigma
     608           0 :       return (dEdxExpectedEtaCorrected * multiplicityCorrFactor) 
     609           0 :               * (sqrt(fSigmaPar0 * fSigmaPar0 + sigmaPar1 * sigmaPar1 / nPoints) * multiplicitySigmaCorrFactor);
     610             :     }
     611             :     else {
     612           0 :       return GetExpectedSignal(track, species, dEdx, responseFunction, kTRUE, kFALSE)*
     613           0 :              sqrt(fSigmaPar0 * fSigmaPar0 + sigmaPar1 * sigmaPar1 / nPoints);
     614             :     }
     615             :   }
     616             :   else { 
     617             :     // One should never have/take tracks with 0 dEdx clusters!
     618           0 :     return 999;
     619             :   }
     620        1206 : }
     621             : 
     622             : 
     623             : //_________________________________________________________________________
     624             : Double_t AliTPCPIDResponse::GetExpectedSigma(const AliVTrack* track, 
     625             :                                              AliPID::EParticleType species,
     626             :                                              ETPCdEdxSource dedxSource,
     627             :                                              Bool_t correctEta,
     628             :                                              Bool_t correctMultiplicity) const 
     629             : {
     630             :   // Calculates the expected sigma of the PID signal as the function of 
     631             :   // the information stored in the track, for the specified particle type 
     632             :   // and dedx scenario
     633             :   //
     634             :   
     635        1206 :   Double_t dEdx = -1;
     636        1206 :   Int_t nPoints = -1;
     637        1206 :   ETPCgainScenario gainScenario = kGainScenarioInvalid;
     638        1206 :   TSpline3* responseFunction = 0x0;
     639             :   
     640        1206 :   if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
     641           0 :     return 999; //TODO: better handling!
     642             :   
     643        1206 :   return GetExpectedSigma(track, species, gainScenario, dEdx, nPoints, responseFunction, correctEta, correctMultiplicity);
     644        1206 : }
     645             : 
     646             : 
     647             : //_________________________________________________________________________
     648             : Float_t AliTPCPIDResponse::GetNumberOfSigmas(const AliVTrack* track, 
     649             :                              AliPID::EParticleType species,
     650             :                              ETPCdEdxSource dedxSource,
     651             :                              Bool_t correctEta,
     652             :                              Bool_t correctMultiplicity) const
     653             : {
     654             :   //Calculates the number of sigmas of the PID signal from the expected value
     655             :   //for a given particle species in the presence of multiple gain scenarios
     656             :   //inside the TPC
     657             :   
     658           0 :   Double_t dEdx = -1;
     659           0 :   Int_t nPoints = -1;
     660           0 :   ETPCgainScenario gainScenario = kGainScenarioInvalid;
     661           0 :   TSpline3* responseFunction = 0x0;
     662             :   
     663           0 :   if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
     664           0 :     return -999; //TODO: Better handling!
     665             :     
     666           0 :   Double_t bethe = GetExpectedSignal(track, species, dEdx, responseFunction, correctEta, correctMultiplicity);
     667           0 :   Double_t sigma = GetExpectedSigma(track, species, gainScenario, dEdx, nPoints, responseFunction, correctEta, correctMultiplicity);
     668             :   // 999 will be returned by GetExpectedSigma e.g. in case of 0 dEdx clusters
     669           0 :   if (sigma >= 998) 
     670           0 :     return -999;
     671             :   else
     672           0 :     return (dEdx-bethe)/sigma;
     673           0 : }
     674             : 
     675             : //_________________________________________________________________________
     676             : Float_t AliTPCPIDResponse::GetSignalDelta(const AliVTrack* track,
     677             :                                           AliPID::EParticleType species,
     678             :                                           ETPCdEdxSource dedxSource,
     679             :                                           Bool_t correctEta,
     680             :                                           Bool_t correctMultiplicity,
     681             :                                           Bool_t ratio/*=kFALSE*/)const
     682             : {
     683             :   //Calculates the number of sigmas of the PID signal from the expected value
     684             :   //for a given particle species in the presence of multiple gain scenarios
     685             :   //inside the TPC
     686             : 
     687           0 :   Double_t dEdx = -1;
     688           0 :   Int_t nPoints = -1;
     689           0 :   ETPCgainScenario gainScenario = kGainScenarioInvalid;
     690           0 :   TSpline3* responseFunction = 0x0;
     691             : 
     692           0 :   if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
     693           0 :     return -9999.; //TODO: Better handling!
     694             : 
     695           0 :   const Double_t bethe = GetExpectedSignal(track, species, dEdx, responseFunction, correctEta, correctMultiplicity);
     696             : 
     697             :   Double_t delta=-9999.;
     698           0 :   if (!ratio) delta=dEdx-bethe;
     699           0 :   else if (bethe>1.e-20) delta=dEdx/bethe;
     700             :   
     701           0 :   return delta;
     702           0 : }
     703             : 
     704             : //_________________________________________________________________________
     705             : Bool_t AliTPCPIDResponse::ResponseFunctiondEdxN( const AliVTrack* track, 
     706             :                                                  AliPID::EParticleType species,
     707             :                                                  ETPCdEdxSource dedxSource,
     708             :                                                  Double_t& dEdx,
     709             :                                                  Int_t& nPoints,
     710             :                                                  ETPCgainScenario& gainScenario,
     711             :                                                  TSpline3** responseFunction) const 
     712             : {
     713             :   // Calculates the right parameters for PID
     714             :   //   dEdx parametrization for the proper gain scenario, dEdx 
     715             :   //   and NPoints used for dEdx
     716             :   // based on the track geometry (which chambers it crosses) for the specified particle type 
     717             :   // and preferred source of dedx.
     718             :   // returns true on success
     719             :   
     720             :   
     721        2412 :   if (dedxSource == kdEdxDefault) {
     722             :     // Fast handling for default case. In addition: Keep it simple (don't call additional functions) to
     723             :     // avoid possible bugs
     724             :     
     725             :     // GetTPCsignalTunedOnData will be non-positive, if it has not been set (i.e. in case of MC NOT tuned to data).
     726             :     // If this is the case, just take the normal signal
     727        1206 :     dEdx = track->GetTPCsignalTunedOnData();
     728        1206 :     if (dEdx <= 0) {
     729             : //       dEdx = track->GetTPCsignal();
     730        1206 :       dEdx = GetTrackdEdx(track);
     731        1206 :     }
     732             :     
     733        1206 :     nPoints = track->GetTPCsignalN();
     734        1206 :     gainScenario = kDefault;
     735             :     
     736        1206 :     TObject* obj = fResponseFunctions.UncheckedAt(ResponseFunctionIndex(species,gainScenario));
     737        2412 :     *responseFunction = dynamic_cast<TSpline3*>(obj); //TODO:maybe static cast?
     738             :   
     739             :     return kTRUE;
     740             :   }
     741             :   
     742             :   //TODO Proper handle of tuneMConData for other dEdx sources
     743             :   
     744           0 :   Double32_t signal[4]; //0: IROC, 1: OROC medium, 2:OROC long, 3: OROC all (def. truncation used)
     745           0 :   Char_t ncl[3];        //same
     746           0 :   Char_t nrows[3];      //same
     747           0 :   const AliTPCdEdxInfo* dEdxInfo = track->GetTPCdEdxInfo();
     748             :   
     749           0 :   if (!dEdxInfo && dedxSource!=kdEdxDefault)  //in one case its ok if we dont have the info
     750             :   {
     751           0 :     AliError("AliTPCdEdxInfo not available");
     752           0 :     return kFALSE;
     753             :   }
     754             : 
     755           0 :   if (dEdxInfo) dEdxInfo->GetTPCSignalRegionInfo(signal,ncl,nrows);
     756             : 
     757             :   //check if we cross a bad OROC in which case we reject
     758           0 :   EChamberStatus trackOROCStatus = TrackStatus(track,2);
     759           0 :   if (trackOROCStatus==kChamberOff || trackOROCStatus==kChamberLowGain)
     760             :   {
     761           0 :     return kFALSE;
     762             :   }
     763             : 
     764           0 :   switch (dedxSource)
     765             :   {
     766             :     case kdEdxOROC:
     767             :       {
     768           0 :         if (trackOROCStatus==kChamberInvalid) return kFALSE; //never reached OROC
     769           0 :         dEdx = signal[3];
     770           0 :         nPoints = ncl[2]+ncl[1];
     771           0 :         gainScenario = kOROChigh;
     772           0 :         break;
     773             :       }
     774             :     case kdEdxHybrid:
     775             :       {
     776             :         //if we cross a bad IROC we use OROC dedx, if we dont we use combined
     777           0 :         EChamberStatus status = TrackStatus(track,1);
     778           0 :         if (status!=kChamberHighGain)
     779             :         {
     780           0 :           dEdx = signal[3];
     781           0 :           nPoints = ncl[2]+ncl[1];
     782           0 :           gainScenario = kOROChigh;
     783           0 :         }
     784             :         else
     785             :         {
     786             : //           dEdx = track->GetTPCsignal();
     787           0 :           dEdx = GetTrackdEdx(track);
     788           0 :           nPoints = track->GetTPCsignalN();
     789           0 :           gainScenario = kALLhigh;
     790             :         }
     791             :         break;
     792             :       }
     793             :     default:
     794             :       {
     795           0 :          dEdx = 0.;
     796           0 :          nPoints = 0;
     797           0 :          gainScenario = kGainScenarioInvalid;
     798           0 :          return kFALSE;
     799             :       }
     800             :   }
     801           0 :   TObject* obj = fResponseFunctions.UncheckedAt(ResponseFunctionIndex(species,gainScenario));
     802           0 :   *responseFunction = dynamic_cast<TSpline3*>(obj); //TODO:maybe static cast?
     803             :   
     804             :   return kTRUE;
     805        1206 : }
     806             : 
     807             : 
     808             : //_________________________________________________________________________
     809             : Double_t AliTPCPIDResponse::GetEtaCorrectionFast(const AliVTrack *track, Double_t dEdxSplines) const
     810             : {
     811             :   // NOTE: For expert use only -> Non-experts are advised to use the function without the "Fast" suffix or stick to AliPIDResponse directly.
     812             :   //
     813             :   // Get eta correction for the given parameters.
     814             :   //
     815             :   
     816           0 :   if (!fhEtaCorr) {
     817             :     // Calling this function means to request eta correction in some way. Print error message, if no map is available!
     818           0 :     AliError("Eta correction requested, but map not initialised (usually via AliPIDResponse). Returning eta correction factor 1!");
     819           0 :     return 1.;
     820             :   }
     821             :   
     822             :   Double_t tpcSignal = dEdxSplines;
     823             :   
     824           0 :   if (tpcSignal < 1.)
     825           0 :     return 1.;
     826             :   
     827           0 :   Double_t tanTheta = GetTrackTanTheta(track); 
     828           0 :   Int_t binX = fhEtaCorr->GetXaxis()->FindFixBin(tanTheta);
     829           0 :   Int_t binY = fhEtaCorr->GetYaxis()->FindFixBin(1. / tpcSignal);
     830             :   
     831           0 :   if (binX == 0) 
     832           0 :     binX = 1;
     833           0 :   if (binX > fhEtaCorr->GetXaxis()->GetNbins())
     834           0 :     binX = fhEtaCorr->GetXaxis()->GetNbins();
     835             :   
     836           0 :   if (binY == 0)
     837           0 :     binY = 1;
     838           0 :   if (binY > fhEtaCorr->GetYaxis()->GetNbins())
     839           0 :     binY = fhEtaCorr->GetYaxis()->GetNbins();
     840             :   
     841           0 :   return fhEtaCorr->GetBinContent(binX, binY);
     842           0 : }
     843             : 
     844             : 
     845             : //_________________________________________________________________________
     846             : Double_t AliTPCPIDResponse::GetEtaCorrection(const AliVTrack *track, AliPID::EParticleType species, ETPCdEdxSource dedxSource) const
     847             : {
     848             :   //
     849             :   // Get eta correction for the given track.
     850             :   //
     851             :   
     852           0 :   if (!fhEtaCorr)
     853           0 :     return 1.;
     854             :   
     855           0 :   Double_t dEdx = -1;
     856           0 :   Int_t nPoints = -1;
     857           0 :   ETPCgainScenario gainScenario = kGainScenarioInvalid;
     858           0 :   TSpline3* responseFunction = 0x0;
     859             :   
     860           0 :   if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
     861           0 :     return 1.; 
     862             :   
     863             :   // For the eta correction, do NOT take the multiplicity corrected value of dEdx
     864           0 :   Double_t dEdxSplines = GetExpectedSignal(track, species, dEdx, responseFunction, kFALSE, kFALSE);
     865             :   
     866             :   //TODO Alternatively take current track dEdx
     867             :   //return GetEtaCorrectionFast(track, dEdx);
     868             :   
     869           0 :   return GetEtaCorrectionFast(track, dEdxSplines);
     870           0 : }
     871             : 
     872             : 
     873             : //_________________________________________________________________________
     874             : Double_t AliTPCPIDResponse::GetEtaCorrectedTrackdEdx(const AliVTrack *track, AliPID::EParticleType species, ETPCdEdxSource dedxSource) const
     875             : {
     876             :   //
     877             :   // Get eta corrected dEdx for the given track. For the correction, the expected dEdx of
     878             :   // the specified species will be used. If the species is set to AliPID::kUnknown, the
     879             :   // dEdx of the track is used instead.
     880             :   // WARNING: In the latter case, the eta correction might not be as good as if the
     881             :   // expected dEdx is used, which is the way the correction factor is designed
     882             :   // for.
     883             :   // In any case, one has to decide carefully to which expected signal one wants to
     884             :   // compare the corrected value - to the corrected or uncorrected.
     885             :   // Anyhow, a safer way of looking e.g. at the n-sigma is to call
     886             :   // the corresponding function GetNumberOfSigmas!
     887             :   //
     888             :   
     889           0 :   Double_t dEdx = -1;
     890           0 :   Int_t nPoints = -1;
     891           0 :   ETPCgainScenario gainScenario = kGainScenarioInvalid;
     892           0 :   TSpline3* responseFunction = 0x0;
     893             :   
     894             :   // Note: In case of species == AliPID::kUnknown, the responseFunction might not be set. However, in this case
     895             :   // it is not used anyway, so this causes no trouble.
     896           0 :   if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
     897           0 :     return -1.;
     898             :   
     899             :   Double_t etaCorr = 0.;
     900             :   
     901           0 :   if (species < AliPID::kUnknown) {
     902             :     // For the eta correction, do NOT take the multiplicity corrected value of dEdx
     903           0 :     Double_t dEdxSplines = GetExpectedSignal(track, species, dEdx, responseFunction, kFALSE, kFALSE);
     904           0 :     etaCorr = GetEtaCorrectionFast(track, dEdxSplines);
     905           0 :   }
     906             :   else {
     907           0 :     etaCorr = GetEtaCorrectionFast(track, dEdx);
     908             :   }
     909             :     
     910           0 :   if (etaCorr <= 0)
     911           0 :     return -1.;
     912             :   
     913           0 :   return dEdx / etaCorr; 
     914           0 : }
     915             : 
     916             : 
     917             : //_________________________________________________________________________
     918             : Double_t AliTPCPIDResponse::GetSigmaPar1Fast(const AliVTrack *track, AliPID::EParticleType species, Double_t dEdx,
     919             :                                              const TSpline3* responseFunction) const
     920             : {
     921             :   // NOTE: For expert use only -> Non-experts are advised to use the function without the "Fast" suffix or stick to AliPIDResponse directly.
     922             :   //
     923             :   // Get parameter 1 of sigma parametrisation of TPC dEdx from the histogram for the given track.
     924             :   //
     925             :   
     926           0 :   if (!fhEtaSigmaPar1) {
     927             :     // Calling this function means to request new sigma parametrisation in some way. Print error message, if no map is available!
     928           0 :     AliError("New sigma parametrisation requested, but sigma map not initialised (usually via AliPIDResponse). Returning error value for sigma parameter1 = 999!");
     929           0 :     return 999;
     930             :   }
     931             :   
     932             :   // The sigma maps are created with data sets that are already eta corrected and for which the 
     933             :   // splines have been re-created. Therefore, the value for the lookup needs to be the value of
     934             :   // the splines without any additional eta correction.
     935             :   // NOTE: This is due to the method the maps are created. The track dEdx (not the expected one!)
     936             :   // is corrected to uniquely related a momemtum bin with an expected dEdx, where the expected dEdx
     937             :   // equals the track dEdx for all eta (thanks to the correction and the re-fit of the splines).
     938             :   // Consequently, looking up the uncorrected expected dEdx at a given tanTheta yields the correct
     939             :   // sigma parameter!
     940             :   // Also: It has to be the spline dEdx, since one wants to get the sigma for the assumption(!)
     941             :   // of such a particle, which by assumption then has this dEdx value
     942             :   
     943             :   // For the eta correction, do NOT take the multiplicity corrected value of dEdx
     944           0 :   Double_t dEdxExpected = GetExpectedSignal(track, species, dEdx, responseFunction, kFALSE, kFALSE);
     945             :   
     946           0 :   if (dEdxExpected < 1.)
     947           0 :     return 999;
     948             :   
     949           0 :   Double_t tanTheta = GetTrackTanTheta(track);
     950           0 :   Int_t binX = fhEtaSigmaPar1->GetXaxis()->FindFixBin(tanTheta);
     951           0 :   Int_t binY = fhEtaSigmaPar1->GetYaxis()->FindFixBin(1. / dEdxExpected);
     952             :     
     953           0 :   if (binX == 0) 
     954           0 :     binX = 1;
     955           0 :   if (binX > fhEtaSigmaPar1->GetXaxis()->GetNbins())
     956           0 :     binX = fhEtaSigmaPar1->GetXaxis()->GetNbins();
     957             :     
     958           0 :   if (binY == 0)
     959           0 :     binY = 1;
     960           0 :   if (binY > fhEtaSigmaPar1->GetYaxis()->GetNbins())
     961           0 :     binY = fhEtaSigmaPar1->GetYaxis()->GetNbins();
     962             :     
     963           0 :   return fhEtaSigmaPar1->GetBinContent(binX, binY);
     964           0 : }
     965             : 
     966             : 
     967             : //_________________________________________________________________________
     968             : Double_t AliTPCPIDResponse::GetSigmaPar1(const AliVTrack *track, AliPID::EParticleType species, ETPCdEdxSource dedxSource) const
     969             : {
     970             :   //
     971             :   // Get parameter 1 of sigma parametrisation of TPC dEdx from the histogram for the given track.
     972             :   //
     973             :   
     974           0 :   if (!fhEtaSigmaPar1)
     975           0 :     return 999;
     976             :   
     977           0 :   Double_t dEdx = -1;
     978           0 :   Int_t nPoints = -1;
     979           0 :   ETPCgainScenario gainScenario = kGainScenarioInvalid;
     980           0 :   TSpline3* responseFunction = 0x0;
     981             :   
     982           0 :   if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
     983           0 :     return 999; 
     984             :   
     985           0 :   return GetSigmaPar1Fast(track, species, dEdx, responseFunction);
     986           0 : }
     987             : 
     988             : 
     989             : //_________________________________________________________________________
     990             : Bool_t AliTPCPIDResponse::SetEtaCorrMap(TH2D* hMap)
     991             : {
     992             :   //
     993             :   // Load map for TPC eta correction (a copy is stored and will be deleted automatically).
     994             :   // If hMap is 0x0,the eta correction will be disabled and kFALSE is returned. 
     995             :   // If the map can be set, kTRUE is returned.
     996             :   //
     997             :   
     998           0 :   delete fhEtaCorr;
     999             :   
    1000           0 :   if (!hMap) {
    1001           0 :     fhEtaCorr = 0x0;
    1002             :     
    1003           0 :     return kFALSE;
    1004             :   }
    1005             :   
    1006           0 :   fhEtaCorr = (TH2D*)(hMap->Clone());
    1007           0 :   fhEtaCorr->SetDirectory(0);
    1008             :       
    1009           0 :   return kTRUE;
    1010           0 : }
    1011             : 
    1012             : 
    1013             : //_________________________________________________________________________
    1014             : Bool_t AliTPCPIDResponse::SetSigmaParams(TH2D* hSigmaPar1Map, Double_t sigmaPar0)
    1015             : {
    1016             :   //
    1017             :   // Load map for TPC sigma map (a copy is stored and will be deleted automatically):
    1018             :   // Parameter 1 is stored as a 2D map (1/dEdx vs. tanTheta_local) and parameter 0 is
    1019             :   // a constant. If hSigmaPar1Map is 0x0, the old sigma parametrisation will be used
    1020             :   // (and sigmaPar0 is ignored!) and kFALSE is returned. 
    1021             :   // If the map can be set, sigmaPar0 is also set and kTRUE will be returned.
    1022             :   //
    1023             :   
    1024           0 :   delete fhEtaSigmaPar1;
    1025             :   
    1026           0 :   if (!hSigmaPar1Map) {
    1027           0 :     fhEtaSigmaPar1 = 0x0;
    1028           0 :     fSigmaPar0 = 0.0;
    1029             :     
    1030           0 :     return kFALSE;
    1031             :   }
    1032             :   
    1033           0 :   fhEtaSigmaPar1 = (TH2D*)(hSigmaPar1Map->Clone());
    1034           0 :   fhEtaSigmaPar1->SetDirectory(0);
    1035           0 :   fSigmaPar0 = sigmaPar0;
    1036             :   
    1037           0 :   return kTRUE;
    1038           0 : }
    1039             : 
    1040             : 
    1041             : //_________________________________________________________________________
    1042             : Double_t AliTPCPIDResponse::GetTrackTanTheta(const AliVTrack *track) const
    1043             : {
    1044             :   // Extract the tanTheta from the information available in the AliVTrack
    1045             :   
    1046             :   // For ESD tracks, the local tanTheta could be used (esdTrack->GetInnerParam()->GetTgl()).
    1047             :   // However, this value is not available for AODs and, thus, not for AliVTrack.
    1048             :   // Fortunately, the following formula allows to approximate the local tanTheta with the 
    1049             :   // global theta angle -> This is for by far most of the tracks the same, but gives at
    1050             :   // maybe the percent level differences within +- 0.2 in tanTheta -> Which is still ok.
    1051             :   
    1052             :   /*
    1053             :   const AliExternalTrackParam* innerParam = track->GetInnerParam();
    1054             :   Double_t tanTheta = 0;
    1055             :   if (innerParam) 
    1056             :     tanTheta = innerParam->GetTgl();
    1057             :   else
    1058             :     tanTheta = TMath::Tan(-track->Theta() + TMath::Pi() / 2.0);
    1059             :   
    1060             :   // Constant in formula for B in kGauss (factor 0.1 to convert B from Tesla to kGauss),
    1061             :   // pT in GeV/c (factor c*1e-9 to arrive at GeV/c) and curvature in 1/cm (factor 0.01 to get from m to cm)
    1062             :   const Double_t constant = TMath::C()* 1e-9 * 0.1 * 0.01; 
    1063             :   const Double_t curvature = fMagField * constant / track->Pt(); // in 1./cm
    1064             :   
    1065             :   Double_t averageddzdr = 0.;
    1066             :   Int_t nParts = 0;
    1067             : 
    1068             :   for (Double_t r = 85; r < 245; r++) {
    1069             :     Double_t sinPhiLocal = TMath::Abs(r*curvature*0.5);
    1070             :     
    1071             :     // Cut on |sin(phi)| as during reco
    1072             :     if (TMath::Abs(sinPhiLocal) <= 0.95) {
    1073             :       const Double_t phiLocal = TMath::ASin(sinPhiLocal);
    1074             :       const Double_t tanPhiLocal = TMath::Tan(phiLocal);
    1075             :       
    1076             :       averageddzdr += tanTheta * TMath::Sqrt(1. + tanPhiLocal * tanPhiLocal); 
    1077             :       nParts++;
    1078             :     }
    1079             :   }
    1080             :   
    1081             :   if (nParts > 0)
    1082             :     averageddzdr /= nParts; 
    1083             :   else {
    1084             :     AliError("Problems during determination of dz/dr. Returning pure tanTheta as best estimate!");
    1085             :     return tanTheta;
    1086             :   }
    1087             :   
    1088             :   //printf("pT: %f\nFactor/magField(kGs)/curvature^-1: %f / %f /%f\ntanThetaGlobalFromTheta/tanTheta/Averageddzdr: %f / %f / %f\n\n",
    1089             :   //          track->Pt(), constant, fMagField, 1./curvature, TMath::Tan(-track->Theta() + TMath::Pi() / 2.0), tanTheta, averageddzdr);
    1090             :   
    1091             :   return averageddzdr;
    1092             :   */
    1093             :   
    1094             :   
    1095             :   // Alternatively (in average, the effect is found to be negligable!):
    1096             :   // Take local tanTheta from TPC inner wall, if available (currently only for ESDs available)
    1097             :   //const AliExternalTrackParam* innerParam = track->GetInnerParam();
    1098             :   //if (innerParam) {
    1099             :   //  return innerParam->GetTgl();
    1100             :   //}
    1101             :   
    1102           0 :   return TMath::Tan(-track->Theta() + TMath::Pi() / 2.0);
    1103             : }
    1104             : 
    1105             : 
    1106             : //_________________________________________________________________________
    1107             : Double_t AliTPCPIDResponse::GetMultiplicityCorrectionFast(const AliVTrack *track, Double_t dEdxExpected, Int_t multiplicity) const
    1108             : {
    1109             :   // NOTE: For expert use only -> Non-experts are advised to use the function without the "Fast" suffix or stick to AliPIDResponse directly.
    1110             :   //
    1111             :   // Calculate the multiplicity correction factor for this track for the given multiplicity.
    1112             :   // The parameter dEdxExpected should take into account the eta correction already!
    1113             :   
    1114             :   // Multiplicity depends on pure dEdx. Therefore, correction factor depends indirectly on eta
    1115             :   // => Use eta corrected value for dEdexExpected.
    1116             :   
    1117           0 :   if (dEdxExpected <= 0 || multiplicity <= 0)
    1118           0 :     return 1.0;
    1119             :   
    1120           0 :   const Double_t dEdxExpectedInv = 1. / dEdxExpected;
    1121           0 :   Double_t relSlope = fCorrFuncMultiplicity->Eval(dEdxExpectedInv);
    1122             :   
    1123           0 :   const Double_t tanTheta = GetTrackTanTheta(track);
    1124           0 :   relSlope += fCorrFuncMultiplicityTanTheta->Eval(tanTheta);
    1125             : 
    1126           0 :   return (1. + relSlope * multiplicity);
    1127           0 : }
    1128             : 
    1129             : 
    1130             : //_________________________________________________________________________
    1131             : Double_t AliTPCPIDResponse::GetMultiplicityCorrection(const AliVTrack *track, AliPID::EParticleType species, ETPCdEdxSource dedxSource) const
    1132             : {
    1133             :   //
    1134             :   // Get multiplicity correction for the given track (w.r.t. the multiplicity of the current event)
    1135             :   //
    1136             :   
    1137             :   //TODO Should return error value, if no eta correction is enabled (needs eta correction). OR: Reset correction in case of no eta correction in PIDresponse
    1138             :   
    1139             :   // No correction in case of multiplicity <= 0
    1140           0 :   if (fCurrentEventMultiplicity <= 0)
    1141           0 :     return 1.;
    1142             :   
    1143           0 :   Double_t dEdx = -1;
    1144           0 :   Int_t nPoints = -1;
    1145           0 :   ETPCgainScenario gainScenario = kGainScenarioInvalid;
    1146           0 :   TSpline3* responseFunction = 0x0;
    1147             :   
    1148           0 :   if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
    1149           0 :     return 1.; 
    1150             :   
    1151             :   //TODO Does it make sense to use the multiplicity correction WITHOUT eta correction?! Are the fit parameters still valid?
    1152             :   // To get the expected signal to determine the multiplicity correction, do NOT ask for the multiplicity corrected value (of course)
    1153           0 :   Double_t dEdxExpected = GetExpectedSignal(track, species, dEdx, responseFunction, kTRUE, kFALSE);
    1154             :   
    1155           0 :   return GetMultiplicityCorrectionFast(track, dEdxExpected, fCurrentEventMultiplicity);
    1156           0 : }
    1157             : 
    1158             : 
    1159             : //_________________________________________________________________________
    1160             : Double_t AliTPCPIDResponse::GetMultiplicityCorrectedTrackdEdx(const AliVTrack *track, AliPID::EParticleType species, ETPCdEdxSource dedxSource) const
    1161             : {
    1162             :   //
    1163             :   // Get multiplicity corrected dEdx for the given track. For the correction, the expected dEdx of
    1164             :   // the specified species will be used. If the species is set to AliPID::kUnknown, the
    1165             :   // dEdx of the track is used instead.
    1166             :   // WARNING: In the latter case, the correction might not be as good as if the
    1167             :   // expected dEdx is used, which is the way the correction factor is designed
    1168             :   // for.
    1169             :   // In any case, one has to decide carefully to which expected signal one wants to
    1170             :   // compare the corrected value - to the corrected or uncorrected.
    1171             :   // Anyhow, a safer way of looking e.g. at the n-sigma is to call
    1172             :   // the corresponding function GetNumberOfSigmas!
    1173             :   //
    1174             :   
    1175             :   //TODO Should return error value, if no eta correction is enabled (needs eta correction). OR: Reset correction in case of no eta correction in PIDresponse
    1176             :   
    1177           0 :   Double_t dEdx = -1;
    1178           0 :   Int_t nPoints = -1;
    1179           0 :   ETPCgainScenario gainScenario = kGainScenarioInvalid;
    1180           0 :   TSpline3* responseFunction = 0x0;
    1181             :   
    1182             :   // Note: In case of species == AliPID::kUnknown, the responseFunction might not be set. However, in this case
    1183             :   // it is not used anyway, so this causes no trouble.
    1184           0 :   if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
    1185           0 :     return -1.;
    1186             :   
    1187             :   
    1188             :   // No correction in case of multiplicity <= 0
    1189           0 :   if (fCurrentEventMultiplicity <= 0)
    1190           0 :     return dEdx;
    1191             :   
    1192             :   Double_t multiplicityCorr = 0.;
    1193             :   
    1194             :   // TODO Normally, one should use the eta corrected values in BOTH of the following cases. Does it make sense to use the uncorrected dEdx values?
    1195           0 :   if (species < AliPID::kUnknown) {
    1196             :     // To get the expected signal to determine the multiplicity correction, do NOT ask for the multiplicity corrected value (of course).
    1197             :     // However, one needs the eta corrected value!
    1198           0 :     Double_t dEdxSplines = GetExpectedSignal(track, species, dEdx, responseFunction, kTRUE, kFALSE);
    1199           0 :     multiplicityCorr = GetMultiplicityCorrectionFast(track, dEdxSplines, fCurrentEventMultiplicity);
    1200           0 :   }
    1201             :   else {
    1202             :     // One needs the eta corrected value to determine the multiplicity correction factor!
    1203           0 :     Double_t etaCorr = GetEtaCorrectionFast(track, dEdx);
    1204           0 :     multiplicityCorr = GetMultiplicityCorrectionFast(track, dEdx * etaCorr, fCurrentEventMultiplicity);
    1205             :   }
    1206             :     
    1207           0 :   if (multiplicityCorr <= 0)
    1208           0 :     return -1.;
    1209             :   
    1210           0 :   return dEdx / multiplicityCorr; 
    1211           0 : }
    1212             : 
    1213             : 
    1214             : //_________________________________________________________________________
    1215             : Double_t AliTPCPIDResponse::GetEtaAndMultiplicityCorrectedTrackdEdx(const AliVTrack *track, AliPID::EParticleType species,
    1216             :                                                                     ETPCdEdxSource dedxSource) const
    1217             : {
    1218             :   //
    1219             :   // Get multiplicity and eta corrected dEdx for the given track. For the correction,
    1220             :   // the expected dEdx of the specified species will be used. If the species is set 
    1221             :   // to AliPID::kUnknown, the dEdx of the track is used instead.
    1222             :   // WARNING: In the latter case, the correction might not be as good as if the
    1223             :   // expected dEdx is used, which is the way the correction factor is designed
    1224             :   // for.
    1225             :   // In any case, one has to decide carefully to which expected signal one wants to
    1226             :   // compare the corrected value - to the corrected or uncorrected.
    1227             :   // Anyhow, a safer way of looking e.g. at the n-sigma is to call
    1228             :   // the corresponding function GetNumberOfSigmas!
    1229             :   //
    1230             :   
    1231           0 :   Double_t dEdx = -1;
    1232           0 :   Int_t nPoints = -1;
    1233           0 :   ETPCgainScenario gainScenario = kGainScenarioInvalid;
    1234           0 :   TSpline3* responseFunction = 0x0;
    1235             :   
    1236             :   // Note: In case of species == AliPID::kUnknown, the responseFunction might not be set. However, in this case
    1237             :   // it is not used anyway, so this causes no trouble.
    1238           0 :   if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
    1239           0 :     return -1.;
    1240             :   
    1241             :   Double_t multiplicityCorr = 0.;
    1242             :   Double_t etaCorr = 0.;
    1243             :     
    1244           0 :   if (species < AliPID::kUnknown) {
    1245             :     // To get the expected signal to determine the multiplicity correction, do NOT ask for the multiplicity corrected value (of course)
    1246           0 :     Double_t dEdxSplines = GetExpectedSignal(track, species, dEdx, responseFunction, kFALSE, kFALSE);
    1247           0 :     etaCorr = GetEtaCorrectionFast(track, dEdxSplines);
    1248           0 :     multiplicityCorr = GetMultiplicityCorrectionFast(track, dEdxSplines * etaCorr, fCurrentEventMultiplicity);
    1249           0 :   }
    1250             :   else {
    1251           0 :     etaCorr = GetEtaCorrectionFast(track, dEdx);
    1252           0 :     multiplicityCorr = GetMultiplicityCorrectionFast(track, dEdx * etaCorr, fCurrentEventMultiplicity);
    1253             :   }
    1254             : 
    1255           0 :   if (multiplicityCorr <= 0 || etaCorr <= 0)
    1256           0 :     return -1.;
    1257             : 
    1258           0 :   return dEdx / multiplicityCorr / etaCorr;
    1259           0 : }
    1260             : 
    1261             : 
    1262             : //_________________________________________________________________________
    1263             : Double_t AliTPCPIDResponse::GetMultiplicitySigmaCorrectionFast(Double_t dEdxExpected, Int_t multiplicity) const
    1264             : {
    1265             :   // NOTE: For expert use only -> Non-experts are advised to use the function without the "Fast" suffix or stick to AliPIDResponse directly.
    1266             :   //
    1267             :   // Calculate the multiplicity sigma correction factor for the corresponding expected dEdx and for the given multiplicity.
    1268             :   // The parameter dEdxExpected should take into account the eta correction already!
    1269             : 
    1270             :   // Multiplicity dependence of sigma depends on the real dEdx at zero multiplicity,
    1271             :   // i.e. the eta (only) corrected dEdxExpected value has to be used
    1272             :   // since all maps etc. have been created for ~zero multiplicity
    1273             : 
    1274           0 :   if (dEdxExpected <= 0 || multiplicity <= 0)
    1275           0 :     return 1.0;
    1276             : 
    1277           0 :   Double_t relSigmaSlope = fCorrFuncSigmaMultiplicity->Eval(1. / dEdxExpected);
    1278             : 
    1279           0 :   return (1. + relSigmaSlope * multiplicity);
    1280           0 : }
    1281             : 
    1282             : 
    1283             : //_________________________________________________________________________
    1284             : Double_t AliTPCPIDResponse::GetMultiplicitySigmaCorrection(const AliVTrack *track, AliPID::EParticleType species, ETPCdEdxSource dedxSource) const
    1285             : {
    1286             :   //
    1287             :   // Get multiplicity sigma correction for the given track (w.r.t. the multiplicity of the current event)
    1288             :   //
    1289             : 
    1290             :   //TODO Should return error value, if no eta correction is enabled (needs eta correction). OR: Reset correction in case of no eta correction in PIDresponse
    1291             : 
    1292             :   // No correction in case of multiplicity <= 0
    1293           0 :   if (fCurrentEventMultiplicity <= 0)
    1294           0 :     return 1.;
    1295             : 
    1296           0 :   Double_t dEdx = -1;
    1297           0 :   Int_t nPoints = -1;
    1298           0 :   ETPCgainScenario gainScenario = kGainScenarioInvalid;
    1299           0 :   TSpline3* responseFunction = 0x0;
    1300             : 
    1301           0 :   if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
    1302           0 :     return 1.;
    1303             : 
    1304             :   //TODO Does it make sense to use the multiplicity correction WITHOUT eta correction?! Are the fit parameters still valid?
    1305             :   // To get the expected signal to determine the multiplicity correction, do NOT ask for the multiplicity corrected value (of course)
    1306           0 :   Double_t dEdxExpected = GetExpectedSignal(track, species, dEdx, responseFunction, kTRUE, kFALSE);
    1307             : 
    1308           0 :   return GetMultiplicitySigmaCorrectionFast(dEdxExpected, fCurrentEventMultiplicity);
    1309           0 : }
    1310             : 
    1311             : //_____________________________________________________________________________
    1312             : Double_t AliTPCPIDResponse::GetTrackdEdx(const AliVTrack* track) const
    1313             : {
    1314             :   // get dEdx of the track depending on the selected dEdx type
    1315        2412 :   if (fdEdxType == kdEdxInfo) {
    1316           0 :     const AliTPCdEdxInfo *dEdxInfo = track->GetTPCdEdxInfo();
    1317           0 :     if (dEdxInfo) {
    1318           0 :       return dEdxInfo->GetWeightedMean(fdEdxChargeType, fdEdxWeightType, fIROCweight, fOROCmedWeight, fOROClongWeight);
    1319             :     } else {
    1320           0 :       AliError("Could not find dEdx info, using default signal");
    1321             :     }
    1322           0 :   }
    1323             : 
    1324        1206 :   return track->GetTPCsignal();
    1325        1206 : }
    1326             : 
    1327             : 
    1328             : //_________________________________________________________________________
    1329             : void AliTPCPIDResponse::ResetMultiplicityCorrectionFunctions()
    1330             : {
    1331             :   // Default values: No correction, i.e. overall correction factor should be one
    1332             :   
    1333             :   // This function should always return 0.0, if multcorr disabled
    1334          20 :   fCorrFuncMultiplicity->SetParameter(0, 0.);
    1335          10 :   fCorrFuncMultiplicity->SetParameter(1, 0.);
    1336          10 :   fCorrFuncMultiplicity->SetParameter(2, 0.);
    1337          10 :   fCorrFuncMultiplicity->SetParameter(3, 0.);
    1338          10 :   fCorrFuncMultiplicity->SetParameter(4, 0.);
    1339             :     
    1340             :   // This function should always return 0., if multCorr disabled
    1341          10 :   fCorrFuncMultiplicityTanTheta->SetParameter(0, 0.);
    1342          10 :   fCorrFuncMultiplicityTanTheta->SetParameter(1, 0.);
    1343          10 :   fCorrFuncMultiplicityTanTheta->SetParameter(2, 0.);
    1344             :   
    1345             :   // This function should always return 0.0, if mutlcorr disabled
    1346          10 :   fCorrFuncSigmaMultiplicity->SetParameter(0, 0.);
    1347          10 :   fCorrFuncSigmaMultiplicity->SetParameter(1, 0.);
    1348          10 :   fCorrFuncSigmaMultiplicity->SetParameter(2, 0.);
    1349          10 :   fCorrFuncSigmaMultiplicity->SetParameter(3, 0.);
    1350          10 : }
    1351             : 
    1352             : 
    1353             : //_________________________________________________________________________
    1354             : Bool_t AliTPCPIDResponse::sectorNumbersInOut(Double_t* trackPositionInner,
    1355             :                                              Double_t* trackPositionOuter,
    1356             :                                              Float_t& inphi,
    1357             :                                              Float_t& outphi,
    1358             :                                              Int_t& in,
    1359             :                                              Int_t& out ) const
    1360             : {
    1361             :   //calculate the sector numbers (equivalent to IROC chamber numbers) a track crosses
    1362             :   //for OROC chamber numbers add 36
    1363             :   //returned angles are between (0,2pi)
    1364             : 
    1365           0 :   inphi = TMath::ATan2(trackPositionInner[1],trackPositionInner[0]);
    1366           0 :   outphi = TMath::ATan2(trackPositionOuter[1], trackPositionOuter[0]);
    1367             : 
    1368           0 :   if (inphi<0) {inphi+=TMath::TwoPi();} //because ATan2 gives angles between -pi,pi
    1369           0 :   if (outphi<0) {outphi+=TMath::TwoPi();} //because ATan2 gives angles between -pi,pi
    1370             : 
    1371           0 :   in = sectorNumber(inphi);
    1372           0 :   out = sectorNumber(outphi);
    1373             : 
    1374             :   //for the C side (positive z) offset by 18
    1375           0 :   if (trackPositionInner[2]>0.0)
    1376             :   {
    1377           0 :     in+=18;
    1378           0 :     out+=18;
    1379           0 :   }
    1380           0 :   return kTRUE;
    1381             : }
    1382             : 
    1383             : 
    1384             : //_____________________________________________________________________________
    1385             : Int_t AliTPCPIDResponse::sectorNumber(Double_t phi) const
    1386             : {
    1387             :   //calculate sector number
    1388           0 :   const Float_t width=TMath::TwoPi()/18.;
    1389           0 :   return TMath::Floor(phi/width);
    1390             : }
    1391             : 
    1392             : 
    1393             : //_____________________________________________________________________________
    1394             : void AliTPCPIDResponse::Print(Option_t* /*option*/) const
    1395             : {
    1396             :   //Print info
    1397           0 :   fResponseFunctions.Print();
    1398           0 : }
    1399             : 
    1400             : 
    1401             : //_____________________________________________________________________________
    1402             : AliTPCPIDResponse::EChamberStatus AliTPCPIDResponse::TrackStatus(const AliVTrack* track, Int_t layer) const
    1403             : {
    1404             :   //status of the track: if it crosses any bad chambers return kChamberOff;
    1405             :   //IROC:layer=1, OROC:layer=2
    1406           0 :   if (layer<1 || layer>2) layer=1;
    1407           0 :   Int_t in=0;
    1408           0 :   Int_t out=0;
    1409           0 :   Float_t inphi=0.;
    1410           0 :   Float_t outphi=0.;
    1411           0 :   Float_t innerRadius = (layer==1)?83.0:133.7;
    1412           0 :   Float_t outerRadius = (layer==1)?133.5:247.7;
    1413             : 
    1414             :   /////////////////////////////////////////////////////////////////////////////
    1415             :   //find out where track enters and leaves the layer.
    1416             :   //
    1417           0 :   Double_t trackPositionInner[3];
    1418           0 :   Double_t trackPositionOuter[3];
    1419             :  
    1420             :   //if there is no inner param this could mean we're using the AOD track,
    1421             :   //we still can extrapolate from the vertex - so use those params.
    1422           0 :   const AliExternalTrackParam* ip = track->GetInnerParam();
    1423           0 :   if (ip) track=dynamic_cast<const AliVTrack*>(ip);
    1424             : 
    1425           0 :   Bool_t trackAtInner = track->GetXYZAt(innerRadius, fMagField, trackPositionInner);
    1426           0 :   Bool_t trackAtOuter = track->GetXYZAt(outerRadius, fMagField, trackPositionOuter);
    1427             : 
    1428           0 :   if (!trackAtInner)
    1429             :   {
    1430             :     //if we dont even enter inner radius we do nothing and return invalid
    1431           0 :     inphi=0.0;
    1432           0 :     outphi=0.0;
    1433           0 :     in=0;
    1434           0 :     out=0;
    1435           0 :     return kChamberInvalid;
    1436             :   }
    1437             : 
    1438           0 :   if (!trackAtOuter)
    1439             :   {
    1440             :     //if we don't reach the outer radius check that the apex is indeed within the outer radius and use apex position
    1441           0 :     Bool_t haveApex = TrackApex(track, fMagField, trackPositionOuter);
    1442           0 :     Float_t apexRadius = TMath::Sqrt(trackPositionOuter[0]*trackPositionOuter[0]+trackPositionOuter[1]*trackPositionOuter[1]);
    1443           0 :     if ( haveApex && apexRadius<=outerRadius && apexRadius>innerRadius)
    1444             :     {
    1445             :       //printf("pt: %.2f, apexRadius: %.2f(%s), x: %.2f, y: %.2f\n",track->Pt(),apexRadius,(haveApex)?"OK":"BAD",trackPositionOuter[0],trackPositionOuter[1]);
    1446             :     }
    1447             :     else
    1448             :     {
    1449           0 :       inphi=0.0;
    1450           0 :       outphi=0.0;
    1451           0 :       in=0;
    1452           0 :       out=0;
    1453           0 :       return kChamberInvalid;
    1454             :     }
    1455           0 :   }
    1456             : 
    1457             : 
    1458           0 :   if (!sectorNumbersInOut(trackPositionInner,
    1459             :                           trackPositionOuter,
    1460             :                           inphi,
    1461             :                           outphi,
    1462             :                           in,
    1463           0 :                           out)) return kChamberInvalid;
    1464             : 
    1465             :   /////////////////////////////////////////////////////////////////////////////
    1466             :   //now we have the location of the track we can check
    1467             :   //if it is in a good/bad chamber
    1468             :   //
    1469             :   Bool_t sideA = kTRUE;
    1470             :  
    1471           0 :   if (((in/18)%2==1) && ((out/18)%2==1)) sideA=kFALSE;
    1472             : 
    1473           0 :   in=in%18;
    1474           0 :   out=out%18;
    1475             : 
    1476           0 :   if (TMath::Abs(in-out)>9)
    1477             :   {
    1478           0 :     if (TMath::Max(in,out)==out)
    1479             :     {
    1480             :       Int_t tmp=out;
    1481           0 :       out = in;
    1482           0 :       in = tmp;
    1483           0 :       Float_t tmpphi=outphi;
    1484           0 :       outphi=inphi;
    1485           0 :       inphi=tmpphi;
    1486           0 :     }
    1487           0 :     in-=18;
    1488           0 :     inphi-=TMath::TwoPi();
    1489           0 :   }
    1490             :   else
    1491             :   {
    1492           0 :     if (TMath::Max(in,out)==in)
    1493             :     {
    1494           0 :       Int_t tmp=out;
    1495           0 :       out=in;
    1496           0 :       in=tmp;
    1497           0 :       Float_t tmpphi=outphi;
    1498           0 :       outphi=inphi;
    1499           0 :       inphi=tmpphi;
    1500           0 :     }
    1501             :   }
    1502             : 
    1503             :   Float_t trackLengthInBad = 0.;
    1504             :   Float_t trackLengthInLowGain = 0.;
    1505           0 :   Float_t trackLengthTotal = TMath::Abs(outphi-inphi);
    1506             :   Float_t lengthFractionInBadSectors = 0.;
    1507             : 
    1508           0 :   const Float_t sectorWidth = TMath::TwoPi()/18.;  
    1509             :  
    1510           0 :   for (Int_t i=in; i<=out; i++)
    1511             :   {
    1512             :     int j=i;
    1513           0 :     if (i<0) j+=18;    //correct for the negative values
    1514           0 :     if (!sideA) j+=18; //move to the correct side
    1515             :    
    1516             :     Float_t deltaPhi = 0.;
    1517           0 :     Float_t phiEdge=sectorWidth*i;
    1518           0 :     if (inphi>phiEdge) {deltaPhi=phiEdge+sectorWidth-inphi;}
    1519           0 :     else if ((outphi>=phiEdge) && (outphi<(phiEdge+sectorWidth))) {deltaPhi=outphi-phiEdge;}
    1520             :     else {deltaPhi=sectorWidth;}
    1521             :    
    1522           0 :     Float_t v = fVoltageMap[(layer==1)?(j):(j+36)];
    1523           0 :     if (v<=fBadIROCthreshhold)
    1524             :     {
    1525           0 :       trackLengthInBad+=deltaPhi;
    1526             :       lengthFractionInBadSectors=1.;
    1527           0 :     }
    1528           0 :     if (v<=fLowGainIROCthreshold && v>fBadIROCthreshhold)
    1529             :     {
    1530           0 :       trackLengthInLowGain+=deltaPhi;
    1531             :       lengthFractionInBadSectors=1.;
    1532           0 :     }
    1533             :   }
    1534             : 
    1535             :   //for now low gain and bad (off) chambers are treated equally
    1536           0 :   if (trackLengthTotal>0)
    1537           0 :     lengthFractionInBadSectors = (trackLengthInLowGain+trackLengthInBad)/trackLengthTotal;
    1538             : 
    1539             :   //printf("### side: %s, pt: %.2f, pz: %.2f, in: %i, out: %i, phiIN: %.2f, phiOUT: %.2f, rIN: %.2f, rOUT: %.2f\n",(sideA)?"A":"C",track->Pt(),track->Pz(),in,out,inphi,outphi,innerRadius,outerRadius);
    1540             :  
    1541           0 :   if (lengthFractionInBadSectors>fMaxBadLengthFraction)
    1542             :   {
    1543             :     //printf("%%%%%%%% %s kChamberLowGain\n",(layer==1)?"IROC":"OROC");
    1544           0 :     return kChamberLowGain;
    1545             :   }
    1546             :  
    1547           0 :   return kChamberHighGain;
    1548           0 : }
    1549             : 
    1550             : 
    1551             : //_____________________________________________________________________________
    1552             : Float_t AliTPCPIDResponse::MaxClusterRadius(const AliVTrack* track) const
    1553             : {
    1554             :   //return the radius of the outermost padrow containing a cluster in TPC
    1555             :   //for the track
    1556           0 :   const TBits* clusterMap=track->GetTPCClusterMapPtr();
    1557           0 :   if (!clusterMap) return 0.;
    1558             : 
    1559             :   //from AliTPCParam, radius of first IROC row
    1560             :   const Float_t rfirstIROC = 8.52249984741210938e+01;
    1561             :   const Float_t padrowHeightIROC = 0.75;
    1562             :   const Float_t rfirstOROC0 = 1.35100006103515625e+02;
    1563             :   const Float_t padrowHeightOROC0 = 1.0;
    1564             :   const Float_t rfirstOROC1 = 1.99350006103515625e+02;
    1565             :   const Float_t padrowHeightOROC1 = 1.5;
    1566             : 
    1567             :   Int_t maxPadRow=160;
    1568           0 :   while ((--maxPadRow)>0 && !clusterMap->TestBitNumber(maxPadRow)){}
    1569           0 :   if (maxPadRow>126) return rfirstOROC1+(maxPadRow-126-1)*padrowHeightOROC1;
    1570           0 :   if (maxPadRow>62) return rfirstOROC0+(maxPadRow-62-1)*padrowHeightOROC0;
    1571           0 :   if (maxPadRow>0) return rfirstIROC+(maxPadRow-1)*padrowHeightIROC;
    1572           0 :   return 0.0;
    1573           0 : }
    1574             : 
    1575             : 
    1576             : //_____________________________________________________________________________
    1577             : Bool_t AliTPCPIDResponse::TrackApex(const AliVTrack* track, Float_t magField, Double_t position[3]) const
    1578             : {
    1579             :   //calculate the coordinates of the apex of the track
    1580           0 :   Double_t x[3];
    1581           0 :   track->GetXYZ(x);
    1582           0 :   Double_t p[3];
    1583           0 :   track->GetPxPyPz(p);
    1584           0 :   Double_t r = 1./track->OneOverPt()/0.0299792458/magField; //signed - will determine the direction of b
    1585             :   //printf("b: %.2f, x:%.2f, y:%.2f, pt: %.2f, px:%.2f, py%.2f, r: %.2f\n",magField, x[0],x[1],track->Pt(), p[0],p[1],r);
    1586             :   //find orthogonal vector (Gram-Schmidt)
    1587           0 :   Double_t alpha = (p[0]*x[0] + p[1]*x[1])/(p[0]*p[0] + p[1]*p[1]);
    1588             :   Double_t b[2];
    1589           0 :   b[0]=x[0]-alpha*p[0];
    1590           0 :   b[1]=x[1]-alpha*p[1];
    1591             :  
    1592           0 :   Double_t norm = TMath::Sqrt(b[0]*b[0]+b[1]*b[1]);
    1593           0 :   if (TMath::AreEqualAbs(norm,0.0,1e-10)) return kFALSE;
    1594           0 :   b[0]/=norm;
    1595           0 :   b[1]/=norm;
    1596           0 :   b[0]*=r;
    1597           0 :   b[1]*=r;
    1598           0 :   b[0]+=x[0];
    1599           0 :   b[1]+=x[1];
    1600             :   //printf("center: x:%.2f, y:%.2f\n",b[0],b[1]);
    1601             :  
    1602           0 :   norm = TMath::Sqrt(b[0]*b[0]+b[1]*b[1]);
    1603           0 :   if (TMath::AreEqualAbs(norm,0.0,1e-10)) return kFALSE;
    1604             :  
    1605           0 :   position[0]=b[0]+b[0]*TMath::Abs(r)/norm;
    1606           0 :   position[1]=b[1]+b[1]*TMath::Abs(r)/norm;
    1607           0 :   position[2]=0.;
    1608           0 :   return kTRUE;
    1609           0 : }
    1610             : 
    1611             : Double_t AliTPCPIDResponse::EvaldEdxSpline(Double_t bg,Int_t entry){
    1612             :   //
    1613             :   // Evaluate the dEdx response for given entry
    1614             :   //
    1615           0 :   TSpline * spline = (TSpline*)fSplineArray.At(entry);
    1616           0 :   if (spline) return spline->Eval(bg);
    1617           0 :   return 0;
    1618           0 : }
    1619             : 
    1620             : 
    1621             : Bool_t   AliTPCPIDResponse::RegisterSpline(const char * name, Int_t index){
    1622             :   //
    1623             :   // register spline to be used for drawing comparisons
    1624             :   // 
    1625           0 :   TFile * fTPCBB = TFile::Open("$ALICE_PHYSICS/OADB/COMMON/PID/data/TPCPIDResponse.root");
    1626           0 :   TObjArray  *arrayTPCPID= (TObjArray*)  fTPCBB->Get("TPCPIDResponse");
    1627           0 :   if (fSplineArray.GetEntriesFast()<index) fSplineArray.Expand(index*2);
    1628             :   TSpline3 *spline=0;
    1629           0 :   if (arrayTPCPID){
    1630           0 :     spline = (TSpline3*)arrayTPCPID->FindObject(name);
    1631           0 :     if (spline) fSplineArray.AddAt(spline->Clone(),index);    
    1632             :   }
    1633           0 :   delete arrayTPCPID;
    1634           0 :   delete fTPCBB;
    1635           0 :   return (spline!=0);
    1636             : }
    1637             : 
    1638             : //_____________________________________________________________________________
    1639             : Bool_t AliTPCPIDResponse::InitFromOADB(const Int_t run, const char* pass, const char* oadbFile/*="$ALICE_PHYSICS/OADB/COMMON/PID/data/TPCPIDResponseOADB.root"*/, Bool_t initMultiplicityCorrection/*=kTRUE*/)
    1640             : {
    1641             :   //
    1642             :   //
    1643             :   //
    1644             : 
    1645           0 :   AliInfo(                "----------------------| Initialisation TPC PID Response from OADB |----------------------");
    1646           0 :   AliInfo(TString::Format("----------------------| Run: %d, pass: %-19s |----------------------", run, pass));
    1647           0 :   if (!fOADBContainer) {
    1648           0 :     fOADBContainer = new AliOADBContainer("TPCSplines");
    1649           0 :     fOADBContainer->InitFromFile(oadbFile,"TPCSplines");
    1650           0 :   }
    1651             : 
    1652           0 :   const TString spass(pass);
    1653           0 :   const Int_t passOrig=spass.Atoi();
    1654             :   Int_t passIter=passOrig;
    1655             : 
    1656           0 :   const TObjArray *arr=dynamic_cast<TObjArray*>(fOADBContainer->GetObject(run,"",spass.Data()));
    1657           0 :   while (!arr && --passIter > 0) {
    1658           0 :     TString passCurrent=TString::Format("%d", passIter);
    1659           0 :     arr=dynamic_cast<TObjArray*>(fOADBContainer->GetObject(run,"",passCurrent.Data()));
    1660           0 :   }
    1661             : 
    1662           0 :   if (!arr) {
    1663           0 :     AliError("***** Risk for unreliable TPC PID detected:                      ********");
    1664           0 :     AliError(Form("      could not find a valid OADB object for run %d pass %s", run, pass));
    1665           0 :     AliError(     "      Most probably this is because the PID response for this pass is not available, yet");
    1666           0 :     AliError(     "      Please also check https://twiki.cern.ch/twiki/bin/view/ALICE/TPCSplines");
    1667           0 :     return kFALSE;
    1668             :   }
    1669             : 
    1670           0 :   if (passIter<passOrig) {
    1671           0 :     AliWarning(     "***** Risk for unreliable TPC PID detected:                      ********");
    1672           0 :     AliWarning(Form("      Using splines from a previous pass: %d<%d", passIter, passOrig));
    1673           0 :     AliWarning(     "      Most probably this is because the PID response for this pass has not been extracted, yet");
    1674           0 :     AliWarning(     "      Please also check https://twiki.cern.ch/twiki/bin/view/ALICE/TPCSplines");
    1675             :   }
    1676             : 
    1677             :   //===| Set up of splines |====================================================
    1678             :   // clear response functions and reset spline usage
    1679           0 :   fResponseFunctions.Clear();
    1680           0 :   SetUseDatabase(kFALSE);
    1681             : 
    1682           0 :   const TObjArray *arrSplines = static_cast<TObjArray*>(arr->FindObject("Splines"));
    1683           0 :   if (!arrSplines) {
    1684           0 :     AliError("***** Risk for unreliable TPC PID detected:                      ********");
    1685           0 :     AliError(Form("      could not find array of splines for run %d", run));
    1686           0 :     AliError(     "      This should not happen, plese report");
    1687           0 :     return kFALSE;
    1688             :   }
    1689           0 :   SetSplinesFromArray(arrSplines);
    1690             : 
    1691             :   //===| Set up multiplicity correction |=======================================
    1692           0 :   if (initMultiplicityCorrection) {
    1693           0 :     const TObject *multiplicityCorrection=arr->FindObject("MultiplicityCorrection");
    1694           0 :     if (multiplicityCorrection) {
    1695           0 :       const TString multiplicityData(multiplicityCorrection->GetTitle());
    1696           0 :       const Bool_t res=SetMultiplicityCorrectionFromString(multiplicityData);
    1697           0 :       if (!res) {
    1698           0 :         AliError("Problem setting up multiplicity correction for TPC PID");
    1699             :       }
    1700           0 :     }
    1701           0 :   } else {
    1702           0 :     AliInfo("Multiplicity correction explicitly disabled");
    1703             :   }
    1704             : 
    1705             :   //===| Set up of dEdx type |==================================================
    1706           0 :   const TNamed *dEdxType=static_cast<TNamed*>(arr->FindObject("dEdxType"));
    1707           0 :   if (dEdxType) {
    1708           0 :     const TString dEdxTypeSet(dEdxType->GetTitle());
    1709           0 :     SetdEdxTypeFromString(dEdxTypeSet);
    1710           0 :   }
    1711             : 
    1712             :   //===| resolution parametrisation |===========================================
    1713           0 :   const TNamed *dEdxResolution=static_cast<TNamed*>(arr->FindObject("dEdxResolution"));
    1714           0 :   if (dEdxResolution) {
    1715           0 :     const TString dEdxResolutionString(dEdxResolution->GetTitle());
    1716           0 :     SetdEdxResolutionFromString(dEdxResolutionString);
    1717           0 :   }
    1718             : 
    1719             :   return kTRUE;
    1720           0 : }
    1721             : 
    1722             : //______________________________________________________________________________
    1723             : Bool_t AliTPCPIDResponse::SetSplinesFromArray(const TObjArray* arrSplines)
    1724             : {
    1725             :   // Set up internal spline array from order array of splines 'arrSplines'
    1726             :   // arrSplines is assumes to have the splines for the single particles inc
    1727             :   // the numbered position as given by AliPID::EParticleType
    1728             : 
    1729             :   //---| get default splines for missing species |------------------------------
    1730           0 :   TObject *protonSpline = arrSplines->At(AliPID::kProton  );
    1731           0 :   TObject *pionSpline   = arrSplines->At(AliPID::kPion    );
    1732             : //   TObject *allSpline    = arrSplines->At(AliPID::kSPECIESC);
    1733             : 
    1734             :   //---| set up the spline array |----------------------------------------------
    1735           0 :   for (Int_t ispecie=0; ispecie<AliPID::kSPECIESC; ++ispecie) {
    1736           0 :     TSpline3 *responseFunction = static_cast<TSpline3*>(arrSplines->At(ispecie));
    1737             : 
    1738             :     //---| spline replacement |-------------------------------------------------
    1739             :     //     usually no splines are extracted for muons and light nuclei
    1740             :     //     in case there is no dedicated spline, use the
    1741             :     //     * pion spline for muons and the
    1742             :     //     * proton spline for light nuclei
    1743           0 :     if (!responseFunction) {
    1744           0 :       if (ispecie==Int_t(AliPID::kMuon)) {
    1745           0 :         responseFunction=static_cast<TSpline3*>(pionSpline);
    1746           0 :       } else if (ispecie>Int_t(AliPID::kProton)) {
    1747           0 :         responseFunction=static_cast<TSpline3*>(protonSpline);
    1748           0 :       }
    1749             :     }
    1750             : 
    1751           0 :     if (!responseFunction) {
    1752           0 :       AliError("***** Risk for unreliable TPC PID detected:                      ********");
    1753           0 :       AliError(Form("      No spline found for %s, this should not happen, please report", AliPID::ParticleName(ispecie) ));
    1754           0 :       continue;
    1755             :     }
    1756           0 :     SetUseDatabase(kTRUE);
    1757           0 :     SetResponseFunction((AliPID::EParticleType)ispecie, responseFunction);
    1758           0 :     AliInfo(Form("Adding spline: %d - %s (MD5(spline) = %s)",ispecie,responseFunction->GetName(),
    1759             :                  GetChecksum(responseFunction).Data()));
    1760             : 
    1761           0 :   }
    1762             : 
    1763           0 :   return kTRUE;
    1764           0 : }
    1765             : 
    1766             : //______________________________________________________________________________
    1767             : Bool_t AliTPCPIDResponse::SetMultiplicityCorrectionFromString(const TString& multiplicityData)
    1768             : {
    1769             :   //
    1770             :   //
    1771             :   //
    1772             : 
    1773             :   const TObjArray *arrParameters=0x0;
    1774           0 :   if (!(arrParameters=GetMultiplicityCorrectionArrayFromString(multiplicityData))) {
    1775           0 :     return kFALSE;
    1776             :   }
    1777             : 
    1778           0 :   TString log("Setting multiplicity correction parameters for mean; tan theta; sigma: ");
    1779           0 :   log.Append(multiplicityData);
    1780           0 :   AliInfo(log.Data());
    1781             : 
    1782           0 :   const TObjArray *arrPar1 = static_cast<TObjArray*>(arrParameters->At(0));
    1783           0 :   for (Int_t ipar=0; ipar<arrPar1->GetEntriesFast(); ++ipar) {
    1784           0 :     SetParameterMultiplicityCorrection(ipar, static_cast<TObjString*>(arrPar1->At(ipar))->String().Atof());
    1785             :   }
    1786             : 
    1787           0 :   const TObjArray *arrPar2 = static_cast<TObjArray*>(arrParameters->At(1));
    1788           0 :   for (Int_t ipar=0; ipar<arrPar2->GetEntriesFast(); ++ipar) {
    1789           0 :     SetParameterMultiplicityCorrectionTanTheta(ipar, static_cast<TObjString*>(arrPar2->At(ipar))->String().Atof());
    1790             :   }
    1791             : 
    1792           0 :   const TObjArray *arrPar3 = static_cast<TObjArray*>(arrParameters->At(2));
    1793           0 :   for (Int_t ipar=0; ipar<arrPar3->GetEntriesFast(); ++ipar) {
    1794           0 :     SetParameterMultiplicitySigmaCorrection(ipar, static_cast<TObjString*>(arrPar3->At(ipar))->String().Atof());
    1795             :   }
    1796             : 
    1797           0 :   delete arrParameters;
    1798             :   return kTRUE;
    1799           0 : }
    1800             : 
    1801             : //______________________________________________________________________________
    1802             : TObjArray* AliTPCPIDResponse::GetMultiplicityCorrectionArrayFromString(const TString& corrections)
    1803             : {
    1804             :   // the corrections string is supposed to be in the format
    1805             :   // parMC_0,parMC_1,parMC_2,parMC_3, parMC_4; parMCTT_0,parMCTT_1,parMCTT_2; parMSC_0,parMSC_1,parMSC_2, parMSC_3
    1806             :   // where parMC are the parameters for AliTPCPIDResponse::SetParameterMultiplicityCorrection
    1807             :   // parMCTT are the parameters for AliTPCPIDResponse::SetParameterMultiplicityCorrectionTanTheta
    1808             :   // parMSC are the parameters for AliTPCPIDResponse::SetParameterMultiplicitySigmaCorrection
    1809             : 
    1810             :   const Int_t nSets=3;
    1811             :   const Int_t nPars[nSets]={5,3,4};
    1812             : 
    1813           0 :   AliTPCPIDResponse temp;
    1814           0 :   TObjArray *arrCorrectionSets = corrections.Tokenize(";");
    1815           0 :   if (arrCorrectionSets->GetEntriesFast() != nSets){
    1816           0 :     temp.Error("AliTPCPIDResponse::CheckMultiplicityCorrectionString","Number of parameter sets not equal to %d. Please read documentation of this function", nSets);
    1817           0 :     delete arrCorrectionSets;
    1818           0 :     return 0x0;
    1819             :   }
    1820             : 
    1821           0 :   for (Int_t iset=0 ;iset<nSets; ++iset) {
    1822           0 :     TObjString *string=(TObjString*)arrCorrectionSets->RemoveAt(iset);
    1823           0 :     TObjArray *arrTmp=string->String().Tokenize(",");
    1824           0 :     delete string;
    1825             :     string=0x0;
    1826             : 
    1827           0 :     if (arrTmp->GetEntriesFast() != nPars[iset]){
    1828           0 :       temp.Error("AliTPCPIDResponse::CheckMultiplicityCorrectionString","Number of parameters in set %d not equal to %d. Please read documentation of this function", iset, nPars[iset]);
    1829           0 :       delete arrCorrectionSets;
    1830           0 :       delete arrTmp;
    1831           0 :       return 0x0;
    1832             :     }
    1833             : 
    1834           0 :     arrCorrectionSets->AddAt(arrTmp, iset);
    1835           0 :   }
    1836             : 
    1837           0 :   return arrCorrectionSets;
    1838           0 : }
    1839             : 
    1840             : //______________________________________________________________________________
    1841             : Bool_t AliTPCPIDResponse::SetdEdxTypeFromString(const TString& dEdxTypeSet)
    1842             : {
    1843             :   // Set up the dEdx usage parsing dEdxTypeSet
    1844             :   // 6 comma separated values are expected.
    1845             :   //
    1846             :   // The format assumes is:
    1847             :   // 0: dEdxType           (AliTPCPIDResponse::ETPCdEdxType)
    1848             :   // 1: dEdxChargeType     (qTot, qMax)
    1849             :   // 2: dEdxWeightType     (0-measured pid clusters, 1-measured pid clusters + subThreshold clusters)
    1850             :   // 3: dEdxIROCweight     (specific weight for IROC)
    1851             :   // 4: dEdxOROCmedWeight  (specific weight for OROC medium pads)
    1852             :   // 5: dEdxOROClongWeight (specific weight for OROC long pads)
    1853           0 :   TObjArray *arrParams = dEdxTypeSet.Tokenize(",");
    1854             : 
    1855             :   Bool_t retVal=kFALSE;
    1856             : 
    1857           0 :   if (arrParams->GetEntriesFast() == 6) {
    1858           0 :     const Int_t    dEdxType           = ((TObjString*)arrParams->At(0))->String().Atoi();
    1859           0 :     const Int_t    dEdxChargeType     = ((TObjString*)arrParams->At(1))->String().Atoi();
    1860           0 :     const Int_t    dEdxWeightType     = ((TObjString*)arrParams->At(2))->String().Atoi();
    1861           0 :     const Double_t dEdxIROCweight     = ((TObjString*)arrParams->At(3))->String().Atof();
    1862           0 :     const Double_t dEdxOROCmedWeight  = ((TObjString*)arrParams->At(4))->String().Atof();
    1863           0 :     const Double_t dEdxOROClongWeight = ((TObjString*)arrParams->At(5))->String().Atof();
    1864           0 :     SetdEdxType((AliTPCPIDResponse::ETPCdEdxType)dEdxType, dEdxChargeType, dEdxWeightType, dEdxIROCweight, dEdxOROCmedWeight, dEdxOROClongWeight);
    1865           0 :     AliInfo(TString::Format("Setting custom TPC dEdxType: %d, %d, %d, %.2f, %.2f, %.2f",
    1866             :                             dEdxType, dEdxChargeType, dEdxWeightType, dEdxIROCweight, dEdxOROCmedWeight, dEdxOROClongWeight));
    1867             :     retVal=kTRUE;
    1868           0 :   } else {
    1869           0 :     AliError("Wrong number of parameters for custom TPC dEdxType");
    1870             :   }
    1871           0 :   delete arrParams;
    1872             : 
    1873           0 :   return retVal;
    1874           0 : }
    1875             : 
    1876             : //______________________________________________________________________________
    1877             : Bool_t AliTPCPIDResponse::SetdEdxResolutionFromString(const TString& dEdxResolutionString)
    1878             : {
    1879             :   // Set up the dEdx resolution parsing dEdxResolutionString
    1880             :   // 2 comma separated values are expected to describe the relative resolution
    1881             :   // if resN2=0 no dependence on the number of clusters will be described
    1882             :   // sigma_rel = res0 * sqrt(1+resN2/npoint)
    1883             :   //
    1884             :   // The format assumes is:
    1885             :   // 0: res0
    1886             :   // 1: resN2
    1887           0 :   TObjArray *arrParams = dEdxResolutionString.Tokenize(",");
    1888             : 
    1889             :   Bool_t retVal=kFALSE;
    1890             : 
    1891           0 :   if (arrParams->GetEntriesFast() == 2) {
    1892           0 :     const Float_t    res0  = ((TObjString*)arrParams->At(0))->String().Atoi();
    1893           0 :     const Float_t    resN2 = ((TObjString*)arrParams->At(1))->String().Atoi();
    1894           0 :     AliInfo(TString::Format("Setting custom TPC dEdxResolution: %.2f, %.2f",
    1895             :                             fRes0[0], fResN2[0]));
    1896           0 :     fRes0 [0]=res0;
    1897           0 :     fResN2[0]=resN2;
    1898             :     retVal=kTRUE;
    1899           0 :   } else {
    1900           0 :     AliError("Wrong number of parameters for custom TPC dEdxResolution");
    1901             :   }
    1902           0 :   delete arrParams;
    1903             : 
    1904           0 :   return retVal;
    1905           0 : }
    1906             : 
    1907             : //______________________________________________________________________________
    1908             : TString AliTPCPIDResponse::GetChecksum(const TObject* obj)
    1909             : {
    1910             :   // Return the checksum for an object obj (tested to work properly at least for histograms and TSplines).
    1911             : 
    1912           0 :   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!
    1913             : 
    1914             :   // For parallel processing, a unique file pathname is required. Uniqueness can be guaranteed by using a unique directory name
    1915             :   UInt_t index = 0;
    1916           0 :   TString uniquePathName = Form("tempChecksum_%u", index);
    1917             : 
    1918             :   // To get a unique path name, increase the index until no directory
    1919             :   // of such a name exists.
    1920             :   // NOTE: gSystem->AccessPathName(...) returns kTRUE, if the access FAILED!
    1921           0 :   while (!gSystem->AccessPathName(uniquePathName.Data()))
    1922           0 :     uniquePathName = Form("tempChecksum_%u", ++index);
    1923             : 
    1924           0 :   AliTPCPIDResponse temp;
    1925           0 :   if (gSystem->mkdir(uniquePathName.Data()) < 0) {
    1926           0 :     temp.Error("AliTPCPIDResponse::GetChecksum","Could not create temporary directory to store temp file for checksum determination!");
    1927           0 :     return "ERROR";
    1928             :   }
    1929             : 
    1930           0 :   TString option = "";
    1931             : 
    1932             :   // Save object as a macro, which will be deleted immediately after the checksum has been computed
    1933             :   // (does not work for desired data types if saved as *.root for some reason) - one only wants to compare the content, not
    1934             :   // the modification time etc. ...
    1935           0 :   if (dynamic_cast<const TH1*>(obj)) {
    1936           0 :     option = "colz"; // Histos need this option, since w/o this option, a counter is added to the filename
    1937             :   }
    1938             : 
    1939             : 
    1940             :   // SaveAs must be called with the fixed fileName only, since the first argument goes into the file content
    1941             :   // for some object types. Thus, change the directory, save the file and then go back
    1942           0 :   TString oldDir = gSystem->pwd();
    1943           0 :   gSystem->cd(uniquePathName.Data());
    1944           0 :   obj->SaveAs(fileName.Data(), option.Data());
    1945           0 :   gSystem->cd(oldDir.Data());
    1946             : 
    1947             :   // Use the file to calculate the MD5 checksum
    1948           0 :   TMD5* md5 = TMD5::FileChecksum(Form("%s/%s", uniquePathName.Data(), fileName.Data()));
    1949           0 :   TString checksum = md5->AsString();
    1950             : 
    1951             :   // Clean up
    1952           0 :   delete md5;
    1953           0 :   gSystem->Exec(Form("rm -rf %s", uniquePathName.Data()));
    1954             : 
    1955           0 :   return checksum;
    1956           0 : }

Generated by: LCOV version 1.11