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"
42 ClassImp(AliTPCPIDResponse);
44 const char* AliTPCPIDResponse::fgkGainScenarioName[fgkNumberOfGainScenarios+1]=
46 "", //default - no name
52 //_________________________________________________________________________
53 AliTPCPIDResponse::AliTPCPIDResponse():
64 fResponseFunctions(fgkNumberOfParticleSpecies*fgkNumberOfGainScenarios),
66 fLowGainIROCthreshold(-40),
67 fBadIROCthreshhold(-70),
68 fLowGainOROCthreshold(-40),
69 fBadOROCthreshhold(-40),
70 fMaxBadLengthFraction(0.5),
75 fCurrentEventMultiplicity(0),
76 fCorrFuncMultiplicity(0x0),
77 fCorrFuncMultiplicityTanTheta(0x0),
78 fCorrFuncSigmaMultiplicity(0x0)
81 // The default constructor
84 AliLog::SetClassDebugLevel("AliTPCPIDResponse", AliLog::kInfo);
86 for (Int_t i=0; i<fgkNumberOfGainScenarios; i++) {fRes0[i]=0.07;fResN2[i]=0.0;}
88 fCorrFuncMultiplicity = new TF1("fCorrFuncMultiplicity",
89 "[0] + [1]*TMath::Max([4], TMath::Min(x, [3])) + [2] * TMath::Power(TMath::Max([4], TMath::Min(x, [3])), 2)",
91 fCorrFuncMultiplicityTanTheta = new TF1("fCorrFuncMultiplicityTanTheta", "[0] * (x - [2]) + [1] * (x * x - [2] * [2])", -1.5, 1.5);
92 fCorrFuncSigmaMultiplicity = new TF1("fCorrFuncSigmaMultiplicity",
93 "TMath::Max(0, [0] + [1]*TMath::Min(x, [3]) + [2] * TMath::Power(TMath::Min(x, [3]), 2))", 0., 0.2);
96 ResetMultiplicityCorrectionFunctions();
99 //_________________________________________________________________________
100 AliTPCPIDResponse::AliTPCPIDResponse(const Double_t *param):
110 fUseDatabase(kFALSE),
111 fResponseFunctions(fgkNumberOfParticleSpecies*fgkNumberOfGainScenarios),
113 fLowGainIROCthreshold(-40),
114 fBadIROCthreshhold(-70),
115 fLowGainOROCthreshold(-40),
116 fBadOROCthreshhold(-40),
117 fMaxBadLengthFraction(0.5),
124 // The main constructor
126 for (Int_t i=0; i<fgkNumberOfGainScenarios; i++) {fRes0[i]=param[1];fResN2[i]=param[2];}
130 //_________________________________________________________________________
131 AliTPCPIDResponse::~AliTPCPIDResponse()
140 delete fhEtaSigmaPar1;
141 fhEtaSigmaPar1 = 0x0;
143 delete fCorrFuncMultiplicity;
144 fCorrFuncMultiplicity = 0x0;
146 delete fCorrFuncMultiplicityTanTheta;
147 fCorrFuncMultiplicityTanTheta = 0x0;
149 delete fCorrFuncSigmaMultiplicity;
150 fCorrFuncSigmaMultiplicity = 0x0;
154 //_________________________________________________________________________
155 AliTPCPIDResponse::AliTPCPIDResponse(const AliTPCPIDResponse& that):
165 fUseDatabase(that.fUseDatabase),
166 fResponseFunctions(that.fResponseFunctions),
167 fVoltageMap(that.fVoltageMap),
168 fLowGainIROCthreshold(that.fLowGainIROCthreshold),
169 fBadIROCthreshhold(that.fBadIROCthreshhold),
170 fLowGainOROCthreshold(that.fLowGainOROCthreshold),
171 fBadOROCthreshhold(that.fBadOROCthreshhold),
172 fMaxBadLengthFraction(that.fMaxBadLengthFraction),
173 fMagField(that.fMagField),
176 fSigmaPar0(that.fSigmaPar0),
177 fCurrentEventMultiplicity(that.fCurrentEventMultiplicity),
178 fCorrFuncMultiplicity(0x0),
179 fCorrFuncMultiplicityTanTheta(0x0),
180 fCorrFuncSigmaMultiplicity(0x0)
183 for (Int_t i=0; i<fgkNumberOfGainScenarios; i++) {fRes0[i]=that.fRes0[i];fResN2[i]=that.fResN2[i];}
186 if (that.fhEtaCorr) {
187 fhEtaCorr = new TH2D(*(that.fhEtaCorr));
188 fhEtaCorr->SetDirectory(0);
191 if (that.fhEtaSigmaPar1) {
192 fhEtaSigmaPar1 = new TH2D(*(that.fhEtaSigmaPar1));
193 fhEtaSigmaPar1->SetDirectory(0);
196 // Copy multiplicity correction functions
197 if (that.fCorrFuncMultiplicity) {
198 fCorrFuncMultiplicity = new TF1(*(that.fCorrFuncMultiplicity));
201 if (that.fCorrFuncMultiplicityTanTheta) {
202 fCorrFuncMultiplicityTanTheta = new TF1(*(that.fCorrFuncMultiplicityTanTheta));
205 if (that.fCorrFuncSigmaMultiplicity) {
206 fCorrFuncSigmaMultiplicity = new TF1(*(that.fCorrFuncSigmaMultiplicity));
210 //_________________________________________________________________________
211 AliTPCPIDResponse& AliTPCPIDResponse::operator=(const AliTPCPIDResponse& that)
214 if (&that==this) return *this;
215 TNamed::operator=(that);
222 fUseDatabase=that.fUseDatabase;
223 fResponseFunctions=that.fResponseFunctions;
224 fVoltageMap=that.fVoltageMap;
225 fLowGainIROCthreshold=that.fLowGainIROCthreshold;
226 fBadIROCthreshhold=that.fBadIROCthreshhold;
227 fLowGainOROCthreshold=that.fLowGainOROCthreshold;
228 fBadOROCthreshhold=that.fBadOROCthreshhold;
229 fMaxBadLengthFraction=that.fMaxBadLengthFraction;
230 fMagField=that.fMagField;
231 fCurrentEventMultiplicity=that.fCurrentEventMultiplicity;
232 for (Int_t i=0; i<fgkNumberOfGainScenarios; i++) {fRes0[i]=that.fRes0[i];fResN2[i]=that.fResN2[i];}
236 if (that.fhEtaCorr) {
237 fhEtaCorr = new TH2D(*(that.fhEtaCorr));
238 fhEtaCorr->SetDirectory(0);
241 delete fhEtaSigmaPar1;
243 if (that.fhEtaSigmaPar1) {
244 fhEtaSigmaPar1 = new TH2D(*(that.fhEtaSigmaPar1));
245 fhEtaSigmaPar1->SetDirectory(0);
248 fSigmaPar0 = that.fSigmaPar0;
250 delete fCorrFuncMultiplicity;
251 fCorrFuncMultiplicity = 0x0;
252 if (that.fCorrFuncMultiplicity) {
253 fCorrFuncMultiplicity = new TF1(*(that.fCorrFuncMultiplicity));
256 delete fCorrFuncMultiplicityTanTheta;
257 fCorrFuncMultiplicityTanTheta = 0x0;
258 if (that.fCorrFuncMultiplicityTanTheta) {
259 fCorrFuncMultiplicityTanTheta = new TF1(*(that.fCorrFuncMultiplicityTanTheta));
262 delete fCorrFuncSigmaMultiplicity;
263 fCorrFuncSigmaMultiplicity = 0x0;
264 if (that.fCorrFuncSigmaMultiplicity) {
265 fCorrFuncSigmaMultiplicity = new TF1(*(that.fCorrFuncSigmaMultiplicity));
271 //_________________________________________________________________________
272 Double_t AliTPCPIDResponse::Bethe(Double_t betaGamma) const {
274 // This is the Bethe-Bloch function normalised to 1 at the minimum
276 // Simulated and reconstructed Bethe-Bloch differs
277 // Simulated curve is the dNprim/dx
278 // Reconstructed is proportianal dNtot/dx
279 // Temporary fix for production - Simple linear correction function
280 // Future 2 Bethe Bloch formulas needed
282 // 2. for reconstructed PID
285 // const Float_t kmeanCorrection =0.1;
287 AliExternalTrackParam::BetheBlochAleph(betaGamma,fKp1,fKp2,fKp3,fKp4,fKp5);
291 //_________________________________________________________________________
292 void AliTPCPIDResponse::SetBetheBlochParameters(Double_t kp1,
298 // Set the parameters of the ALEPH Bethe-Bloch formula
307 //_________________________________________________________________________
308 void AliTPCPIDResponse::SetSigma(Float_t res0, Float_t resN2) {
310 // Set the relative resolution sigma_rel = res0 * sqrt(1+resN2/npoint)
312 for (Int_t i=0; i<fgkNumberOfGainScenarios; i++) {fRes0[i]=res0;fResN2[i]=resN2;}
315 //_________________________________________________________________________
316 Double_t AliTPCPIDResponse::GetExpectedSignal(Float_t mom,
317 AliPID::EParticleType n) const {
319 // Deprecated function (for backward compatibility). Please use
320 // GetExpectedSignal(const AliVTrack* track, AliPID::EParticleType species, ETPCdEdxSource dedxSource,
321 // Bool_t correctEta, Bool_t correctMultiplicity);
325 // Calculates the expected PID signal as the function of
326 // the information stored in the track, for the specified particle type
328 // At the moment, these signals are just the results of calling the
329 // Bethe-Bloch formula.
330 // This can be improved. By taking into account the number of
331 // assigned clusters and/or the track dip angle, for example.
334 //charge factor. BB goes with z^2, however in reality it is slightly larger (calibration, threshold effects, ...)
335 // !!! Splines for light nuclei need to be normalised to this factor !!!
336 const Double_t chargeFactor = TMath::Power(AliPID::ParticleCharge(n),2.3);
338 Double_t mass=AliPID::ParticleMassZ(n);
339 if (!fUseDatabase) return Bethe(mom/mass) * chargeFactor;
341 const TSpline3 * responseFunction = (TSpline3 *) fResponseFunctions.UncheckedAt(n);
343 if (!responseFunction) return Bethe(mom/mass) * chargeFactor;
345 return fMIP*responseFunction->Eval(mom/mass)*chargeFactor;
349 //_________________________________________________________________________
350 Double_t AliTPCPIDResponse::GetExpectedSigma(Float_t mom,
352 AliPID::EParticleType n) const {
354 // Deprecated function (for backward compatibility). Please use
355 // GetExpectedSigma(onst AliVTrack* track, AliPID::EParticleType species,
356 // ETPCdEdxSource dedxSource, Bool_t correctEta) instead!
359 // Calculates the expected sigma of the PID signal as the function of
360 // the information stored in the track, for the specified particle type
364 return GetExpectedSignal(mom,n)*fRes0[0]*sqrt(1. + fResN2[0]/nPoints);
366 return GetExpectedSignal(mom,n)*fRes0[0];
369 ////////////////////////////////////////////////////NEW//////////////////////////////
371 //_________________________________________________________________________
372 void AliTPCPIDResponse::SetSigma(Float_t res0, Float_t resN2, ETPCgainScenario gainScenario) {
374 // Set the relative resolution sigma_rel = res0 * sqrt(1+resN2/npoint)
376 if ((Int_t)gainScenario>=(Int_t)fgkNumberOfGainScenarios) return; //TODO: better handling!
377 fRes0[gainScenario]=res0;
378 fResN2[gainScenario]=resN2;
382 //_________________________________________________________________________
383 Double_t AliTPCPIDResponse::GetExpectedSignal(const AliVTrack* track,
384 AliPID::EParticleType species,
386 const TSpline3* responseFunction,
388 Bool_t correctMultiplicity) const
390 // Calculates the expected PID signal as the function of
391 // the information stored in the track and the given parameters,
392 // for the specified particle type
394 // At the moment, these signals are just the results of calling the
395 // Bethe-Bloch formula plus, if desired, taking into account the eta dependence
396 // and the multiplicity dependence (for PbPb).
397 // This can be improved. By taking into account the number of
398 // assigned clusters and/or the track dip angle, for example.
401 Double_t mom=track->GetTPCmomentum();
402 Double_t mass=AliPID::ParticleMassZ(species);
404 //charge factor. BB goes with z^2, however in reality it is slightly larger (calibration, threshold effects, ...)
405 // !!! Splines for light nuclei need to be normalised to this factor !!!
406 const Double_t chargeFactor = TMath::Power(AliPID::ParticleCharge(species),2.3);
408 if (!responseFunction)
409 return Bethe(mom/mass) * chargeFactor;
411 Double_t dEdxSplines = fMIP*responseFunction->Eval(mom/mass) * chargeFactor;
413 if (!correctEta && !correctMultiplicity)
416 Double_t corrFactorEta = 1.0;
417 Double_t corrFactorMultiplicity = 1.0;
420 corrFactorEta = GetEtaCorrectionFast(track, dEdxSplines);
421 //TODO Alternatively take current track dEdx
422 //corrFactorEta = GetEtaCorrectionFast(track, dEdx);
425 if (correctMultiplicity)
426 corrFactorMultiplicity = GetMultiplicityCorrectionFast(track, dEdxSplines * corrFactorEta, fCurrentEventMultiplicity);
428 return dEdxSplines * corrFactorEta * corrFactorMultiplicity;
432 //_________________________________________________________________________
433 Double_t AliTPCPIDResponse::GetExpectedSignal(const AliVTrack* track,
434 AliPID::EParticleType species,
435 ETPCdEdxSource dedxSource,
437 Bool_t correctMultiplicity) const
439 // Calculates the expected PID signal as the function of
440 // the information stored in the track, for the specified particle type
442 // At the moment, these signals are just the results of calling the
443 // Bethe-Bloch formula plus, if desired, taking into account the eta dependence
444 // and the multiplicity dependence (for PbPb).
445 // This can be improved. By taking into account the number of
446 // assigned clusters and/or the track dip angle, for example.
450 //charge factor. BB goes with z^2, however in reality it is slightly larger (calibration, threshold effects, ...)
451 // !!! Splines for light nuclei need to be normalised to this factor !!!
452 const Double_t chargeFactor = TMath::Power(AliPID::ParticleCharge(species),2.3);
454 return Bethe(track->GetTPCmomentum() / AliPID::ParticleMassZ(species)) * chargeFactor;
459 ETPCgainScenario gainScenario = kGainScenarioInvalid;
460 TSpline3* responseFunction = 0x0;
462 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction)) {
463 // Something is wrong with the track -> Return obviously invalid value
467 // Charge factor already taken into account inside the following function call
468 return GetExpectedSignal(track, species, dEdx, responseFunction, correctEta, correctMultiplicity);
471 //_________________________________________________________________________
472 TSpline3* AliTPCPIDResponse::GetResponseFunction( AliPID::EParticleType type,
473 AliTPCPIDResponse::ETPCgainScenario gainScenario ) const
475 //get response function
476 return dynamic_cast<TSpline3*>(fResponseFunctions.At(ResponseFunctionIndex(type,gainScenario)));
479 //_________________________________________________________________________
480 TSpline3* AliTPCPIDResponse::GetResponseFunction( const AliVTrack* track,
481 AliPID::EParticleType species,
482 ETPCdEdxSource dedxSource) const
484 //the splines are stored in an array, different scenarios
488 ETPCgainScenario gainScenario = kGainScenarioInvalid;
489 TSpline3* responseFunction = 0x0;
491 if (ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
492 return responseFunction;
497 //_________________________________________________________________________
498 void AliTPCPIDResponse::ResetSplines()
500 //reset the array with splines
501 for (Int_t i=0;i<fResponseFunctions.GetEntriesFast();i++)
503 fResponseFunctions.AddAt(NULL,i);
506 //_________________________________________________________________________
507 Int_t AliTPCPIDResponse::ResponseFunctionIndex( AliPID::EParticleType species,
508 ETPCgainScenario gainScenario ) const
510 //get the index in fResponseFunctions given type and scenario
511 return Int_t(species)+Int_t(gainScenario)*fgkNumberOfParticleSpecies;
514 //_________________________________________________________________________
515 void AliTPCPIDResponse::SetResponseFunction( TObject* o,
516 AliPID::EParticleType species,
517 ETPCgainScenario gainScenario )
519 fResponseFunctions.AddAtAndExpand(o,ResponseFunctionIndex(species,gainScenario));
523 //_________________________________________________________________________
524 Double_t AliTPCPIDResponse::GetExpectedSigma(const AliVTrack* track,
525 AliPID::EParticleType species,
526 ETPCgainScenario gainScenario,
529 const TSpline3* responseFunction,
531 Bool_t correctMultiplicity) const
533 // Calculates the expected sigma of the PID signal as the function of
534 // the information stored in the track and the given parameters,
535 // for the specified particle type
538 if (!responseFunction)
541 //TODO Check whether it makes sense to set correctMultiplicity to kTRUE while correctEta might be kFALSE
543 // If eta correction (=> new sigma parametrisation) is requested, but no sigma map is available, print error message
544 if (correctEta && !fhEtaSigmaPar1) {
545 AliError("New sigma parametrisation requested, but sigma map not initialised (usually via AliPIDResponse). Old sigma parametrisation will be used!");
548 // If no sigma map is available or if no eta correction is requested (sigma maps only for corrected eta!), use the old parametrisation
549 if (!fhEtaSigmaPar1 || !correctEta) {
551 return GetExpectedSignal(track, species, dEdx, responseFunction, kFALSE, correctMultiplicity) *
552 fRes0[gainScenario] * sqrt(1. + fResN2[gainScenario]/nPoints);
554 return GetExpectedSignal(track, species, dEdx, responseFunction, kFALSE, correctMultiplicity)*fRes0[gainScenario];
558 // Use eta correction (+ eta-dependent sigma)
559 Double_t sigmaPar1 = GetSigmaPar1Fast(track, species, dEdx, responseFunction);
561 if (correctMultiplicity) {
562 // In addition, take into account multiplicity dependence of mean and sigma of dEdx
563 Double_t dEdxExpectedEtaCorrected = GetExpectedSignal(track, species, dEdx, responseFunction, kTRUE, kFALSE);
565 // GetMultiplicityCorrection and GetMultiplicitySigmaCorrection both need the eta corrected dEdxExpected
566 Double_t multiplicityCorrFactor = GetMultiplicityCorrectionFast(track, dEdxExpectedEtaCorrected, fCurrentEventMultiplicity);
567 Double_t multiplicitySigmaCorrFactor = GetMultiplicitySigmaCorrectionFast(dEdxExpectedEtaCorrected, fCurrentEventMultiplicity);
569 // multiplicityCorrFactor to correct dEdxExpected for multiplicity. In addition: Correction factor for sigma
570 return (dEdxExpectedEtaCorrected * multiplicityCorrFactor)
571 * (sqrt(fSigmaPar0 * fSigmaPar0 + sigmaPar1 * sigmaPar1 / nPoints) * multiplicitySigmaCorrFactor);
574 return GetExpectedSignal(track, species, dEdx, responseFunction, kTRUE, kFALSE)*
575 sqrt(fSigmaPar0 * fSigmaPar0 + sigmaPar1 * sigmaPar1 / nPoints);
579 // One should never have/take tracks with 0 dEdx clusters!
585 //_________________________________________________________________________
586 Double_t AliTPCPIDResponse::GetExpectedSigma(const AliVTrack* track,
587 AliPID::EParticleType species,
588 ETPCdEdxSource dedxSource,
590 Bool_t correctMultiplicity) const
592 // Calculates the expected sigma of the PID signal as the function of
593 // the information stored in the track, for the specified particle type
599 ETPCgainScenario gainScenario = kGainScenarioInvalid;
600 TSpline3* responseFunction = 0x0;
602 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
603 return 999; //TODO: better handling!
605 return GetExpectedSigma(track, species, gainScenario, dEdx, nPoints, responseFunction, correctEta, correctMultiplicity);
609 //_________________________________________________________________________
610 Float_t AliTPCPIDResponse::GetNumberOfSigmas(const AliVTrack* track,
611 AliPID::EParticleType species,
612 ETPCdEdxSource dedxSource,
614 Bool_t correctMultiplicity) const
616 //Calculates the number of sigmas of the PID signal from the expected value
617 //for a given particle species in the presence of multiple gain scenarios
622 ETPCgainScenario gainScenario = kGainScenarioInvalid;
623 TSpline3* responseFunction = 0x0;
625 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
626 return -999; //TODO: Better handling!
628 Double_t bethe = GetExpectedSignal(track, species, dEdx, responseFunction, correctEta, correctMultiplicity);
629 Double_t sigma = GetExpectedSigma(track, species, gainScenario, dEdx, nPoints, responseFunction, correctEta, correctMultiplicity);
630 // 999 will be returned by GetExpectedSigma e.g. in case of 0 dEdx clusters
634 return (dEdx-bethe)/sigma;
637 //_________________________________________________________________________
638 Float_t AliTPCPIDResponse::GetSignalDelta(const AliVTrack* track,
639 AliPID::EParticleType species,
640 ETPCdEdxSource dedxSource,
642 Bool_t correctMultiplicity,
643 Bool_t ratio/*=kFALSE*/)const
645 //Calculates the number of sigmas of the PID signal from the expected value
646 //for a given particle species in the presence of multiple gain scenarios
651 ETPCgainScenario gainScenario = kGainScenarioInvalid;
652 TSpline3* responseFunction = 0x0;
654 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
655 return -9999.; //TODO: Better handling!
657 const Double_t bethe = GetExpectedSignal(track, species, dEdx, responseFunction, correctEta, correctMultiplicity);
659 Double_t delta=-9999.;
660 if (!ratio) delta=dEdx-bethe;
661 else if (bethe>1.e-20) delta=dEdx/bethe;
666 //_________________________________________________________________________
667 Bool_t AliTPCPIDResponse::ResponseFunctiondEdxN( const AliVTrack* track,
668 AliPID::EParticleType species,
669 ETPCdEdxSource dedxSource,
672 ETPCgainScenario& gainScenario,
673 TSpline3** responseFunction) const
675 // Calculates the right parameters for PID
676 // dEdx parametrization for the proper gain scenario, dEdx
677 // and NPoints used for dEdx
678 // based on the track geometry (which chambers it crosses) for the specified particle type
679 // and preferred source of dedx.
680 // returns true on success
683 if (dedxSource == kdEdxDefault) {
684 // Fast handling for default case. In addition: Keep it simple (don't call additional functions) to
685 // avoid possible bugs
687 // GetTPCsignalTunedOnData will be non-positive, if it has not been set (i.e. in case of MC NOT tuned to data).
688 // If this is the case, just take the normal signal
689 dEdx = track->GetTPCsignalTunedOnData();
691 dEdx = track->GetTPCsignal();
694 nPoints = track->GetTPCsignalN();
695 gainScenario = kDefault;
697 TObject* obj = fResponseFunctions.UncheckedAt(ResponseFunctionIndex(species,gainScenario));
698 *responseFunction = dynamic_cast<TSpline3*>(obj); //TODO:maybe static cast?
703 //TODO Proper handle of tuneMConData for other dEdx sources
705 Double32_t signal[4]; //0: IROC, 1: OROC medium, 2:OROC long, 3: OROC all (def. truncation used)
706 Char_t ncl[3]; //same
707 Char_t nrows[3]; //same
708 const AliTPCdEdxInfo* dEdxInfo = track->GetTPCdEdxInfo();
710 if (!dEdxInfo && dedxSource!=kdEdxDefault) //in one case its ok if we dont have the info
712 AliError("AliTPCdEdxInfo not available");
716 if (dEdxInfo) dEdxInfo->GetTPCSignalRegionInfo(signal,ncl,nrows);
718 //check if we cross a bad OROC in which case we reject
719 EChamberStatus trackOROCStatus = TrackStatus(track,2);
720 if (trackOROCStatus==kChamberOff || trackOROCStatus==kChamberLowGain)
729 if (trackOROCStatus==kChamberInvalid) return kFALSE; //never reached OROC
731 nPoints = ncl[2]+ncl[1];
732 gainScenario = kOROChigh;
737 //if we cross a bad IROC we use OROC dedx, if we dont we use combined
738 EChamberStatus status = TrackStatus(track,1);
739 if (status!=kChamberHighGain)
742 nPoints = ncl[2]+ncl[1];
743 gainScenario = kOROChigh;
747 dEdx = track->GetTPCsignal();
748 nPoints = track->GetTPCsignalN();
749 gainScenario = kALLhigh;
757 gainScenario = kGainScenarioInvalid;
761 TObject* obj = fResponseFunctions.UncheckedAt(ResponseFunctionIndex(species,gainScenario));
762 *responseFunction = dynamic_cast<TSpline3*>(obj); //TODO:maybe static cast?
768 //_________________________________________________________________________
769 Double_t AliTPCPIDResponse::GetEtaCorrectionFast(const AliVTrack *track, Double_t dEdxSplines) const
771 // NOTE: For expert use only -> Non-experts are advised to use the function without the "Fast" suffix or stick to AliPIDResponse directly.
773 // Get eta correction for the given parameters.
777 // Calling this function means to request eta correction in some way. Print error message, if no map is available!
778 AliError("Eta correction requested, but map not initialised (usually via AliPIDResponse). Returning eta correction factor 1!");
782 Double_t tpcSignal = dEdxSplines;
787 Double_t tanTheta = GetTrackTanTheta(track);
788 Int_t binX = fhEtaCorr->GetXaxis()->FindFixBin(tanTheta);
789 Int_t binY = fhEtaCorr->GetYaxis()->FindFixBin(1. / tpcSignal);
793 if (binX > fhEtaCorr->GetXaxis()->GetNbins())
794 binX = fhEtaCorr->GetXaxis()->GetNbins();
798 if (binY > fhEtaCorr->GetYaxis()->GetNbins())
799 binY = fhEtaCorr->GetYaxis()->GetNbins();
801 return fhEtaCorr->GetBinContent(binX, binY);
805 //_________________________________________________________________________
806 Double_t AliTPCPIDResponse::GetEtaCorrection(const AliVTrack *track, AliPID::EParticleType species, ETPCdEdxSource dedxSource) const
809 // Get eta correction for the given track.
817 ETPCgainScenario gainScenario = kGainScenarioInvalid;
818 TSpline3* responseFunction = 0x0;
820 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
823 // For the eta correction, do NOT take the multiplicity corrected value of dEdx
824 Double_t dEdxSplines = GetExpectedSignal(track, species, dEdx, responseFunction, kFALSE, kFALSE);
826 //TODO Alternatively take current track dEdx
827 //return GetEtaCorrectionFast(track, dEdx);
829 return GetEtaCorrectionFast(track, dEdxSplines);
833 //_________________________________________________________________________
834 Double_t AliTPCPIDResponse::GetEtaCorrectedTrackdEdx(const AliVTrack *track, AliPID::EParticleType species, ETPCdEdxSource dedxSource) const
837 // Get eta corrected dEdx for the given track. For the correction, the expected dEdx of
838 // the specified species will be used. If the species is set to AliPID::kUnknown, the
839 // dEdx of the track is used instead.
840 // WARNING: In the latter case, the eta correction might not be as good as if the
841 // expected dEdx is used, which is the way the correction factor is designed
843 // In any case, one has to decide carefully to which expected signal one wants to
844 // compare the corrected value - to the corrected or uncorrected.
845 // Anyhow, a safer way of looking e.g. at the n-sigma is to call
846 // the corresponding function GetNumberOfSigmas!
851 ETPCgainScenario gainScenario = kGainScenarioInvalid;
852 TSpline3* responseFunction = 0x0;
854 // Note: In case of species == AliPID::kUnknown, the responseFunction might not be set. However, in this case
855 // it is not used anyway, so this causes no trouble.
856 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
859 Double_t etaCorr = 0.;
861 if (species < AliPID::kUnknown) {
862 // For the eta correction, do NOT take the multiplicity corrected value of dEdx
863 Double_t dEdxSplines = GetExpectedSignal(track, species, dEdx, responseFunction, kFALSE, kFALSE);
864 etaCorr = GetEtaCorrectionFast(track, dEdxSplines);
867 etaCorr = GetEtaCorrectionFast(track, dEdx);
873 return dEdx / etaCorr;
877 //_________________________________________________________________________
878 Double_t AliTPCPIDResponse::GetSigmaPar1Fast(const AliVTrack *track, AliPID::EParticleType species, Double_t dEdx,
879 const TSpline3* responseFunction) const
881 // NOTE: For expert use only -> Non-experts are advised to use the function without the "Fast" suffix or stick to AliPIDResponse directly.
883 // Get parameter 1 of sigma parametrisation of TPC dEdx from the histogram for the given track.
886 if (!fhEtaSigmaPar1) {
887 // Calling this function means to request new sigma parametrisation in some way. Print error message, if no map is available!
888 AliError("New sigma parametrisation requested, but sigma map not initialised (usually via AliPIDResponse). Returning error value for sigma parameter1 = 999!");
892 // The sigma maps are created with data sets that are already eta corrected and for which the
893 // splines have been re-created. Therefore, the value for the lookup needs to be the value of
894 // the splines without any additional eta correction.
895 // NOTE: This is due to the method the maps are created. The track dEdx (not the expected one!)
896 // is corrected to uniquely related a momemtum bin with an expected dEdx, where the expected dEdx
897 // equals the track dEdx for all eta (thanks to the correction and the re-fit of the splines).
898 // Consequently, looking up the uncorrected expected dEdx at a given tanTheta yields the correct
900 // Also: It has to be the spline dEdx, since one wants to get the sigma for the assumption(!)
901 // of such a particle, which by assumption then has this dEdx value
903 // For the eta correction, do NOT take the multiplicity corrected value of dEdx
904 Double_t dEdxExpected = GetExpectedSignal(track, species, dEdx, responseFunction, kFALSE, kFALSE);
906 if (dEdxExpected < 1.)
909 Double_t tanTheta = GetTrackTanTheta(track);
910 Int_t binX = fhEtaSigmaPar1->GetXaxis()->FindFixBin(tanTheta);
911 Int_t binY = fhEtaSigmaPar1->GetYaxis()->FindFixBin(1. / dEdxExpected);
915 if (binX > fhEtaSigmaPar1->GetXaxis()->GetNbins())
916 binX = fhEtaSigmaPar1->GetXaxis()->GetNbins();
920 if (binY > fhEtaSigmaPar1->GetYaxis()->GetNbins())
921 binY = fhEtaSigmaPar1->GetYaxis()->GetNbins();
923 return fhEtaSigmaPar1->GetBinContent(binX, binY);
927 //_________________________________________________________________________
928 Double_t AliTPCPIDResponse::GetSigmaPar1(const AliVTrack *track, AliPID::EParticleType species, ETPCdEdxSource dedxSource) const
931 // Get parameter 1 of sigma parametrisation of TPC dEdx from the histogram for the given track.
939 ETPCgainScenario gainScenario = kGainScenarioInvalid;
940 TSpline3* responseFunction = 0x0;
942 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
945 return GetSigmaPar1Fast(track, species, dEdx, responseFunction);
949 //_________________________________________________________________________
950 Bool_t AliTPCPIDResponse::SetEtaCorrMap(TH2D* hMap)
953 // Load map for TPC eta correction (a copy is stored and will be deleted automatically).
954 // If hMap is 0x0,the eta correction will be disabled and kFALSE is returned.
955 // If the map can be set, kTRUE is returned.
966 fhEtaCorr = (TH2D*)(hMap->Clone());
967 fhEtaCorr->SetDirectory(0);
973 //_________________________________________________________________________
974 Bool_t AliTPCPIDResponse::SetSigmaParams(TH2D* hSigmaPar1Map, Double_t sigmaPar0)
977 // Load map for TPC sigma map (a copy is stored and will be deleted automatically):
978 // Parameter 1 is stored as a 2D map (1/dEdx vs. tanTheta_local) and parameter 0 is
979 // a constant. If hSigmaPar1Map is 0x0, the old sigma parametrisation will be used
980 // (and sigmaPar0 is ignored!) and kFALSE is returned.
981 // If the map can be set, sigmaPar0 is also set and kTRUE will be returned.
984 delete fhEtaSigmaPar1;
986 if (!hSigmaPar1Map) {
987 fhEtaSigmaPar1 = 0x0;
993 fhEtaSigmaPar1 = (TH2D*)(hSigmaPar1Map->Clone());
994 fhEtaSigmaPar1->SetDirectory(0);
995 fSigmaPar0 = sigmaPar0;
1001 //_________________________________________________________________________
1002 Double_t AliTPCPIDResponse::GetTrackTanTheta(const AliVTrack *track) const
1004 // Extract the tanTheta from the information available in the AliVTrack
1006 // For ESD tracks, the local tanTheta could be used (esdTrack->GetInnerParam()->GetTgl()).
1007 // However, this value is not available for AODs and, thus, not for AliVTrack.
1008 // Fortunately, the following formula allows to approximate the local tanTheta with the
1009 // global theta angle -> This is for by far most of the tracks the same, but gives at
1010 // maybe the percent level differences within +- 0.2 in tanTheta -> Which is still ok.
1013 const AliExternalTrackParam* innerParam = track->GetInnerParam();
1014 Double_t tanTheta = 0;
1016 tanTheta = innerParam->GetTgl();
1018 tanTheta = TMath::Tan(-track->Theta() + TMath::Pi() / 2.0);
1020 // Constant in formula for B in kGauss (factor 0.1 to convert B from Tesla to kGauss),
1021 // 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)
1022 const Double_t constant = TMath::C()* 1e-9 * 0.1 * 0.01;
1023 const Double_t curvature = fMagField * constant / track->Pt(); // in 1./cm
1025 Double_t averageddzdr = 0.;
1028 for (Double_t r = 85; r < 245; r++) {
1029 Double_t sinPhiLocal = TMath::Abs(r*curvature*0.5);
1031 // Cut on |sin(phi)| as during reco
1032 if (TMath::Abs(sinPhiLocal) <= 0.95) {
1033 const Double_t phiLocal = TMath::ASin(sinPhiLocal);
1034 const Double_t tanPhiLocal = TMath::Tan(phiLocal);
1036 averageddzdr += tanTheta * TMath::Sqrt(1. + tanPhiLocal * tanPhiLocal);
1042 averageddzdr /= nParts;
1044 AliError("Problems during determination of dz/dr. Returning pure tanTheta as best estimate!");
1048 //printf("pT: %f\nFactor/magField(kGs)/curvature^-1: %f / %f /%f\ntanThetaGlobalFromTheta/tanTheta/Averageddzdr: %f / %f / %f\n\n",
1049 // track->Pt(), constant, fMagField, 1./curvature, TMath::Tan(-track->Theta() + TMath::Pi() / 2.0), tanTheta, averageddzdr);
1051 return averageddzdr;
1055 // Alternatively (in average, the effect is found to be negligable!):
1056 // Take local tanTheta from TPC inner wall, if available (currently only for ESDs available)
1057 //const AliExternalTrackParam* innerParam = track->GetInnerParam();
1059 // return innerParam->GetTgl();
1062 return TMath::Tan(-track->Theta() + TMath::Pi() / 2.0);
1066 //_________________________________________________________________________
1067 Double_t AliTPCPIDResponse::GetMultiplicityCorrectionFast(const AliVTrack *track, Double_t dEdxExpected, Int_t multiplicity) const
1069 // NOTE: For expert use only -> Non-experts are advised to use the function without the "Fast" suffix or stick to AliPIDResponse directly.
1071 // Calculate the multiplicity correction factor for this track for the given multiplicity.
1072 // The parameter dEdxExpected should take into account the eta correction already!
1074 // Multiplicity depends on pure dEdx. Therefore, correction factor depends indirectly on eta
1075 // => Use eta corrected value for dEdexExpected.
1077 if (dEdxExpected <= 0 || multiplicity <= 0)
1080 const Double_t dEdxExpectedInv = 1. / dEdxExpected;
1081 Double_t relSlope = fCorrFuncMultiplicity->Eval(dEdxExpectedInv);
1083 const Double_t tanTheta = GetTrackTanTheta(track);
1084 relSlope += fCorrFuncMultiplicityTanTheta->Eval(tanTheta);
1086 return (1. + relSlope * multiplicity);
1090 //_________________________________________________________________________
1091 Double_t AliTPCPIDResponse::GetMultiplicityCorrection(const AliVTrack *track, AliPID::EParticleType species, ETPCdEdxSource dedxSource) const
1094 // Get multiplicity correction for the given track (w.r.t. the mulitplicity of the current event)
1097 //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
1099 // No correction in case of multiplicity <= 0
1100 if (fCurrentEventMultiplicity <= 0)
1105 ETPCgainScenario gainScenario = kGainScenarioInvalid;
1106 TSpline3* responseFunction = 0x0;
1108 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
1111 //TODO Does it make sense to use the multiplicity correction WITHOUT eta correction?! Are the fit parameters still valid?
1112 // To get the expected signal to determine the multiplicity correction, do NOT ask for the multiplicity corrected value (of course)
1113 Double_t dEdxExpected = GetExpectedSignal(track, species, dEdx, responseFunction, kTRUE, kFALSE);
1115 return GetMultiplicityCorrectionFast(track, dEdxExpected, fCurrentEventMultiplicity);
1119 //_________________________________________________________________________
1120 Double_t AliTPCPIDResponse::GetMultiplicityCorrectedTrackdEdx(const AliVTrack *track, AliPID::EParticleType species, ETPCdEdxSource dedxSource) const
1123 // Get multiplicity corrected dEdx for the given track. For the correction, the expected dEdx of
1124 // the specified species will be used. If the species is set to AliPID::kUnknown, the
1125 // dEdx of the track is used instead.
1126 // WARNING: In the latter case, the correction might not be as good as if the
1127 // expected dEdx is used, which is the way the correction factor is designed
1129 // In any case, one has to decide carefully to which expected signal one wants to
1130 // compare the corrected value - to the corrected or uncorrected.
1131 // Anyhow, a safer way of looking e.g. at the n-sigma is to call
1132 // the corresponding function GetNumberOfSigmas!
1135 //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
1139 ETPCgainScenario gainScenario = kGainScenarioInvalid;
1140 TSpline3* responseFunction = 0x0;
1142 // Note: In case of species == AliPID::kUnknown, the responseFunction might not be set. However, in this case
1143 // it is not used anyway, so this causes no trouble.
1144 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
1148 // No correction in case of multiplicity <= 0
1149 if (fCurrentEventMultiplicity <= 0)
1152 Double_t multiplicityCorr = 0.;
1154 // 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?
1155 if (species < AliPID::kUnknown) {
1156 // To get the expected signal to determine the multiplicity correction, do NOT ask for the multiplicity corrected value (of course).
1157 // However, one needs the eta corrected value!
1158 Double_t dEdxSplines = GetExpectedSignal(track, species, dEdx, responseFunction, kTRUE, kFALSE);
1159 multiplicityCorr = GetMultiplicityCorrectionFast(track, dEdxSplines, fCurrentEventMultiplicity);
1162 // One needs the eta corrected value to determine the multiplicity correction factor!
1163 Double_t etaCorr = GetEtaCorrectionFast(track, dEdx);
1164 multiplicityCorr = GetMultiplicityCorrectionFast(track, dEdx * etaCorr, fCurrentEventMultiplicity);
1167 if (multiplicityCorr <= 0)
1170 return dEdx / multiplicityCorr;
1174 //_________________________________________________________________________
1175 Double_t AliTPCPIDResponse::GetEtaAndMultiplicityCorrectedTrackdEdx(const AliVTrack *track, AliPID::EParticleType species,
1176 ETPCdEdxSource dedxSource) const
1179 // Get multiplicity and eta corrected dEdx for the given track. For the correction,
1180 // the expected dEdx of the specified species will be used. If the species is set
1181 // to AliPID::kUnknown, the dEdx of the track is used instead.
1182 // WARNING: In the latter case, the correction might not be as good as if the
1183 // expected dEdx is used, which is the way the correction factor is designed
1185 // In any case, one has to decide carefully to which expected signal one wants to
1186 // compare the corrected value - to the corrected or uncorrected.
1187 // Anyhow, a safer way of looking e.g. at the n-sigma is to call
1188 // the corresponding function GetNumberOfSigmas!
1193 ETPCgainScenario gainScenario = kGainScenarioInvalid;
1194 TSpline3* responseFunction = 0x0;
1196 // Note: In case of species == AliPID::kUnknown, the responseFunction might not be set. However, in this case
1197 // it is not used anyway, so this causes no trouble.
1198 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
1201 Double_t multiplicityCorr = 0.;
1202 Double_t etaCorr = 0.;
1204 if (species < AliPID::kUnknown) {
1205 // To get the expected signal to determine the multiplicity correction, do NOT ask for the multiplicity corrected value (of course)
1206 Double_t dEdxSplines = GetExpectedSignal(track, species, dEdx, responseFunction, kFALSE, kFALSE);
1207 etaCorr = GetEtaCorrectionFast(track, dEdxSplines);
1208 multiplicityCorr = GetMultiplicityCorrectionFast(track, dEdxSplines * etaCorr, fCurrentEventMultiplicity);
1211 etaCorr = GetEtaCorrectionFast(track, dEdx);
1212 multiplicityCorr = GetMultiplicityCorrectionFast(track, dEdx * etaCorr, fCurrentEventMultiplicity);
1215 if (multiplicityCorr <= 0 || etaCorr <= 0)
1218 return dEdx / multiplicityCorr / etaCorr;
1222 //_________________________________________________________________________
1223 Double_t AliTPCPIDResponse::GetMultiplicitySigmaCorrectionFast(Double_t dEdxExpected, Int_t multiplicity) const
1225 // NOTE: For expert use only -> Non-experts are advised to use the function without the "Fast" suffix or stick to AliPIDResponse directly.
1227 // Calculate the multiplicity sigma correction factor for the corresponding expected dEdx and for the given multiplicity.
1228 // The parameter dEdxExpected should take into account the eta correction already!
1230 // Multiplicity dependence of sigma depends on the real dEdx at zero multiplicity,
1231 // i.e. the eta (only) corrected dEdxExpected value has to be used
1232 // since all maps etc. have been created for ~zero multiplicity
1234 if (dEdxExpected <= 0 || multiplicity <= 0)
1237 Double_t relSigmaSlope = fCorrFuncSigmaMultiplicity->Eval(1. / dEdxExpected);
1239 return (1. + relSigmaSlope * multiplicity);
1243 //_________________________________________________________________________
1244 Double_t AliTPCPIDResponse::GetMultiplicitySigmaCorrection(const AliVTrack *track, AliPID::EParticleType species, ETPCdEdxSource dedxSource) const
1247 // Get multiplicity sigma correction for the given track (w.r.t. the mulitplicity of the current event)
1250 //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
1252 // No correction in case of multiplicity <= 0
1253 if (fCurrentEventMultiplicity <= 0)
1258 ETPCgainScenario gainScenario = kGainScenarioInvalid;
1259 TSpline3* responseFunction = 0x0;
1261 if (!ResponseFunctiondEdxN(track, species, dedxSource, dEdx, nPoints, gainScenario, &responseFunction))
1264 //TODO Does it make sense to use the multiplicity correction WITHOUT eta correction?! Are the fit parameters still valid?
1265 // To get the expected signal to determine the multiplicity correction, do NOT ask for the multiplicity corrected value (of course)
1266 Double_t dEdxExpected = GetExpectedSignal(track, species, dEdx, responseFunction, kTRUE, kFALSE);
1268 return GetMultiplicitySigmaCorrectionFast(dEdxExpected, fCurrentEventMultiplicity);
1272 //_________________________________________________________________________
1273 void AliTPCPIDResponse::ResetMultiplicityCorrectionFunctions()
1275 // Default values: No correction, i.e. overall correction factor should be one
1277 // This function should always return 0.0, if multcorr disabled
1278 fCorrFuncMultiplicity->SetParameter(0, 0.);
1279 fCorrFuncMultiplicity->SetParameter(1, 0.);
1280 fCorrFuncMultiplicity->SetParameter(2, 0.);
1281 fCorrFuncMultiplicity->SetParameter(3, 0.);
1282 fCorrFuncMultiplicity->SetParameter(4, 0.);
1284 // This function should always return 0., if multCorr disabled
1285 fCorrFuncMultiplicityTanTheta->SetParameter(0, 0.);
1286 fCorrFuncMultiplicityTanTheta->SetParameter(1, 0.);
1287 fCorrFuncMultiplicityTanTheta->SetParameter(2, 0.);
1289 // This function should always return 0.0, if mutlcorr disabled
1290 fCorrFuncSigmaMultiplicity->SetParameter(0, 0.);
1291 fCorrFuncSigmaMultiplicity->SetParameter(1, 0.);
1292 fCorrFuncSigmaMultiplicity->SetParameter(2, 0.);
1293 fCorrFuncSigmaMultiplicity->SetParameter(3, 0.);
1297 //_________________________________________________________________________
1298 Bool_t AliTPCPIDResponse::sectorNumbersInOut(Double_t* trackPositionInner,
1299 Double_t* trackPositionOuter,
1305 //calculate the sector numbers (equivalent to IROC chamber numbers) a track crosses
1306 //for OROC chamber numbers add 36
1307 //returned angles are between (0,2pi)
1309 inphi = TMath::ATan2(trackPositionInner[1],trackPositionInner[0]);
1310 outphi = TMath::ATan2(trackPositionOuter[1], trackPositionOuter[0]);
1312 if (inphi<0) {inphi+=TMath::TwoPi();} //because ATan2 gives angles between -pi,pi
1313 if (outphi<0) {outphi+=TMath::TwoPi();} //because ATan2 gives angles between -pi,pi
1315 in = sectorNumber(inphi);
1316 out = sectorNumber(outphi);
1318 //for the C side (positive z) offset by 18
1319 if (trackPositionInner[2]>0.0)
1328 //_____________________________________________________________________________
1329 Int_t AliTPCPIDResponse::sectorNumber(Double_t phi) const
1331 //calculate sector number
1332 const Float_t width=TMath::TwoPi()/18.;
1333 return TMath::Floor(phi/width);
1337 //_____________________________________________________________________________
1338 void AliTPCPIDResponse::Print(Option_t* /*option*/) const
1341 fResponseFunctions.Print();
1345 //_____________________________________________________________________________
1346 AliTPCPIDResponse::EChamberStatus AliTPCPIDResponse::TrackStatus(const AliVTrack* track, Int_t layer) const
1348 //status of the track: if it crosses any bad chambers return kChamberOff;
1349 //IROC:layer=1, OROC:layer=2
1350 if (layer<1 || layer>2) layer=1;
1355 Float_t innerRadius = (layer==1)?83.0:133.7;
1356 Float_t outerRadius = (layer==1)?133.5:247.7;
1358 /////////////////////////////////////////////////////////////////////////////
1359 //find out where track enters and leaves the layer.
1361 Double_t trackPositionInner[3];
1362 Double_t trackPositionOuter[3];
1364 //if there is no inner param this could mean we're using the AOD track,
1365 //we still can extrapolate from the vertex - so use those params.
1366 const AliExternalTrackParam* ip = track->GetInnerParam();
1369 Bool_t trackAtInner = track->GetXYZAt(innerRadius, fMagField, trackPositionInner);
1370 Bool_t trackAtOuter = track->GetXYZAt(outerRadius, fMagField, trackPositionOuter);
1374 //if we dont even enter inner radius we do nothing and return invalid
1379 return kChamberInvalid;
1384 //if we don't reach the outer radius check that the apex is indeed within the outer radius and use apex position
1385 Bool_t haveApex = TrackApex(track, fMagField, trackPositionOuter);
1386 Float_t apexRadius = TMath::Sqrt(trackPositionOuter[0]*trackPositionOuter[0]+trackPositionOuter[1]*trackPositionOuter[1]);
1387 if ( haveApex && apexRadius<=outerRadius && apexRadius>innerRadius)
1389 //printf("pt: %.2f, apexRadius: %.2f(%s), x: %.2f, y: %.2f\n",track->Pt(),apexRadius,(haveApex)?"OK":"BAD",trackPositionOuter[0],trackPositionOuter[1]);
1397 return kChamberInvalid;
1402 if (!sectorNumbersInOut(trackPositionInner,
1407 out)) return kChamberInvalid;
1409 /////////////////////////////////////////////////////////////////////////////
1410 //now we have the location of the track we can check
1411 //if it is in a good/bad chamber
1413 Bool_t sideA = kTRUE;
1415 if (((in/18)%2==1) && ((out/18)%2==1)) sideA=kFALSE;
1420 if (TMath::Abs(in-out)>9)
1422 if (TMath::Max(in,out)==out)
1427 Float_t tmpphi=outphi;
1432 inphi-=TMath::TwoPi();
1436 if (TMath::Max(in,out)==in)
1441 Float_t tmpphi=outphi;
1447 Float_t trackLengthInBad = 0.;
1448 Float_t trackLengthInLowGain = 0.;
1449 Float_t trackLengthTotal = TMath::Abs(outphi-inphi);
1450 Float_t lengthFractionInBadSectors = 0.;
1452 const Float_t sectorWidth = TMath::TwoPi()/18.;
1454 for (Int_t i=in; i<=out; i++)
1457 if (i<0) j+=18; //correct for the negative values
1458 if (!sideA) j+=18; //move to the correct side
1460 Float_t deltaPhi = 0.;
1461 Float_t phiEdge=sectorWidth*i;
1462 if (inphi>phiEdge) {deltaPhi=phiEdge+sectorWidth-inphi;}
1463 else if ((outphi>=phiEdge) && (outphi<(phiEdge+sectorWidth))) {deltaPhi=outphi-phiEdge;}
1464 else {deltaPhi=sectorWidth;}
1466 Float_t v = fVoltageMap[(layer==1)?(j):(j+36)];
1467 if (v<=fBadIROCthreshhold)
1469 trackLengthInBad+=deltaPhi;
1470 lengthFractionInBadSectors=1.;
1472 if (v<=fLowGainIROCthreshold && v>fBadIROCthreshhold)
1474 trackLengthInLowGain+=deltaPhi;
1475 lengthFractionInBadSectors=1.;
1479 //for now low gain and bad (off) chambers are treated equally
1480 if (trackLengthTotal>0)
1481 lengthFractionInBadSectors = (trackLengthInLowGain+trackLengthInBad)/trackLengthTotal;
1483 //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);
1485 if (lengthFractionInBadSectors>fMaxBadLengthFraction)
1487 //printf("%%%%%%%% %s kChamberLowGain\n",(layer==1)?"IROC":"OROC");
1488 return kChamberLowGain;
1491 return kChamberHighGain;
1495 //_____________________________________________________________________________
1496 Float_t AliTPCPIDResponse::MaxClusterRadius(const AliVTrack* track) const
1498 //return the radius of the outermost padrow containing a cluster in TPC
1500 const TBits* clusterMap=track->GetTPCClusterMapPtr();
1501 if (!clusterMap) return 0.;
1503 //from AliTPCParam, radius of first IROC row
1504 const Float_t rfirstIROC = 8.52249984741210938e+01;
1505 const Float_t padrowHeightIROC = 0.75;
1506 const Float_t rfirstOROC0 = 1.35100006103515625e+02;
1507 const Float_t padrowHeightOROC0 = 1.0;
1508 const Float_t rfirstOROC1 = 1.99350006103515625e+02;
1509 const Float_t padrowHeightOROC1 = 1.5;
1511 Int_t maxPadRow=160;
1512 while ((--maxPadRow)>0 && !clusterMap->TestBitNumber(maxPadRow)){}
1513 if (maxPadRow>126) return rfirstOROC1+(maxPadRow-126-1)*padrowHeightOROC1;
1514 if (maxPadRow>62) return rfirstOROC0+(maxPadRow-62-1)*padrowHeightOROC0;
1515 if (maxPadRow>0) return rfirstIROC+(maxPadRow-1)*padrowHeightIROC;
1520 //_____________________________________________________________________________
1521 Bool_t AliTPCPIDResponse::TrackApex(const AliVTrack* track, Float_t magField, Double_t position[3]) const
1523 //calculate the coordinates of the apex of the track
1527 track->GetPxPyPz(p);
1528 Double_t r = 1./track->OneOverPt()/0.0299792458/magField; //signed - will determine the direction of b
1529 //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);
1530 //find orthogonal vector (Gram-Schmidt)
1531 Double_t alpha = (p[0]*x[0] + p[1]*x[1])/(p[0]*p[0] + p[1]*p[1]);
1533 b[0]=x[0]-alpha*p[0];
1534 b[1]=x[1]-alpha*p[1];
1536 Double_t norm = TMath::Sqrt(b[0]*b[0]+b[1]*b[1]);
1537 if (TMath::AreEqualAbs(norm,0.0,1e-10)) return kFALSE;
1544 //printf("center: x:%.2f, y:%.2f\n",b[0],b[1]);
1546 norm = TMath::Sqrt(b[0]*b[0]+b[1]*b[1]);
1547 if (TMath::AreEqualAbs(norm,0.0,1e-10)) return kFALSE;
1549 position[0]=b[0]+b[0]*TMath::Abs(r)/norm;
1550 position[1]=b[1]+b[1]*TMath::Abs(r)/norm;