1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
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 // ...and some modifications by
24 // Mikolaj Krzewicki, GSI, mikolaj.krzewicki@cern.ch
25 // ...and some modifications plus eta correction functions by
26 // Benjamin Hess, University of Tuebingen, bhess@cern.ch
27 //-----------------------------------------------------------------
30 #include <TObjArray.h>
37 #include "AliExternalTrackParam.h"
38 #include "AliVTrack.h"
39 #include "AliTPCPIDResponse.h"
40 #include "AliTPCdEdxInfo.h"
44 ClassImp(AliTPCPIDResponse);
47 AliTPCPIDResponse *AliTPCPIDResponse::fgInstance =0;
49 const char* AliTPCPIDResponse::fgkGainScenarioName[fgkNumberOfGainScenarios+1]=
51 "", //default - no name
57 //_________________________________________________________________________
58 AliTPCPIDResponse::AliTPCPIDResponse():
69 fResponseFunctions(fgkNumberOfParticleSpecies*fgkNumberOfGainScenarios),
71 fLowGainIROCthreshold(-40),
72 fBadIROCthreshhold(-70),
73 fLowGainOROCthreshold(-40),
74 fBadOROCthreshhold(-40),
75 fMaxBadLengthFraction(0.5),
80 fCurrentEventMultiplicity(0),
81 fCorrFuncMultiplicity(0x0),
82 fCorrFuncMultiplicityTanTheta(0x0),
83 fCorrFuncSigmaMultiplicity(0x0),
87 // The default constructor
90 AliLog::SetClassDebugLevel("AliTPCPIDResponse", AliLog::kInfo);
92 for (Int_t i=0; i<fgkNumberOfGainScenarios; i++) {fRes0[i]=0.07;fResN2[i]=0.0;}
94 fCorrFuncMultiplicity = new TF1("fCorrFuncMultiplicity",
95 "[0] + [1]*TMath::Max([4], TMath::Min(x, [3])) + [2] * TMath::Power(TMath::Max([4], TMath::Min(x, [3])), 2)",
97 fCorrFuncMultiplicityTanTheta = new TF1("fCorrFuncMultiplicityTanTheta", "[0] * (x - [2]) + [1] * (x * x - [2] * [2])", -1.5, 1.5);
98 fCorrFuncSigmaMultiplicity = new TF1("fCorrFuncSigmaMultiplicity",
99 "TMath::Max(0, [0] + [1]*TMath::Min(x, [3]) + [2] * TMath::Power(TMath::Min(x, [3]), 2))", 0., 0.2);
102 ResetMultiplicityCorrectionFunctions();
106 //_________________________________________________________________________
107 AliTPCPIDResponse::AliTPCPIDResponse(const Double_t *param):
117 fUseDatabase(kFALSE),
118 fResponseFunctions(fgkNumberOfParticleSpecies*fgkNumberOfGainScenarios),
120 fLowGainIROCthreshold(-40),
121 fBadIROCthreshhold(-70),
122 fLowGainOROCthreshold(-40),
123 fBadOROCthreshhold(-40),
124 fMaxBadLengthFraction(0.5),
131 // The main constructor
133 for (Int_t i=0; i<fgkNumberOfGainScenarios; i++) {fRes0[i]=param[1];fResN2[i]=param[2];}
137 //_________________________________________________________________________
138 AliTPCPIDResponse::~AliTPCPIDResponse()
147 delete fhEtaSigmaPar1;
148 fhEtaSigmaPar1 = 0x0;
150 delete fCorrFuncMultiplicity;
151 fCorrFuncMultiplicity = 0x0;
153 delete fCorrFuncMultiplicityTanTheta;
154 fCorrFuncMultiplicityTanTheta = 0x0;
156 delete fCorrFuncSigmaMultiplicity;
157 fCorrFuncSigmaMultiplicity = 0x0;
158 if (fgInstance==this) fgInstance=0;
162 //_________________________________________________________________________
163 AliTPCPIDResponse::AliTPCPIDResponse(const AliTPCPIDResponse& that):
173 fUseDatabase(that.fUseDatabase),
174 fResponseFunctions(that.fResponseFunctions),
175 fVoltageMap(that.fVoltageMap),
176 fLowGainIROCthreshold(that.fLowGainIROCthreshold),
177 fBadIROCthreshhold(that.fBadIROCthreshhold),
178 fLowGainOROCthreshold(that.fLowGainOROCthreshold),
179 fBadOROCthreshhold(that.fBadOROCthreshhold),
180 fMaxBadLengthFraction(that.fMaxBadLengthFraction),
181 fMagField(that.fMagField),
184 fSigmaPar0(that.fSigmaPar0),
185 fCurrentEventMultiplicity(that.fCurrentEventMultiplicity),
186 fCorrFuncMultiplicity(0x0),
187 fCorrFuncMultiplicityTanTheta(0x0),
188 fCorrFuncSigmaMultiplicity(0x0),
192 for (Int_t i=0; i<fgkNumberOfGainScenarios; i++) {fRes0[i]=that.fRes0[i];fResN2[i]=that.fResN2[i];}
195 if (that.fhEtaCorr) {
196 fhEtaCorr = new TH2D(*(that.fhEtaCorr));
197 fhEtaCorr->SetDirectory(0);
200 if (that.fhEtaSigmaPar1) {
201 fhEtaSigmaPar1 = new TH2D(*(that.fhEtaSigmaPar1));
202 fhEtaSigmaPar1->SetDirectory(0);
205 // Copy multiplicity correction functions
206 if (that.fCorrFuncMultiplicity) {
207 fCorrFuncMultiplicity = new TF1(*(that.fCorrFuncMultiplicity));
210 if (that.fCorrFuncMultiplicityTanTheta) {
211 fCorrFuncMultiplicityTanTheta = new TF1(*(that.fCorrFuncMultiplicityTanTheta));
214 if (that.fCorrFuncSigmaMultiplicity) {
215 fCorrFuncSigmaMultiplicity = new TF1(*(that.fCorrFuncSigmaMultiplicity));
219 //_________________________________________________________________________
220 AliTPCPIDResponse& AliTPCPIDResponse::operator=(const AliTPCPIDResponse& that)
223 if (&that==this) return *this;
224 TNamed::operator=(that);
231 fUseDatabase=that.fUseDatabase;
232 fResponseFunctions=that.fResponseFunctions;
233 fVoltageMap=that.fVoltageMap;
234 fLowGainIROCthreshold=that.fLowGainIROCthreshold;
235 fBadIROCthreshhold=that.fBadIROCthreshhold;
236 fLowGainOROCthreshold=that.fLowGainOROCthreshold;
237 fBadOROCthreshhold=that.fBadOROCthreshhold;
238 fMaxBadLengthFraction=that.fMaxBadLengthFraction;
239 fMagField=that.fMagField;
240 fCurrentEventMultiplicity=that.fCurrentEventMultiplicity;
241 for (Int_t i=0; i<fgkNumberOfGainScenarios; i++) {fRes0[i]=that.fRes0[i];fResN2[i]=that.fResN2[i];}
245 if (that.fhEtaCorr) {
246 fhEtaCorr = new TH2D(*(that.fhEtaCorr));
247 fhEtaCorr->SetDirectory(0);
250 delete fhEtaSigmaPar1;
252 if (that.fhEtaSigmaPar1) {
253 fhEtaSigmaPar1 = new TH2D(*(that.fhEtaSigmaPar1));
254 fhEtaSigmaPar1->SetDirectory(0);
257 fSigmaPar0 = that.fSigmaPar0;
259 delete fCorrFuncMultiplicity;
260 fCorrFuncMultiplicity = 0x0;
261 if (that.fCorrFuncMultiplicity) {
262 fCorrFuncMultiplicity = new TF1(*(that.fCorrFuncMultiplicity));
265 delete fCorrFuncMultiplicityTanTheta;
266 fCorrFuncMultiplicityTanTheta = 0x0;
267 if (that.fCorrFuncMultiplicityTanTheta) {
268 fCorrFuncMultiplicityTanTheta = new TF1(*(that.fCorrFuncMultiplicityTanTheta));
271 delete fCorrFuncSigmaMultiplicity;
272 fCorrFuncSigmaMultiplicity = 0x0;
273 if (that.fCorrFuncSigmaMultiplicity) {
274 fCorrFuncSigmaMultiplicity = new TF1(*(that.fCorrFuncSigmaMultiplicity));
280 //_________________________________________________________________________
281 Double_t AliTPCPIDResponse::Bethe(Double_t betaGamma) const {
283 // This is the Bethe-Bloch function normalised to 1 at the minimum
285 // Simulated and reconstructed Bethe-Bloch differs
286 // Simulated curve is the dNprim/dx
287 // Reconstructed is proportianal dNtot/dx
288 // Temporary fix for production - Simple linear correction function
289 // Future 2 Bethe Bloch formulas needed
291 // 2. for reconstructed PID
294 // const Float_t kmeanCorrection =0.1;
296 AliExternalTrackParam::BetheBlochAleph(betaGamma,fKp1,fKp2,fKp3,fKp4,fKp5);
300 //_________________________________________________________________________
301 void AliTPCPIDResponse::SetBetheBlochParameters(Double_t kp1,
307 // Set the parameters of the ALEPH Bethe-Bloch formula
316 //_________________________________________________________________________
317 void AliTPCPIDResponse::SetSigma(Float_t res0, Float_t resN2) {
319 // Set the relative resolution sigma_rel = res0 * sqrt(1+resN2/npoint)
321 for (Int_t i=0; i<fgkNumberOfGainScenarios; i++) {fRes0[i]=res0;fResN2[i]=resN2;}
324 //_________________________________________________________________________
325 Double_t AliTPCPIDResponse::GetExpectedSignal(Float_t mom,
326 AliPID::EParticleType n) const {
328 // Deprecated function (for backward compatibility). Please use
329 // GetExpectedSignal(const AliVTrack* track, AliPID::EParticleType species, ETPCdEdxSource dedxSource,
330 // Bool_t correctEta, Bool_t correctMultiplicity);
334 // Calculates the expected PID signal as the function of
335 // the information stored in the track, for the specified particle type
337 // At the moment, these signals are just the results of calling the
338 // Bethe-Bloch formula.
339 // This can be improved. By taking into account the number of
340 // assigned clusters and/or the track dip angle, for example.
343 //charge factor. BB goes with z^2, however in reality it is slightly larger (calibration, threshold effects, ...)
344 // !!! Splines for light nuclei need to be normalised to this factor !!!
345 const Double_t chargeFactor = TMath::Power(AliPID::ParticleCharge(n),2.3);
347 Double_t mass=AliPID::ParticleMassZ(n);
348 if (!fUseDatabase) return Bethe(mom/mass) * chargeFactor;
350 const TSpline3 * responseFunction = (TSpline3 *) fResponseFunctions.UncheckedAt(n);
352 if (!responseFunction) return Bethe(mom/mass) * chargeFactor;
354 return fMIP*responseFunction->Eval(mom/mass)*chargeFactor;
358 //_________________________________________________________________________
359 Double_t AliTPCPIDResponse::GetExpectedSigma(Float_t mom,
361 AliPID::EParticleType n) const {
363 // Deprecated function (for backward compatibility). Please use
364 // GetExpectedSigma(onst AliVTrack* track, AliPID::EParticleType species,
365 // ETPCdEdxSource dedxSource, Bool_t correctEta) instead!
368 // Calculates the expected sigma of the PID signal as the function of
369 // the information stored in the track, for the specified particle type
373 return GetExpectedSignal(mom,n)*fRes0[0]*sqrt(1. + fResN2[0]/nPoints);
375 return GetExpectedSignal(mom,n)*fRes0[0];
378 ////////////////////////////////////////////////////NEW//////////////////////////////
380 //_________________________________________________________________________
381 void AliTPCPIDResponse::SetSigma(Float_t res0, Float_t resN2, ETPCgainScenario gainScenario) {
383 // Set the relative resolution sigma_rel = res0 * sqrt(1+resN2/npoint)
385 if ((Int_t)gainScenario>=(Int_t)fgkNumberOfGainScenarios) return; //TODO: better handling!
386 fRes0[gainScenario]=res0;
387 fResN2[gainScenario]=resN2;
391 //_________________________________________________________________________
392 Double_t AliTPCPIDResponse::GetExpectedSignal(const AliVTrack* track,
393 AliPID::EParticleType species,
395 const TSpline3* responseFunction,
397 Bool_t correctMultiplicity) const
399 // Calculates the expected PID signal as the function of
400 // the information stored in the track and the given parameters,
401 // for the specified particle type
403 // At the moment, these signals are just the results of calling the
404 // Bethe-Bloch formula plus, if desired, taking into account the eta dependence
405 // and the multiplicity dependence (for PbPb).
406 // This can be improved. By taking into account the number of
407 // assigned clusters and/or the track dip angle, for example.
410 Double_t mom=track->GetTPCmomentum();
411 Double_t mass=AliPID::ParticleMassZ(species);
413 //charge factor. BB goes with z^2, however in reality it is slightly larger (calibration, threshold effects, ...)
414 // !!! Splines for light nuclei need to be normalised to this factor !!!
415 const Double_t chargeFactor = TMath::Power(AliPID::ParticleCharge(species),2.3);
417 if (!responseFunction)
418 return Bethe(mom/mass) * chargeFactor;
420 Double_t dEdxSplines = fMIP*responseFunction->Eval(mom/mass) * chargeFactor;
422 if (!correctEta && !correctMultiplicity)
425 Double_t corrFactorEta = 1.0;
426 Double_t corrFactorMultiplicity = 1.0;
429 corrFactorEta = GetEtaCorrectionFast(track, dEdxSplines);
430 //TODO Alternatively take current track dEdx
431 //corrFactorEta = GetEtaCorrectionFast(track, dEdx);
434 if (correctMultiplicity)
435 corrFactorMultiplicity = GetMultiplicityCorrectionFast(track, dEdxSplines * corrFactorEta, fCurrentEventMultiplicity);
437 return dEdxSplines * corrFactorEta * corrFactorMultiplicity;
441 //_________________________________________________________________________
442 Double_t AliTPCPIDResponse::GetExpectedSignal(const AliVTrack* track,
443 AliPID::EParticleType species,
444 ETPCdEdxSource dedxSource,
446 Bool_t correctMultiplicity) const
448 // Calculates the expected PID signal as the function of
449 // the information stored in the track, for the specified particle type
451 // At the moment, these signals are just the results of calling the
452 // Bethe-Bloch formula plus, if desired, taking into account the eta dependence
453 // and the multiplicity dependence (for PbPb).
454 // This can be improved. By taking into account the number of
455 // assigned clusters and/or the track dip angle, for example.
459 //charge factor. BB goes with z^2, however in reality it is slightly larger (calibration, threshold effects, ...)
460 // !!! Splines for light nuclei need to be normalised to this factor !!!
461 const Double_t chargeFactor = TMath::Power(AliPID::ParticleCharge(species),2.3);
463 return Bethe(track->GetTPCmomentum() / AliPID::ParticleMassZ(species)) * chargeFactor;
468 ETPCgainScenario gainScenario = kGainScenarioInvalid;
469 TSpline3* responseFunction = 0x0;
471 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction)) {
472 // Something is wrong with the track -> Return obviously invalid value
476 // Charge factor already taken into account inside the following function call
477 return GetExpectedSignal(track, species, dEdx, responseFunction, correctEta, correctMultiplicity);
480 //_________________________________________________________________________
481 TSpline3* AliTPCPIDResponse::GetResponseFunction( AliPID::EParticleType type,
482 AliTPCPIDResponse::ETPCgainScenario gainScenario ) const
484 //get response function
485 return dynamic_cast<TSpline3*>(fResponseFunctions.At(ResponseFunctionIndex(type,gainScenario)));
488 //_________________________________________________________________________
489 TSpline3* AliTPCPIDResponse::GetResponseFunction( const AliVTrack* track,
490 AliPID::EParticleType species,
491 ETPCdEdxSource dedxSource) const
493 //the splines are stored in an array, different scenarios
497 ETPCgainScenario gainScenario = kGainScenarioInvalid;
498 TSpline3* responseFunction = 0x0;
500 if (ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
501 return responseFunction;
506 //_________________________________________________________________________
507 void AliTPCPIDResponse::ResetSplines()
509 //reset the array with splines
510 for (Int_t i=0;i<fResponseFunctions.GetEntriesFast();i++)
512 fResponseFunctions.AddAt(NULL,i);
515 //_________________________________________________________________________
516 Int_t AliTPCPIDResponse::ResponseFunctionIndex( AliPID::EParticleType species,
517 ETPCgainScenario gainScenario ) const
519 //get the index in fResponseFunctions given type and scenario
520 return Int_t(species)+Int_t(gainScenario)*fgkNumberOfParticleSpecies;
523 //_________________________________________________________________________
524 void AliTPCPIDResponse::SetResponseFunction( TObject* o,
525 AliPID::EParticleType species,
526 ETPCgainScenario gainScenario )
528 fResponseFunctions.AddAtAndExpand(o,ResponseFunctionIndex(species,gainScenario));
532 //_________________________________________________________________________
533 Double_t AliTPCPIDResponse::GetExpectedSigma(const AliVTrack* track,
534 AliPID::EParticleType species,
535 ETPCgainScenario gainScenario,
538 const TSpline3* responseFunction,
540 Bool_t correctMultiplicity) const
542 // Calculates the expected sigma of the PID signal as the function of
543 // the information stored in the track and the given parameters,
544 // for the specified particle type
547 if (!responseFunction)
550 //TODO Check whether it makes sense to set correctMultiplicity to kTRUE while correctEta might be kFALSE
552 // If eta correction (=> new sigma parametrisation) is requested, but no sigma map is available, print error message
553 if (correctEta && !fhEtaSigmaPar1) {
554 AliError("New sigma parametrisation requested, but sigma map not initialised (usually via AliPIDResponse). Old sigma parametrisation will be used!");
557 // If no sigma map is available or if no eta correction is requested (sigma maps only for corrected eta!), use the old parametrisation
558 if (!fhEtaSigmaPar1 || !correctEta) {
560 return GetExpectedSignal(track, species, dEdx, responseFunction, kFALSE, correctMultiplicity) *
561 fRes0[gainScenario] * sqrt(1. + fResN2[gainScenario]/nPoints);
563 return GetExpectedSignal(track, species, dEdx, responseFunction, kFALSE, correctMultiplicity)*fRes0[gainScenario];
567 // Use eta correction (+ eta-dependent sigma)
568 Double_t sigmaPar1 = GetSigmaPar1Fast(track, species, dEdx, responseFunction);
570 if (correctMultiplicity) {
571 // In addition, take into account multiplicity dependence of mean and sigma of dEdx
572 Double_t dEdxExpectedEtaCorrected = GetExpectedSignal(track, species, dEdx, responseFunction, kTRUE, kFALSE);
574 // GetMultiplicityCorrection and GetMultiplicitySigmaCorrection both need the eta corrected dEdxExpected
575 Double_t multiplicityCorrFactor = GetMultiplicityCorrectionFast(track, dEdxExpectedEtaCorrected, fCurrentEventMultiplicity);
576 Double_t multiplicitySigmaCorrFactor = GetMultiplicitySigmaCorrectionFast(dEdxExpectedEtaCorrected, fCurrentEventMultiplicity);
578 // multiplicityCorrFactor to correct dEdxExpected for multiplicity. In addition: Correction factor for sigma
579 return (dEdxExpectedEtaCorrected * multiplicityCorrFactor)
580 * (sqrt(fSigmaPar0 * fSigmaPar0 + sigmaPar1 * sigmaPar1 / nPoints) * multiplicitySigmaCorrFactor);
583 return GetExpectedSignal(track, species, dEdx, responseFunction, kTRUE, kFALSE)*
584 sqrt(fSigmaPar0 * fSigmaPar0 + sigmaPar1 * sigmaPar1 / nPoints);
588 // One should never have/take tracks with 0 dEdx clusters!
594 //_________________________________________________________________________
595 Double_t AliTPCPIDResponse::GetExpectedSigma(const AliVTrack* track,
596 AliPID::EParticleType species,
597 ETPCdEdxSource dedxSource,
599 Bool_t correctMultiplicity) const
601 // Calculates the expected sigma of the PID signal as the function of
602 // the information stored in the track, for the specified particle type
608 ETPCgainScenario gainScenario = kGainScenarioInvalid;
609 TSpline3* responseFunction = 0x0;
611 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
612 return 999; //TODO: better handling!
614 return GetExpectedSigma(track, species, gainScenario, dEdx, nPoints, responseFunction, correctEta, correctMultiplicity);
618 //_________________________________________________________________________
619 Float_t AliTPCPIDResponse::GetNumberOfSigmas(const AliVTrack* track,
620 AliPID::EParticleType species,
621 ETPCdEdxSource dedxSource,
623 Bool_t correctMultiplicity) const
625 //Calculates the number of sigmas of the PID signal from the expected value
626 //for a given particle species in the presence of multiple gain scenarios
631 ETPCgainScenario gainScenario = kGainScenarioInvalid;
632 TSpline3* responseFunction = 0x0;
634 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
635 return -999; //TODO: Better handling!
637 Double_t bethe = GetExpectedSignal(track, species, dEdx, responseFunction, correctEta, correctMultiplicity);
638 Double_t sigma = GetExpectedSigma(track, species, gainScenario, dEdx, nPoints, responseFunction, correctEta, correctMultiplicity);
639 // 999 will be returned by GetExpectedSigma e.g. in case of 0 dEdx clusters
643 return (dEdx-bethe)/sigma;
646 //_________________________________________________________________________
647 Float_t AliTPCPIDResponse::GetSignalDelta(const AliVTrack* track,
648 AliPID::EParticleType species,
649 ETPCdEdxSource dedxSource,
651 Bool_t correctMultiplicity,
652 Bool_t ratio/*=kFALSE*/)const
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
660 ETPCgainScenario gainScenario = kGainScenarioInvalid;
661 TSpline3* responseFunction = 0x0;
663 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
664 return -9999.; //TODO: Better handling!
666 const Double_t bethe = GetExpectedSignal(track, species, dEdx, responseFunction, correctEta, correctMultiplicity);
668 Double_t delta=-9999.;
669 if (!ratio) delta=dEdx-bethe;
670 else if (bethe>1.e-20) delta=dEdx/bethe;
675 //_________________________________________________________________________
676 Bool_t AliTPCPIDResponse::ResponseFunctiondEdxN( const AliVTrack* track,
677 AliPID::EParticleType species,
678 ETPCdEdxSource dedxSource,
681 ETPCgainScenario& gainScenario,
682 TSpline3** responseFunction) const
684 // Calculates the right parameters for PID
685 // dEdx parametrization for the proper gain scenario, dEdx
686 // and NPoints used for dEdx
687 // based on the track geometry (which chambers it crosses) for the specified particle type
688 // and preferred source of dedx.
689 // returns true on success
692 if (dedxSource == kdEdxDefault) {
693 // Fast handling for default case. In addition: Keep it simple (don't call additional functions) to
694 // avoid possible bugs
696 // GetTPCsignalTunedOnData will be non-positive, if it has not been set (i.e. in case of MC NOT tuned to data).
697 // If this is the case, just take the normal signal
698 dEdx = track->GetTPCsignalTunedOnData();
700 dEdx = track->GetTPCsignal();
703 nPoints = track->GetTPCsignalN();
704 gainScenario = kDefault;
706 TObject* obj = fResponseFunctions.UncheckedAt(ResponseFunctionIndex(species,gainScenario));
707 *responseFunction = dynamic_cast<TSpline3*>(obj); //TODO:maybe static cast?
712 //TODO Proper handle of tuneMConData for other dEdx sources
714 Double32_t signal[4]; //0: IROC, 1: OROC medium, 2:OROC long, 3: OROC all (def. truncation used)
715 Char_t ncl[3]; //same
716 Char_t nrows[3]; //same
717 const AliTPCdEdxInfo* dEdxInfo = track->GetTPCdEdxInfo();
719 if (!dEdxInfo && dedxSource!=kdEdxDefault) //in one case its ok if we dont have the info
721 AliError("AliTPCdEdxInfo not available");
725 if (dEdxInfo) dEdxInfo->GetTPCSignalRegionInfo(signal,ncl,nrows);
727 //check if we cross a bad OROC in which case we reject
728 EChamberStatus trackOROCStatus = TrackStatus(track,2);
729 if (trackOROCStatus==kChamberOff || trackOROCStatus==kChamberLowGain)
738 if (trackOROCStatus==kChamberInvalid) return kFALSE; //never reached OROC
740 nPoints = ncl[2]+ncl[1];
741 gainScenario = kOROChigh;
746 //if we cross a bad IROC we use OROC dedx, if we dont we use combined
747 EChamberStatus status = TrackStatus(track,1);
748 if (status!=kChamberHighGain)
751 nPoints = ncl[2]+ncl[1];
752 gainScenario = kOROChigh;
756 dEdx = track->GetTPCsignal();
757 nPoints = track->GetTPCsignalN();
758 gainScenario = kALLhigh;
766 gainScenario = kGainScenarioInvalid;
770 TObject* obj = fResponseFunctions.UncheckedAt(ResponseFunctionIndex(species,gainScenario));
771 *responseFunction = dynamic_cast<TSpline3*>(obj); //TODO:maybe static cast?
777 //_________________________________________________________________________
778 Double_t AliTPCPIDResponse::GetEtaCorrectionFast(const AliVTrack *track, Double_t dEdxSplines) const
780 // NOTE: For expert use only -> Non-experts are advised to use the function without the "Fast" suffix or stick to AliPIDResponse directly.
782 // Get eta correction for the given parameters.
786 // Calling this function means to request eta correction in some way. Print error message, if no map is available!
787 AliError("Eta correction requested, but map not initialised (usually via AliPIDResponse). Returning eta correction factor 1!");
791 Double_t tpcSignal = dEdxSplines;
796 Double_t tanTheta = GetTrackTanTheta(track);
797 Int_t binX = fhEtaCorr->GetXaxis()->FindFixBin(tanTheta);
798 Int_t binY = fhEtaCorr->GetYaxis()->FindFixBin(1. / tpcSignal);
802 if (binX > fhEtaCorr->GetXaxis()->GetNbins())
803 binX = fhEtaCorr->GetXaxis()->GetNbins();
807 if (binY > fhEtaCorr->GetYaxis()->GetNbins())
808 binY = fhEtaCorr->GetYaxis()->GetNbins();
810 return fhEtaCorr->GetBinContent(binX, binY);
814 //_________________________________________________________________________
815 Double_t AliTPCPIDResponse::GetEtaCorrection(const AliVTrack *track, AliPID::EParticleType species, ETPCdEdxSource dedxSource) const
818 // Get eta correction for the given track.
826 ETPCgainScenario gainScenario = kGainScenarioInvalid;
827 TSpline3* responseFunction = 0x0;
829 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
832 // For the eta correction, do NOT take the multiplicity corrected value of dEdx
833 Double_t dEdxSplines = GetExpectedSignal(track, species, dEdx, responseFunction, kFALSE, kFALSE);
835 //TODO Alternatively take current track dEdx
836 //return GetEtaCorrectionFast(track, dEdx);
838 return GetEtaCorrectionFast(track, dEdxSplines);
842 //_________________________________________________________________________
843 Double_t AliTPCPIDResponse::GetEtaCorrectedTrackdEdx(const AliVTrack *track, AliPID::EParticleType species, ETPCdEdxSource dedxSource) const
846 // Get eta corrected dEdx for the given track. For the correction, the expected dEdx of
847 // the specified species will be used. If the species is set to AliPID::kUnknown, the
848 // dEdx of the track is used instead.
849 // WARNING: In the latter case, the eta correction might not be as good as if the
850 // expected dEdx is used, which is the way the correction factor is designed
852 // In any case, one has to decide carefully to which expected signal one wants to
853 // compare the corrected value - to the corrected or uncorrected.
854 // Anyhow, a safer way of looking e.g. at the n-sigma is to call
855 // the corresponding function GetNumberOfSigmas!
860 ETPCgainScenario gainScenario = kGainScenarioInvalid;
861 TSpline3* responseFunction = 0x0;
863 // Note: In case of species == AliPID::kUnknown, the responseFunction might not be set. However, in this case
864 // it is not used anyway, so this causes no trouble.
865 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
868 Double_t etaCorr = 0.;
870 if (species < AliPID::kUnknown) {
871 // For the eta correction, do NOT take the multiplicity corrected value of dEdx
872 Double_t dEdxSplines = GetExpectedSignal(track, species, dEdx, responseFunction, kFALSE, kFALSE);
873 etaCorr = GetEtaCorrectionFast(track, dEdxSplines);
876 etaCorr = GetEtaCorrectionFast(track, dEdx);
882 return dEdx / etaCorr;
886 //_________________________________________________________________________
887 Double_t AliTPCPIDResponse::GetSigmaPar1Fast(const AliVTrack *track, AliPID::EParticleType species, Double_t dEdx,
888 const TSpline3* responseFunction) const
890 // NOTE: For expert use only -> Non-experts are advised to use the function without the "Fast" suffix or stick to AliPIDResponse directly.
892 // Get parameter 1 of sigma parametrisation of TPC dEdx from the histogram for the given track.
895 if (!fhEtaSigmaPar1) {
896 // Calling this function means to request new sigma parametrisation in some way. Print error message, if no map is available!
897 AliError("New sigma parametrisation requested, but sigma map not initialised (usually via AliPIDResponse). Returning error value for sigma parameter1 = 999!");
901 // The sigma maps are created with data sets that are already eta corrected and for which the
902 // splines have been re-created. Therefore, the value for the lookup needs to be the value of
903 // the splines without any additional eta correction.
904 // NOTE: This is due to the method the maps are created. The track dEdx (not the expected one!)
905 // is corrected to uniquely related a momemtum bin with an expected dEdx, where the expected dEdx
906 // equals the track dEdx for all eta (thanks to the correction and the re-fit of the splines).
907 // Consequently, looking up the uncorrected expected dEdx at a given tanTheta yields the correct
909 // Also: It has to be the spline dEdx, since one wants to get the sigma for the assumption(!)
910 // of such a particle, which by assumption then has this dEdx value
912 // For the eta correction, do NOT take the multiplicity corrected value of dEdx
913 Double_t dEdxExpected = GetExpectedSignal(track, species, dEdx, responseFunction, kFALSE, kFALSE);
915 if (dEdxExpected < 1.)
918 Double_t tanTheta = GetTrackTanTheta(track);
919 Int_t binX = fhEtaSigmaPar1->GetXaxis()->FindFixBin(tanTheta);
920 Int_t binY = fhEtaSigmaPar1->GetYaxis()->FindFixBin(1. / dEdxExpected);
924 if (binX > fhEtaSigmaPar1->GetXaxis()->GetNbins())
925 binX = fhEtaSigmaPar1->GetXaxis()->GetNbins();
929 if (binY > fhEtaSigmaPar1->GetYaxis()->GetNbins())
930 binY = fhEtaSigmaPar1->GetYaxis()->GetNbins();
932 return fhEtaSigmaPar1->GetBinContent(binX, binY);
936 //_________________________________________________________________________
937 Double_t AliTPCPIDResponse::GetSigmaPar1(const AliVTrack *track, AliPID::EParticleType species, ETPCdEdxSource dedxSource) const
940 // Get parameter 1 of sigma parametrisation of TPC dEdx from the histogram for the given track.
948 ETPCgainScenario gainScenario = kGainScenarioInvalid;
949 TSpline3* responseFunction = 0x0;
951 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
954 return GetSigmaPar1Fast(track, species, dEdx, responseFunction);
958 //_________________________________________________________________________
959 Bool_t AliTPCPIDResponse::SetEtaCorrMap(TH2D* hMap)
962 // Load map for TPC eta correction (a copy is stored and will be deleted automatically).
963 // If hMap is 0x0,the eta correction will be disabled and kFALSE is returned.
964 // If the map can be set, kTRUE is returned.
975 fhEtaCorr = (TH2D*)(hMap->Clone());
976 fhEtaCorr->SetDirectory(0);
982 //_________________________________________________________________________
983 Bool_t AliTPCPIDResponse::SetSigmaParams(TH2D* hSigmaPar1Map, Double_t sigmaPar0)
986 // Load map for TPC sigma map (a copy is stored and will be deleted automatically):
987 // Parameter 1 is stored as a 2D map (1/dEdx vs. tanTheta_local) and parameter 0 is
988 // a constant. If hSigmaPar1Map is 0x0, the old sigma parametrisation will be used
989 // (and sigmaPar0 is ignored!) and kFALSE is returned.
990 // If the map can be set, sigmaPar0 is also set and kTRUE will be returned.
993 delete fhEtaSigmaPar1;
995 if (!hSigmaPar1Map) {
996 fhEtaSigmaPar1 = 0x0;
1002 fhEtaSigmaPar1 = (TH2D*)(hSigmaPar1Map->Clone());
1003 fhEtaSigmaPar1->SetDirectory(0);
1004 fSigmaPar0 = sigmaPar0;
1010 //_________________________________________________________________________
1011 Double_t AliTPCPIDResponse::GetTrackTanTheta(const AliVTrack *track) const
1013 // Extract the tanTheta from the information available in the AliVTrack
1015 // For ESD tracks, the local tanTheta could be used (esdTrack->GetInnerParam()->GetTgl()).
1016 // However, this value is not available for AODs and, thus, not for AliVTrack.
1017 // Fortunately, the following formula allows to approximate the local tanTheta with the
1018 // global theta angle -> This is for by far most of the tracks the same, but gives at
1019 // maybe the percent level differences within +- 0.2 in tanTheta -> Which is still ok.
1022 const AliExternalTrackParam* innerParam = track->GetInnerParam();
1023 Double_t tanTheta = 0;
1025 tanTheta = innerParam->GetTgl();
1027 tanTheta = TMath::Tan(-track->Theta() + TMath::Pi() / 2.0);
1029 // Constant in formula for B in kGauss (factor 0.1 to convert B from Tesla to kGauss),
1030 // 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)
1031 const Double_t constant = TMath::C()* 1e-9 * 0.1 * 0.01;
1032 const Double_t curvature = fMagField * constant / track->Pt(); // in 1./cm
1034 Double_t averageddzdr = 0.;
1037 for (Double_t r = 85; r < 245; r++) {
1038 Double_t sinPhiLocal = TMath::Abs(r*curvature*0.5);
1040 // Cut on |sin(phi)| as during reco
1041 if (TMath::Abs(sinPhiLocal) <= 0.95) {
1042 const Double_t phiLocal = TMath::ASin(sinPhiLocal);
1043 const Double_t tanPhiLocal = TMath::Tan(phiLocal);
1045 averageddzdr += tanTheta * TMath::Sqrt(1. + tanPhiLocal * tanPhiLocal);
1051 averageddzdr /= nParts;
1053 AliError("Problems during determination of dz/dr. Returning pure tanTheta as best estimate!");
1057 //printf("pT: %f\nFactor/magField(kGs)/curvature^-1: %f / %f /%f\ntanThetaGlobalFromTheta/tanTheta/Averageddzdr: %f / %f / %f\n\n",
1058 // track->Pt(), constant, fMagField, 1./curvature, TMath::Tan(-track->Theta() + TMath::Pi() / 2.0), tanTheta, averageddzdr);
1060 return averageddzdr;
1064 // Alternatively (in average, the effect is found to be negligable!):
1065 // Take local tanTheta from TPC inner wall, if available (currently only for ESDs available)
1066 //const AliExternalTrackParam* innerParam = track->GetInnerParam();
1068 // return innerParam->GetTgl();
1071 return TMath::Tan(-track->Theta() + TMath::Pi() / 2.0);
1075 //_________________________________________________________________________
1076 Double_t AliTPCPIDResponse::GetMultiplicityCorrectionFast(const AliVTrack *track, Double_t dEdxExpected, Int_t multiplicity) const
1078 // NOTE: For expert use only -> Non-experts are advised to use the function without the "Fast" suffix or stick to AliPIDResponse directly.
1080 // Calculate the multiplicity correction factor for this track for the given multiplicity.
1081 // The parameter dEdxExpected should take into account the eta correction already!
1083 // Multiplicity depends on pure dEdx. Therefore, correction factor depends indirectly on eta
1084 // => Use eta corrected value for dEdexExpected.
1086 if (dEdxExpected <= 0 || multiplicity <= 0)
1089 const Double_t dEdxExpectedInv = 1. / dEdxExpected;
1090 Double_t relSlope = fCorrFuncMultiplicity->Eval(dEdxExpectedInv);
1092 const Double_t tanTheta = GetTrackTanTheta(track);
1093 relSlope += fCorrFuncMultiplicityTanTheta->Eval(tanTheta);
1095 return (1. + relSlope * multiplicity);
1099 //_________________________________________________________________________
1100 Double_t AliTPCPIDResponse::GetMultiplicityCorrection(const AliVTrack *track, AliPID::EParticleType species, ETPCdEdxSource dedxSource) const
1103 // Get multiplicity correction for the given track (w.r.t. the mulitplicity of the current event)
1106 //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
1108 // No correction in case of multiplicity <= 0
1109 if (fCurrentEventMultiplicity <= 0)
1114 ETPCgainScenario gainScenario = kGainScenarioInvalid;
1115 TSpline3* responseFunction = 0x0;
1117 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
1120 //TODO Does it make sense to use the multiplicity correction WITHOUT eta correction?! Are the fit parameters still valid?
1121 // To get the expected signal to determine the multiplicity correction, do NOT ask for the multiplicity corrected value (of course)
1122 Double_t dEdxExpected = GetExpectedSignal(track, species, dEdx, responseFunction, kTRUE, kFALSE);
1124 return GetMultiplicityCorrectionFast(track, dEdxExpected, fCurrentEventMultiplicity);
1128 //_________________________________________________________________________
1129 Double_t AliTPCPIDResponse::GetMultiplicityCorrectedTrackdEdx(const AliVTrack *track, AliPID::EParticleType species, ETPCdEdxSource dedxSource) const
1132 // Get multiplicity corrected dEdx for the given track. For the correction, the expected dEdx of
1133 // the specified species will be used. If the species is set to AliPID::kUnknown, the
1134 // dEdx of the track is used instead.
1135 // WARNING: In the latter case, the correction might not be as good as if the
1136 // expected dEdx is used, which is the way the correction factor is designed
1138 // In any case, one has to decide carefully to which expected signal one wants to
1139 // compare the corrected value - to the corrected or uncorrected.
1140 // Anyhow, a safer way of looking e.g. at the n-sigma is to call
1141 // the corresponding function GetNumberOfSigmas!
1144 //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
1148 ETPCgainScenario gainScenario = kGainScenarioInvalid;
1149 TSpline3* responseFunction = 0x0;
1151 // Note: In case of species == AliPID::kUnknown, the responseFunction might not be set. However, in this case
1152 // it is not used anyway, so this causes no trouble.
1153 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
1157 // No correction in case of multiplicity <= 0
1158 if (fCurrentEventMultiplicity <= 0)
1161 Double_t multiplicityCorr = 0.;
1163 // 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?
1164 if (species < AliPID::kUnknown) {
1165 // To get the expected signal to determine the multiplicity correction, do NOT ask for the multiplicity corrected value (of course).
1166 // However, one needs the eta corrected value!
1167 Double_t dEdxSplines = GetExpectedSignal(track, species, dEdx, responseFunction, kTRUE, kFALSE);
1168 multiplicityCorr = GetMultiplicityCorrectionFast(track, dEdxSplines, fCurrentEventMultiplicity);
1171 // One needs the eta corrected value to determine the multiplicity correction factor!
1172 Double_t etaCorr = GetEtaCorrectionFast(track, dEdx);
1173 multiplicityCorr = GetMultiplicityCorrectionFast(track, dEdx * etaCorr, fCurrentEventMultiplicity);
1176 if (multiplicityCorr <= 0)
1179 return dEdx / multiplicityCorr;
1183 //_________________________________________________________________________
1184 Double_t AliTPCPIDResponse::GetEtaAndMultiplicityCorrectedTrackdEdx(const AliVTrack *track, AliPID::EParticleType species,
1185 ETPCdEdxSource dedxSource) const
1188 // Get multiplicity and eta corrected dEdx for the given track. For the correction,
1189 // the expected dEdx of the specified species will be used. If the species is set
1190 // to AliPID::kUnknown, the dEdx of the track is used instead.
1191 // WARNING: In the latter case, the correction might not be as good as if the
1192 // expected dEdx is used, which is the way the correction factor is designed
1194 // In any case, one has to decide carefully to which expected signal one wants to
1195 // compare the corrected value - to the corrected or uncorrected.
1196 // Anyhow, a safer way of looking e.g. at the n-sigma is to call
1197 // the corresponding function GetNumberOfSigmas!
1202 ETPCgainScenario gainScenario = kGainScenarioInvalid;
1203 TSpline3* responseFunction = 0x0;
1205 // Note: In case of species == AliPID::kUnknown, the responseFunction might not be set. However, in this case
1206 // it is not used anyway, so this causes no trouble.
1207 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
1210 Double_t multiplicityCorr = 0.;
1211 Double_t etaCorr = 0.;
1213 if (species < AliPID::kUnknown) {
1214 // To get the expected signal to determine the multiplicity correction, do NOT ask for the multiplicity corrected value (of course)
1215 Double_t dEdxSplines = GetExpectedSignal(track, species, dEdx, responseFunction, kFALSE, kFALSE);
1216 etaCorr = GetEtaCorrectionFast(track, dEdxSplines);
1217 multiplicityCorr = GetMultiplicityCorrectionFast(track, dEdxSplines * etaCorr, fCurrentEventMultiplicity);
1220 etaCorr = GetEtaCorrectionFast(track, dEdx);
1221 multiplicityCorr = GetMultiplicityCorrectionFast(track, dEdx * etaCorr, fCurrentEventMultiplicity);
1224 if (multiplicityCorr <= 0 || etaCorr <= 0)
1227 return dEdx / multiplicityCorr / etaCorr;
1231 //_________________________________________________________________________
1232 Double_t AliTPCPIDResponse::GetMultiplicitySigmaCorrectionFast(Double_t dEdxExpected, Int_t multiplicity) const
1234 // NOTE: For expert use only -> Non-experts are advised to use the function without the "Fast" suffix or stick to AliPIDResponse directly.
1236 // Calculate the multiplicity sigma correction factor for the corresponding expected dEdx and for the given multiplicity.
1237 // The parameter dEdxExpected should take into account the eta correction already!
1239 // Multiplicity dependence of sigma depends on the real dEdx at zero multiplicity,
1240 // i.e. the eta (only) corrected dEdxExpected value has to be used
1241 // since all maps etc. have been created for ~zero multiplicity
1243 if (dEdxExpected <= 0 || multiplicity <= 0)
1246 Double_t relSigmaSlope = fCorrFuncSigmaMultiplicity->Eval(1. / dEdxExpected);
1248 return (1. + relSigmaSlope * multiplicity);
1252 //_________________________________________________________________________
1253 Double_t AliTPCPIDResponse::GetMultiplicitySigmaCorrection(const AliVTrack *track, AliPID::EParticleType species, ETPCdEdxSource dedxSource) const
1256 // Get multiplicity sigma correction for the given track (w.r.t. the mulitplicity of the current event)
1259 //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
1261 // No correction in case of multiplicity <= 0
1262 if (fCurrentEventMultiplicity <= 0)
1267 ETPCgainScenario gainScenario = kGainScenarioInvalid;
1268 TSpline3* responseFunction = 0x0;
1270 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
1273 //TODO Does it make sense to use the multiplicity correction WITHOUT eta correction?! Are the fit parameters still valid?
1274 // To get the expected signal to determine the multiplicity correction, do NOT ask for the multiplicity corrected value (of course)
1275 Double_t dEdxExpected = GetExpectedSignal(track, species, dEdx, responseFunction, kTRUE, kFALSE);
1277 return GetMultiplicitySigmaCorrectionFast(dEdxExpected, fCurrentEventMultiplicity);
1281 //_________________________________________________________________________
1282 void AliTPCPIDResponse::ResetMultiplicityCorrectionFunctions()
1284 // Default values: No correction, i.e. overall correction factor should be one
1286 // This function should always return 0.0, if multcorr disabled
1287 fCorrFuncMultiplicity->SetParameter(0, 0.);
1288 fCorrFuncMultiplicity->SetParameter(1, 0.);
1289 fCorrFuncMultiplicity->SetParameter(2, 0.);
1290 fCorrFuncMultiplicity->SetParameter(3, 0.);
1291 fCorrFuncMultiplicity->SetParameter(4, 0.);
1293 // This function should always return 0., if multCorr disabled
1294 fCorrFuncMultiplicityTanTheta->SetParameter(0, 0.);
1295 fCorrFuncMultiplicityTanTheta->SetParameter(1, 0.);
1296 fCorrFuncMultiplicityTanTheta->SetParameter(2, 0.);
1298 // This function should always return 0.0, if mutlcorr disabled
1299 fCorrFuncSigmaMultiplicity->SetParameter(0, 0.);
1300 fCorrFuncSigmaMultiplicity->SetParameter(1, 0.);
1301 fCorrFuncSigmaMultiplicity->SetParameter(2, 0.);
1302 fCorrFuncSigmaMultiplicity->SetParameter(3, 0.);
1306 //_________________________________________________________________________
1307 Bool_t AliTPCPIDResponse::sectorNumbersInOut(Double_t* trackPositionInner,
1308 Double_t* trackPositionOuter,
1314 //calculate the sector numbers (equivalent to IROC chamber numbers) a track crosses
1315 //for OROC chamber numbers add 36
1316 //returned angles are between (0,2pi)
1318 inphi = TMath::ATan2(trackPositionInner[1],trackPositionInner[0]);
1319 outphi = TMath::ATan2(trackPositionOuter[1], trackPositionOuter[0]);
1321 if (inphi<0) {inphi+=TMath::TwoPi();} //because ATan2 gives angles between -pi,pi
1322 if (outphi<0) {outphi+=TMath::TwoPi();} //because ATan2 gives angles between -pi,pi
1324 in = sectorNumber(inphi);
1325 out = sectorNumber(outphi);
1327 //for the C side (positive z) offset by 18
1328 if (trackPositionInner[2]>0.0)
1337 //_____________________________________________________________________________
1338 Int_t AliTPCPIDResponse::sectorNumber(Double_t phi) const
1340 //calculate sector number
1341 const Float_t width=TMath::TwoPi()/18.;
1342 return TMath::Floor(phi/width);
1346 //_____________________________________________________________________________
1347 void AliTPCPIDResponse::Print(Option_t* /*option*/) const
1350 fResponseFunctions.Print();
1354 //_____________________________________________________________________________
1355 AliTPCPIDResponse::EChamberStatus AliTPCPIDResponse::TrackStatus(const AliVTrack* track, Int_t layer) const
1357 //status of the track: if it crosses any bad chambers return kChamberOff;
1358 //IROC:layer=1, OROC:layer=2
1359 if (layer<1 || layer>2) layer=1;
1364 Float_t innerRadius = (layer==1)?83.0:133.7;
1365 Float_t outerRadius = (layer==1)?133.5:247.7;
1367 /////////////////////////////////////////////////////////////////////////////
1368 //find out where track enters and leaves the layer.
1370 Double_t trackPositionInner[3];
1371 Double_t trackPositionOuter[3];
1373 //if there is no inner param this could mean we're using the AOD track,
1374 //we still can extrapolate from the vertex - so use those params.
1375 const AliExternalTrackParam* ip = track->GetInnerParam();
1378 Bool_t trackAtInner = track->GetXYZAt(innerRadius, fMagField, trackPositionInner);
1379 Bool_t trackAtOuter = track->GetXYZAt(outerRadius, fMagField, trackPositionOuter);
1383 //if we dont even enter inner radius we do nothing and return invalid
1388 return kChamberInvalid;
1393 //if we don't reach the outer radius check that the apex is indeed within the outer radius and use apex position
1394 Bool_t haveApex = TrackApex(track, fMagField, trackPositionOuter);
1395 Float_t apexRadius = TMath::Sqrt(trackPositionOuter[0]*trackPositionOuter[0]+trackPositionOuter[1]*trackPositionOuter[1]);
1396 if ( haveApex && apexRadius<=outerRadius && apexRadius>innerRadius)
1398 //printf("pt: %.2f, apexRadius: %.2f(%s), x: %.2f, y: %.2f\n",track->Pt(),apexRadius,(haveApex)?"OK":"BAD",trackPositionOuter[0],trackPositionOuter[1]);
1406 return kChamberInvalid;
1411 if (!sectorNumbersInOut(trackPositionInner,
1416 out)) return kChamberInvalid;
1418 /////////////////////////////////////////////////////////////////////////////
1419 //now we have the location of the track we can check
1420 //if it is in a good/bad chamber
1422 Bool_t sideA = kTRUE;
1424 if (((in/18)%2==1) && ((out/18)%2==1)) sideA=kFALSE;
1429 if (TMath::Abs(in-out)>9)
1431 if (TMath::Max(in,out)==out)
1436 Float_t tmpphi=outphi;
1441 inphi-=TMath::TwoPi();
1445 if (TMath::Max(in,out)==in)
1450 Float_t tmpphi=outphi;
1456 Float_t trackLengthInBad = 0.;
1457 Float_t trackLengthInLowGain = 0.;
1458 Float_t trackLengthTotal = TMath::Abs(outphi-inphi);
1459 Float_t lengthFractionInBadSectors = 0.;
1461 const Float_t sectorWidth = TMath::TwoPi()/18.;
1463 for (Int_t i=in; i<=out; i++)
1466 if (i<0) j+=18; //correct for the negative values
1467 if (!sideA) j+=18; //move to the correct side
1469 Float_t deltaPhi = 0.;
1470 Float_t phiEdge=sectorWidth*i;
1471 if (inphi>phiEdge) {deltaPhi=phiEdge+sectorWidth-inphi;}
1472 else if ((outphi>=phiEdge) && (outphi<(phiEdge+sectorWidth))) {deltaPhi=outphi-phiEdge;}
1473 else {deltaPhi=sectorWidth;}
1475 Float_t v = fVoltageMap[(layer==1)?(j):(j+36)];
1476 if (v<=fBadIROCthreshhold)
1478 trackLengthInBad+=deltaPhi;
1479 lengthFractionInBadSectors=1.;
1481 if (v<=fLowGainIROCthreshold && v>fBadIROCthreshhold)
1483 trackLengthInLowGain+=deltaPhi;
1484 lengthFractionInBadSectors=1.;
1488 //for now low gain and bad (off) chambers are treated equally
1489 if (trackLengthTotal>0)
1490 lengthFractionInBadSectors = (trackLengthInLowGain+trackLengthInBad)/trackLengthTotal;
1492 //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);
1494 if (lengthFractionInBadSectors>fMaxBadLengthFraction)
1496 //printf("%%%%%%%% %s kChamberLowGain\n",(layer==1)?"IROC":"OROC");
1497 return kChamberLowGain;
1500 return kChamberHighGain;
1504 //_____________________________________________________________________________
1505 Float_t AliTPCPIDResponse::MaxClusterRadius(const AliVTrack* track) const
1507 //return the radius of the outermost padrow containing a cluster in TPC
1509 const TBits* clusterMap=track->GetTPCClusterMapPtr();
1510 if (!clusterMap) return 0.;
1512 //from AliTPCParam, radius of first IROC row
1513 const Float_t rfirstIROC = 8.52249984741210938e+01;
1514 const Float_t padrowHeightIROC = 0.75;
1515 const Float_t rfirstOROC0 = 1.35100006103515625e+02;
1516 const Float_t padrowHeightOROC0 = 1.0;
1517 const Float_t rfirstOROC1 = 1.99350006103515625e+02;
1518 const Float_t padrowHeightOROC1 = 1.5;
1520 Int_t maxPadRow=160;
1521 while ((--maxPadRow)>0 && !clusterMap->TestBitNumber(maxPadRow)){}
1522 if (maxPadRow>126) return rfirstOROC1+(maxPadRow-126-1)*padrowHeightOROC1;
1523 if (maxPadRow>62) return rfirstOROC0+(maxPadRow-62-1)*padrowHeightOROC0;
1524 if (maxPadRow>0) return rfirstIROC+(maxPadRow-1)*padrowHeightIROC;
1529 //_____________________________________________________________________________
1530 Bool_t AliTPCPIDResponse::TrackApex(const AliVTrack* track, Float_t magField, Double_t position[3]) const
1532 //calculate the coordinates of the apex of the track
1536 track->GetPxPyPz(p);
1537 Double_t r = 1./track->OneOverPt()/0.0299792458/magField; //signed - will determine the direction of b
1538 //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);
1539 //find orthogonal vector (Gram-Schmidt)
1540 Double_t alpha = (p[0]*x[0] + p[1]*x[1])/(p[0]*p[0] + p[1]*p[1]);
1542 b[0]=x[0]-alpha*p[0];
1543 b[1]=x[1]-alpha*p[1];
1545 Double_t norm = TMath::Sqrt(b[0]*b[0]+b[1]*b[1]);
1546 if (TMath::AreEqualAbs(norm,0.0,1e-10)) return kFALSE;
1553 //printf("center: x:%.2f, y:%.2f\n",b[0],b[1]);
1555 norm = TMath::Sqrt(b[0]*b[0]+b[1]*b[1]);
1556 if (TMath::AreEqualAbs(norm,0.0,1e-10)) return kFALSE;
1558 position[0]=b[0]+b[0]*TMath::Abs(r)/norm;
1559 position[1]=b[1]+b[1]*TMath::Abs(r)/norm;
1564 Double_t AliTPCPIDResponse::EvaldEdxSpline(Double_t bg,Int_t entry){
1566 // Evaluate the dEdx response for given entry
1568 TSpline * spline = (TSpline*)fSplineArray.At(entry);
1569 if (spline) return spline->Eval(bg);
1574 Bool_t AliTPCPIDResponse::RegisterSpline(const char * name, Int_t index){
1576 // register spline to be used for drawing comparisons
1578 TFile * fTPCBB = TFile::Open("$ALICE_ROOT/OADB/COMMON/PID/data/TPCPIDResponse.root");
1579 TObjArray *arrayTPCPID= (TObjArray*) fTPCBB->Get("TPCPIDResponse");
1580 if (fSplineArray.GetEntriesFast()<index) fSplineArray.Expand(index*2);
1583 spline = (TSpline3*)arrayTPCPID->FindObject(name);
1584 if (spline) fSplineArray.AddAt(spline->Clone(),index);